Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
afterEach, describe, expect, it,
} from '@jest/globals';
import { data } from '@js/core/element_data';
import $ from '@js/core/renderer';
import Validator from '@ts/ui/validator';

import type { EditorProperties } from '../editor';
import Editor from '../editor';

const VALIDATION_TARGET = 'dx-validation-target';

interface ValidationRequestArgs {
value: unknown;
editor: unknown;
}

const disposables: { dispose: () => void }[] = [];

const createEditor = (options: Partial<EditorProperties> = {}): Editor => {
const element = $('<div>').appendTo(document.body).get(0) as HTMLElement;
// @ts-expect-error DOMComponent constructor is not typed for direct instantiation
const instance: Editor = new Editor(element, options);

disposables.push(instance);

return instance;
};

describe('Editor initialization', () => {
afterEach(() => {
disposables.forEach((instance) => instance.dispose());
disposables.length = 0;
document.body.innerHTML = '';
});

it('lets a validator attach while the editor initialization is deferred by beginUpdate', () => {
const instance = createEditor({
onInitializing(this: Editor): void {
this.beginUpdate();
},
} as Partial<EditorProperties>);

expect(() => {
// @ts-expect-error DOMComponent constructor is not typed for direct instantiation
const validator: Validator = new Validator(instance.$element().get(0), {});

disposables.push(validator);
}).not.toThrow();

instance.endUpdate();
});

it('marks the element as a validation target with the validation state ready', () => {
const instance = createEditor();
const element = instance.$element().get(0) as HTMLElement;

expect(data(element, VALIDATION_TARGET)).toBe(instance);
expect(instance.validationRequest).toBeDefined();
expect(instance.showValidationMessageTimeout).toBeUndefined();
});

it('fires validationRequest when the value changes', () => {
const instance = createEditor({ value: 'initial' });
const calls: ValidationRequestArgs[] = [];

instance.validationRequest.add((args: ValidationRequestArgs) => {
calls.push(args);
});
instance.option('value', 'changed');

expect(calls).toHaveLength(1);
expect(calls[0].value).toBe('changed');
expect(calls[0].editor).toBe(instance);
});
});
9 changes: 2 additions & 7 deletions packages/devextreme/js/__internal/ui/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,10 @@ class Editor<
return instance instanceof Editor;
}

ctor(element: Element, options: TProperties): void {
this.showValidationMessageTimeout = undefined;
this.validationRequest = Callbacks();

super.ctor(element, options);
}

_createElement(element: Element): void {
super._createElement(element);
this.showValidationMessageTimeout = undefined;
this.validationRequest = Callbacks();
const $element = this.$element();
if ($element) {
data($element[0], VALIDATION_TARGET, this);
Expand Down
10 changes: 4 additions & 6 deletions packages/devextreme/js/__internal/ui/map/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,11 @@ class Map extends Widget<MapProperties> {
]);
}

ctor(element: Element, options: MapProperties): void {
super.ctor(element, options);
_initOptions(options: MapProperties): void {
super._initOptions(options);

if (options) {
if ('provider' in options && options.provider === 'bing') {
this._logDeprecatedBingProvider();
}
if ('provider' in options && options.provider === 'bing') {
this._logDeprecatedBingProvider();
}
}

Expand Down
10 changes: 4 additions & 6 deletions packages/devextreme/js/__internal/ui/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,11 @@ class Overlay<
return this._$content;
}

ctor(element: Element, options: TProperties): void {
super.ctor(element, options);
_initOptions(options: TProperties): void {
super._initOptions(options);

if (options) {
if ('preventScrollEvents' in options && !options._ignorePreventScrollEventsDeprecation) {
this._logDeprecatedPreventScrollEventsInfo();
}
if ('preventScrollEvents' in options && !options._ignorePreventScrollEventsDeprecation) {
this._logDeprecatedPreventScrollEventsInfo();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
afterEach, describe, expect, it,
} from '@jest/globals';
import $ from '@js/core/renderer';

import TextBox, { type TextBoxProperties } from '../text_box';

const textBoxes: TextBox[] = [];

const createTextBox = (options: Partial<TextBoxProperties> = {}): TextBox => {
const element = $('<div>').appendTo(document.body).get(0) as HTMLElement;
// @ts-expect-error DOMComponent constructor is not typed for direct instantiation
const instance: TextBox = new TextBox(element, options);

textBoxes.push(instance);

return instance;
};

describe('TextBox search mode and the clear button', () => {
afterEach(() => {
textBoxes.forEach((instance) => instance.dispose());
textBoxes.length = 0;
document.body.innerHTML = '';
});

it('turns the clear button on in search mode when showClearButton is not specified', () => {
const instance = createTextBox({ mode: 'search' });

expect(instance.option('showClearButton')).toBe(true);
});

it('keeps showClearButton disabled in search mode when it is specified explicitly (T218573)', () => {
const instance = createTextBox({ mode: 'search', showClearButton: false });

expect(instance.option('showClearButton')).toBe(false);
});

it('restores the original showClearButton when search mode is turned off', () => {
const instance = createTextBox({ mode: 'search' });

expect(instance.option('showClearButton')).toBe(true);

instance.option('mode', 'text');

expect(instance.option('showClearButton')).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
afterEach, describe, expect, it,
} from '@jest/globals';
import $ from '@js/core/renderer';

import TextEditor from '../text_editor';
import type { TextEditorBaseProperties } from '../text_editor.base';

class ProbeTextEditor extends TextEditor {
public hasButtonCollectionOnInitMarkup?: boolean;

_initMarkup(): void {
this.hasButtonCollectionOnInitMarkup = Boolean(this._buttonCollection);

super._initMarkup();
}
}

const editors: ProbeTextEditor[] = [];

const createEditor = (options: Partial<TextEditorBaseProperties> = {}): ProbeTextEditor => {
const element = $('<div>').appendTo(document.body).get(0) as HTMLElement;
// @ts-expect-error DOMComponent constructor is not typed for direct instantiation
const instance: ProbeTextEditor = new ProbeTextEditor(element, options);

editors.push(instance);

return instance;
};

const customButton: NonNullable<TextEditorBaseProperties['buttons']> = [
{ name: 'custom', location: 'after', options: { text: 'Go' } },
];

describe('TextEditorBase buttons initialization', () => {
afterEach(() => {
editors.forEach((instance) => instance.dispose());
editors.length = 0;
document.body.innerHTML = '';
});

it('creates the button collection before the markup is rendered', () => {
const instance = createEditor();

expect(instance.hasButtonCollectionOnInitMarkup).toBe(true);
});

it('renders a button declared in the buttons option', () => {
const instance = createEditor({ buttons: customButton });

expect(instance.getButton('custom')).toBeDefined();
expect(instance._$afterButtonsContainer).not.toBeNull();
});

it('renders the declared button again after repaint', () => {
const instance = createEditor({ buttons: customButton });

instance.repaint();

expect(instance.getButton('custom')).toBeDefined();
});

it('throws E1053 when the buttons option is not an array', () => {
expect(() => createEditor({
buttons: 'custom' as unknown as TextEditorBaseProperties['buttons'],
})).toThrow(/E1053/);
});
});
8 changes: 3 additions & 5 deletions packages/devextreme/js/__internal/ui/text_box/text_box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ class TextBox<

_showClearButton?: boolean;

ctor(element: Element, options: TProperties): void {
if (options) {
this._showClearButton = options.showClearButton;
}
_initOptions(options: TProperties): void {
super._initOptions(options);

super.ctor(element, options);
this._showClearButton = options.showClearButton;
}

_getDefaultOptions(): TProperties {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ class TextEditorBase<

_enterKeyAction?: ((event?: Record<string, unknown>) => void);

ctor(element: Element, options: TProperties): void {
if (options) {
checkButtonsOptionType(options.buttons);
}
_init(): void {
super._init();

const { buttons } = this.option();

checkButtonsOptionType(buttons);

this._buttonCollection = new TextEditorButtonCollection(
this as unknown as TextEditorBase,
Expand All @@ -146,8 +148,6 @@ class TextEditorBase<
this._$beforeButtonsContainer = null;
this._$afterButtonsContainer = null;
this._labelContainerElement = null;

super.ctor(element, options);
}

_getDefaultOptions(): TProperties {
Expand Down
Loading