From d681883bc97734992060ec2d0ec98282e29c8977 Mon Sep 17 00:00:00 2001 From: Alex Lavrov Date: Wed, 14 Jun 2023 13:16:31 +0400 Subject: [PATCH] =?UTF-8?q?Release=2023.1.3=20Cherry-picked=20changesets:?= =?UTF-8?q?=20=20=205ed002cc=20marker=20dao=20=C2=AE=20-=20TextEditor:=20R?= =?UTF-8?q?eplace=20destructuring=20=20=20631d26ba=20Shpileva=20Yuliya=20-?= =?UTF-8?q?=20Accordion:=20fix=20title=20render=20in=20react=20if=20templa?= =?UTF-8?q?te=20is=20used=20(T1166943)=20(#24824)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/ui/accordion.js | 19 ++++- js/ui/text_box/ui.text_editor.base.js | 2 +- .../DevExpress.knockout/textBox.tests.js | 30 +++++++ .../DevExpress.ui.widgets/accordion.tests.js | 79 +++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 testing/tests/DevExpress.knockout/textBox.tests.js diff --git a/js/ui/accordion.js b/js/ui/accordion.js index 573e9ac098bf..1a3000b1bfa1 100644 --- a/js/ui/accordion.js +++ b/js/ui/accordion.js @@ -130,6 +130,7 @@ const Accordion = CollectionWidget.inherit({ _initMarkup: function() { this._deferredItems = []; + this._deferredTemplateItems = []; this.callBase(); this.setAria({ @@ -146,7 +147,9 @@ const Accordion = CollectionWidget.inherit({ _render: function() { this.callBase(); - this._updateItemHeightsWrapper(true); + when.apply(this, this._deferredTemplateItems).done(() => { + this._updateItemHeights(true); + }); }, _itemDataKey: function() { @@ -195,6 +198,8 @@ const Accordion = CollectionWidget.inherit({ }, _renderItemContent: function(args) { + this._deferredTemplateItems[args.index] = new Deferred(); + const itemTitle = this.callBase(extend({}, args, { contentClass: ACCORDION_ITEM_TITLE_CLASS, templateProperty: 'titleTemplate', @@ -220,6 +225,13 @@ const Accordion = CollectionWidget.inherit({ }))); }, + _onItemTemplateRendered: function(_, renderArgs) { + return () => { + const item = this._deferredTemplateItems[renderArgs.index]; + item && item.resolve(); + }; + }, + _attachItemTitleClickAction: function(itemTitle) { const eventName = addNamespace(clickEventName, this.NAME); @@ -263,6 +275,7 @@ const Accordion = CollectionWidget.inherit({ }, _updateItemHeightsWrapper: function(skipAnimation) { + // Note: require for proper animation in angularjs (T520346) if(this.option('templatesRenderAsynchronously')) { this._animationTimer = setTimeout(function() { this._updateItemHeights(skipAnimation); @@ -371,6 +384,10 @@ const Accordion = CollectionWidget.inherit({ }, _clean: function() { + this._deferredTemplateItems.forEach(item => { + item.reject(); + }); + this._deferredTemplateItems = []; clearTimeout(this._animationTimer); this.callBase(); }, diff --git a/js/ui/text_box/ui.text_editor.base.js b/js/ui/text_box/ui.text_editor.base.js index fa7bc59bec16..1256ebf12828 100644 --- a/js/ui/text_box/ui.text_editor.base.js +++ b/js/ui/text_box/ui.text_editor.base.js @@ -526,7 +526,7 @@ const TextEditorBase = Editor.inherit({ } const $input = this._input(); - const { placeholder } = this.option(); + const placeholder = this.option('placeholder'); const placeholderAttributes = { 'id': placeholder ? `dx-${new Guid()}` : undefined, 'data-dx_placeholder': placeholder, diff --git a/testing/tests/DevExpress.knockout/textBox.tests.js b/testing/tests/DevExpress.knockout/textBox.tests.js new file mode 100644 index 000000000000..ac3600bacca0 --- /dev/null +++ b/testing/tests/DevExpress.knockout/textBox.tests.js @@ -0,0 +1,30 @@ +import ko from 'knockout'; +import TextBox from 'ui/text_box'; + +import 'integration/knockout'; + +const PLACEHOLDER_CLASS = 'dx-placeholder'; + +if(QUnit.urlParams['nojquery']) { + QUnit.module('textBox'); +} else { + QUnit.module.skip('textBox'); +} + +QUnit.testStart(function() { + const textBoxContainer = document.createElement('div'); + + textBoxContainer.setAttribute('id', 'text-box'); + + document.getElementById('qunit-fixture').appendChild(textBoxContainer); +}); + +QUnit.test('text box placeholder must have a string value', function(assert) { + const $textBox = document.getElementById('text-box'); + + new TextBox($textBox, { placeholder: ko.computed(_ => 'CUSTOM') }); + + const $placeholder = document.getElementsByClassName(PLACEHOLDER_CLASS)[0]; + + assert.strictEqual($placeholder.getAttribute('data-dx_placeholder'), 'CUSTOM'); +}); diff --git a/testing/tests/DevExpress.ui.widgets/accordion.tests.js b/testing/tests/DevExpress.ui.widgets/accordion.tests.js index c3ca7905c16d..21faf1fb65bc 100644 --- a/testing/tests/DevExpress.ui.widgets/accordion.tests.js +++ b/testing/tests/DevExpress.ui.widgets/accordion.tests.js @@ -566,6 +566,85 @@ QUnit.module('widget options', moduleSetup, () => { assert.equal($element.find('.' + ACCORDION_ITEM_CLASS).eq(1).outerHeight(), (widgetHeight - closedItemHeight * closedItemsCount) / openedItemsCount, 'opened item content height is correct'); assert.equal($element.find('.' + ACCORDION_WRAPPER_CLASS).height(), widgetHeight, 'item container height is correct'); }); + + QUnit.test('closed items should have correct height if async template is used (T1166943)', function(assert) { + const $element = $('#html-template-accordion'); + const clock = sinon.useFakeTimers(); + const items = [ + { ID: 1 }, + { ID: 2 }, + { ID: 3 }, + { ID: 4 } + ]; + $element.dxAccordion({ + dataSource: items, + itemTitleTemplate: 'custom', + templatesRenderAsynchronously: true, + integrationOptions: { + templates: { + custom: { + render: function({ container, onRendered }) { + setTimeout(() => { + $('
Test1
').appendTo(container); + onRendered(); + }, 10); + } + } + } + } + }); + + clock.tick(50); + + const closedItems = $element.find(`.${ACCORDION_ITEM_CLOSED_CLASS}`); + + assert.strictEqual(closedItems.length, 3); + + for(let i = 0; i < closedItems.length; i++) { + assert.roughEqual(closedItems.eq(i).outerHeight(), 42.4219, 1); + } + + clock.restore(); + }); + + QUnit.test('should not be errors if dispose widget was called and async template is used', function(assert) { + const $element = $('#html-template-accordion'); + const clock = sinon.useFakeTimers(); + const items = [ + { ID: 1 }, + { ID: 2 }, + { ID: 3 }, + { ID: 4 } + ]; + try { + const instance = $element.dxAccordion({ + dataSource: items, + itemTitleTemplate: 'custom', + templatesRenderAsynchronously: true, + integrationOptions: { + templates: { + custom: { + render: function({ container, onRendered }) { + setTimeout(() => { + $('
Test1
').appendTo(container); + onRendered(); + }, 10); + } + } + } + } + }).dxAccordion('instance'); + + instance.dispose(); + + clock.tick(50); + + assert.ok(true); + } catch(e) { + assert.ok(false, `error is raised: ${e.message}`); + } + clock.restore(); + }); }); QUnit.module('widget options changed', moduleSetup, () => {