From 1455a2afb2949b7db10a3cfa30258e0f03bcbf31 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Tue, 28 Nov 2023 21:37:28 +0800 Subject: [PATCH] feat: add control disabled rule --- docs/en/guide/schema.md | 1 + docs/guide/schema.md | 1 + src/editor/core/command/CommandAdapt.ts | 81 ++++++++++++------- src/editor/core/draw/Draw.ts | 4 +- src/editor/core/draw/control/Control.ts | 45 ++++++----- .../draw/control/checkbox/CheckboxControl.ts | 32 +++++--- .../core/draw/control/select/SelectControl.ts | 31 ++++++- .../core/draw/control/text/TextControl.ts | 28 ++++++- src/editor/core/event/handlers/input.ts | 3 +- src/editor/core/event/handlers/mousedown.ts | 30 +++---- src/editor/interface/Control.ts | 11 ++- 11 files changed, 180 insertions(+), 87 deletions(-) diff --git a/docs/en/guide/schema.md b/docs/en/guide/schema.md index f19ac05..f4ea970 100644 --- a/docs/en/guide/schema.md +++ b/docs/en/guide/schema.md @@ -82,6 +82,7 @@ interface IElement { underline?: boolean; extension?: unknown; deletable?: boolean; + disabled?: boolean; code: string | null; min?: number; max?: number; diff --git a/docs/guide/schema.md b/docs/guide/schema.md index 1c0ec9a..4b67722 100644 --- a/docs/guide/schema.md +++ b/docs/guide/schema.md @@ -82,6 +82,7 @@ interface IElement { underline?: boolean; extension?: unknown; deletable?: boolean; + disabled?: boolean; code: string | null; min?: number; max?: number; diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index 7169661..580c09a 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -242,8 +242,6 @@ export class CommandAdapt { } public painter(options: IPainterOption) { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return const selection = this.range.getSelection() if (!selection) return const painterStyle: IElementStyle = {} @@ -260,12 +258,16 @@ export class CommandAdapt { } public applyPainterStyle() { + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return this.canvasEvent.applyPainterStyle() } public format() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { @@ -280,8 +282,9 @@ export class CommandAdapt { } public font(payload: string) { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { @@ -293,8 +296,9 @@ export class CommandAdapt { public size(payload: number) { const { minSize, maxSize, defaultSize } = this.options if (payload < minSize || payload > maxSize) return - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return let isExistUpdate = false @@ -314,8 +318,9 @@ export class CommandAdapt { } public sizeAdd() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return const { defaultSize, maxSize } = this.options @@ -338,8 +343,9 @@ export class CommandAdapt { } public sizeMinus() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getTextLikeSelectionElementList() if (!selection || !selection.length) return const { defaultSize, minSize } = this.options @@ -362,8 +368,9 @@ export class CommandAdapt { } public bold() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const noBoldIndex = selection.findIndex(s => !s.bold) @@ -374,8 +381,9 @@ export class CommandAdapt { } public italic() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const noItalicIndex = selection.findIndex(s => !s.italic) @@ -386,8 +394,9 @@ export class CommandAdapt { } public underline() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const noUnderlineIndex = selection.findIndex(s => !s.underline) @@ -401,8 +410,9 @@ export class CommandAdapt { } public strikeout() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const noStrikeoutIndex = selection.findIndex(s => !s.strikeout) @@ -416,8 +426,9 @@ export class CommandAdapt { } public superscript() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const superscriptIndex = selection.findIndex( @@ -445,8 +456,9 @@ export class CommandAdapt { } public subscript() { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return const subscriptIndex = selection.findIndex( @@ -474,8 +486,9 @@ export class CommandAdapt { } public color(payload: string) { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { @@ -488,8 +501,9 @@ export class CommandAdapt { } public highlight(payload: string) { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const selection = this.range.getSelectionElementList() if (!selection) return selection.forEach(el => { @@ -1447,6 +1461,8 @@ export class CommandAdapt { } public deleteHyperlink() { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return // 获取超链接索引 const hyperRange = this.getHyperlinkRange() if (!hyperRange) return @@ -1468,6 +1484,8 @@ export class CommandAdapt { } public cancelHyperlink() { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return // 获取超链接索引 const hyperRange = this.getHyperlinkRange() if (!hyperRange) return @@ -1491,6 +1509,8 @@ export class CommandAdapt { } public editHyperlink(payload: string) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return // 获取超链接索引 const hyperRange = this.getHyperlinkRange() if (!hyperRange) return @@ -1595,8 +1615,9 @@ export class CommandAdapt { } public image(payload: IDrawImagePayload) { - const isReadonly = this.draw.isReadonly() - if (isReadonly) return + const isDisabled = + this.draw.isReadonly() || this.control.isDisabledControl() + if (isDisabled) return const activeControl = this.control.getActiveControl() if (activeControl) return const { startIndex, endIndex } = this.range.getRange() diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index beba060..3212157 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -560,7 +560,9 @@ export class Draw { // 判断是否在控件内 const activeControl = this.control.getActiveControl() if (activeControl && !this.control.isRangInPostfix()) { - curIndex = activeControl.setValue(payload) + curIndex = activeControl.setValue(payload, undefined, { + isIgnoreDisabledRule: true + }) } else { const elementList = this.getElementList() const isCollapsed = startIndex === endIndex diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index 18f0c4a..2abb1d9 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -6,6 +6,7 @@ import { IControlInitOption, IControlInstance, IControlOption, + IControlRuleOption, IGetControlValueOption, IGetControlValueResult, ISetControlExtensionOption, @@ -122,6 +123,10 @@ export class Control { return false } + public isDisabledControl(): boolean { + return !!this.activeControl?.getElement().control?.disabled + } + public getContainer(): HTMLDivElement { return this.draw.getContainer() } @@ -226,11 +231,18 @@ export class Control { } } - public repaintControl(curIndex: number) { - this.range.setRange(curIndex, curIndex) - this.draw.render({ - curIndex - }) + public repaintControl(curIndex?: number) { + if (curIndex === undefined) { + this.range.clearRange() + this.draw.render({ + isSetCursor: false + }) + } else { + this.range.setRange(curIndex, curIndex) + this.draw.render({ + curIndex + }) + } } public moveCursor(position: IControlInitOption): IMoveCursorResult { @@ -528,6 +540,9 @@ export class Control { range: fakeRange, elementList } + const controlRule: IControlRuleOption = { + isIgnoreDisabledRule: true + } if (type === ControlType.TEXT) { const formatValue = [{ value }] formatElementList(formatValue, { @@ -536,31 +551,21 @@ export class Control { }) const text = new TextControl(element, this) if (value) { - text.setValue(formatValue, controlContext) + text.setValue(formatValue, controlContext, controlRule) } else { - text.clearValue(controlContext) + text.clearValue(controlContext, controlRule) } } else if (type === ControlType.SELECT) { const select = new SelectControl(element, this) if (value) { - select.setSelect(value, controlContext) + select.setSelect(value, controlContext, controlRule) } else { - select.clearSelect(controlContext) + select.clearSelect(controlContext, controlRule) } } else if (type === ControlType.CHECKBOX) { const checkbox = new CheckboxControl(element, this) - const checkboxElementList = elementList.slice( - fakeRange.startIndex + 1, - fakeRange.endIndex + 1 - ) const codes = value?.split(',') || [] - for (const checkElement of checkboxElementList) { - if (checkElement.controlComponent === ControlComponent.CHECKBOX) { - const checkboxItem = checkElement.checkbox! - checkboxItem.value = codes.includes(checkboxItem.code!) - } - } - checkbox.setSelect(controlContext) + checkbox.setSelect(codes, controlContext, controlRule) } // 修改后控件结束索引 let newEndIndex = i diff --git a/src/editor/core/draw/control/checkbox/CheckboxControl.ts b/src/editor/core/draw/control/checkbox/CheckboxControl.ts index 63f8895..d1d55d2 100644 --- a/src/editor/core/draw/control/checkbox/CheckboxControl.ts +++ b/src/editor/core/draw/control/checkbox/CheckboxControl.ts @@ -2,7 +2,8 @@ import { ControlComponent } from '../../../../dataset/enum/Control' import { KeyMap } from '../../../../dataset/enum/KeyMap' import { IControlContext, - IControlInstance + IControlInstance, + IControlRuleOption } from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { Control } from '../Control' @@ -66,12 +67,19 @@ export class CheckboxControl implements IControlInstance { return -1 } - public setSelect(context: IControlContext = {}) { + public setSelect( + codes: string[], + context: IControlContext = {}, + options: IControlRuleOption = {} + ) { + // 校验是否可以设置 + if (!options.isIgnoreDisabledRule && this.control.isDisabledControl()) { + return + } const { control } = this.element const elementList = context.elementList || this.control.getElementList() const { startIndex } = context.range || this.control.getRange() const startElement = elementList[startIndex] - const data: string[] = [] // 向左查找 let preIndex = startIndex while (preIndex > 0) { @@ -83,10 +91,8 @@ export class CheckboxControl implements IControlInstance { break } if (preElement.controlComponent === ControlComponent.CHECKBOX) { - const checkbox = preElement.checkbox - if (checkbox && checkbox.value && checkbox.code) { - data.unshift(checkbox.code) - } + const checkbox = preElement.checkbox! + checkbox.value = codes.includes(checkbox.code!) } preIndex-- } @@ -101,17 +107,19 @@ export class CheckboxControl implements IControlInstance { break } if (nextElement.controlComponent === ControlComponent.CHECKBOX) { - const checkbox = nextElement.checkbox - if (checkbox && checkbox.value && checkbox.code) { - data.push(checkbox.code) - } + const checkbox = nextElement.checkbox! + checkbox.value = codes.includes(checkbox.code!) } nextIndex++ } - control!.code = data.join(',') + control!.code = codes.join(',') + this.control.repaintControl() } public keydown(evt: KeyboardEvent): number | null { + if (this.control.isDisabledControl()) { + return null + } const range = this.control.getRange() // 收缩边界到Value内 this.control.shrinkBoundary() diff --git a/src/editor/core/draw/control/select/SelectControl.ts b/src/editor/core/draw/control/select/SelectControl.ts index bd2e09a..b4be457 100644 --- a/src/editor/core/draw/control/select/SelectControl.ts +++ b/src/editor/core/draw/control/select/SelectControl.ts @@ -8,7 +8,8 @@ import { EditorComponent } from '../../../../dataset/enum/Editor' import { KeyMap } from '../../../../dataset/enum/KeyMap' import { IControlContext, - IControlInstance + IControlInstance, + IControlRuleOption } from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { omitObject, pickObject, splitText } from '../../../../utils' @@ -79,6 +80,9 @@ export class SelectControl implements IControlInstance { } public keydown(evt: KeyboardEvent): number | null { + if (this.control.isDisabledControl()) { + return null + } const elementList = this.control.getElementList() const range = this.control.getRange() // 收缩边界到Value内 @@ -129,6 +133,9 @@ export class SelectControl implements IControlInstance { } public cut(): number { + if (this.control.isDisabledControl()) { + return -1 + } this.control.shrinkBoundary() const { startIndex, endIndex } = this.control.getRange() if (startIndex === endIndex) { @@ -138,7 +145,14 @@ export class SelectControl implements IControlInstance { return this.clearSelect() } - public clearSelect(context: IControlContext = {}): number { + public clearSelect( + context: IControlContext = {}, + options: IControlRuleOption = {} + ): number { + // 校验是否可以设置 + if (!options.isIgnoreDisabledRule && this.control.isDisabledControl()) { + return -1 + } const elementList = context.elementList || this.control.getElementList() const { startIndex } = context.range || this.control.getRange() const startElement = elementList[startIndex] @@ -180,7 +194,15 @@ export class SelectControl implements IControlInstance { return preIndex } - public setSelect(code: string, context: IControlContext = {}) { + public setSelect( + code: string, + context: IControlContext = {}, + options: IControlRuleOption = {} + ) { + // 校验是否可以设置 + if (!options.isIgnoreDisabledRule && this.control.isDisabledControl()) { + return + } const control = this.element.control! const valueSets = control.valueSets if (!Array.isArray(valueSets) || !valueSets.length) return @@ -195,6 +217,7 @@ export class SelectControl implements IControlInstance { ) // 清空选项 const prefixIndex = this.clearSelect(context) + if (!~prefixIndex) return this.control.removePlaceholder(prefixIndex, context) // 属性赋值元素-默认为前缀属性 const propertyElement = omitObject( @@ -266,7 +289,7 @@ export class SelectControl implements IControlInstance { } public awake() { - if (this.isPopup) return + if (this.isPopup || this.control.isDisabledControl()) return const { startIndex } = this.control.getRange() const elementList = this.control.getElementList() if (elementList[startIndex + 1]?.controlId !== this.element.controlId) { diff --git a/src/editor/core/draw/control/text/TextControl.ts b/src/editor/core/draw/control/text/TextControl.ts index fca689e..537949d 100644 --- a/src/editor/core/draw/control/text/TextControl.ts +++ b/src/editor/core/draw/control/text/TextControl.ts @@ -3,7 +3,8 @@ import { ControlComponent } from '../../../../dataset/enum/Control' import { KeyMap } from '../../../../dataset/enum/KeyMap' import { IControlContext, - IControlInstance + IControlInstance, + IControlRuleOption } from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { omitObject, pickObject } from '../../../../utils' @@ -61,7 +62,15 @@ export class TextControl implements IControlInstance { return data } - public setValue(data: IElement[], context: IControlContext = {}): number { + public setValue( + data: IElement[], + context: IControlContext = {}, + options: IControlRuleOption = {} + ): number { + // 校验是否可以设置 + if (!options.isIgnoreDisabledRule && this.control.isDisabledControl()) { + return -1 + } const elementList = context.elementList || this.control.getElementList() const range = context.range || this.control.getRange() // 收缩边界到Value内 @@ -97,7 +106,14 @@ export class TextControl implements IControlInstance { return start + data.length - 1 } - public clearValue(context: IControlContext = {}): number { + public clearValue( + context: IControlContext = {}, + options: IControlRuleOption = {} + ): number { + // 校验是否可以设置 + if (!options.isIgnoreDisabledRule && this.control.isDisabledControl()) { + return -1 + } const elementList = context.elementList || this.control.getElementList() const range = context.range || this.control.getRange() const { startIndex, endIndex } = range @@ -112,6 +128,9 @@ export class TextControl implements IControlInstance { } public keydown(evt: KeyboardEvent): number | null { + if (this.control.isDisabledControl()) { + return null + } const elementList = this.control.getElementList() const range = this.control.getRange() // 收缩边界到Value内 @@ -190,6 +209,9 @@ export class TextControl implements IControlInstance { } public cut(): number { + if (this.control.isDisabledControl()) { + return -1 + } this.control.shrinkBoundary() const { startIndex, endIndex } = this.control.getRange() if (startIndex === endIndex) { diff --git a/src/editor/core/event/handlers/input.ts b/src/editor/core/event/handlers/input.ts index a6de7ca..69abc95 100644 --- a/src/editor/core/event/handlers/input.ts +++ b/src/editor/core/event/handlers/input.ts @@ -27,7 +27,6 @@ export function input(data: string, host: CanvasEvent) { const cursor = draw.getCursor() cursor.clearAgentDomValue() } - const activeControl = control.getActiveControl() const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE } = ElementType const text = data.replaceAll(`\n`, ZERO) const rangeManager = draw.getRange() @@ -65,7 +64,7 @@ export function input(data: string, host: CanvasEvent) { }) // 控件-移除placeholder let curIndex: number - if (activeControl && !control.isRangInPostfix()) { + if (control.getActiveControl() && !control.isRangInPostfix()) { curIndex = control.setValue(inputData) } else { const start = startIndex + 1 diff --git a/src/editor/core/event/handlers/mousedown.ts b/src/editor/core/event/handlers/mousedown.ts index 38cbb00..18f1352 100644 --- a/src/editor/core/event/handlers/mousedown.ts +++ b/src/editor/core/event/handlers/mousedown.ts @@ -67,26 +67,28 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) { // 复选框 const isSetCheckbox = isDirectHitCheckbox && !isReadonly if (isSetCheckbox) { - const { checkbox } = curElement - if (checkbox) { - checkbox.value = !checkbox.value + const { checkbox, control } = curElement + const codes = control?.code?.split(',') || [] + if (checkbox?.value) { + const codeIndex = codes.findIndex(c => c === checkbox.code) + codes.splice(codeIndex, 1) } else { - curElement.checkbox = { - value: true + if (checkbox?.code) { + codes.push(checkbox.code) } } - const control = draw.getControl() - const activeControl = control.getActiveControl() + const activeControl = draw.getControl().getActiveControl() if (activeControl instanceof CheckboxControl) { - activeControl.setSelect() + activeControl.setSelect(codes) } + } else { + draw.render({ + curIndex, + isCompute: false, + isSubmitHistory: false, + isSetCursor: !isDirectHitImage && !isDirectHitCheckbox + }) } - draw.render({ - curIndex, - isSubmitHistory: isSetCheckbox, - isSetCursor: !isDirectHitImage && !isDirectHitCheckbox, - isCompute: false - }) // 首字需定位到行首,非上一行最后一个字后 if (hitLineStartIndex) { host.getDraw().getCursor().drawCursor({ diff --git a/src/editor/interface/Control.ts b/src/editor/interface/Control.ts index 035987f..27a0728 100644 --- a/src/editor/interface/Control.ts +++ b/src/editor/interface/Control.ts @@ -23,6 +23,7 @@ export interface IControlCheckbox { export interface IControlRule { deletable?: boolean + disabled?: boolean } export interface IControlBasic { @@ -66,7 +67,11 @@ export interface IControlInstance { getValue(): IElement[] - setValue(data: IElement[]): number + setValue( + data: IElement[], + context?: IControlContext, + options?: IControlRuleOption + ): number keydown(evt: KeyboardEvent): number | null @@ -78,6 +83,10 @@ export interface IControlContext { elementList?: IElement[] } +export interface IControlRuleOption { + isIgnoreDisabledRule?: boolean // 忽略禁用校验规则 +} + export interface IGetControlValueOption { conceptId: string }