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
@@ -61,7 +61,8 @@ interface IEditorOption {
|
|||||||
wordBreak?: WordBreak // Word and punctuation breaks: No punctuation in the first line of the BREAK_WORD &The word is not split, and the line is folded after BREAK_ALL full according to the width of the character. default: BREAK_WORD
|
wordBreak?: WordBreak // Word and punctuation breaks: No punctuation in the first line of the BREAK_WORD &The word is not split, and the line is folded after BREAK_ALL full according to the width of the character. default: BREAK_WORD
|
||||||
watermark?: IWatermark // Watermark{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
watermark?: IWatermark // Watermark{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
||||||
control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;}
|
control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;}
|
||||||
checkbox?: ICheckboxOption // Checkbox {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; fontStyle?: string;}
|
checkbox?: ICheckboxOption // Checkbox {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
||||||
|
radio?: IRadioOption // Radio {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
||||||
cursor?: ICursorOption // Cursor style. {width?: number; color?: string; dragWidth?: number; dragColor?: string;}
|
cursor?: ICursorOption // Cursor style. {width?: number; color?: string; dragWidth?: number; dragColor?: string;}
|
||||||
title?: ITitleOption // Title configuration.{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
title?: ITitleOption // Title configuration.{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
placeholder?: IPlaceholder // Placeholder text
|
placeholder?: IPlaceholder // Placeholder text
|
||||||
|
|||||||
+18
-2
@@ -15,6 +15,7 @@ interface IElement {
|
|||||||
PAGE_BREAK = 'pageBreak',
|
PAGE_BREAK = 'pageBreak',
|
||||||
CONTROL = 'control',
|
CONTROL = 'control',
|
||||||
CHECKBOX = 'checkbox',
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
LATEX = 'latex',
|
LATEX = 'latex',
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
DATE = 'date',
|
DATE = 'date',
|
||||||
@@ -76,7 +77,8 @@ interface IElement {
|
|||||||
type: {
|
type: {
|
||||||
TEXT = 'text',
|
TEXT = 'text',
|
||||||
SELECT = 'select',
|
SELECT = 'select',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
};
|
};
|
||||||
value: IElement[] | null;
|
value: IElement[] | null;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@@ -98,6 +100,13 @@ interface IElement {
|
|||||||
code: string;
|
code: string;
|
||||||
}[];
|
}[];
|
||||||
checkbox?: {
|
checkbox?: {
|
||||||
|
value: boolean | null;
|
||||||
|
code?: string;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
radio?: {
|
||||||
value: boolean | null;
|
value: boolean | null;
|
||||||
code?: string;
|
code?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -115,7 +124,8 @@ interface IElement {
|
|||||||
POSTFIX = 'postfix',
|
POSTFIX = 'postfix',
|
||||||
PLACEHOLDER = 'placeholder',
|
PLACEHOLDER = 'placeholder',
|
||||||
VALUE = 'value',
|
VALUE = 'value',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
};
|
};
|
||||||
// checkbox
|
// checkbox
|
||||||
checkbox?: {
|
checkbox?: {
|
||||||
@@ -123,6 +133,12 @@ interface IElement {
|
|||||||
code?: string;
|
code?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
// radio
|
||||||
|
radio?: {
|
||||||
|
value: boolean | null;
|
||||||
|
code?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
// LaTeX
|
// LaTeX
|
||||||
laTexSVG?: string;
|
laTexSVG?: string;
|
||||||
// date
|
// date
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ interface IEditorOption {
|
|||||||
wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
||||||
watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
||||||
control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;}
|
control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;}
|
||||||
checkbox?: ICheckboxOption // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; fontStyle?: string;}
|
checkbox?: ICheckboxOption // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
||||||
|
radio?: IRadioOption // 单选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
||||||
cursor?: ICursorOption // 光标样式。{width?: number; color?: string; dragWidth?: number; dragColor?: string;}
|
cursor?: ICursorOption // 光标样式。{width?: number; color?: string; dragWidth?: number; dragColor?: string;}
|
||||||
title?: ITitleOption // 标题配置。{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
title?: ITitleOption // 标题配置。{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
placeholder?: IPlaceholder // 编辑器空白占位文本
|
placeholder?: IPlaceholder // 编辑器空白占位文本
|
||||||
|
|||||||
+18
-2
@@ -15,6 +15,7 @@ interface IElement {
|
|||||||
PAGE_BREAK = 'pageBreak',
|
PAGE_BREAK = 'pageBreak',
|
||||||
CONTROL = 'control',
|
CONTROL = 'control',
|
||||||
CHECKBOX = 'checkbox',
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
LATEX = 'latex',
|
LATEX = 'latex',
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
DATE = 'date',
|
DATE = 'date',
|
||||||
@@ -76,7 +77,8 @@ interface IElement {
|
|||||||
type: {
|
type: {
|
||||||
TEXT = 'text',
|
TEXT = 'text',
|
||||||
SELECT = 'select',
|
SELECT = 'select',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
};
|
};
|
||||||
value: IElement[] | null;
|
value: IElement[] | null;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@@ -98,6 +100,13 @@ interface IElement {
|
|||||||
code: string;
|
code: string;
|
||||||
}[];
|
}[];
|
||||||
checkbox?: {
|
checkbox?: {
|
||||||
|
value: boolean | null;
|
||||||
|
code?: string;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
radio?: {
|
||||||
value: boolean | null;
|
value: boolean | null;
|
||||||
code?: string;
|
code?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -115,7 +124,8 @@ interface IElement {
|
|||||||
POSTFIX = 'postfix',
|
POSTFIX = 'postfix',
|
||||||
PLACEHOLDER = 'placeholder',
|
PLACEHOLDER = 'placeholder',
|
||||||
VALUE = 'value',
|
VALUE = 'value',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
};
|
};
|
||||||
// 复选框
|
// 复选框
|
||||||
checkbox?: {
|
checkbox?: {
|
||||||
@@ -123,6 +133,12 @@ interface IElement {
|
|||||||
code?: string;
|
code?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
// 单选框
|
||||||
|
radio?: {
|
||||||
|
value: boolean | null;
|
||||||
|
code?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
// LaTeX
|
// LaTeX
|
||||||
laTexSVG?: string;
|
laTexSVG?: string;
|
||||||
// 日期
|
// 日期
|
||||||
|
|||||||
@@ -280,12 +280,16 @@
|
|||||||
<li data-control='text'>文本</li>
|
<li data-control='text'>文本</li>
|
||||||
<li data-control="select">列举</li>
|
<li data-control="select">列举</li>
|
||||||
<li data-control="checkbox">复选框</li>
|
<li data-control="checkbox">复选框</li>
|
||||||
|
<li data-control="radio">单选框</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item__checkbox" title="复选框">
|
<div class="menu-item__checkbox" title="复选框">
|
||||||
<i></i>
|
<i></i>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-item__radio" title="单选框">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
<div class="menu-item__latex" title="LateX">
|
<div class="menu-item__latex" title="LateX">
|
||||||
<i></i>
|
<i></i>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="#3d4757" stroke-width="2" fill="none" />
|
||||||
|
<circle cx="12" cy="12" r="4" fill="#3d4757" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 236 B |
@@ -65,6 +65,7 @@ import {
|
|||||||
import { Control } from './control/Control'
|
import { Control } from './control/Control'
|
||||||
import { getSlimCloneElementList, zipElementList } from '../../utils/element'
|
import { getSlimCloneElementList, zipElementList } from '../../utils/element'
|
||||||
import { CheckboxParticle } from './particle/CheckboxParticle'
|
import { CheckboxParticle } from './particle/CheckboxParticle'
|
||||||
|
import { RadioParticle } from './particle/RadioParticle'
|
||||||
import { DeepRequired, IPadding } from '../../interface/Common'
|
import { DeepRequired, IPadding } from '../../interface/Common'
|
||||||
import {
|
import {
|
||||||
ControlComponent,
|
ControlComponent,
|
||||||
@@ -142,6 +143,7 @@ export class Draw {
|
|||||||
private superscriptParticle: SuperscriptParticle
|
private superscriptParticle: SuperscriptParticle
|
||||||
private subscriptParticle: SubscriptParticle
|
private subscriptParticle: SubscriptParticle
|
||||||
private checkboxParticle: CheckboxParticle
|
private checkboxParticle: CheckboxParticle
|
||||||
|
private radioParticle: RadioParticle
|
||||||
private blockParticle: BlockParticle
|
private blockParticle: BlockParticle
|
||||||
private listParticle: ListParticle
|
private listParticle: ListParticle
|
||||||
private lineBreakParticle: LineBreakParticle
|
private lineBreakParticle: LineBreakParticle
|
||||||
@@ -216,6 +218,7 @@ export class Draw {
|
|||||||
this.superscriptParticle = new SuperscriptParticle()
|
this.superscriptParticle = new SuperscriptParticle()
|
||||||
this.subscriptParticle = new SubscriptParticle()
|
this.subscriptParticle = new SubscriptParticle()
|
||||||
this.checkboxParticle = new CheckboxParticle(this)
|
this.checkboxParticle = new CheckboxParticle(this)
|
||||||
|
this.radioParticle = new RadioParticle(this)
|
||||||
this.blockParticle = new BlockParticle(this)
|
this.blockParticle = new BlockParticle(this)
|
||||||
this.listParticle = new ListParticle(this)
|
this.listParticle = new ListParticle(this)
|
||||||
this.lineBreakParticle = new LineBreakParticle(this)
|
this.lineBreakParticle = new LineBreakParticle(this)
|
||||||
@@ -751,6 +754,10 @@ export class Draw {
|
|||||||
return this.checkboxParticle
|
return this.checkboxParticle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getRadioParticle(): RadioParticle {
|
||||||
|
return this.radioParticle
|
||||||
|
}
|
||||||
|
|
||||||
public getControl(): Control {
|
public getControl(): Control {
|
||||||
return this.control
|
return this.control
|
||||||
}
|
}
|
||||||
@@ -1414,6 +1421,15 @@ export class Draw {
|
|||||||
element.width = availableWidth / scale
|
element.width = availableWidth / scale
|
||||||
metrics.width = availableWidth
|
metrics.width = availableWidth
|
||||||
metrics.height = defaultSize
|
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 (
|
} else if (
|
||||||
element.type === ElementType.CHECKBOX ||
|
element.type === ElementType.CHECKBOX ||
|
||||||
element.controlComponent === ControlComponent.CHECKBOX
|
element.controlComponent === ControlComponent.CHECKBOX
|
||||||
@@ -1805,6 +1821,12 @@ export class Draw {
|
|||||||
) {
|
) {
|
||||||
this.textParticle.complete()
|
this.textParticle.complete()
|
||||||
this.checkboxParticle.render(ctx, element, x, y + offsetY)
|
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) {
|
} else if (element.type === ElementType.TAB) {
|
||||||
this.textParticle.complete()
|
this.textParticle.complete()
|
||||||
} else if (element.rowFlex === RowFlex.ALIGNMENT) {
|
} else if (element.rowFlex === RowFlex.ALIGNMENT) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import { Listener } from '../../listener/Listener'
|
|||||||
import { RangeManager } from '../../range/RangeManager'
|
import { RangeManager } from '../../range/RangeManager'
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
import { CheckboxControl } from './checkbox/CheckboxControl'
|
import { CheckboxControl } from './checkbox/CheckboxControl'
|
||||||
|
import { RadioControl } from './radio/RadioControl'
|
||||||
import { ControlSearch } from './interactive/ControlSearch'
|
import { ControlSearch } from './interactive/ControlSearch'
|
||||||
import { ControlBorder } from './richtext/Border'
|
import { ControlBorder } from './richtext/Border'
|
||||||
import { SelectControl } from './select/SelectControl'
|
import { SelectControl } from './select/SelectControl'
|
||||||
@@ -236,6 +237,8 @@ export class Control {
|
|||||||
selectControl.awake()
|
selectControl.awake()
|
||||||
} else if (control.type === ControlType.CHECKBOX) {
|
} else if (control.type === ControlType.CHECKBOX) {
|
||||||
this.activeControl = new CheckboxControl(element, this)
|
this.activeControl = new CheckboxControl(element, this)
|
||||||
|
} else if (control.type === ControlType.RADIO) {
|
||||||
|
this.activeControl = new RadioControl(element, this)
|
||||||
}
|
}
|
||||||
// 激活控件回调
|
// 激活控件回调
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -522,7 +525,8 @@ export class Control {
|
|||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
type === ControlType.SELECT ||
|
type === ControlType.SELECT ||
|
||||||
type === ControlType.CHECKBOX
|
type === ControlType.CHECKBOX ||
|
||||||
|
type === ControlType.RADIO
|
||||||
) {
|
) {
|
||||||
const innerText = code
|
const innerText = code
|
||||||
?.split(',')
|
?.split(',')
|
||||||
@@ -629,6 +633,10 @@ export class Control {
|
|||||||
const checkbox = new CheckboxControl(element, this)
|
const checkbox = new CheckboxControl(element, this)
|
||||||
const codes = value?.split(',') || []
|
const codes = value?.split(',') || []
|
||||||
checkbox.setSelect(codes, controlContext, controlRule)
|
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
|
let newEndIndex = i
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { IElement } from '../../../../interface/Element'
|
|||||||
import { Control } from '../Control'
|
import { Control } from '../Control'
|
||||||
|
|
||||||
export class CheckboxControl implements IControlInstance {
|
export class CheckboxControl implements IControlInstance {
|
||||||
private element: IElement
|
protected element: IElement
|
||||||
private control: Control
|
protected control: Control
|
||||||
|
|
||||||
constructor(element: IElement, control: Control) {
|
constructor(element: IElement, control: Control) {
|
||||||
this.element = element
|
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
|
y: number
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
checkbox: { gap, lineWidth, fillStyle, fontStyle },
|
checkbox: { gap, lineWidth, fillStyle, strokeStyle },
|
||||||
scale
|
scale
|
||||||
} = this.options
|
} = this.options
|
||||||
const { metrics, checkbox } = element
|
const { metrics, checkbox } = element
|
||||||
@@ -60,7 +60,7 @@ export class CheckboxParticle {
|
|||||||
ctx.fillRect(left, top, width, height)
|
ctx.fillRect(left, top, width, height)
|
||||||
// 勾选对号
|
// 勾选对号
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.strokeStyle = fontStyle
|
ctx.strokeStyle = strokeStyle
|
||||||
ctx.lineWidth = lineWidth * 2 * scale
|
ctx.lineWidth = lineWidth * 2 * scale
|
||||||
ctx.moveTo(left + 2 * scale, top + height / 2)
|
ctx.moveTo(left + 2 * scale, top + height / 2)
|
||||||
ctx.lineTo(left + width / 2, top + height - 3 * scale)
|
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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 复选框双击时是切换选择状态,禁用扩选
|
// 复选/单选框双击时是切换选择状态,禁用扩选
|
||||||
if (positionContext.isCheckbox && positionContext.isDirectHit) return
|
if (
|
||||||
|
(positionContext.isCheckbox || positionContext.isRadio) &&
|
||||||
|
positionContext.isDirectHit
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 自动扩选文字-分词处理,优先使用分词器否则降级使用光标所在位置
|
// 自动扩选文字-分词处理,优先使用分词器否则降级使用光标所在位置
|
||||||
const rangeManager = draw.getRange()
|
const rangeManager = draw.getRange()
|
||||||
const segmenterRange =
|
const segmenterRange =
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { MouseEventButton } from '../../../dataset/enum/Event'
|
|||||||
import { deepClone } from '../../../utils'
|
import { deepClone } from '../../../utils'
|
||||||
import { isMod } from '../../../utils/hotkey'
|
import { isMod } from '../../../utils/hotkey'
|
||||||
import { CheckboxControl } from '../../draw/control/checkbox/CheckboxControl'
|
import { CheckboxControl } from '../../draw/control/checkbox/CheckboxControl'
|
||||||
|
import { RadioControl } from '../../draw/control/radio/RadioControl'
|
||||||
import { CanvasEvent } from '../CanvasEvent'
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
export function setRangeCache(host: CanvasEvent) {
|
export function setRangeCache(host: CanvasEvent) {
|
||||||
@@ -54,6 +55,7 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
|||||||
index,
|
index,
|
||||||
isDirectHit,
|
isDirectHit,
|
||||||
isCheckbox,
|
isCheckbox,
|
||||||
|
isRadio,
|
||||||
isImage,
|
isImage,
|
||||||
isTable,
|
isTable,
|
||||||
tdValueIndex,
|
tdValueIndex,
|
||||||
@@ -73,11 +75,14 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
|||||||
// 绘制
|
// 绘制
|
||||||
const isDirectHitImage = !!(isDirectHit && isImage)
|
const isDirectHitImage = !!(isDirectHit && isImage)
|
||||||
const isDirectHitCheckbox = !!(isDirectHit && isCheckbox)
|
const isDirectHitCheckbox = !!(isDirectHit && isCheckbox)
|
||||||
|
const isDirectHitRadio = !!(isDirectHit && isRadio)
|
||||||
if (~index) {
|
if (~index) {
|
||||||
rangeManager.setRange(curIndex, curIndex)
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
position.setCursorPosition(positionList[curIndex])
|
position.setCursorPosition(positionList[curIndex])
|
||||||
// 复选框
|
// 复选框
|
||||||
const isSetCheckbox = isDirectHitCheckbox && !isReadonly
|
const isSetCheckbox = isDirectHitCheckbox && !isReadonly
|
||||||
|
// 单选框
|
||||||
|
const isSetRadio = isDirectHitRadio && !isReadonly
|
||||||
if (isSetCheckbox) {
|
if (isSetCheckbox) {
|
||||||
const { checkbox, control } = curElement
|
const { checkbox, control } = curElement
|
||||||
// 复选框不在控件内独立控制
|
// 复选框不在控件内独立控制
|
||||||
@@ -98,12 +103,25 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
|||||||
activeControl.setSelect(codes)
|
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 {
|
} else {
|
||||||
draw.render({
|
draw.render({
|
||||||
curIndex,
|
curIndex,
|
||||||
isCompute: false,
|
isCompute: false,
|
||||||
isSubmitHistory: false,
|
isSubmitHistory: false,
|
||||||
isSetCursor: !isDirectHitImage && !isDirectHitCheckbox
|
isSetCursor:
|
||||||
|
!isDirectHitImage && !isDirectHitCheckbox && !isDirectHitRadio
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 首字需定位到行首,非上一行最后一个字后
|
// 首字需定位到行首,非上一行最后一个字后
|
||||||
|
|||||||
@@ -394,6 +394,9 @@ export class Position {
|
|||||||
tdValueElement.type === ElementType.CHECKBOX ||
|
tdValueElement.type === ElementType.CHECKBOX ||
|
||||||
tdValueElement.controlComponent ===
|
tdValueElement.controlComponent ===
|
||||||
ControlComponent.CHECKBOX,
|
ControlComponent.CHECKBOX,
|
||||||
|
isRadio:
|
||||||
|
tdValueElement.type === ElementType.RADIO ||
|
||||||
|
tdValueElement.controlComponent === ControlComponent.RADIO,
|
||||||
isControl: !!tdValueElement.controlId,
|
isControl: !!tdValueElement.controlId,
|
||||||
isImage: tablePosition.isImage,
|
isImage: tablePosition.isImage,
|
||||||
isDirectHit: tablePosition.isDirectHit,
|
isDirectHit: tablePosition.isDirectHit,
|
||||||
@@ -431,6 +434,16 @@ export class Position {
|
|||||||
isCheckbox: true
|
isCheckbox: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
element.type === ElementType.RADIO ||
|
||||||
|
element.controlComponent === ControlComponent.RADIO
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
index: curPositionIndex,
|
||||||
|
isDirectHit: true,
|
||||||
|
isRadio: true
|
||||||
|
}
|
||||||
|
}
|
||||||
let hitLineStartIndex: number | undefined
|
let hitLineStartIndex: number | undefined
|
||||||
// 判断是否在文字中间前后
|
// 判断是否在文字中间前后
|
||||||
if (elementList[index].value !== ZERO) {
|
if (elementList[index].value !== ZERO) {
|
||||||
@@ -651,6 +664,7 @@ export class Position {
|
|||||||
const {
|
const {
|
||||||
index,
|
index,
|
||||||
isCheckbox,
|
isCheckbox,
|
||||||
|
isRadio,
|
||||||
isControl,
|
isControl,
|
||||||
isTable,
|
isTable,
|
||||||
trIndex,
|
trIndex,
|
||||||
@@ -663,6 +677,7 @@ export class Position {
|
|||||||
this.setPositionContext({
|
this.setPositionContext({
|
||||||
isTable: isTable || false,
|
isTable: isTable || false,
|
||||||
isCheckbox: isCheckbox || false,
|
isCheckbox: isCheckbox || false,
|
||||||
|
isRadio: isRadio || false,
|
||||||
isControl: isControl || false,
|
isControl: isControl || false,
|
||||||
index,
|
index,
|
||||||
trIndex,
|
trIndex,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ enum ElementType {
|
|||||||
PAGE_BREAK = 'pageBreak',
|
PAGE_BREAK = 'pageBreak',
|
||||||
CONTROL = 'control',
|
CONTROL = 'control',
|
||||||
CHECKBOX = 'checkbox',
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
LATEX = 'latex',
|
LATEX = 'latex',
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
DATE = 'date',
|
DATE = 'date',
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ export const defaultCheckboxOption: Readonly<Required<ICheckboxOption>> = {
|
|||||||
gap: 5,
|
gap: 5,
|
||||||
lineWidth: 1,
|
lineWidth: 1,
|
||||||
fillStyle: '#5175f4',
|
fillStyle: '#5175f4',
|
||||||
fontStyle: '#ffffff'
|
strokeStyle: '#ffffff'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
|
|||||||
'valueList',
|
'valueList',
|
||||||
'control',
|
'control',
|
||||||
'checkbox',
|
'checkbox',
|
||||||
|
'radio',
|
||||||
'dateFormat',
|
'dateFormat',
|
||||||
'block',
|
'block',
|
||||||
'level',
|
'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 {
|
export enum ControlType {
|
||||||
TEXT = 'text',
|
TEXT = 'text',
|
||||||
SELECT = 'select',
|
SELECT = 'select',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ControlComponent {
|
export enum ControlComponent {
|
||||||
@@ -9,7 +10,8 @@ export enum ControlComponent {
|
|||||||
POSTFIX = 'postfix',
|
POSTFIX = 'postfix',
|
||||||
PLACEHOLDER = 'placeholder',
|
PLACEHOLDER = 'placeholder',
|
||||||
VALUE = 'value',
|
VALUE = 'value',
|
||||||
CHECKBOX = 'checkbox'
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 控件内容缩进方式
|
// 控件内容缩进方式
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export enum ElementType {
|
|||||||
PAGE_BREAK = 'pageBreak',
|
PAGE_BREAK = 'pageBreak',
|
||||||
CONTROL = 'control',
|
CONTROL = 'control',
|
||||||
CHECKBOX = 'checkbox',
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
LATEX = 'latex',
|
LATEX = 'latex',
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
DATE = 'date',
|
DATE = 'date',
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ import { ControlIndentation, ControlType } from './dataset/enum/Control'
|
|||||||
import { defaultControlOption } from './dataset/constant/Control'
|
import { defaultControlOption } from './dataset/constant/Control'
|
||||||
import { IControlOption } from './interface/Control'
|
import { IControlOption } from './interface/Control'
|
||||||
import { ICheckboxOption } from './interface/Checkbox'
|
import { ICheckboxOption } from './interface/Checkbox'
|
||||||
|
import { IRadioOption } from './interface/Radio'
|
||||||
import { defaultCheckboxOption } from './dataset/constant/Checkbox'
|
import { defaultCheckboxOption } from './dataset/constant/Checkbox'
|
||||||
|
import { defaultRadioOption } from './dataset/constant/Radio'
|
||||||
import { DeepRequired } from './interface/Common'
|
import { DeepRequired } from './interface/Common'
|
||||||
import { INavigateInfo } from './core/draw/interactive/Search'
|
import { INavigateInfo } from './core/draw/interactive/Search'
|
||||||
import { Shortcut } from './core/shortcut/Shortcut'
|
import { Shortcut } from './core/shortcut/Shortcut'
|
||||||
@@ -117,6 +119,10 @@ export default class Editor {
|
|||||||
...defaultCheckboxOption,
|
...defaultCheckboxOption,
|
||||||
...options.checkbox
|
...options.checkbox
|
||||||
}
|
}
|
||||||
|
const radioOptions: Required<IRadioOption> = {
|
||||||
|
...defaultRadioOption,
|
||||||
|
...options.radio
|
||||||
|
}
|
||||||
const cursorOptions: Required<ICursorOption> = {
|
const cursorOptions: Required<ICursorOption> = {
|
||||||
...defaultCursorOption,
|
...defaultCursorOption,
|
||||||
...options.cursor
|
...options.cursor
|
||||||
@@ -200,6 +206,7 @@ export default class Editor {
|
|||||||
watermark: waterMarkOptions,
|
watermark: waterMarkOptions,
|
||||||
control: controlOptions,
|
control: controlOptions,
|
||||||
checkbox: checkboxOptions,
|
checkbox: checkboxOptions,
|
||||||
|
radio: radioOptions,
|
||||||
cursor: cursorOptions,
|
cursor: cursorOptions,
|
||||||
title: titleOptions,
|
title: titleOptions,
|
||||||
placeholder: placeholderOptions,
|
placeholder: placeholderOptions,
|
||||||
|
|||||||
@@ -10,5 +10,5 @@ export interface ICheckboxOption {
|
|||||||
gap?: number
|
gap?: number
|
||||||
lineWidth?: number
|
lineWidth?: number
|
||||||
fillStyle?: string
|
fillStyle?: string
|
||||||
fontStyle?: string
|
strokeStyle?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ControlType, ControlIndentation } from '../dataset/enum/Control'
|
|||||||
import { EditorZone } from '../dataset/enum/Editor'
|
import { EditorZone } from '../dataset/enum/Editor'
|
||||||
import { ICheckbox } from './Checkbox'
|
import { ICheckbox } from './Checkbox'
|
||||||
import { IElement } from './Element'
|
import { IElement } from './Element'
|
||||||
|
import { IRadio } from './Radio'
|
||||||
import { IRange } from './Range'
|
import { IRange } from './Range'
|
||||||
|
|
||||||
export interface IValueSet {
|
export interface IValueSet {
|
||||||
@@ -22,6 +23,12 @@ export interface IControlCheckbox {
|
|||||||
checkbox?: ICheckbox
|
checkbox?: ICheckbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IControlRadio {
|
||||||
|
code: string | null
|
||||||
|
valueSets: IValueSet[]
|
||||||
|
radio?: IRadio
|
||||||
|
}
|
||||||
|
|
||||||
export interface IControlHighlightRule {
|
export interface IControlHighlightRule {
|
||||||
keyword: string
|
keyword: string
|
||||||
alpha?: number
|
alpha?: number
|
||||||
@@ -65,6 +72,7 @@ export type IControl = IControlBasic &
|
|||||||
IControlRule &
|
IControlRule &
|
||||||
Partial<IControlSelect> &
|
Partial<IControlSelect> &
|
||||||
Partial<IControlCheckbox> &
|
Partial<IControlCheckbox> &
|
||||||
|
Partial<IControlRadio> &
|
||||||
Partial<IControlStyle>
|
Partial<IControlStyle>
|
||||||
|
|
||||||
export interface IControlOption {
|
export interface IControlOption {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from '../dataset/enum/Editor'
|
} from '../dataset/enum/Editor'
|
||||||
import { IBackgroundOption } from './Background'
|
import { IBackgroundOption } from './Background'
|
||||||
import { ICheckboxOption } from './Checkbox'
|
import { ICheckboxOption } from './Checkbox'
|
||||||
|
import { IRadioOption } from './Radio'
|
||||||
import { IPadding } from './Common'
|
import { IPadding } from './Common'
|
||||||
import { IControlOption } from './Control'
|
import { IControlOption } from './Control'
|
||||||
import { ICursorOption } from './Cursor'
|
import { ICursorOption } from './Cursor'
|
||||||
@@ -77,6 +78,7 @@ export interface IEditorOption {
|
|||||||
watermark?: IWatermark
|
watermark?: IWatermark
|
||||||
control?: IControlOption
|
control?: IControlOption
|
||||||
checkbox?: ICheckboxOption
|
checkbox?: ICheckboxOption
|
||||||
|
radio?: IRadioOption
|
||||||
cursor?: ICursorOption
|
cursor?: ICursorOption
|
||||||
title?: ITitleOption
|
title?: ITitleOption
|
||||||
placeholder?: IPlaceholder
|
placeholder?: IPlaceholder
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TableBorder } from '../dataset/enum/table/Table'
|
|||||||
import { IBlock } from './Block'
|
import { IBlock } from './Block'
|
||||||
import { ICheckbox } from './Checkbox'
|
import { ICheckbox } from './Checkbox'
|
||||||
import { IControl } from './Control'
|
import { IControl } from './Control'
|
||||||
|
import { IRadio } from './Radio'
|
||||||
import { ITextDecoration } from './Text'
|
import { ITextDecoration } from './Text'
|
||||||
import { IColgroup } from './table/Colgroup'
|
import { IColgroup } from './table/Colgroup'
|
||||||
import { ITr } from './table/Tr'
|
import { ITr } from './table/Tr'
|
||||||
@@ -94,6 +95,10 @@ export interface ICheckboxElement {
|
|||||||
checkbox?: ICheckbox
|
checkbox?: ICheckbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRadioElement {
|
||||||
|
radio?: IRadio
|
||||||
|
}
|
||||||
|
|
||||||
export interface ILaTexElement {
|
export interface ILaTexElement {
|
||||||
laTexSVG?: string
|
laTexSVG?: string
|
||||||
}
|
}
|
||||||
@@ -124,6 +129,7 @@ export type IElement = IElementBasic &
|
|||||||
ISeparator &
|
ISeparator &
|
||||||
IControlElement &
|
IControlElement &
|
||||||
ICheckboxElement &
|
ICheckboxElement &
|
||||||
|
IRadioElement &
|
||||||
ILaTexElement &
|
ILaTexElement &
|
||||||
IDateElement &
|
IDateElement &
|
||||||
IImageElement &
|
IImageElement &
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export interface ICurrentPosition {
|
|||||||
x?: number
|
x?: number
|
||||||
y?: number
|
y?: number
|
||||||
isCheckbox?: boolean
|
isCheckbox?: boolean
|
||||||
|
isRadio?: boolean
|
||||||
isControl?: boolean
|
isControl?: boolean
|
||||||
isImage?: boolean
|
isImage?: boolean
|
||||||
isTable?: boolean
|
isTable?: boolean
|
||||||
@@ -41,6 +42,7 @@ export type IGetFloatPositionByXYPayload = IGetPositionByXYPayload & {
|
|||||||
export interface IPositionContext {
|
export interface IPositionContext {
|
||||||
isTable: boolean
|
isTable: boolean
|
||||||
isCheckbox?: boolean
|
isCheckbox?: boolean
|
||||||
|
isRadio?: boolean
|
||||||
isControl?: boolean
|
isControl?: boolean
|
||||||
index?: number
|
index?: number
|
||||||
trIndex?: 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 } =
|
const { prefix, postfix, value, placeholder, code, type, valueSets } =
|
||||||
el.control
|
el.control
|
||||||
const {
|
const {
|
||||||
editorOptions: { control: controlOption, checkbox: checkboxOption }
|
editorOptions: {
|
||||||
|
control: controlOption,
|
||||||
|
checkbox: checkboxOption,
|
||||||
|
radio: radioOption
|
||||||
|
}
|
||||||
} = options
|
} = options
|
||||||
const controlId = getUUID()
|
const controlId = getUUID()
|
||||||
// 移除父节点
|
// 移除父节点
|
||||||
@@ -258,6 +262,7 @@ export function formatElementList(
|
|||||||
if (
|
if (
|
||||||
(value && value.length) ||
|
(value && value.length) ||
|
||||||
type === ControlType.CHECKBOX ||
|
type === ControlType.CHECKBOX ||
|
||||||
|
type === ControlType.RADIO ||
|
||||||
(type === ControlType.SELECT && code && (!value || !value.length))
|
(type === ControlType.SELECT && code && (!value || !value.length))
|
||||||
) {
|
) {
|
||||||
let valueList: IElement[] = value || []
|
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 {
|
} else {
|
||||||
if (!value || !value.length) {
|
if (!value || !value.length) {
|
||||||
if (Array.isArray(valueSets) && valueSets.length) {
|
if (Array.isArray(valueSets) && valueSets.length) {
|
||||||
@@ -955,6 +1007,13 @@ export function createDomFromElementList(
|
|||||||
checkbox.setAttribute('checked', 'true')
|
checkbox.setAttribute('checked', 'true')
|
||||||
}
|
}
|
||||||
clipboardDom.append(checkbox)
|
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) {
|
} else if (element.type === ElementType.TAB) {
|
||||||
const tab = document.createElement('span')
|
const tab = document.createElement('span')
|
||||||
tab.innerHTML = `${NON_BREAKING_SPACE}${NON_BREAKING_SPACE}`
|
tab.innerHTML = `${NON_BREAKING_SPACE}${NON_BREAKING_SPACE}`
|
||||||
@@ -1200,6 +1259,17 @@ export function getElementListByHTML(
|
|||||||
value: (<HTMLInputElement>node).checked
|
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 {
|
} else {
|
||||||
findTextNode(node)
|
findTextNode(node)
|
||||||
if (node.nodeType === 1 && n !== childNodes.length - 1) {
|
if (node.nodeType === 1 && n !== childNodes.length - 1) {
|
||||||
@@ -1275,6 +1345,8 @@ export function getTextFromElementList(elementList: IElement[]) {
|
|||||||
})
|
})
|
||||||
} else if (element.type === ElementType.CHECKBOX) {
|
} else if (element.type === ElementType.CHECKBOX) {
|
||||||
text += element.checkbox?.value ? `☑` : `□`
|
text += element.checkbox?.value ? `☑` : `□`
|
||||||
|
} else if (element.type === ElementType.RADIO) {
|
||||||
|
text += element.radio?.value ? `☉` : `○`
|
||||||
} else if (
|
} else if (
|
||||||
!element.type ||
|
!element.type ||
|
||||||
element.type === ElementType.LATEX ||
|
element.type === ElementType.LATEX ||
|
||||||
|
|||||||
+52
@@ -768,6 +768,44 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
case ControlType.RADIO:
|
||||||
|
new Dialog({
|
||||||
|
title: '单选框控件',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '默认值',
|
||||||
|
name: 'code',
|
||||||
|
placeholder: '请输入默认值'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'textarea',
|
||||||
|
label: '值集',
|
||||||
|
name: 'valueSets',
|
||||||
|
required: true,
|
||||||
|
height: 100,
|
||||||
|
placeholder: `请输入值集JSON,例:\n[{\n"value":"有",\n"code":"98175"\n}]`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onConfirm: payload => {
|
||||||
|
const valueSets = payload.find(p => p.name === 'valueSets')?.value
|
||||||
|
if (!valueSets) return
|
||||||
|
const code = payload.find(p => p.name === 'code')?.value
|
||||||
|
instance.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type: ElementType.CONTROL,
|
||||||
|
value: '',
|
||||||
|
control: {
|
||||||
|
type,
|
||||||
|
code,
|
||||||
|
value: null,
|
||||||
|
valueSets: JSON.parse(valueSets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -789,6 +827,20 @@ window.onload = function () {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const radioDom = document.querySelector<HTMLDivElement>('.menu-item__radio')!
|
||||||
|
radioDom.onclick = function () {
|
||||||
|
console.log('radio')
|
||||||
|
instance.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type: ElementType.RADIO,
|
||||||
|
checkbox: {
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
const latexDom = document.querySelector<HTMLDivElement>('.menu-item__latex')!
|
const latexDom = document.querySelector<HTMLDivElement>('.menu-item__latex')!
|
||||||
latexDom.onclick = function () {
|
latexDom.onclick = function () {
|
||||||
console.log('LaTeX')
|
console.log('LaTeX')
|
||||||
|
|||||||
@@ -540,6 +540,10 @@ ul {
|
|||||||
background-image: url('./assets/images/checkbox.svg');
|
background-image: url('./assets/images/checkbox.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-item__radio i {
|
||||||
|
background-image: url('./assets/images/radio.svg');
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item__latex i {
|
.menu-item__latex i {
|
||||||
background-image: url('./assets/images/latex.svg');
|
background-image: url('./assets/images/latex.svg');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user