Skip to content

Commit c8ee496

Browse files
Splitter re-initializes templates for items that are at the same level as an item being shown/hidden (T1267030) (#28876) (#28881)
1 parent 2f7fcab commit c8ee496

File tree

6 files changed

+499
-51
lines changed

6 files changed

+499
-51
lines changed

packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ class CollectionWidget<
630630

631631
_itemOptionChanged(
632632
item: TItem,
633-
property: string,
633+
property: keyof TItem,
634634
value: unknown,
635635
// eslint-disable-next-line @typescript-eslint/no-unused-vars
636636
prevValue?: unknown,

packages/devextreme/js/__internal/ui/collection/m_item.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class CollectionItem<
150150
_renderVisible(
151151
value: boolean | undefined,
152152
// eslint-disable-next-line @typescript-eslint/no-unused-vars
153-
oldValue?: boolean | undefined,
153+
oldValue?: boolean,
154154
): void {
155155
this._$element.toggleClass(INVISIBLE_STATE_CLASS, value !== undefined && !value);
156156
}

packages/devextreme/js/__internal/ui/splitter/splitter.ts

Lines changed: 155 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
116116

117117
private _panesCacheSize: (PaneCache | undefined)[] = [];
118118

119+
private _panesCacheSizeVisible: (PaneCache | undefined)[] = [];
120+
119121
private _savedCollapsingEvent?: InteractionEvent;
120122

121123
private _shouldRecalculateLayout?: boolean;
@@ -198,6 +200,8 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
198200
super._initMarkup();
199201

200202
this._panesCacheSize = [];
203+
this._panesCacheSizeVisible = [];
204+
201205
this._attachResizeObserverSubscription();
202206
}
203207

@@ -320,44 +324,53 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
320324

321325
_updateResizeHandlesResizableState(): void {
322326
this._getResizeHandles().forEach((resizeHandle) => {
323-
const $resizeHandle = (resizeHandle.$element() as unknown) as dxElementWrapper;
327+
this._updateResizeHandleResizableState(resizeHandle);
328+
});
329+
}
330+
331+
_updateResizeHandleResizableState(resizeHandle: ResizeHandle): void {
332+
const $resizeHandle = resizeHandle.$element();
324333

325-
const $leftItem = this._getResizeHandleLeftItem($resizeHandle);
326-
const $rightItem = this._getResizeHandleRightItem($resizeHandle);
327-
const leftItemData = this._getItemData($leftItem);
328-
const rightItemData = this._getItemData($rightItem);
329-
const resizable = leftItemData.resizable !== false
334+
const $leftItem = this._getResizeHandleLeftItem($resizeHandle);
335+
const $rightItem = this._getResizeHandleRightItem($resizeHandle);
336+
const leftItemData = this._getItemData($leftItem);
337+
const rightItemData = this._getItemData($rightItem);
338+
339+
const resizable = leftItemData.resizable !== false
330340
&& rightItemData.resizable !== false
331341
&& leftItemData.collapsed !== true
332342
&& rightItemData.collapsed !== true;
333343

334-
resizeHandle.option('resizable', resizable);
344+
resizeHandle.option('resizable', resizable);
335345

336-
resizeHandle.option('disabled', resizeHandle.isInactive());
337-
});
346+
resizeHandle.option('disabled', resizeHandle.isInactive());
338347
}
339348

340349
_updateResizeHandlesCollapsibleState(): void {
341350
this._getResizeHandles().forEach((resizeHandle) => {
342-
const $resizeHandle = $(resizeHandle.element());
351+
this._updateResizeHandleCollapsibleState(resizeHandle);
352+
});
353+
}
343354

344-
const $leftItem = this._getResizeHandleLeftItem($resizeHandle);
345-
const $rightItem = this._getResizeHandleRightItem($resizeHandle);
346-
const leftItemData = this._getItemData($leftItem);
347-
const rightItemData = this._getItemData($rightItem);
355+
_updateResizeHandleCollapsibleState(resizeHandle: ResizeHandle): void {
356+
const $resizeHandle = $(resizeHandle.element());
348357

349-
const showCollapsePrev = rightItemData.collapsed === true
350-
? rightItemData.collapsible === true && leftItemData.collapsed !== true
351-
: leftItemData.collapsible === true && leftItemData.collapsed !== true;
358+
const $leftItem = this._getResizeHandleLeftItem($resizeHandle);
359+
const $rightItem = this._getResizeHandleRightItem($resizeHandle);
360+
const leftItemData = this._getItemData($leftItem);
361+
const rightItemData = this._getItemData($rightItem);
352362

353-
const showCollapseNext = leftItemData.collapsed === true
354-
? leftItemData.collapsible === true
355-
: rightItemData.collapsible === true && rightItemData.collapsed !== true;
363+
const showCollapsePrev = rightItemData.collapsed === true
364+
? rightItemData.collapsible === true && leftItemData.collapsed !== true
365+
: leftItemData.collapsible === true && leftItemData.collapsed !== true;
356366

357-
resizeHandle.option({ showCollapsePrev, showCollapseNext });
367+
const showCollapseNext = leftItemData.collapsed === true
368+
? leftItemData.collapsible === true
369+
: rightItemData.collapsible === true && rightItemData.collapsed !== true;
358370

359-
resizeHandle.option('disabled', resizeHandle.isInactive());
360-
});
371+
resizeHandle.option({ showCollapsePrev, showCollapseNext });
372+
373+
resizeHandle.option('disabled', resizeHandle.isInactive());
361374
}
362375

363376
_updateNestedSplitterOption(optionName: string, optionValue: unknown): void {
@@ -639,7 +652,12 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
639652
.toggleClass(VERTICAL_ORIENTATION_CLASS, !this._isHorizontalOrientation());
640653
}
641654

642-
_itemOptionChanged(item: Item, property: string, value: unknown, prevValue: unknown): void {
655+
_itemOptionChanged(
656+
item: Item,
657+
property: keyof Item,
658+
value: unknown,
659+
prevValue: unknown,
660+
): void {
643661
switch (property) {
644662
case 'size':
645663
case 'maxSize':
@@ -650,24 +668,111 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
650668
this._applyStylesFromLayout(this.getLayout());
651669
this._updateItemSizes();
652670
break;
653-
case 'collapsed':
654-
this._itemCollapsedOptionChanged(item, value as boolean, prevValue as boolean);
671+
case 'collapsed': {
672+
type PropertyType = Item[typeof property];
673+
674+
this._itemCollapsedOptionChanged(item, value as PropertyType, prevValue as PropertyType);
655675
break;
676+
}
656677
case 'resizable':
657678
this._updateResizeHandlesResizableState();
658679
break;
659680
case 'collapsible':
660681
this._updateResizeHandlesCollapsibleState();
661682
break;
662-
case 'visible':
663-
this._invalidate();
683+
case 'visible': {
684+
type PropertyType = Item[typeof property];
685+
686+
super._itemOptionChanged(item, property, value, prevValue);
687+
688+
this._itemVisibleOptionChanged(item, value as PropertyType, prevValue as PropertyType);
664689
break;
690+
}
665691
default:
666692
super._itemOptionChanged(item, property, value, prevValue);
667693
}
668694
}
669695

670-
_itemCollapsedOptionChanged(item: Item, value: boolean, prevValue: boolean): void {
696+
_itemVisibleOptionChanged(item: Item, value = true, prevValue = true): void {
697+
if (Boolean(prevValue) === Boolean(value)) {
698+
return;
699+
}
700+
701+
const { direction, paneIndex } = this._getDistributionData(item, value);
702+
703+
this._updateResizeHandles();
704+
705+
if (paneIndex && paneIndex < 0) { return; }
706+
707+
this._updateItemsRestrictions();
708+
709+
const collapsedDelta = this._getCollapseDelta(
710+
item,
711+
!value,
712+
this._panesCacheSizeVisible,
713+
direction,
714+
);
715+
716+
this._itemRestrictions.forEach((pane) => {
717+
pane.maxSize = undefined;
718+
pane.resizable = undefined;
719+
});
720+
721+
this._layout = getNextLayout(
722+
this.getLayout(),
723+
collapsedDelta,
724+
paneIndex,
725+
this._itemRestrictions,
726+
);
727+
728+
this._applyStylesFromLayout(this.getLayout());
729+
this._updateItemSizes();
730+
}
731+
732+
_getDistributionData(item: Item, value: boolean | undefined): {
733+
direction: CollapseExpandDirection;
734+
paneIndex: number;
735+
} {
736+
const itemIndex = this._getIndexByItem(item);
737+
const $item = $(this._itemElements()[itemIndex]);
738+
const { items = [] } = this.option();
739+
740+
const isLastVisible = itemIndex >= findLastIndexOfVisibleItem(items);
741+
742+
const direction = isLastVisible === (value === false)
743+
? CollapseExpandDirection.Next
744+
: CollapseExpandDirection.Previous;
745+
746+
const paneIndex = this._getPaneIndexByElement(
747+
isLastVisible ? this._getResizeHandleLeftItem($item) : $item,
748+
);
749+
750+
return { direction, paneIndex };
751+
}
752+
753+
_updateResizeHandles(): void {
754+
this._iterateItems((_, itemElement) => {
755+
const item = this._getItemInstance($(itemElement));
756+
757+
item.updateResizeHandle();
758+
759+
const resizeHandle = item.getResizeHandle();
760+
if (resizeHandle) {
761+
this._updateResizeHandleResizableState(resizeHandle);
762+
this._updateResizeHandleCollapsibleState(resizeHandle);
763+
}
764+
});
765+
}
766+
767+
_getPaneIndexByElement(
768+
$element: dxElementWrapper,
769+
): number {
770+
const itemData = this._getItemData($element);
771+
772+
return this._getIndexByItem(itemData);
773+
}
774+
775+
_itemCollapsedOptionChanged(item: Item, value?: boolean, prevValue?: boolean): void {
671776
if (Boolean(value) === Boolean(prevValue)) {
672777
return;
673778
}
@@ -721,13 +826,16 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
721826

722827
this._updateItemsRestrictions();
723828

724-
const collapsedDelta = this._getCollapseDelta(item, value);
829+
const collapsedDelta = this._getCollapseDelta(
830+
item,
831+
value,
832+
this._panesCacheSize,
833+
this._collapseDirection,
834+
);
725835

726-
this._itemRestrictions.map((pane) => {
836+
this._itemRestrictions.forEach((pane) => {
727837
pane.maxSize = undefined;
728838
pane.resizable = undefined;
729-
730-
return item;
731839
});
732840

733841
this._layout = getNextLayout(
@@ -777,7 +885,12 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
777885
return 0;
778886
}
779887

780-
_getCollapseDelta(item: Item, newCollapsedState: boolean): number {
888+
_getCollapseDelta(
889+
item: Item,
890+
newCollapsedState: boolean | undefined,
891+
panesCacheSize: (PaneCache | undefined)[],
892+
direction?: CollapseExpandDirection,
893+
): number {
781894
const itemIndex = this._getIndexByItem(item);
782895

783896
const { collapsedSize = 0, minSize = 0, maxSize = 100 } = this._itemRestrictions[itemIndex];
@@ -788,30 +901,30 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
788901
const targetPaneSize = collapsedSize;
789902

790903
if (currentPaneSize > targetPaneSize) {
791-
this._panesCacheSize[itemIndex] = {
904+
panesCacheSize[itemIndex] = {
792905
size: currentPaneSize,
793-
direction: this._collapseDirection === CollapseExpandDirection.Next
906+
direction: direction === CollapseExpandDirection.Next
794907
? CollapseExpandDirection.Previous
795908
: CollapseExpandDirection.Next,
796909
};
797910
}
798911

799-
const delta = this._collapseDirection === CollapseExpandDirection.Previous
912+
const delta = direction === CollapseExpandDirection.Previous
800913
? targetPaneSize - currentPaneSize
801914
: currentPaneSize - targetPaneSize;
802915

803916
return delta;
804917
}
805918

806-
const paneCache = this._panesCacheSize[itemIndex];
807-
this._panesCacheSize[itemIndex] = undefined;
919+
const paneCache = panesCacheSize[itemIndex];
920+
panesCacheSize[itemIndex] = undefined;
808921

809922
let targetPaneSize = 0;
810923

811-
if (paneCache && paneCache.direction === this._collapseDirection) {
924+
if (paneCache && paneCache.direction === direction) {
812925
targetPaneSize = paneCache.size - collapsedSize;
813926
} else {
814-
targetPaneSize = this._collapseDirection === CollapseExpandDirection.Previous
927+
targetPaneSize = direction === CollapseExpandDirection.Previous
815928
? this._calculateExpandToLeftSize(itemIndex - 1)
816929
: this._calculateExpandToRightSize(itemIndex + 1);
817930
}
@@ -822,7 +935,7 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
822935

823936
adjustedSize = Math.min(maxSize, adjustedSize);
824937

825-
const deltaSign = this._collapseDirection === CollapseExpandDirection.Previous ? -1 : 1;
938+
const deltaSign = direction === CollapseExpandDirection.Previous ? -1 : 1;
826939

827940
const delta = adjustedSize * deltaSign;
828941

packages/devextreme/js/__internal/ui/splitter/splitter_item.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class SplitterItem extends CollectionWidgetItem<Item> {
2828
}
2929

3030
_renderResizeHandle(): void {
31-
if (this._rawData?.visible !== false && !this.isLast()) {
31+
if (this._shouldHaveResizeHandle()) {
3232
const id = `dx_${new Guid()}`;
3333

3434
this._setIdAttr(id);
@@ -43,10 +43,28 @@ class SplitterItem extends CollectionWidgetItem<Item> {
4343
}
4444
}
4545

46+
_shouldHaveResizeHandle(): boolean {
47+
return this._rawData?.visible !== false && !this.isLast();
48+
}
49+
50+
updateResizeHandle(): void {
51+
if (this._shouldHaveResizeHandle()) {
52+
if (this.getResizeHandle()) return;
53+
this._renderResizeHandle();
54+
} else {
55+
this._removeIdAttr();
56+
this._removeResizeHandle();
57+
}
58+
}
59+
4660
_setIdAttr(id: string): void {
4761
this._$element.attr('id', id);
4862
}
4963

64+
_removeIdAttr(): void {
65+
this._$element.attr('id', null);
66+
}
67+
5068
getIndex(): number {
5169
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
5270
return this._owner._getIndexByItemData(this._rawData);
@@ -56,6 +74,11 @@ class SplitterItem extends CollectionWidgetItem<Item> {
5674
return this._resizeHandle;
5775
}
5876

77+
_removeResizeHandle(): void {
78+
this.getResizeHandle()?.$element().remove();
79+
delete this._resizeHandle;
80+
}
81+
5982
isLast(): boolean {
6083
return this._owner._isLastVisibleItem(this.getIndex());
6184
}

packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.markup.tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ QUnit.module('Aria attributes', moduleConfig, () => {
288288
}]
289289
});
290290

291+
assert.strictEqual(this.getItems().eq(1).attr('id'), undefined, 'id attribute is not set for invisible item');
292+
291293
this.instance.option('items[1].visible', true);
292294

293295
assert.strictEqual(this.getItems().eq(1).attr('id'), this.getResizeHandles().eq(1).attr('aria-controls'), 'aria-controls of the resize handle are linked with id attribute of the pane');

0 commit comments

Comments
 (0)