diff --git a/packages/common/src/editors/autocompleterEditor.ts b/packages/common/src/editors/autocompleterEditor.ts index b8168fc02..fdd0197d4 100644 --- a/packages/common/src/editors/autocompleterEditor.ts +++ b/packages/common/src/editors/autocompleterEditor.ts @@ -1,29 +1,25 @@ -import { BindingEventService } from '@slickgrid-universal/binding'; import { classNameToList, createDomElement, isObject, isPrimitiveValue, setDeepValue, toKebabCase } from '@slickgrid-universal/utils'; import autocompleter from 'autocompleter'; import type { AutocompleteItem, AutocompleteResult, AutocompleteSettings } from 'autocompleter'; import { addAutocompleteLoadingByOverridingFetch } from '../commonEditorFilter/commonEditorFilterUtils.js'; -import { applyHtmlToElement, SlickEventData, type SlickGrid } from '../core/index.js'; +import { applyHtmlToElement } from '../core/index.js'; import { textValidator } from '../editorValidators/textValidator.js'; import type { AutocompleterOption, AutocompleteSearchItem, CollectionCustomStructure, CollectionOverrideArgs, - Column, - ColumnEditor, CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, - EditorValidator, - GridOption, Locale, ValidateOption, } from '../interfaces/index.js'; import type { TranslaterService } from '../services/translater.service.js'; import { findOrDefault, getDescendantProperty } from '../services/utilities.js'; import { Constants } from './../constants.js'; +import { BaseEditorClass } from './baseEditorClass.js'; // minimum length of chars to type before starting to start querying const MIN_LENGTH = 3; @@ -32,9 +28,8 @@ const MIN_LENGTH = 3; * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class AutocompleterEditor implements Editor { +export class AutocompleterEditor extends BaseEditorClass implements Editor { protected _autocompleterOptions!: Partial>; - protected _bindEventService: BindingEventService; protected _currentValue: any; protected _defaultTextValue!: string; protected _originalValue: any; @@ -56,12 +51,6 @@ export class AutocompleterEditor implements Ed /** The translate library */ protected _translater?: TranslaterService; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - /** The property name for labels in the collection */ labelName!: string; @@ -80,15 +69,13 @@ export class AutocompleterEditor implements Ed finalCollection: T[] = []; constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this._bindEventService = new BindingEventService(); + super(args); if (this.gridOptions?.translater) { this._translater = this.gridOptions.translater; } // get locales provided by user in forRoot or else use default English locales via the Constants this._locales = this.gridOptions?.locales || Constants.locales; - this.init(); } @@ -112,16 +99,6 @@ export class AutocompleterEditor implements Ed return this._elementCollection; } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor || ({} as ColumnEditor); - } - /** Getter for the Custom Structure if exist */ get customStructure(): CollectionCustomStructure | undefined { let customStructure = this.columnEditor?.customStructure; @@ -144,25 +121,11 @@ export class AutocompleterEditor implements Ed return { ...this.gridOptions.defaultEditorOptions?.autocompleter, ...this.columnEditor?.options }; } - /** Getter for the Grid Options pulled through the Grid Object */ - get gridOptions(): GridOption { - return this.grid?.getOptions() ?? {}; - } - /** Kraaden AutoComplete instance */ get instance(): AutocompleteResult | undefined { return this._instance; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { this.labelName = this.customStructure?.label ?? 'label'; this.valueName = this.customStructure?.value ?? 'value'; @@ -441,17 +404,7 @@ export class AutocompleterEditor implements Ed /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -461,11 +414,6 @@ export class AutocompleterEditor implements Ed triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -474,25 +422,7 @@ export class AutocompleterEditor implements Ed } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData(event) - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } // this function should be protected but for unit tests purposes we'll make it public until a better solution is found diff --git a/packages/common/src/editors/baseEditorClass.ts b/packages/common/src/editors/baseEditorClass.ts new file mode 100644 index 000000000..232addb3a --- /dev/null +++ b/packages/common/src/editors/baseEditorClass.ts @@ -0,0 +1,102 @@ +import { BindingEventService } from '@slickgrid-universal/binding'; +import { SlickEventData, type SlickGrid } from '../core/index.js'; +import type { Column, ColumnEditor, CompositeEditorOption, EditorArguments, EditorValidator, GridOption } from './../interfaces/index.js'; + +/* + * An example of a 'detached' editor. + * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. + */ +export class BaseEditorClass { + protected _bindEventService: BindingEventService; + /** is the Editor disabled? */ + disabled = false; + + /** SlickGrid Grid object */ + protected grid: SlickGrid; + + /** Grid options */ + protected gridOptions: GridOption; + + constructor(protected readonly args: EditorArguments) { + this.grid = args.grid; + this.gridOptions = (this.grid.getOptions() || {}) as GridOption; + this._bindEventService = new BindingEventService(); + } + + /** Get Column Definition object */ + get columnDef(): Column { + return this.args.column; + } + + /** Get Column Editor object */ + get columnEditor(): ColumnEditor { + return this.columnDef?.editor || ({} as ColumnEditor); + } + + /** Getter for the item data context object */ + get dataContext(): any { + return this.args.item; + } + + get hasAutoCommitEdit(): boolean { + return this.gridOptions.autoCommitEdit ?? false; + } + + /** Get the Validator function, can be passed in Editor property or Column Definition */ + get validator(): EditorValidator | undefined { + return this.columnEditor?.validator ?? this.columnDef?.validator; + } + + // -- + // protected functions + // ------------------ + + /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ + protected checkInputUsabilityState(): boolean { + const activeCell = this.grid.getActiveCell(); + const isCellEditable = this.grid.onBeforeEditCell + .notify({ + ...activeCell, + item: this.dataContext, + column: this.args.column, + grid: this.grid, + target: 'composite', + compositeEditorOptions: this.args.compositeEditorOptions, + }) + .getReturnValue(); + return isCellEditable; + } + + protected handleChangeOnCompositeEditor( + event: Event | null, + compositeEditorOptions: CompositeEditorOption, + triggeredBy: 'user' | 'system' = 'user', + isCalledByClearValue = false + ): void { + const activeCell = this.grid.getActiveCell(); + const column = this.args.column; + const columnId = this.columnDef?.id ?? ''; + const item = this.dataContext; + const grid = this.grid; + + const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; + if ( + isCalledByClearValue || + (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) + ) { + delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object + } + grid.onCompositeEditorChange.notify( + { + ...activeCell, + item, + grid, + column, + formValues: compositeEditorOptions.formValues, + editors: compositeEditorOptions.editors, + triggeredBy, + }, + new SlickEventData(event) + ); + } +} diff --git a/packages/common/src/editors/checkboxEditor.ts b/packages/common/src/editors/checkboxEditor.ts index 9262c2f33..edf8ef435 100644 --- a/packages/common/src/editors/checkboxEditor.ts +++ b/packages/common/src/editors/checkboxEditor.ts @@ -1,76 +1,29 @@ -import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, setDeepValue, toSentenceCase } from '@slickgrid-universal/utils'; -import { SlickEventData, type SlickGrid } from '../core/index.js'; import { getDescendantProperty } from '../services/utilities.js'; import { Constants } from './../constants.js'; -import type { - Column, - ColumnEditor, - CompositeEditorOption, - Editor, - EditorArguments, - EditorValidationResult, - EditorValidator, - GridOption, - ValidateOption, -} from './../interfaces/index.js'; +import type { CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, ValidateOption } from './../interfaces/index.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /* * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class CheckboxEditor implements Editor { - protected _bindEventService: BindingEventService; +export class CheckboxEditor extends BaseEditorClass implements Editor { protected _checkboxContainerElm!: HTMLDivElement; protected _input!: HTMLInputElement; protected _isValueTouched = false; protected _originalValue?: boolean | string; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this.gridOptions = (this.grid.getOptions() || {}) as GridOption; - this._bindEventService = new BindingEventService(); + super(args); this.init(); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor || ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): any { return this._input; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { const columnId = this.columnDef?.id ?? ''; const compositeEditorOptions = this.args.compositeEditorOptions; @@ -297,17 +250,7 @@ export class CheckboxEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -317,11 +260,6 @@ export class CheckboxEditor implements Editor { triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -330,24 +268,6 @@ export class CheckboxEditor implements Editor { } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData(event) - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } } diff --git a/packages/common/src/editors/dateEditor.ts b/packages/common/src/editors/dateEditor.ts index c3ee6d159..15f341963 100644 --- a/packages/common/src/editors/dateEditor.ts +++ b/packages/common/src/editors/dateEditor.ts @@ -1,31 +1,26 @@ import { parse } from '@formkit/tempo'; -import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, emptyElement, extend, queueMicrotaskPolyfill, setDeepValue } from '@slickgrid-universal/utils'; import { Calendar, type FormatDateString, type Options } from 'vanilla-calendar-pro'; import { resetDatePicker, setPickerDates, setPickerFocus } from '../commonEditorFilter/commonEditorFilterUtils.js'; -import { SlickEventData, type SlickGrid } from '../core/index.js'; import { formatDateByFieldType, mapTempoDateFormatWithFieldType } from '../services/dateUtils.js'; import type { TranslaterService } from '../services/translater.service.js'; import { Constants } from './../constants.js'; import type { - Column, - ColumnEditor, CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, - EditorValidator, GridOption, ValidateOption, VanillaCalendarOption, } from './../interfaces/index.js'; import { getDescendantProperty } from './../services/utilities.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /* * An example of a date picker editor using Vanilla-Calendar-Pro */ -export class DateEditor implements Editor { - protected _bindEventService: BindingEventService; +export class DateEditor extends BaseEditorClass implements Editor { protected _clearButtonElm!: HTMLButtonElement; protected _editorInputGroupElm!: HTMLDivElement; protected _inputElm!: HTMLInputElement; @@ -40,43 +35,17 @@ export class DateEditor implements Editor { defaultDate?: string; hasTimePicker = false; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - /** The translate library */ protected _translaterService: TranslaterService | undefined; constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this.gridOptions = (this.grid.getOptions() || {}) as GridOption; + super(args); if (this.gridOptions?.translater) { this._translaterService = this.gridOptions.translater; } - this._bindEventService = new BindingEventService(); this.init(); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor || ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): HTMLInputElement { return this._inputElm; @@ -87,19 +56,10 @@ export class DateEditor implements Editor { return { ...this.gridOptions.defaultEditorOptions?.date, ...this.columnEditor?.options }; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - get pickerOptions(): VanillaCalendarOption { return this._pickerMergedOptions; } - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - async init(): Promise { if (this.args && this.columnDef) { const columnId = this.columnDef?.id ?? ''; @@ -321,7 +281,7 @@ export class DateEditor implements Editor { // if it's set by a Composite Editor, then also trigger a change for it const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions && triggerOnCompositeEditorChange) { - this.handleChangeOnCompositeEditor(compositeEditorOptions, 'system'); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions, 'system'); } } } @@ -410,7 +370,7 @@ export class DateEditor implements Editor { const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions && triggerCompositeEventWhenExist) { const shouldDeleteFormValue = !clearByDisableCommand; - this.handleChangeOnCompositeEditor(compositeEditorOptions, 'user', shouldDeleteFormValue); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions, 'user', shouldDeleteFormValue); } } @@ -466,17 +426,7 @@ export class DateEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -486,7 +436,7 @@ export class DateEditor implements Editor { if (this.args) { const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions) { - this.handleChangeOnCompositeEditor(compositeEditorOptions); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions); } else { this.save(); } @@ -496,15 +446,11 @@ export class DateEditor implements Editor { } protected handleChangeOnCompositeEditor( + event: Event | null, compositeEditorOptions: CompositeEditorOption, triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -513,24 +459,6 @@ export class DateEditor implements Editor { } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData() - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } } diff --git a/packages/common/src/editors/dualInputEditor.ts b/packages/common/src/editors/dualInputEditor.ts index 429ad43c6..52131494f 100644 --- a/packages/common/src/editors/dualInputEditor.ts +++ b/packages/common/src/editors/dualInputEditor.ts @@ -1,28 +1,23 @@ -import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, setDeepValue, toSentenceCase } from '@slickgrid-universal/utils'; -import { SlickEventData, SlickEventHandler, type SlickGrid } from '../core/index.js'; +import { SlickEventData, SlickEventHandler } from '../core/index.js'; import { floatValidator, integerValidator, textValidator } from '../editorValidators/index.js'; import type { - Column, - ColumnEditor, ColumnEditorDualInput, CompositeEditorOption, DOMEvent, Editor, EditorArguments, EditorValidationResult, - EditorValidator, - GridOption, ValidateOption, } from '../interfaces/index.js'; import { getDescendantProperty } from '../services/utilities.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /* * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class DualInputEditor implements Editor { - protected _bindEventService: BindingEventService; +export class DualInputEditor extends BaseEditorClass implements Editor { protected _eventHandler: SlickEventHandler; protected _isInternalFocusInProgress = false; protected _isValueSaveCalled = false; @@ -38,40 +33,13 @@ export class DualInputEditor implements Editor { protected _originalRightValue!: string | number; protected _timer?: any; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this.gridOptions = (this.grid.getOptions() || {}) as GridOption; + super(args); this._eventHandler = new SlickEventHandler(); - this._bindEventService = new BindingEventService(); this.init(); - this._eventHandler.subscribe(this.grid.onValidationError, () => (this._isValueSaveCalled = true)); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor || ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): { leftInput: HTMLInputElement; rightInput: HTMLInputElement } { return { leftInput: this._leftInput, rightInput: this._rightInput }; @@ -85,19 +53,10 @@ export class DualInputEditor implements Editor { return this._eventHandler; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - get isValueSaveCalled(): boolean { return this._isValueSaveCalled; } - /** Get the Shared Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { if ( !this.editorParams || @@ -538,17 +497,7 @@ export class DualInputEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } diff --git a/packages/common/src/editors/inputEditor.ts b/packages/common/src/editors/inputEditor.ts index 98b085578..3645d2968 100644 --- a/packages/common/src/editors/inputEditor.ts +++ b/packages/common/src/editors/inputEditor.ts @@ -1,19 +1,8 @@ -import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, setDeepValue, toSentenceCase } from '@slickgrid-universal/utils'; -import { SlickEventData, type SlickGrid } from '../core/index.js'; import { textValidator } from '../editorValidators/textValidator.js'; -import type { - Column, - ColumnEditor, - CompositeEditorOption, - Editor, - EditorArguments, - EditorValidationResult, - EditorValidator, - GridOption, - ValidateOption, -} from '../interfaces/index.js'; +import type { CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, ValidateOption } from '../interfaces/index.js'; import { getDescendantProperty } from '../services/utilities.js'; +import { BaseEditorClass } from './baseEditorClass.js'; const DEFAULT_DECIMAL_PLACES = 0; @@ -21,8 +10,7 @@ const DEFAULT_DECIMAL_PLACES = 0; * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class InputEditor implements Editor { - protected _bindEventService: BindingEventService; +export class InputEditor extends BaseEditorClass implements Editor { protected _isInternalFocusInProgress = false; protected _input!: HTMLInputElement | undefined; protected _inputType = 'text'; @@ -31,50 +19,20 @@ export class InputEditor implements Editor { protected _originalValue?: number | string; protected _timer?: any; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - constructor( protected readonly args: EditorArguments, inputType = 'text' ) { - this.grid = args.grid; - this.gridOptions = args.grid?.getOptions() as GridOption; - this._bindEventService = new BindingEventService(); + super(args); this.inputType = inputType; this.init(); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor || ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): any { return this._input; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - /** Getter of input type (text, number, password) */ get inputType(): string { return this._inputType; @@ -85,11 +43,6 @@ export class InputEditor implements Editor { this._inputType = type; } - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { const columnId = this.columnDef?.id ?? ''; @@ -345,17 +298,7 @@ export class InputEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -365,11 +308,6 @@ export class InputEditor implements Editor { triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -378,25 +316,7 @@ export class InputEditor implements Editor { } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData(event) - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } protected handleOnInputChange(event: KeyboardEvent): void { diff --git a/packages/common/src/editors/longTextEditor.ts b/packages/common/src/editors/longTextEditor.ts index c136f5f16..5f836d065 100644 --- a/packages/common/src/editors/longTextEditor.ts +++ b/packages/common/src/editors/longTextEditor.ts @@ -1,17 +1,13 @@ import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, getOffset, setDeepValue, toSentenceCase, type HtmlElementPosition } from '@slickgrid-universal/utils'; -import { SlickEventData, SlickEventHandler, type SlickGrid } from '../core/index.js'; +import { SlickEventHandler } from '../core/index.js'; import { textValidator } from '../editorValidators/textValidator.js'; import type { - Column, - ColumnEditor, CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, - EditorValidator, ElementPosition, - GridOption, Locale, LongTextEditorOption, ValidateOption, @@ -19,14 +15,14 @@ import type { import type { TranslaterService } from '../services/translater.service.js'; import { getDescendantProperty, getTranslationPrefix } from '../services/utilities.js'; import { Constants } from './../constants.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /* * An example of a 'detached' editor. * The UI is added onto document BODY and .position(), .show() and .hide() are implemented. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class LongTextEditor implements Editor { - protected _bindEventService: BindingEventService; +export class LongTextEditor extends BaseEditorClass implements Editor { protected _eventHandler: SlickEventHandler; protected _defaultTextValue: any; protected _isValueTouched = false; @@ -36,21 +32,11 @@ export class LongTextEditor implements Editor { protected _textareaElm!: HTMLTextAreaElement; protected _wrapperElm!: HTMLDivElement; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - /** The translate library */ protected _translater?: TranslaterService; constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this.gridOptions = args.grid?.getOptions() as GridOption; + super(args); const options = this.gridOptions || this.args.column.params || {}; if (options?.translater) { this._translater = options.translater; @@ -64,21 +50,6 @@ export class LongTextEditor implements Editor { this.init(); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor ?? ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): HTMLTextAreaElement { return this._textareaElm; @@ -88,15 +59,6 @@ export class LongTextEditor implements Editor { return { ...this.gridOptions.defaultEditorOptions?.longText, ...this.columnEditor?.options }; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions?.autoCommitEdit ?? false; - } - - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { let cancelText = ''; let saveText = ''; @@ -418,17 +380,7 @@ export class LongTextEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -502,11 +454,6 @@ export class LongTextEditor implements Editor { triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -515,25 +462,7 @@ export class LongTextEditor implements Editor { } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData(event) - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } /** diff --git a/packages/common/src/editors/selectEditor.ts b/packages/common/src/editors/selectEditor.ts index 2ff97101e..1666ba77f 100644 --- a/packages/common/src/editors/selectEditor.ts +++ b/packages/common/src/editors/selectEditor.ts @@ -8,30 +8,26 @@ import { sortCollectionWithOptions, } from '../commonEditorFilter/commonEditorFilterUtils.js'; import { Constants } from '../constants.js'; -import { SlickEventData, type SlickGrid } from '../core/index.js'; import { buildMsSelectCollectionList, CollectionService, findOrDefault, type TranslaterService } from '../services/index.js'; import { getDescendantProperty, getTranslationPrefix } from '../services/utilities.js'; import type { CollectionCustomStructure, CollectionOption, CollectionOverrideArgs, - Column, - ColumnEditor, CompositeEditorOption, Editor, EditorArguments, EditorValidationResult, - EditorValidator, - GridOption, Locale, SelectOption, ValidateOption, } from './../interfaces/index.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /** * Slickgrid editor class for multiple/single select lists */ -export class SelectEditor implements Editor { +export class SelectEditor extends BaseEditorClass implements Editor { protected _isValueTouched = false; /** Locales */ @@ -52,9 +48,6 @@ export class SelectEditor implements Editor { /** Editor DOM element */ editorElm?: HTMLElement; - /** is the Editor disabled? */ - disabled = false; - /** Editor Multiple-Select options */ editorElmOptions!: Partial; @@ -82,15 +75,9 @@ export class SelectEditor implements Editor { /** The property name for values in the collection */ valueName!: string; - /** Grid options */ - gridOptions: GridOption; - /** Do we translate the label? */ enableTranslateLabel = false; - /** SlickGrid Grid object */ - grid: SlickGrid; - /** Final collection displayed in the UI, that is after processing filter/sort/override */ finalCollection: any[] = []; @@ -98,8 +85,7 @@ export class SelectEditor implements Editor { protected readonly args: EditorArguments, protected readonly isMultipleSelect: boolean ) { - this.grid = args.grid; - this.gridOptions = (this.grid.getOptions() || {}) as GridOption; + super(args); if (this.gridOptions?.translater) { this._translaterService = this.gridOptions.translater; } @@ -148,7 +134,7 @@ export class SelectEditor implements Editor { } if (compositeEditorOptions) { - this.handleChangeOnCompositeEditor(compositeEditorOptions); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions); } else { this._isDisposingOrCallingSave = true; this.save(this.hasAutoCommitEdit); @@ -185,25 +171,10 @@ export class SelectEditor implements Editor { return this.columnEditor?.collectionOptions; } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - get columnId(): string | number { return this.columnDef?.id ?? ''; } - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return (this.columnDef?.editor ?? {}) as ColumnEditor; - } - - /** Getter for item data context object */ - get dataContext(): any { - return this.args.item; - } - get editorOptions(): MultipleSelectOption { return { ...this.gridOptions.defaultEditorOptions?.select, ...this.columnEditor?.options }; } @@ -213,10 +184,6 @@ export class SelectEditor implements Editor { return this.columnDef?.editor?.customStructure; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - get msInstance(): MultipleSelectInstance | undefined { return this._msInstance; } @@ -320,11 +287,6 @@ export class SelectEditor implements Editor { return ''; } - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor?.validator ?? this.columnDef?.validator; - } - init(): void { if (!this.columnDef || !this.columnDef.editor || (!this.columnDef.editor.collection && !this.columnDef.editor.collectionAsync)) { throw new Error(`[Slickgrid-Universal] You need to pass a "collection" (or "collectionAsync") inside Column Definition Editor for the MultipleSelect/SingleSelect Editor to work correctly. @@ -374,7 +336,7 @@ export class SelectEditor implements Editor { // if it's set by a Composite Editor, then also trigger a change for it const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions && triggerOnCompositeEditorChange) { - this.handleChangeOnCompositeEditor(compositeEditorOptions, 'system'); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions, 'system'); } } } @@ -491,7 +453,7 @@ export class SelectEditor implements Editor { // if it's set by a Composite Editor, then also trigger a change for it const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions) { - this.handleChangeOnCompositeEditor(compositeEditorOptions); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions); } } } @@ -580,7 +542,7 @@ export class SelectEditor implements Editor { const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions && triggerCompositeEventWhenExist) { const shouldDeleteFormValue = !clearByDisableCommand; - this.handleChangeOnCompositeEditor(compositeEditorOptions, 'user', shouldDeleteFormValue); + this.handleChangeOnCompositeEditor(null, compositeEditorOptions, 'user', shouldDeleteFormValue); } } @@ -637,17 +599,7 @@ export class SelectEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -778,40 +730,19 @@ export class SelectEditor implements Editor { } protected handleChangeOnCompositeEditor( + event: Event | null, compositeEditorOptions: CompositeEditorOption, triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const item = this.dataContext; - const grid = this.grid; - const newValues = this.serializeValue(); + const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object if (this.validate().valid) { - this.applyValue(this.dataContext, newValues); + this.applyValue(this.dataContext, newValue); } - this.applyValue(compositeEditorOptions.formValues, newValues); + this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(this.columnId)) - ) { - delete compositeEditorOptions.formValues[this.columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData() - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } } diff --git a/packages/common/src/editors/sliderEditor.ts b/packages/common/src/editors/sliderEditor.ts index 3d8a2c31b..f69e75e09 100644 --- a/packages/common/src/editors/sliderEditor.ts +++ b/packages/common/src/editors/sliderEditor.ts @@ -1,29 +1,25 @@ import { BindingEventService } from '@slickgrid-universal/binding'; import { createDomElement, setDeepValue, toSentenceCase } from '@slickgrid-universal/utils'; import { Constants } from '../constants.js'; -import { SlickEventData, type SlickGrid } from '../core/index.js'; +import { SlickEventData } from '../core/index.js'; import { sliderValidator } from '../editorValidators/sliderValidator.js'; import type { - Column, - ColumnEditor, CompositeEditorOption, CurrentSliderOption, Editor, EditorArguments, EditorValidationResult, - EditorValidator, - GridOption, SliderOption, ValidateOption, } from '../interfaces/index.js'; import { getDescendantProperty } from '../services/utilities.js'; +import { BaseEditorClass } from './baseEditorClass.js'; /* * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ -export class SliderEditor implements Editor { - protected _bindEventService: BindingEventService; +export class SliderEditor extends BaseEditorClass implements Editor { protected _defaultValue = 0; protected _isValueTouched = false; protected _originalValue?: number | string; @@ -34,37 +30,12 @@ export class SliderEditor implements Editor { protected _sliderTrackElm!: HTMLDivElement; protected _sliderNumberElm: HTMLSpanElement | null = null; - /** is the Editor disabled? */ - disabled = false; - - /** SlickGrid Grid object */ - grid: SlickGrid; - - /** Grid options */ - gridOptions: GridOption; - constructor(protected readonly args: EditorArguments) { - this.grid = args.grid; - this.gridOptions = (this.grid.getOptions() || {}) as GridOption; + super(args); this._bindEventService = new BindingEventService(); this.init(); } - /** Get Column Definition object */ - get columnDef(): Column { - return this.args.column; - } - - /** Get Column Editor object */ - get columnEditor(): ColumnEditor { - return this.columnDef?.editor ?? ({} as ColumnEditor); - } - - /** Getter for the item data context object */ - get dataContext(): any { - return this.args.item; - } - /** Getter for the Editor DOM Element */ get editorDomElement(): HTMLDivElement { return this._editorElm; @@ -79,20 +50,11 @@ export class SliderEditor implements Editor { return { ...this.gridOptions.defaultEditorOptions?.slider, ...this.columnEditor?.options }; } - get hasAutoCommitEdit(): boolean { - return this.gridOptions.autoCommitEdit ?? false; - } - /** Getter for the current Slider Options */ get sliderOptions(): CurrentSliderOption | undefined { return this._sliderOptions; } - /** Get the Validator function, can be passed in Editor property or Column Definition */ - get validator(): EditorValidator | undefined { - return this.columnEditor.validator ?? this.columnDef?.validator; - } - init(): void { this._cellContainerElm = this.args?.container; @@ -395,17 +357,7 @@ export class SliderEditor implements Editor { /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ protected applyInputUsabilityState(): void { - const activeCell = this.grid.getActiveCell(); - const isCellEditable = this.grid.onBeforeEditCell - .notify({ - ...activeCell, - item: this.dataContext, - column: this.args.column, - grid: this.grid, - target: 'composite', - compositeEditorOptions: this.args.compositeEditorOptions, - }) - .getReturnValue(); + const isCellEditable = super.checkInputUsabilityState(); this.disable(isCellEditable === false); } @@ -441,11 +393,6 @@ export class SliderEditor implements Editor { triggeredBy: 'user' | 'system' = 'user', isCalledByClearValue = false ): void { - const activeCell = this.grid.getActiveCell(); - const column = this.args.column; - const columnId = this.columnDef?.id ?? ''; - const item = this.dataContext; - const grid = this.grid; const newValue = this.serializeValue(); // when valid, we'll also apply the new value to the dataContext item object @@ -454,25 +401,7 @@ export class SliderEditor implements Editor { } this.applyValue(compositeEditorOptions.formValues, newValue); - const isExcludeDisabledFieldFormValues = this.gridOptions?.compositeEditorOptions?.excludeDisabledFieldFormValues ?? false; - if ( - isCalledByClearValue || - (this.disabled && isExcludeDisabledFieldFormValues && compositeEditorOptions.formValues.hasOwnProperty(columnId)) - ) { - delete compositeEditorOptions.formValues[columnId]; // when the input is disabled we won't include it in the form result object - } - grid.onCompositeEditorChange.notify( - { - ...activeCell, - item, - grid, - column, - formValues: compositeEditorOptions.formValues, - editors: compositeEditorOptions.editors, - triggeredBy, - }, - new SlickEventData(event) - ); + super.handleChangeOnCompositeEditor(event, compositeEditorOptions, triggeredBy, isCalledByClearValue); } /** use keydown event to increase/decrease slider value */