mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-47880 UI breaks when pasting very large text into text field (#12043)
This commit is contained in:
@@ -19,6 +19,7 @@ import { ContainerModel } from './container.model';
|
||||
import { ErrorMessageModel } from './error-message.model';
|
||||
import { FormFieldTypes } from './form-field-types';
|
||||
import {
|
||||
DEFAULT_TEXT_MAX_LENGTH,
|
||||
FixedValueFieldValidator,
|
||||
MaxLengthFieldValidator,
|
||||
MaxValueFieldValidator,
|
||||
@@ -681,6 +682,42 @@ describe('FormFieldValidator', () => {
|
||||
expect(validator.isSupported(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should support text field when fallback maxLength is defined', () => {
|
||||
const fallbackValidator = new MaxLengthFieldValidator([FormFieldTypes.TEXT], undefined, DEFAULT_TEXT_MAX_LENGTH);
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.TEXT
|
||||
});
|
||||
|
||||
expect(fallbackValidator.isSupported(field)).toBe(true);
|
||||
expect(fallbackValidator.getMaxLength(field)).toBe(DEFAULT_TEXT_MAX_LENGTH);
|
||||
});
|
||||
|
||||
it('should validate text field against fallback maxLength when maxLength is not configured', () => {
|
||||
const fallbackValidator = new MaxLengthFieldValidator([FormFieldTypes.TEXT], undefined, DEFAULT_TEXT_MAX_LENGTH);
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.TEXT,
|
||||
value: 'a'.repeat(DEFAULT_TEXT_MAX_LENGTH + 1)
|
||||
});
|
||||
|
||||
field.validationSummary = new ErrorMessageModel();
|
||||
expect(fallbackValidator.validate(field)).toBe(false);
|
||||
expect(field.validationSummary.message).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
expect(field.validationSummary.attributes.get('maxLength')).toBe(DEFAULT_TEXT_MAX_LENGTH.toLocaleString());
|
||||
});
|
||||
|
||||
it('should use configured maxLength instead of fallback maxLength', () => {
|
||||
const fallbackValidator = new MaxLengthFieldValidator([FormFieldTypes.TEXT], undefined, DEFAULT_TEXT_MAX_LENGTH);
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.TEXT,
|
||||
maxLength: 3,
|
||||
value: '1234'
|
||||
});
|
||||
|
||||
field.validationSummary = new ErrorMessageModel();
|
||||
expect(fallbackValidator.validate(field)).toBe(false);
|
||||
expect(field.validationSummary.attributes.get('maxLength')).toBe('3');
|
||||
});
|
||||
|
||||
it('should allow empty values', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.TEXT,
|
||||
|
||||
@@ -21,6 +21,8 @@ import { FormFieldTypes } from './form-field-types';
|
||||
import { isNumberValue } from './form-field-utils';
|
||||
import { FormFieldModel } from './form-field.model';
|
||||
|
||||
export const DEFAULT_TEXT_MAX_LENGTH = 1024;
|
||||
|
||||
export interface FormFieldValidator {
|
||||
isSupported(field: FormFieldModel): boolean;
|
||||
validate(field: FormFieldModel): boolean;
|
||||
@@ -135,7 +137,8 @@ export class MinLengthFieldValidator implements FormFieldValidator {
|
||||
export class MaxLengthFieldValidator implements FormFieldValidator {
|
||||
constructor(
|
||||
private readonly supportedTypes: FormFieldTypes[] = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT],
|
||||
private readonly maxLength?: number
|
||||
private readonly maxLength?: number,
|
||||
private readonly fallbackMaxLength?: number
|
||||
) {}
|
||||
|
||||
isSupported(field: FormFieldModel): boolean {
|
||||
@@ -158,7 +161,11 @@ export class MaxLengthFieldValidator implements FormFieldValidator {
|
||||
}
|
||||
|
||||
getMaxLength(field: FormFieldModel): number | undefined {
|
||||
return this.maxLength ?? field.maxLength;
|
||||
if (this.maxLength !== undefined) {
|
||||
return this.maxLength;
|
||||
}
|
||||
|
||||
return field.maxLength > 0 ? field.maxLength : this.fallbackMaxLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +324,8 @@ export const FORM_FIELD_VALIDATORS = [
|
||||
new RequiredFieldValidator(),
|
||||
new NumberFieldValidator(),
|
||||
new MinLengthFieldValidator(),
|
||||
new MaxLengthFieldValidator(),
|
||||
new MaxLengthFieldValidator([FormFieldTypes.TEXT], undefined, DEFAULT_TEXT_MAX_LENGTH),
|
||||
new MaxLengthFieldValidator([FormFieldTypes.MULTILINE_TEXT]),
|
||||
new MaxLengthFieldValidator([FormFieldTypes.NUMBER], 10),
|
||||
new MinValueFieldValidator(),
|
||||
new MaxValueFieldValidator(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="adf-textfield adf-text-widget {{ field.className }}"
|
||||
[class.adf-invalid]="!field.isValid && isTouched()"
|
||||
[class.adf-invalid]="(!field.isValid || maxLengthPasteError.isActive()) && isTouched()"
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
[class.adf-left-label-input-container]="field.leftLabels">
|
||||
<div *ngIf="field.leftLabels">
|
||||
@@ -26,15 +26,32 @@
|
||||
[placeholder]="placeholder"
|
||||
[title]="field.tooltip"
|
||||
[errorStateMatcher]="errorStateMatcher"
|
||||
(input)="onInput($event)"
|
||||
(paste)="onPaste($event)"
|
||||
(blur)="onBlur()">
|
||||
@if (!fieldStatusTemplate && (field.validationSummary?.message || (isInvalidFieldRequired() && isTouched()))) {
|
||||
@if (!fieldStatusTemplate && (maxLengthPasteError.isActive() || field.validationSummary?.message || (isInvalidFieldRequired() && isTouched()))) {
|
||||
<mat-error>
|
||||
<mat-icon class="adf-error-icon">error_outline</mat-icon>
|
||||
<span class="adf-error-text"
|
||||
>@if (field.validationSummary?.message) {{{ field.validationSummary.message | translate:translateParameters }}} @else {{{ 'FORM.FIELD.REQUIRED' | translate }}}</span>
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<span class="adf-error-text">
|
||||
@if (maxLengthPasteError.isActive()) {
|
||||
{{ maxLengthPasteError.message | translate:maxLengthPasteErrorParameters }}
|
||||
} @else if (field.validationSummary?.message) {
|
||||
{{ field.validationSummary.message | translate:translateParameters }}
|
||||
} @else {
|
||||
{{ 'FORM.FIELD.REQUIRED' | translate }}
|
||||
}
|
||||
</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<ng-container *ngTemplateOutlet="fieldStatusTemplate ?? null; context: { $implicit: this }" />
|
||||
<ng-container *ngTemplateOutlet="maxLengthPasteError.isActive() && fieldStatusTemplate ? maxLengthPasteErrorTemplate : (fieldStatusTemplate ?? null); context: { $implicit: this }" />
|
||||
<ng-template #maxLengthPasteErrorTemplate>
|
||||
<div class="adf-error-container adf-error-messages-container">
|
||||
<div class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ maxLengthPasteError.message | translate:maxLengthPasteErrorParameters }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -142,6 +142,186 @@ describe('TextWidgetComponent', () => {
|
||||
expect(errors[0]).toContain('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
});
|
||||
|
||||
it('should validate against default max length when maxLength is not configured', async () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
await testingUtils.fillMatInput('a'.repeat(1025));
|
||||
|
||||
expect(widget.field.isValid).toBe(false);
|
||||
expect(widget.field.validationSummary.message).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
expect(widget.field.validationSummary.attributes.get('maxLength')).toBe('1,024');
|
||||
});
|
||||
|
||||
it('should block paste when resulting value exceeds configured max length', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
|
||||
expect(pasteEvent.preventDefault).toHaveBeenCalled();
|
||||
expect(widget.maxLengthPasteError.message).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
expect(widget.maxLengthPasteError.attributes.get('maxLength')).toBe('5');
|
||||
|
||||
widget.field.validate();
|
||||
fixture.detectChanges();
|
||||
|
||||
const errorWidget = testingUtils.getByCSS('.adf-error-text').nativeElement;
|
||||
expect(errorWidget.textContent.trim()).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(true);
|
||||
});
|
||||
|
||||
it('should keep paste max length error when value change emits after blocked paste', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
widget.onValueChange('123456');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(true);
|
||||
const errorWidget = testingUtils.getByCSS('.adf-error-text').nativeElement;
|
||||
expect(errorWidget.textContent.trim()).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
});
|
||||
|
||||
it('should keep paste max length error when paste input event emits after blocked paste', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
|
||||
widget.onInput({ inputType: 'insertFromPaste' } as unknown as Event);
|
||||
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(true);
|
||||
});
|
||||
|
||||
it('should clear paste max length error when non-paste input happens after blocked paste', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
widget.onInput({ inputType: 'insertText' } as unknown as Event);
|
||||
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(false);
|
||||
});
|
||||
|
||||
it('should allow paste when selected text keeps resulting value within max length', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '12345',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '12345';
|
||||
inputElement.setSelectionRange(2, 5);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => 'abc' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
|
||||
expect(pasteEvent.preventDefault).not.toHaveBeenCalled();
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(false);
|
||||
});
|
||||
|
||||
it('should block paste when resulting value exceeds default max length', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: 'a'.repeat(1024),
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = 'a'.repeat(1024);
|
||||
inputElement.setSelectionRange(1024, 1024);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => 'b' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
|
||||
expect(pasteEvent.preventDefault).toHaveBeenCalled();
|
||||
expect(widget.maxLengthPasteError.message).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
expect(widget.maxLengthPasteError.attributes.get('maxLength')).toBe('1,024');
|
||||
expect(widget.maxLengthPasteError.isActive()).toBe(true);
|
||||
});
|
||||
|
||||
it('should be able to set regex pattern property for Text widget', async () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
@@ -505,6 +685,59 @@ describe('TextWidgetComponent', () => {
|
||||
const customStatusMessage = testingUtils.getByCSS('.custom-status-message').nativeElement;
|
||||
expect(customStatusMessage?.textContent).toBe(`custom status message for ${widget.field.name}`);
|
||||
});
|
||||
|
||||
it('should display paste max length error with custom status template', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const pasteErrorWidget = testingUtils.getByCSS('.adf-error-text').nativeElement;
|
||||
expect(pasteErrorWidget.innerHTML).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
});
|
||||
|
||||
it('should replace custom status template with paste max length error', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'text-id',
|
||||
name: 'text-name',
|
||||
value: '1234',
|
||||
type: FormFieldTypes.TEXT,
|
||||
readOnly: false,
|
||||
maxLength: 5
|
||||
});
|
||||
fixture.detectChanges();
|
||||
const inputElement = testingUtils.getByCSS('#text-id').nativeElement;
|
||||
inputElement.value = '1234';
|
||||
inputElement.setSelectionRange(4, 4);
|
||||
const pasteEvent = {
|
||||
target: inputElement,
|
||||
clipboardData: { getData: () => '56' },
|
||||
preventDefault: jasmine.createSpy('preventDefault')
|
||||
} as unknown as ClipboardEvent;
|
||||
|
||||
widget.onPaste(pasteEvent);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(testingUtils.getByCSS('.custom-status-message')).toBeNull();
|
||||
const pasteErrorWidget = testingUtils.getByCSS('.adf-error-text').nativeElement;
|
||||
expect(pasteErrorWidget.innerHTML).toBe('FORM.FIELD.VALIDATOR.NO_LONGER_THAN');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { WidgetComponent } from '../widget.component';
|
||||
import { ErrorMessageModel } from '../core/error-message.model';
|
||||
import { FormattableTextWidgetComponent } from '../core/formattable-text.widget';
|
||||
import { DEFAULT_TEXT_MAX_LENGTH } from '../core/form-field-validator';
|
||||
import { InputMaskDirective } from './text-mask.component';
|
||||
import { IconModule } from '../../../../icon/icon.module';
|
||||
|
||||
@@ -67,12 +69,21 @@ export class FieldStatusTemplateDirective {
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class TextWidgetComponent extends FormattableTextWidgetComponent {
|
||||
mask: string;
|
||||
placeholder: string;
|
||||
isMaskReversed: boolean;
|
||||
mask = '';
|
||||
placeholder = '';
|
||||
isMaskReversed = false;
|
||||
fieldStatusTemplate = inject(FIELD_STATUS_TEMPLATE, { optional: true });
|
||||
errorStateMatcher: ErrorStateMatcher;
|
||||
errorStateMatcher!: ErrorStateMatcher;
|
||||
translateParameters: Record<string, string> = {};
|
||||
maxLengthPasteError = new ErrorMessageModel();
|
||||
|
||||
get resolvedMaxLength(): number {
|
||||
return this.field?.maxLength > 0 ? this.field.maxLength : DEFAULT_TEXT_MAX_LENGTH;
|
||||
}
|
||||
|
||||
get maxLengthPasteErrorParameters(): Record<string, string> {
|
||||
return this.maxLengthPasteError.getAttributesAsJsonObj();
|
||||
}
|
||||
|
||||
override ngOnInit() {
|
||||
super.ngOnInit();
|
||||
@@ -88,19 +99,28 @@ export class TextWidgetComponent extends FormattableTextWidgetComponent {
|
||||
this.initErrorStateMatcher();
|
||||
}
|
||||
|
||||
private initErrorStateMatcher(): void {
|
||||
this.errorStateMatcher = {
|
||||
isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean =>
|
||||
!this.fieldStatusTemplate && (!!this.field.validationSummary?.message || (this.isInvalidFieldRequired() && this.isTouched()))
|
||||
};
|
||||
onPaste(event: ClipboardEvent): void {
|
||||
const input = event.target instanceof HTMLInputElement ? event.target : null;
|
||||
const pastedValue = event.clipboardData?.getData('text') ?? '';
|
||||
|
||||
if (!input || this.getLengthAfterPaste(input, pastedValue) <= this.resolvedMaxLength) {
|
||||
this.clearMaxLengthPasteError();
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
this.markAsTouched();
|
||||
this.setMaxLengthPasteError();
|
||||
}
|
||||
|
||||
private updateTranslateParameters(): void {
|
||||
if (this.field.validationSummary?.isActive()) {
|
||||
this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj();
|
||||
} else {
|
||||
this.translateParameters = {};
|
||||
onInput(event: Event): void {
|
||||
const inputType = 'inputType' in event ? event.inputType : undefined;
|
||||
|
||||
if (inputType === 'insertFromPaste') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearMaxLengthPasteError();
|
||||
}
|
||||
|
||||
onBlur(): void {
|
||||
@@ -112,4 +132,41 @@ export class TextWidgetComponent extends FormattableTextWidgetComponent {
|
||||
this.onFieldChanged(this.field);
|
||||
this.updateTranslateParameters();
|
||||
}
|
||||
|
||||
private initErrorStateMatcher(): void {
|
||||
this.errorStateMatcher = {
|
||||
isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean =>
|
||||
!this.fieldStatusTemplate &&
|
||||
(this.maxLengthPasteError.isActive() ||
|
||||
!!this.field.validationSummary?.message ||
|
||||
(this.isInvalidFieldRequired() && this.isTouched()))
|
||||
};
|
||||
}
|
||||
|
||||
private updateTranslateParameters(): void {
|
||||
if (this.field.validationSummary?.isActive()) {
|
||||
this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj();
|
||||
} else {
|
||||
this.translateParameters = {};
|
||||
}
|
||||
}
|
||||
|
||||
private getLengthAfterPaste(input: HTMLInputElement, pastedValue: string): number {
|
||||
const value = input.value ?? '';
|
||||
const selectionStart = input.selectionStart ?? value.length;
|
||||
const selectionEnd = input.selectionEnd ?? selectionStart;
|
||||
|
||||
return value.length - Math.max(selectionEnd - selectionStart, 0) + pastedValue.length;
|
||||
}
|
||||
|
||||
private setMaxLengthPasteError(): void {
|
||||
this.maxLengthPasteError = new ErrorMessageModel({
|
||||
message: 'FORM.FIELD.VALIDATOR.NO_LONGER_THAN',
|
||||
attributes: new Map([['maxLength', this.resolvedMaxLength.toLocaleString()]])
|
||||
});
|
||||
}
|
||||
|
||||
private clearMaxLengthPasteError(): void {
|
||||
this.maxLengthPasteError = new ErrorMessageModel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ import {
|
||||
AuthModule,
|
||||
FormFieldEvent,
|
||||
NoopTranslateModule,
|
||||
NoopAuthModule
|
||||
NoopAuthModule,
|
||||
FORM_FIELD_VALIDATORS
|
||||
} from '@alfresco/adf-core';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
@@ -1394,7 +1395,7 @@ describe('FormCloudComponent', () => {
|
||||
formComponent.formCloudRepresentationJSON = new FormCloudRepresentation(JSON.parse(JSON.stringify(cloudFormMock)));
|
||||
const form = formComponent.parseForm(formComponent.formCloudRepresentationJSON);
|
||||
expect(formComponent.fieldValidators.length).toBe(1);
|
||||
expect(form.fieldValidators.length).toBe(11);
|
||||
expect(form.fieldValidators.length).toBe(FORM_FIELD_VALIDATORS.length + formComponent.fieldValidators.length);
|
||||
});
|
||||
|
||||
describe('form validations', () => {
|
||||
|
||||
Reference in New Issue
Block a user