diff --git a/packages/devextreme/js/__internal/core/widget/widget.ts b/packages/devextreme/js/__internal/core/widget/widget.ts index 10fed27edd87..e955c71e8dc4 100644 --- a/packages/devextreme/js/__internal/core/widget/widget.ts +++ b/packages/devextreme/js/__internal/core/widget/widget.ts @@ -23,7 +23,7 @@ import DOMComponent from './dom_component'; import type { OptionChanged } from './types'; const DISABLED_STATE_CLASS = 'dx-state-disabled'; -const FOCUSED_STATE_CLASS = 'dx-state-focused'; +export const FOCUSED_STATE_CLASS = 'dx-state-focused'; const INVISIBLE_STATE_CLASS = 'dx-state-invisible'; function setAttribute(name, value, target): void { diff --git a/packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_editor.ts b/packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_editor.ts index ee443d0d520c..22f1bd988c20 100644 --- a/packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_editor.ts +++ b/packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_editor.ts @@ -29,7 +29,7 @@ import Widget from '@js/ui/widget/ui.widget'; import DropDownButton from './m_drop_down_button'; import { getElementWidth, getSizeValue } from './m_utils'; -const DROP_DOWN_EDITOR_CLASS = 'dx-dropdowneditor'; +export const DROP_DOWN_EDITOR_CLASS = 'dx-dropdowneditor'; const DROP_DOWN_EDITOR_INPUT_WRAPPER = 'dx-dropdowneditor-input-wrapper'; const DROP_DOWN_EDITOR_BUTTON_ICON = 'dx-dropdowneditor-icon'; const DROP_DOWN_EDITOR_OVERLAY = 'dx-dropdowneditor-overlay'; diff --git a/packages/devextreme/js/__internal/ui/form/m_form.ts b/packages/devextreme/js/__internal/ui/form/m_form.ts index fde3b04ae54d..885287699d3e 100644 --- a/packages/devextreme/js/__internal/ui/form/m_form.ts +++ b/packages/devextreme/js/__internal/ui/form/m_form.ts @@ -26,8 +26,11 @@ import TabPanel from '@js/ui/tab_panel'; import { isMaterial, isMaterialBased } from '@js/ui/themes'; import ValidationEngine from '@js/ui/validation_engine'; import Widget from '@js/ui/widget/ui.widget'; +import { FOCUSED_STATE_CLASS } from '@ts/core/widget/widget'; +import { DROP_DOWN_EDITOR_CLASS } from '@ts/ui/drop_down_editor/m_drop_down_editor'; import { TOOLBAR_CLASS } from '@ts/ui/toolbar/m_constants'; +import { TEXTEDITOR_CLASS, TEXTEDITOR_INPUT_CLASS } from '../text_box/m_text_editor.base'; import { setLabelWidthByMaxLabelWidth, } from './components/m_label'; @@ -66,8 +69,6 @@ import { tryGetTabPath, } from './m_form.utils'; -const FOCUSED_STATE_CLASS = 'dx-state-focused'; - const ITEM_OPTIONS_FOR_VALIDATION_UPDATING = ['items', 'isRequired', 'validationRules', 'visible']; // @ts-expect-error @@ -1201,8 +1202,7 @@ const Form = Widget.inherit({ }, _refresh() { - const editorSelector = `.${FOCUSED_STATE_CLASS} > :not(.dx-dropdowneditor-input-wrapper) input,` - + ` .${FOCUSED_STATE_CLASS} textarea`; + const editorSelector = `.${TEXTEDITOR_CLASS}.${FOCUSED_STATE_CLASS}:not(.${DROP_DOWN_EDITOR_CLASS}) .${TEXTEDITOR_INPUT_CLASS}`; // @ts-expect-error eventsEngine.trigger(this.$element().find(editorSelector), 'change'); diff --git a/packages/devextreme/js/__internal/ui/text_box/m_text_editor.base.ts b/packages/devextreme/js/__internal/ui/text_box/m_text_editor.base.ts index 7e34fe59c61b..4a714f7cd6ed 100644 --- a/packages/devextreme/js/__internal/ui/text_box/m_text_editor.base.ts +++ b/packages/devextreme/js/__internal/ui/text_box/m_text_editor.base.ts @@ -22,9 +22,9 @@ import ClearButton from './m_text_editor.clear'; import { TextEditorLabel } from './m_text_editor.label'; import TextEditorButtonCollection from './texteditor_button_collection/m_index'; -const TEXTEDITOR_CLASS = 'dx-texteditor'; +export const TEXTEDITOR_CLASS = 'dx-texteditor'; const TEXTEDITOR_INPUT_CONTAINER_CLASS = 'dx-texteditor-input-container'; -const TEXTEDITOR_INPUT_CLASS = 'dx-texteditor-input'; +export const TEXTEDITOR_INPUT_CLASS = 'dx-texteditor-input'; const TEXTEDITOR_INPUT_SELECTOR = `.${TEXTEDITOR_INPUT_CLASS}`; const TEXTEDITOR_CONTAINER_CLASS = 'dx-texteditor-container'; const TEXTEDITOR_BUTTONS_CONTAINER_CLASS = 'dx-texteditor-buttons-container'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.tests.js index 2e10e3410ae5..5b830caed243 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.tests.js @@ -6,7 +6,9 @@ import resizeCallbacks from '__internal/core/utils/m_resize_callbacks'; import typeUtils from 'core/utils/type'; import { extend } from 'core/utils/extend'; import visibilityEventsModule from 'common/core/events/visibility_change'; -import { EDITORS_WITHOUT_LABELS } from '__internal/ui/form/m_form.layout_manager.utils'; +import { + EDITORS_WITHOUT_LABELS, +} from '__internal/ui/form/m_form.layout_manager.utils'; import 'generic_light.css!'; import $ from 'jquery'; import 'ui/autocomplete'; @@ -20,6 +22,10 @@ import 'ui/range_slider'; import windowModule from '__internal/core/utils/m_window'; import Form from 'ui/form'; import TextEditorBase from 'ui/text_box/ui.text_editor.base.js'; +import { + TEXTEDITOR_INPUT_CLASS +} from '__internal/ui/text_box/m_text_editor.base'; + import { FIELD_ITEM_CLASS, @@ -95,9 +101,9 @@ if(device.current().deviceType === 'desktop') { }); } -QUnit.testInActiveWindow('Form\'s inputs saves value on refresh', function(assert) { +QUnit.testInActiveWindow('Form\'s textbox input saves value on refresh (T404958)', function(assert) { let screen = 'md'; - const $formContainer = $('#form').dxForm({ + const $form = $('#form').dxForm({ screenByWidth: function() { return screen; }, @@ -113,7 +119,38 @@ QUnit.testInActiveWindow('Form\'s inputs saves value on refresh', function(asser ] }); - $('#form input') + $form.find(`.${TEXTEDITOR_INPUT_CLASS}`) + .first() + .focus() + .val('test'); + + screen = 'sm'; + resizeCallbacks.fire(); + + const formData = $form.dxForm('instance').option('formData'); + + assert.deepEqual(formData, { name: 'test' }, 'textbox value updates'); +}); + +QUnit.testInActiveWindow('Form\'s textarea input saves value on refresh (T404958)', function(assert) { + let screen = 'md'; + const $form = $('#form').dxForm({ + screenByWidth: function() { + return screen; + }, + colCountByScreen: { + sm: 1, + md: 2 + }, + items: [ + { + dataField: 'name', + editorType: 'dxTextArea' + } + ] + }); + + $form.find(`.${TEXTEDITOR_INPUT_CLASS}`) .first() .focus() .val('test'); @@ -121,9 +158,9 @@ QUnit.testInActiveWindow('Form\'s inputs saves value on refresh', function(asser screen = 'sm'; resizeCallbacks.fire(); - const formData = $formContainer.dxForm('instance').option('formData'); + const formData = $form.dxForm('instance').option('formData'); - assert.deepEqual(formData, { name: 'test' }, 'value updates'); + assert.deepEqual(formData, { name: 'test' }, 'textarea value updates'); }); QUnit.test('Check field width on render form with colspan', function(assert) { @@ -4916,39 +4953,126 @@ QUnit.module('reset', () => { assert.strictEqual(summaryItemsAfterValidate.length, 2, 'form has validation summary after validation'); }); - QUnit.test('DropDownBox should not lose its value if form resized (T1196835)', function(assert) { - let screen = 'lg'; - - const value = 'VINET'; - const text = 'Vins et alcools Chevalier (France)'; - const $form = $('#form').dxForm({ - formData: { CustomerID: value }, - screenByWidth: function() { return screen; }, - colCountByScreen: { - sm: 1, - lg: 2 - }, - items: [ - { - itemType: 'simple', - cssClass: 'test-ddbox', - dataField: 'CustomerID', - editorOptions: { - displayExpr: 'Text', - valueExpr: 'Value', - showClearButton: true, - dataSource: [{ Value: value, Text: text }], + [ + 'dxSelectBox', + 'dxDropDownBox' + ].forEach((editorType) => { + QUnit.test(`Focused ${editorType} should not lose its value when the form is resized (T1196835)`, function(assert) { + let screen = 'lg'; + + const name = 'VINET'; + const value = 'Vins et alcools Chevalier (France)'; + const form = $('#form').dxForm({ + formData: { name: name }, + screenByWidth: function() { return screen; }, + colCountByScreen: { + sm: 1, + lg: 2 + }, + items: [ + { + itemType: 'simple', + dataField: 'name', + editorOptions: { + displayExpr: 'Text', + valueExpr: 'Value', + showClearButton: true, + dataSource: [{ Value: name, Text: value }], + }, + editorType, }, - editorType: 'dxDropDownBox', + ] + }).dxForm('instance'); + + const dropDownEditor = form.getEditor('name'); + + screen = 'sm'; + dropDownEditor.focus(); + resizeCallbacks.fire(); + + assert.strictEqual($(form.getEditor('name').field()).val(), value, `${editorType} contains expected value`); + }); + + QUnit.test(`Focused ${editorType} inside a tabbed item should not lose its value when the form is resized (T1196835)`, function(assert) { + let screen = 'lg'; + + const name = 'VINET'; + const value = 'Vins et alcools Chevalier (France)'; + const form = $('#form').dxForm({ + formData: { name: name }, + screenByWidth: function() { return screen; }, + colCountByScreen: { + sm: 1, + lg: 2 }, - ] + items: [{ + itemType: 'tabbed', + tabs: [{ + title: 'Phone', + colCount: 1, + items: [{ + itemType: 'simple', + dataField: 'name', + editorOptions: { + displayExpr: 'Text', + valueExpr: 'Value', + showClearButton: true, + dataSource: [{ Value: name, Text: value }], + }, + editorType, + }], + }], + }], + }).dxForm('instance'); + + const dropDownEditor = form.getEditor('name'); + + screen = 'sm'; + dropDownEditor.focus(); + resizeCallbacks.fire(); + + assert.strictEqual($(form.getEditor('name').field()).val(), value, `${editorType} contains expected value`); }); - const $input = $form.find(`.test-ddbox .${EDITOR_INPUT_CLASS}`); - screen = 'sm'; - $input.focus(); - resizeCallbacks.fire(); + QUnit.test(`${editorType} inside a tabbed item and focused tab should not lose its value when the form is resized (T1196835)`, function(assert) { + let screen = 'lg'; + + const name = 'VINET'; + const value = 'Vins et alcools Chevalier (France)'; + const form = $('#form').dxForm({ + formData: { name: name }, + screenByWidth: function() { return screen; }, + colCountByScreen: { + sm: 1, + lg: 2 + }, + items: [{ + itemType: 'tabbed', + tabs: [{ + title: 'Phone', + colCount: 1, + items: [{ + itemType: 'simple', + dataField: 'name', + editorOptions: { + displayExpr: 'Text', + valueExpr: 'Value', + showClearButton: true, + dataSource: [{ Value: name, Text: value }], + }, + editorType, + }], + }], + }], + }).dxForm('instance'); + + const dropDownEditor = form.getEditor('name'); - assert.strictEqual($input.val(), text, 'ddBox contain correct value'); + screen = 'sm'; + dropDownEditor.focus(); + resizeCallbacks.fire(); + + assert.strictEqual($(form.getEditor('name').field()).val(), value, `${editorType} contains expected value`); + }); }); });