From f2fbbfcad163668b171a923d7e012c1227fe37ce Mon Sep 17 00:00:00 2001 From: Ghislain Beaulac Date: Wed, 1 May 2019 10:24:11 -0400 Subject: [PATCH] fix(editors): not allow grid paste of invalid values, issue #171 - the Editors all have their own "validate()" method that verifies if the value is valid or not and we should also verify the values when pasting into the grid --- src/app/examples/custom-inputEditor.ts | 7 ++++--- .../editors/autoCompleteEditor.ts | 7 ++++--- .../editors/checkboxEditor.ts | 7 ++++--- .../angular-slickgrid/editors/dateEditor.ts | 18 ++++++++++++------ .../angular-slickgrid/editors/floatEditor.ts | 7 ++++--- .../angular-slickgrid/editors/integerEditor.ts | 7 ++++--- .../editors/longTextEditor.ts | 10 +++++----- .../angular-slickgrid/editors/selectEditor.ts | 15 ++++++++------- .../angular-slickgrid/editors/sliderEditor.ts | 7 ++++--- .../angular-slickgrid/editors/textEditor.ts | 7 ++++--- 10 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/app/examples/custom-inputEditor.ts b/src/app/examples/custom-inputEditor.ts index 53a82fbb1..3f900bfeb 100644 --- a/src/app/examples/custom-inputEditor.ts +++ b/src/app/examples/custom-inputEditor.ts @@ -87,7 +87,8 @@ export class CustomInputEditor implements Editor { } applyValue(item: any, state: any) { - item[this.args.column.field] = state; + const validation = this.validate(state); + item[this.args.column.field] = (validation && validation.valid) ? state : ''; } isValueChanged() { @@ -109,9 +110,9 @@ export class CustomInputEditor implements Editor { } } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { if (this.validator) { - const value = this.$input && this.$input.val && this.$input.val(); + const value = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); return this.validator(value, this.args); } diff --git a/src/app/modules/angular-slickgrid/editors/autoCompleteEditor.ts b/src/app/modules/angular-slickgrid/editors/autoCompleteEditor.ts index 5c9a362c5..130cee475 100644 --- a/src/app/modules/angular-slickgrid/editors/autoCompleteEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/autoCompleteEditor.ts @@ -185,7 +185,8 @@ export class AutoCompleteEditor implements Editor { // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = newValue; + const validation = this.validate(newValue); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : ''; } isValueChanged() { @@ -196,9 +197,9 @@ export class AutoCompleteEditor implements Editor { return (!(this.$input.val() === '' && this._defaultTextValue === null)) && (this.$input.val() !== this._defaultTextValue); } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const elmValue = this.$input && this.$input.val && this.$input.val(); + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const errorMsg = this.columnEditor.errorMessage; if (this.validator) { diff --git a/src/app/modules/angular-slickgrid/editors/checkboxEditor.ts b/src/app/modules/angular-slickgrid/editors/checkboxEditor.ts index c775280cf..5edb8182c 100644 --- a/src/app/modules/angular-slickgrid/editors/checkboxEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/checkboxEditor.ts @@ -89,16 +89,17 @@ export class CheckboxEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } isValueChanged() { return (this.serializeValue() !== this.defaultValue); } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const isChecked = this.$input && this.$input.prop && this.$input.prop('checked'); + const isChecked = (inputValue !== undefined) ? inputValue : this.$input && this.$input.prop && this.$input.prop('checked'); const errorMsg = this.columnEditor.errorMessage; if (this.validator) { diff --git a/src/app/modules/angular-slickgrid/editors/dateEditor.ts b/src/app/modules/angular-slickgrid/editors/dateEditor.ts index 1c110507f..658905c05 100644 --- a/src/app/modules/angular-slickgrid/editors/dateEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/dateEditor.ts @@ -35,6 +35,11 @@ export class DateEditor implements Editor { return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {}; } + /** Get Flatpickr options passed to the editor by the user */ + get editorOptions(): any { + return this.columnEditor.editorOptions || {}; + } + /** Get the Validator function, can be passed in Editor property or Column Definition */ get validator(): EditorValidator { return this.columnEditor.validator || this.columnDef.validator; @@ -68,7 +73,7 @@ export class DateEditor implements Editor { }; // merge options with optional user's custom options - const pickerMergedOptions = { ...pickerOptions, ...this.columnEditor.editorOptions }; + const pickerMergedOptions = { ...pickerOptions, ...this.editorOptions }; const inputCssClasses = `.editor-text.editor-${columnId}.flatpickr`; this.$input = $(``); @@ -178,21 +183,22 @@ export class DateEditor implements Editor { // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state ? moment(state, outputFormat).toDate() : ''; + const newValue = state ? moment(state, outputFormat).toDate() : ''; + const validation = this.validate(newValue); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : ''; } isValueChanged() { return (!(this.$input.val() === '' && this.defaultDate == null)) && (this.$input.val() !== this.defaultDate); } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const elmValue = this.$input && this.$input.val && this.$input.val(); + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const errorMsg = this.columnEditor.errorMessage; if (this.validator) { - const value = this.$input && this.$input.val && this.$input.val(); - return this.validator(value, this.args); + return this.validator(elmValue, this.args); } // by default the editor is almost always valid (except when it's required but not provided) diff --git a/src/app/modules/angular-slickgrid/editors/floatEditor.ts b/src/app/modules/angular-slickgrid/editors/floatEditor.ts index 4018a6352..98700fea2 100644 --- a/src/app/modules/angular-slickgrid/editors/floatEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/floatEditor.ts @@ -140,7 +140,8 @@ export class FloatEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } isValueChanged() { @@ -163,8 +164,8 @@ export class FloatEditor implements Editor { } } - validate(): EditorValidatorOutput { - const elmValue = this.$input.val(); + validate(inputValue?: any): EditorValidatorOutput { + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const floatNumber = !isNaN(elmValue as number) ? parseFloat(elmValue) : null; const decPlaces = this.getDecimalPlaces(); const isRequired = this.columnEditor.required; diff --git a/src/app/modules/angular-slickgrid/editors/integerEditor.ts b/src/app/modules/angular-slickgrid/editors/integerEditor.ts index 45af235dd..cdaf6f97c 100644 --- a/src/app/modules/angular-slickgrid/editors/integerEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/integerEditor.ts @@ -99,7 +99,8 @@ export class IntegerEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } isValueChanged() { @@ -124,8 +125,8 @@ export class IntegerEditor implements Editor { } } - validate(): EditorValidatorOutput { - const elmValue = this.$input.val(); + validate(inputValue?: any): EditorValidatorOutput { + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const intNumber = !isNaN(elmValue as number) ? parseInt(elmValue, 10) : null; const errorMsg = this.columnEditor.errorMessage; const isRequired = this.columnEditor.required; diff --git a/src/app/modules/angular-slickgrid/editors/longTextEditor.ts b/src/app/modules/angular-slickgrid/editors/longTextEditor.ts index 9d9e36aee..079965250 100644 --- a/src/app/modules/angular-slickgrid/editors/longTextEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/longTextEditor.ts @@ -168,7 +168,8 @@ export class LongTextEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } @@ -189,14 +190,13 @@ export class LongTextEditor implements Editor { } } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const elmValue = this.$textarea && this.$textarea.val && this.$textarea.val(); + const elmValue = (inputValue !== undefined) ? inputValue : this.$textarea && this.$textarea.val && this.$textarea.val(); const errorMsg = this.columnEditor.errorMessage; if (this.validator) { - const value = this.$textarea && this.$textarea.val && this.$textarea.val(); - return this.validator(value, this.args); + return this.validator(elmValue, this.args); } // by default the editor is almost always valid (except when it's required but not provided) diff --git a/src/app/modules/angular-slickgrid/editors/selectEditor.ts b/src/app/modules/angular-slickgrid/editors/selectEditor.ts index 44fae3ced..030d1618f 100644 --- a/src/app/modules/angular-slickgrid/editors/selectEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/selectEditor.ts @@ -274,22 +274,23 @@ export class SelectEditor implements Editor { applyValue(item: any, state: any): void { const fieldName = this.columnDef && this.columnDef.field; const fieldType = this.columnDef && this.columnDef.type; - let value = state; + let newValue = state; // when the provided user defined the column field type as a possible number then try parsing the state value as that if (fieldType === FieldType.number || fieldType === FieldType.integer || fieldType === FieldType.boolean) { - value = parseFloat(state); + newValue = parseFloat(state); } // when set as a multiple selection, we can assume that the 3rd party lib multiple-select will return a CSV string // we need to re-split that into an array to be the same as the original column if (this.isMultipleSelect && typeof state === 'string' && state.indexOf(',') >= 0) { - value = state.split(','); + newValue = state.split(','); } // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = value; + const validation = this.validate(newValue); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : ''; } destroy() { @@ -365,13 +366,13 @@ export class SelectEditor implements Editor { return this.$editorElm.val() !== this.defaultValue; } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const elmValue = this.$editorElm && this.$editorElm.val && this.$editorElm.val(); + const elmValue = (inputValue !== undefined) ? inputValue : this.$editorElm && this.$editorElm.val && this.$editorElm.val(); const errorMsg = this.columnEditor.errorMessage; if (this.validator) { - const value = this.isMultipleSelect ? this.currentValues : this.currentValue; + const value = (inputValue !== undefined) ? inputValue : (this.isMultipleSelect ? this.currentValues : this.currentValue); return this.validator(value, this.args); } diff --git a/src/app/modules/angular-slickgrid/editors/sliderEditor.ts b/src/app/modules/angular-slickgrid/editors/sliderEditor.ts index e268cf46b..2050117c5 100644 --- a/src/app/modules/angular-slickgrid/editors/sliderEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/sliderEditor.ts @@ -119,7 +119,8 @@ export class SliderEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } isValueChanged() { @@ -131,8 +132,8 @@ export class SliderEditor implements Editor { return (!(elmValue === '' && this.defaultValue === null)) && (elmValue !== this.defaultValue); } - validate(): EditorValidatorOutput { - const elmValue = this.$input.val(); + validate(inputValue?: any): EditorValidatorOutput { + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const isRequired = this.columnEditor.required; const minValue = this.columnEditor.minValue; const maxValue = this.columnEditor.maxValue; diff --git a/src/app/modules/angular-slickgrid/editors/textEditor.ts b/src/app/modules/angular-slickgrid/editors/textEditor.ts index a335ec75f..f1a496049 100644 --- a/src/app/modules/angular-slickgrid/editors/textEditor.ts +++ b/src/app/modules/angular-slickgrid/editors/textEditor.ts @@ -99,7 +99,8 @@ export class TextEditor implements Editor { const fieldName = this.columnDef && this.columnDef.field; // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user" const fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : ''; - item[fieldNameFromComplexObject || fieldName] = state; + const validation = this.validate(state); + item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : ''; } isValueChanged() { @@ -121,9 +122,9 @@ export class TextEditor implements Editor { } } - validate(): EditorValidatorOutput { + validate(inputValue?: any): EditorValidatorOutput { const isRequired = this.columnEditor.required; - const elmValue = this.$input && this.$input.val && this.$input.val(); + const elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val(); const errorMsg = this.columnEditor.errorMessage; if (this.validator) {