feat: add radio element #494
Co-authored-by: jeffycai <caixiaobing@live.cn> Co-authored-by: Hufe921 <huangyunfeihufe@hotmail.com>
This commit is contained in:
co-authored by
jeffycai
Hufe921
parent
2e1403507f
commit
c6d9cffc27
@@ -65,6 +65,7 @@ import {
|
||||
import { Control } from './control/Control'
|
||||
import { getSlimCloneElementList, zipElementList } from '../../utils/element'
|
||||
import { CheckboxParticle } from './particle/CheckboxParticle'
|
||||
import { RadioParticle } from './particle/RadioParticle'
|
||||
import { DeepRequired, IPadding } from '../../interface/Common'
|
||||
import {
|
||||
ControlComponent,
|
||||
@@ -142,6 +143,7 @@ export class Draw {
|
||||
private superscriptParticle: SuperscriptParticle
|
||||
private subscriptParticle: SubscriptParticle
|
||||
private checkboxParticle: CheckboxParticle
|
||||
private radioParticle: RadioParticle
|
||||
private blockParticle: BlockParticle
|
||||
private listParticle: ListParticle
|
||||
private lineBreakParticle: LineBreakParticle
|
||||
@@ -216,6 +218,7 @@ export class Draw {
|
||||
this.superscriptParticle = new SuperscriptParticle()
|
||||
this.subscriptParticle = new SubscriptParticle()
|
||||
this.checkboxParticle = new CheckboxParticle(this)
|
||||
this.radioParticle = new RadioParticle(this)
|
||||
this.blockParticle = new BlockParticle(this)
|
||||
this.listParticle = new ListParticle(this)
|
||||
this.lineBreakParticle = new LineBreakParticle(this)
|
||||
@@ -751,6 +754,10 @@ export class Draw {
|
||||
return this.checkboxParticle
|
||||
}
|
||||
|
||||
public getRadioParticle(): RadioParticle {
|
||||
return this.radioParticle
|
||||
}
|
||||
|
||||
public getControl(): Control {
|
||||
return this.control
|
||||
}
|
||||
@@ -1414,6 +1421,15 @@ export class Draw {
|
||||
element.width = availableWidth / scale
|
||||
metrics.width = availableWidth
|
||||
metrics.height = defaultSize
|
||||
} else if (
|
||||
element.type === ElementType.RADIO ||
|
||||
element.controlComponent === ControlComponent.RADIO
|
||||
) {
|
||||
const { width, height, gap } = this.options.radio
|
||||
const elementWidth = width + gap * 2
|
||||
element.width = elementWidth
|
||||
metrics.width = elementWidth * scale
|
||||
metrics.height = height * scale
|
||||
} else if (
|
||||
element.type === ElementType.CHECKBOX ||
|
||||
element.controlComponent === ControlComponent.CHECKBOX
|
||||
@@ -1805,6 +1821,12 @@ export class Draw {
|
||||
) {
|
||||
this.textParticle.complete()
|
||||
this.checkboxParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (
|
||||
element.type === ElementType.RADIO ||
|
||||
element.controlComponent === ControlComponent.RADIO
|
||||
) {
|
||||
this.textParticle.complete()
|
||||
this.radioParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.TAB) {
|
||||
this.textParticle.complete()
|
||||
} else if (element.rowFlex === RowFlex.ALIGNMENT) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import { Listener } from '../../listener/Listener'
|
||||
import { RangeManager } from '../../range/RangeManager'
|
||||
import { Draw } from '../Draw'
|
||||
import { CheckboxControl } from './checkbox/CheckboxControl'
|
||||
import { RadioControl } from './radio/RadioControl'
|
||||
import { ControlSearch } from './interactive/ControlSearch'
|
||||
import { ControlBorder } from './richtext/Border'
|
||||
import { SelectControl } from './select/SelectControl'
|
||||
@@ -236,6 +237,8 @@ export class Control {
|
||||
selectControl.awake()
|
||||
} else if (control.type === ControlType.CHECKBOX) {
|
||||
this.activeControl = new CheckboxControl(element, this)
|
||||
} else if (control.type === ControlType.RADIO) {
|
||||
this.activeControl = new RadioControl(element, this)
|
||||
}
|
||||
// 激活控件回调
|
||||
nextTick(() => {
|
||||
@@ -522,7 +525,8 @@ export class Control {
|
||||
})
|
||||
} else if (
|
||||
type === ControlType.SELECT ||
|
||||
type === ControlType.CHECKBOX
|
||||
type === ControlType.CHECKBOX ||
|
||||
type === ControlType.RADIO
|
||||
) {
|
||||
const innerText = code
|
||||
?.split(',')
|
||||
@@ -629,6 +633,10 @@ export class Control {
|
||||
const checkbox = new CheckboxControl(element, this)
|
||||
const codes = value?.split(',') || []
|
||||
checkbox.setSelect(codes, controlContext, controlRule)
|
||||
} else if (type === ControlType.RADIO) {
|
||||
const radio = new RadioControl(element, this)
|
||||
const codes = value ? [value] : []
|
||||
radio.setSelect(codes, controlContext, controlRule)
|
||||
}
|
||||
// 修改后控件结束索引
|
||||
let newEndIndex = i
|
||||
|
||||
@@ -9,8 +9,8 @@ import { IElement } from '../../../../interface/Element'
|
||||
import { Control } from '../Control'
|
||||
|
||||
export class CheckboxControl implements IControlInstance {
|
||||
private element: IElement
|
||||
private control: Control
|
||||
protected element: IElement
|
||||
protected control: Control
|
||||
|
||||
constructor(element: IElement, control: Control) {
|
||||
this.element = element
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ControlComponent } from '../../../../dataset/enum/Control'
|
||||
import {
|
||||
IControlContext,
|
||||
IControlRuleOption
|
||||
} from '../../../../interface/Control'
|
||||
import { CheckboxControl } from '../checkbox/CheckboxControl'
|
||||
|
||||
export class RadioControl extends CheckboxControl {
|
||||
public setSelect(
|
||||
codes: string[],
|
||||
context: IControlContext = {},
|
||||
options: IControlRuleOption = {}
|
||||
) {
|
||||
// 校验是否可以设置
|
||||
if (!options.isIgnoreDisabledRule && this.control.getIsDisabledControl()) {
|
||||
return
|
||||
}
|
||||
const { control } = this.element
|
||||
const elementList = context.elementList || this.control.getElementList()
|
||||
const { startIndex } = context.range || this.control.getRange()
|
||||
const startElement = elementList[startIndex]
|
||||
// 向左查找
|
||||
let preIndex = startIndex
|
||||
while (preIndex > 0) {
|
||||
const preElement = elementList[preIndex]
|
||||
if (
|
||||
preElement.controlId !== startElement.controlId ||
|
||||
preElement.controlComponent === ControlComponent.PREFIX
|
||||
) {
|
||||
break
|
||||
}
|
||||
if (preElement.controlComponent === ControlComponent.RADIO) {
|
||||
const radio = preElement.radio!
|
||||
radio.value = codes.includes(radio.code!)
|
||||
}
|
||||
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.RADIO) {
|
||||
const radio = nextElement.radio!
|
||||
radio.value = codes.includes(radio.code!)
|
||||
}
|
||||
nextIndex++
|
||||
}
|
||||
control!.code = codes.join(',')
|
||||
this.control.repaintControl()
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export class CheckboxParticle {
|
||||
y: number
|
||||
) {
|
||||
const {
|
||||
checkbox: { gap, lineWidth, fillStyle, fontStyle },
|
||||
checkbox: { gap, lineWidth, fillStyle, strokeStyle },
|
||||
scale
|
||||
} = this.options
|
||||
const { metrics, checkbox } = element
|
||||
@@ -60,7 +60,7 @@ export class CheckboxParticle {
|
||||
ctx.fillRect(left, top, width, height)
|
||||
// 勾选对号
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = fontStyle
|
||||
ctx.strokeStyle = strokeStyle
|
||||
ctx.lineWidth = lineWidth * 2 * scale
|
||||
ctx.moveTo(left + 2 * scale, top + height / 2)
|
||||
ctx.lineTo(left + width / 2, top + height - 3 * scale)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { DeepRequired } from '../../../interface/Common'
|
||||
import { IEditorOption } from '../../../interface/Editor'
|
||||
import { IElement } from '../../../interface/Element'
|
||||
import { IRowElement } from '../../../interface/Row'
|
||||
import { Draw } from '../Draw'
|
||||
|
||||
export class RadioParticle {
|
||||
private draw: Draw
|
||||
private options: DeepRequired<IEditorOption>
|
||||
|
||||
constructor(draw: Draw) {
|
||||
this.draw = draw
|
||||
this.options = draw.getOptions()
|
||||
}
|
||||
|
||||
public setSelect(element: IElement) {
|
||||
const { radio } = element
|
||||
if (radio) {
|
||||
radio.value = !radio.value
|
||||
} else {
|
||||
element.radio = {
|
||||
value: true
|
||||
}
|
||||
}
|
||||
this.draw.render({
|
||||
isCompute: false,
|
||||
isSetCursor: false
|
||||
})
|
||||
}
|
||||
|
||||
public render(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
element: IRowElement,
|
||||
x: number,
|
||||
y: number
|
||||
) {
|
||||
const {
|
||||
radio: { gap, lineWidth, fillStyle, strokeStyle },
|
||||
scale
|
||||
} = this.options
|
||||
const { metrics, radio } = element
|
||||
// left top 四舍五入避免1像素问题
|
||||
const left = Math.round(x + gap * scale)
|
||||
const top = Math.round(y - metrics.height + lineWidth)
|
||||
const width = metrics.width - gap * 2 * scale
|
||||
const height = metrics.height
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.translate(0.5, 0.5)
|
||||
// 边框
|
||||
ctx.strokeStyle = radio?.value ? fillStyle : strokeStyle
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.arc(left + width / 2, top + height / 2, width / 2, 0, Math.PI * 2)
|
||||
ctx.stroke()
|
||||
// 填充选中色
|
||||
if (radio?.value) {
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = fillStyle
|
||||
ctx.arc(left + width / 2, top + height / 2, width / 3, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
}
|
||||
ctx.closePath()
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
@@ -124,8 +124,13 @@ function dblclick(host: CanvasEvent, evt: MouseEvent) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 复选框双击时是切换选择状态,禁用扩选
|
||||
if (positionContext.isCheckbox && positionContext.isDirectHit) return
|
||||
// 复选/单选框双击时是切换选择状态,禁用扩选
|
||||
if (
|
||||
(positionContext.isCheckbox || positionContext.isRadio) &&
|
||||
positionContext.isDirectHit
|
||||
) {
|
||||
return
|
||||
}
|
||||
// 自动扩选文字-分词处理,优先使用分词器否则降级使用光标所在位置
|
||||
const rangeManager = draw.getRange()
|
||||
const segmenterRange =
|
||||
|
||||
@@ -4,6 +4,7 @@ import { MouseEventButton } from '../../../dataset/enum/Event'
|
||||
import { deepClone } from '../../../utils'
|
||||
import { isMod } from '../../../utils/hotkey'
|
||||
import { CheckboxControl } from '../../draw/control/checkbox/CheckboxControl'
|
||||
import { RadioControl } from '../../draw/control/radio/RadioControl'
|
||||
import { CanvasEvent } from '../CanvasEvent'
|
||||
|
||||
export function setRangeCache(host: CanvasEvent) {
|
||||
@@ -54,6 +55,7 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
||||
index,
|
||||
isDirectHit,
|
||||
isCheckbox,
|
||||
isRadio,
|
||||
isImage,
|
||||
isTable,
|
||||
tdValueIndex,
|
||||
@@ -73,11 +75,14 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
||||
// 绘制
|
||||
const isDirectHitImage = !!(isDirectHit && isImage)
|
||||
const isDirectHitCheckbox = !!(isDirectHit && isCheckbox)
|
||||
const isDirectHitRadio = !!(isDirectHit && isRadio)
|
||||
if (~index) {
|
||||
rangeManager.setRange(curIndex, curIndex)
|
||||
position.setCursorPosition(positionList[curIndex])
|
||||
// 复选框
|
||||
const isSetCheckbox = isDirectHitCheckbox && !isReadonly
|
||||
// 单选框
|
||||
const isSetRadio = isDirectHitRadio && !isReadonly
|
||||
if (isSetCheckbox) {
|
||||
const { checkbox, control } = curElement
|
||||
// 复选框不在控件内独立控制
|
||||
@@ -98,12 +103,25 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
||||
activeControl.setSelect(codes)
|
||||
}
|
||||
}
|
||||
} else if (isSetRadio) {
|
||||
const { control, radio } = curElement
|
||||
// 单选框不在控件内独立控制
|
||||
if (!control) {
|
||||
draw.getRadioParticle().setSelect(curElement)
|
||||
} else {
|
||||
const codes = radio?.code ? [radio.code] : []
|
||||
const activeControl = draw.getControl().getActiveControl()
|
||||
if (activeControl instanceof RadioControl) {
|
||||
activeControl.setSelect(codes)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
draw.render({
|
||||
curIndex,
|
||||
isCompute: false,
|
||||
isSubmitHistory: false,
|
||||
isSetCursor: !isDirectHitImage && !isDirectHitCheckbox
|
||||
isSetCursor:
|
||||
!isDirectHitImage && !isDirectHitCheckbox && !isDirectHitRadio
|
||||
})
|
||||
}
|
||||
// 首字需定位到行首,非上一行最后一个字后
|
||||
|
||||
@@ -394,6 +394,9 @@ export class Position {
|
||||
tdValueElement.type === ElementType.CHECKBOX ||
|
||||
tdValueElement.controlComponent ===
|
||||
ControlComponent.CHECKBOX,
|
||||
isRadio:
|
||||
tdValueElement.type === ElementType.RADIO ||
|
||||
tdValueElement.controlComponent === ControlComponent.RADIO,
|
||||
isControl: !!tdValueElement.controlId,
|
||||
isImage: tablePosition.isImage,
|
||||
isDirectHit: tablePosition.isDirectHit,
|
||||
@@ -431,6 +434,16 @@ export class Position {
|
||||
isCheckbox: true
|
||||
}
|
||||
}
|
||||
if (
|
||||
element.type === ElementType.RADIO ||
|
||||
element.controlComponent === ControlComponent.RADIO
|
||||
) {
|
||||
return {
|
||||
index: curPositionIndex,
|
||||
isDirectHit: true,
|
||||
isRadio: true
|
||||
}
|
||||
}
|
||||
let hitLineStartIndex: number | undefined
|
||||
// 判断是否在文字中间前后
|
||||
if (elementList[index].value !== ZERO) {
|
||||
@@ -651,6 +664,7 @@ export class Position {
|
||||
const {
|
||||
index,
|
||||
isCheckbox,
|
||||
isRadio,
|
||||
isControl,
|
||||
isTable,
|
||||
trIndex,
|
||||
@@ -663,6 +677,7 @@ export class Position {
|
||||
this.setPositionContext({
|
||||
isTable: isTable || false,
|
||||
isCheckbox: isCheckbox || false,
|
||||
isRadio: isRadio || false,
|
||||
isControl: isControl || false,
|
||||
index,
|
||||
trIndex,
|
||||
|
||||
@@ -12,6 +12,7 @@ enum ElementType {
|
||||
PAGE_BREAK = 'pageBreak',
|
||||
CONTROL = 'control',
|
||||
CHECKBOX = 'checkbox',
|
||||
RADIO = 'radio',
|
||||
LATEX = 'latex',
|
||||
TAB = 'tab',
|
||||
DATE = 'date',
|
||||
|
||||
@@ -6,5 +6,5 @@ export const defaultCheckboxOption: Readonly<Required<ICheckboxOption>> = {
|
||||
gap: 5,
|
||||
lineWidth: 1,
|
||||
fillStyle: '#5175f4',
|
||||
fontStyle: '#ffffff'
|
||||
strokeStyle: '#ffffff'
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
|
||||
'valueList',
|
||||
'control',
|
||||
'checkbox',
|
||||
'radio',
|
||||
'dateFormat',
|
||||
'block',
|
||||
'level',
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { IRadioOption } from '../../interface/Radio'
|
||||
|
||||
export const defaultRadioOption: Readonly<Required<IRadioOption>> = {
|
||||
width: 14,
|
||||
height: 14,
|
||||
gap: 5,
|
||||
lineWidth: 1,
|
||||
fillStyle: '#5175f4',
|
||||
strokeStyle: '#000000'
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
export enum ControlType {
|
||||
TEXT = 'text',
|
||||
SELECT = 'select',
|
||||
CHECKBOX = 'checkbox'
|
||||
CHECKBOX = 'checkbox',
|
||||
RADIO = 'radio'
|
||||
}
|
||||
|
||||
export enum ControlComponent {
|
||||
@@ -9,7 +10,8 @@ export enum ControlComponent {
|
||||
POSTFIX = 'postfix',
|
||||
PLACEHOLDER = 'placeholder',
|
||||
VALUE = 'value',
|
||||
CHECKBOX = 'checkbox'
|
||||
CHECKBOX = 'checkbox',
|
||||
RADIO = 'radio'
|
||||
}
|
||||
|
||||
// 控件内容缩进方式
|
||||
|
||||
@@ -9,6 +9,7 @@ export enum ElementType {
|
||||
PAGE_BREAK = 'pageBreak',
|
||||
CONTROL = 'control',
|
||||
CHECKBOX = 'checkbox',
|
||||
RADIO = 'radio',
|
||||
LATEX = 'latex',
|
||||
TAB = 'tab',
|
||||
DATE = 'date',
|
||||
|
||||
@@ -32,7 +32,9 @@ import { ControlIndentation, ControlType } from './dataset/enum/Control'
|
||||
import { defaultControlOption } from './dataset/constant/Control'
|
||||
import { IControlOption } from './interface/Control'
|
||||
import { ICheckboxOption } from './interface/Checkbox'
|
||||
import { IRadioOption } from './interface/Radio'
|
||||
import { defaultCheckboxOption } from './dataset/constant/Checkbox'
|
||||
import { defaultRadioOption } from './dataset/constant/Radio'
|
||||
import { DeepRequired } from './interface/Common'
|
||||
import { INavigateInfo } from './core/draw/interactive/Search'
|
||||
import { Shortcut } from './core/shortcut/Shortcut'
|
||||
@@ -117,6 +119,10 @@ export default class Editor {
|
||||
...defaultCheckboxOption,
|
||||
...options.checkbox
|
||||
}
|
||||
const radioOptions: Required<IRadioOption> = {
|
||||
...defaultRadioOption,
|
||||
...options.radio
|
||||
}
|
||||
const cursorOptions: Required<ICursorOption> = {
|
||||
...defaultCursorOption,
|
||||
...options.cursor
|
||||
@@ -200,6 +206,7 @@ export default class Editor {
|
||||
watermark: waterMarkOptions,
|
||||
control: controlOptions,
|
||||
checkbox: checkboxOptions,
|
||||
radio: radioOptions,
|
||||
cursor: cursorOptions,
|
||||
title: titleOptions,
|
||||
placeholder: placeholderOptions,
|
||||
|
||||
@@ -10,5 +10,5 @@ export interface ICheckboxOption {
|
||||
gap?: number
|
||||
lineWidth?: number
|
||||
fillStyle?: string
|
||||
fontStyle?: string
|
||||
strokeStyle?: string
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ControlType, ControlIndentation } from '../dataset/enum/Control'
|
||||
import { EditorZone } from '../dataset/enum/Editor'
|
||||
import { ICheckbox } from './Checkbox'
|
||||
import { IElement } from './Element'
|
||||
import { IRadio } from './Radio'
|
||||
import { IRange } from './Range'
|
||||
|
||||
export interface IValueSet {
|
||||
@@ -22,6 +23,12 @@ export interface IControlCheckbox {
|
||||
checkbox?: ICheckbox
|
||||
}
|
||||
|
||||
export interface IControlRadio {
|
||||
code: string | null
|
||||
valueSets: IValueSet[]
|
||||
radio?: IRadio
|
||||
}
|
||||
|
||||
export interface IControlHighlightRule {
|
||||
keyword: string
|
||||
alpha?: number
|
||||
@@ -65,6 +72,7 @@ export type IControl = IControlBasic &
|
||||
IControlRule &
|
||||
Partial<IControlSelect> &
|
||||
Partial<IControlCheckbox> &
|
||||
Partial<IControlRadio> &
|
||||
Partial<IControlStyle>
|
||||
|
||||
export interface IControlOption {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '../dataset/enum/Editor'
|
||||
import { IBackgroundOption } from './Background'
|
||||
import { ICheckboxOption } from './Checkbox'
|
||||
import { IRadioOption } from './Radio'
|
||||
import { IPadding } from './Common'
|
||||
import { IControlOption } from './Control'
|
||||
import { ICursorOption } from './Cursor'
|
||||
@@ -77,6 +78,7 @@ export interface IEditorOption {
|
||||
watermark?: IWatermark
|
||||
control?: IControlOption
|
||||
checkbox?: ICheckboxOption
|
||||
radio?: IRadioOption
|
||||
cursor?: ICursorOption
|
||||
title?: ITitleOption
|
||||
placeholder?: IPlaceholder
|
||||
|
||||
@@ -8,6 +8,7 @@ import { TableBorder } from '../dataset/enum/table/Table'
|
||||
import { IBlock } from './Block'
|
||||
import { ICheckbox } from './Checkbox'
|
||||
import { IControl } from './Control'
|
||||
import { IRadio } from './Radio'
|
||||
import { ITextDecoration } from './Text'
|
||||
import { IColgroup } from './table/Colgroup'
|
||||
import { ITr } from './table/Tr'
|
||||
@@ -94,6 +95,10 @@ export interface ICheckboxElement {
|
||||
checkbox?: ICheckbox
|
||||
}
|
||||
|
||||
export interface IRadioElement {
|
||||
radio?: IRadio
|
||||
}
|
||||
|
||||
export interface ILaTexElement {
|
||||
laTexSVG?: string
|
||||
}
|
||||
@@ -124,6 +129,7 @@ export type IElement = IElementBasic &
|
||||
ISeparator &
|
||||
IControlElement &
|
||||
ICheckboxElement &
|
||||
IRadioElement &
|
||||
ILaTexElement &
|
||||
IDateElement &
|
||||
IImageElement &
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface ICurrentPosition {
|
||||
x?: number
|
||||
y?: number
|
||||
isCheckbox?: boolean
|
||||
isRadio?: boolean
|
||||
isControl?: boolean
|
||||
isImage?: boolean
|
||||
isTable?: boolean
|
||||
@@ -41,6 +42,7 @@ export type IGetFloatPositionByXYPayload = IGetPositionByXYPayload & {
|
||||
export interface IPositionContext {
|
||||
isTable: boolean
|
||||
isCheckbox?: boolean
|
||||
isRadio?: boolean
|
||||
isControl?: boolean
|
||||
index?: number
|
||||
trIndex?: number
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export interface IRadio {
|
||||
value: boolean | null
|
||||
code?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export interface IRadioOption {
|
||||
width?: number
|
||||
height?: number
|
||||
gap?: number
|
||||
lineWidth?: number
|
||||
fillStyle?: string
|
||||
strokeStyle?: string
|
||||
}
|
||||
@@ -222,7 +222,11 @@ export function formatElementList(
|
||||
const { prefix, postfix, value, placeholder, code, type, valueSets } =
|
||||
el.control
|
||||
const {
|
||||
editorOptions: { control: controlOption, checkbox: checkboxOption }
|
||||
editorOptions: {
|
||||
control: controlOption,
|
||||
checkbox: checkboxOption,
|
||||
radio: radioOption
|
||||
}
|
||||
} = options
|
||||
const controlId = getUUID()
|
||||
// 移除父节点
|
||||
@@ -258,6 +262,7 @@ export function formatElementList(
|
||||
if (
|
||||
(value && value.length) ||
|
||||
type === ControlType.CHECKBOX ||
|
||||
type === ControlType.RADIO ||
|
||||
(type === ControlType.SELECT && code && (!value || !value.length))
|
||||
) {
|
||||
let valueList: IElement[] = value || []
|
||||
@@ -309,6 +314,53 @@ export function formatElementList(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type === ControlType.RADIO) {
|
||||
if (Array.isArray(valueSets) && valueSets.length) {
|
||||
// 拆分valueList优先使用其属性
|
||||
const valueStyleList = valueList.reduce(
|
||||
(pre, cur) =>
|
||||
pre.concat(
|
||||
cur.value.split('').map(v => ({ ...cur, value: v }))
|
||||
),
|
||||
[] as IElement[]
|
||||
)
|
||||
let valueStyleIndex = 0
|
||||
for (let v = 0; v < valueSets.length; v++) {
|
||||
const valueSet = valueSets[v]
|
||||
// radio组件
|
||||
elementList.splice(i, 0, {
|
||||
...controlContext,
|
||||
controlId,
|
||||
value: '',
|
||||
type: el.type,
|
||||
control: el.control,
|
||||
controlComponent: ControlComponent.RADIO,
|
||||
radio: {
|
||||
code: valueSet.code,
|
||||
value: code === 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, {
|
||||
...controlContext,
|
||||
...controlDefaultStyle,
|
||||
...valueStyleList[valueStyleIndex],
|
||||
controlId,
|
||||
value: value === '\n' ? ZERO : value,
|
||||
letterSpacing: isLastLetter ? radioOption.gap : 0,
|
||||
control: el.control,
|
||||
controlComponent: ControlComponent.VALUE
|
||||
})
|
||||
valueStyleIndex++
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!value || !value.length) {
|
||||
if (Array.isArray(valueSets) && valueSets.length) {
|
||||
@@ -955,6 +1007,13 @@ export function createDomFromElementList(
|
||||
checkbox.setAttribute('checked', 'true')
|
||||
}
|
||||
clipboardDom.append(checkbox)
|
||||
} else if (element.type === ElementType.RADIO) {
|
||||
const radio = document.createElement('input')
|
||||
radio.type = 'radio'
|
||||
if (element.radio?.value) {
|
||||
radio.setAttribute('checked', 'true')
|
||||
}
|
||||
clipboardDom.append(radio)
|
||||
} else if (element.type === ElementType.TAB) {
|
||||
const tab = document.createElement('span')
|
||||
tab.innerHTML = `${NON_BREAKING_SPACE}${NON_BREAKING_SPACE}`
|
||||
@@ -1200,6 +1259,17 @@ export function getElementListByHTML(
|
||||
value: (<HTMLInputElement>node).checked
|
||||
}
|
||||
})
|
||||
} else if (
|
||||
node.nodeName === 'INPUT' &&
|
||||
(<HTMLInputElement>node).type === ControlComponent.RADIO
|
||||
) {
|
||||
elementList.push({
|
||||
type: ElementType.RADIO,
|
||||
value: '',
|
||||
radio: {
|
||||
value: (<HTMLInputElement>node).checked
|
||||
}
|
||||
})
|
||||
} else {
|
||||
findTextNode(node)
|
||||
if (node.nodeType === 1 && n !== childNodes.length - 1) {
|
||||
@@ -1275,6 +1345,8 @@ export function getTextFromElementList(elementList: IElement[]) {
|
||||
})
|
||||
} else if (element.type === ElementType.CHECKBOX) {
|
||||
text += element.checkbox?.value ? `☑` : `□`
|
||||
} else if (element.type === ElementType.RADIO) {
|
||||
text += element.radio?.value ? `☉` : `○`
|
||||
} else if (
|
||||
!element.type ||
|
||||
element.type === ElementType.LATEX ||
|
||||
|
||||
Reference in New Issue
Block a user