Skip to content

Commit d0a88ea

Browse files
Convert CollectionItem class into ES6 class (#28832)
1 parent 8ac57b2 commit d0a88ea

File tree

8 files changed

+136
-66
lines changed

8 files changed

+136
-66
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ export interface CollectionWidgetBaseProperties<
9191

9292
focusOnSelectedItem?: boolean;
9393

94+
encodeNoDataText?: boolean;
95+
9496
_itemAttributes?: Record<string, string>;
97+
98+
selectOnFocus?: boolean;
9599
}
96100

97101
class CollectionWidget<
@@ -575,7 +579,7 @@ class CollectionWidget<
575579
this._updateFocusedItemState($target, true);
576580
// @ts-expect-error ts-error
577581
this.onFocusedItemChanged(this.getFocusedItemId());
578-
// @ts-expect-error ts-error
582+
579583
const { selectOnFocus } = this.option();
580584
const isTargetDisabled = this._isDisabled($target);
581585

@@ -685,12 +689,10 @@ class CollectionWidget<
685689
case 'dataSource':
686690
// @ts-expect-error ts-error
687691
this._refreshDataSource();
688-
// @ts-expect-error ts-error
689692
this._renderEmptyMessage();
690693
break;
691694
case 'noDataText':
692695
case 'encodeNoDataText':
693-
// @ts-expect-error ts-error
694696
this._renderEmptyMessage();
695697
break;
696698
case 'itemTemplate':
@@ -1084,7 +1086,6 @@ class CollectionWidget<
10841086
this._renderItem(this._renderedItemsCount + index, itemData);
10851087
});
10861088
}
1087-
// @ts-expect-error ts-error
10881089
this._renderEmptyMessage();
10891090
}
10901091

@@ -1352,9 +1353,9 @@ class CollectionWidget<
13521353
return this._itemContainer();
13531354
}
13541355

1355-
_renderEmptyMessage(items: TItem[]): void {
1356+
_renderEmptyMessage(rootNodes?: TItem[]): void {
13561357
// eslint-disable-next-line no-param-reassign
1357-
items = items || this.option('items');
1358+
const items = rootNodes ?? this.option('items');
13581359
const noDataText = this.option('noDataText');
13591360
// @ts-expect-error ts-error
13601361
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
Lines changed: 104 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,171 @@
11
import Class from '@js/core/class';
2+
import type { dxElementWrapper } from '@js/core/renderer';
23
import $ from '@js/core/renderer';
34
import { each } from '@js/core/utils/iterator';
45
import { attachInstanceToElement, getInstanceByElement } from '@js/core/utils/public_component';
6+
import type { CollectionWidgetItem } from '@js/ui/collection/ui.collection_widget.base';
57

68
const INVISIBLE_STATE_CLASS = 'dx-state-invisible';
79
const DISABLED_STATE_CLASS = 'dx-state-disabled';
810
const ITEM_CONTENT_PLACEHOLDER_CLASS = 'dx-item-content-placeholder';
911

10-
const forcibleWatcher = function (watchMethod, fn, callback) {
11-
const filteredCallback = (function () {
12-
let oldValue;
13-
return function (value) {
12+
interface Watcher {
13+
dispose: () => void;
14+
force: () => void;
15+
}
16+
17+
const forcibleWatcher = <T>(
18+
watchMethod: (
19+
fn: () => void,
20+
callback: (value: T) => void
21+
) => () => void,
22+
fn: () => T,
23+
callback: (value: T, oldValue: T) => void,
24+
): Watcher => {
25+
const filteredCallback = ((): ((value: T) => void) => {
26+
// eslint-disable-next-line @typescript-eslint/init-declarations
27+
let oldValue: T;
28+
return (value: T): void => {
1429
if (oldValue !== value) {
1530
callback(value, oldValue);
1631
oldValue = value;
1732
}
1833
};
19-
}());
34+
})();
2035

2136
return {
2237
dispose: watchMethod(fn, filteredCallback),
23-
force() {
38+
force(): void {
2439
filteredCallback(fn());
2540
},
2641
};
2742
};
2843

29-
const CollectionItem = Class.inherit({
30-
31-
ctor($element, options, rawData) {
44+
export interface ItemExtraOption<TProperties, T = boolean> {
45+
owner: Record<string, unknown>;
46+
fieldGetter: (
47+
field: keyof TProperties
48+
) => (rawData: TProperties | undefined) => T;
49+
watchMethod: () => (
50+
fn: () => void,
51+
callback: (value: T) => void
52+
) => () => void;
53+
}
54+
55+
class CollectionItem<
56+
TProperties extends CollectionWidgetItem = CollectionWidgetItem,
57+
// @ts-expect-error dxClass inheritance issue
58+
// eslint-disable-next-line @typescript-eslint/ban-types
59+
> extends (Class.inherit({}) as new() => {}) {
60+
_dirty?: boolean;
61+
62+
_watchers!: Watcher[];
63+
64+
_$element!: dxElementWrapper;
65+
66+
_options!: ItemExtraOption<TProperties>;
67+
68+
_rawData?: TProperties;
69+
70+
ctor(
71+
$element: dxElementWrapper,
72+
options: ItemExtraOption<TProperties>,
73+
rawData: TProperties,
74+
): void {
3275
this._$element = $element;
3376
this._options = options;
3477
this._rawData = rawData;
3578

3679
attachInstanceToElement($element, this, this._dispose);
3780

3881
this._render();
39-
},
82+
}
4083

41-
_render() {
84+
_render(): void {
4285
const $placeholder = $('<div>').addClass(ITEM_CONTENT_PLACEHOLDER_CLASS);
4386
this._$element.append($placeholder);
4487

4588
this._watchers = [];
4689
this._renderWatchers();
47-
},
90+
}
4891

49-
_renderWatchers() {
92+
_renderWatchers(): void {
5093
this._startWatcher('disabled', this._renderDisabled.bind(this));
5194
this._startWatcher('visible', this._renderVisible.bind(this));
52-
},
53-
54-
_startWatcher(field, render) {
95+
}
96+
97+
_startWatcher(
98+
field: keyof TProperties,
99+
render: (
100+
value: boolean | undefined,
101+
oldValue: boolean | undefined,
102+
) => void,
103+
): void {
55104
const rawData = this._rawData;
56105
const exprGetter = this._options.fieldGetter(field);
57106

58-
const watcher = forcibleWatcher(this._options.watchMethod(), () => exprGetter(rawData), (value, oldValue) => {
59-
this._dirty = true;
60-
render(value, oldValue);
61-
});
107+
const watcher = forcibleWatcher<boolean>(
108+
this._options.watchMethod(),
109+
() => exprGetter(rawData),
110+
(value, oldValue) => {
111+
this._dirty = true;
112+
render(value, oldValue);
113+
},
114+
);
62115

63116
this._watchers.push(watcher);
64-
},
65-
// @ts-expect-error
66-
setDataField() {
117+
}
118+
119+
setDataField(): boolean {
67120
this._dirty = false;
121+
68122
each(this._watchers, (_, watcher) => {
69123
watcher.force();
70124
});
71-
if (this._dirty) {
72-
return true;
73-
}
74-
},
75125

76-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
77-
_renderDisabled(value, oldValue) {
126+
return this._dirty;
127+
}
128+
129+
_renderDisabled(
130+
value: boolean | undefined,
131+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
132+
oldValue?: boolean | undefined,
133+
): void {
78134
this._$element.toggleClass(DISABLED_STATE_CLASS, !!value);
79135
this._$element.attr('aria-disabled', !!value);
80136

81137
this._updateOwnerFocus(value);
82-
},
138+
}
83139

84-
_updateOwnerFocus(isDisabled) {
140+
_updateOwnerFocus(isDisabled: boolean | undefined): void {
85141
const ownerComponent = this._options.owner;
86142

87143
if (ownerComponent && isDisabled) {
144+
// @ts-expect-error ts-error
88145
ownerComponent._resetItemFocus(this._$element);
89146
}
90-
},
147+
}
91148

92149
// eslint-disable-next-line @typescript-eslint/no-unused-vars
93-
_renderVisible(value, oldValue) {
150+
_renderVisible(
151+
value: boolean | undefined,
152+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
153+
oldValue?: boolean | undefined,
154+
): void {
94155
this._$element.toggleClass(INVISIBLE_STATE_CLASS, value !== undefined && !value);
95-
},
156+
}
96157

97-
_dispose() {
158+
_dispose(): void {
98159
each(this._watchers, (_, watcher) => {
99160
watcher.dispose();
100161
});
101-
},
102-
103-
});
104-
// @ts-expect-error
105-
CollectionItem.getInstance = function ($element) {
106-
return getInstanceByElement($element, this);
107-
};
162+
}
163+
164+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
165+
static getInstance<T = CollectionItem<any>>($element: dxElementWrapper): T {
166+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
167+
return getInstanceByElement($element, this);
168+
}
169+
}
108170

109171
export default CollectionItem;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const BADGE_CLASS = 'dx-badge';
88
const LIST_ITEM_CHEVRON_CONTAINER_CLASS = 'dx-list-item-chevron-container';
99
const LIST_ITEM_CHEVRON_CLASS = 'dx-list-item-chevron';
1010

11+
// @ts-expect-error
1112
const ListItem = CollectionWidgetItem.inherit({
1213

1314
_renderWatchers() {

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
import { isDefined } from '@js/core/utils/type';
1111
import { hasWindow } from '@js/core/utils/window';
1212
import CollectionWidget from '@js/ui//collection/ui.collection_widget.edit';
13+
import type { Item } from '@js/ui/box';
14+
import type { ItemExtraOption } from '@ts/ui/collection/m_item';
1315
import CollectionWidgetItem from '@ts/ui/collection/m_item';
1416

1517
const BOX_CLASS = 'dx-box';
@@ -62,12 +64,21 @@ const setFlexProp = (element, prop, value) => {
6264
}
6365
};
6466

65-
// @ts-expect-error dxClass inheritance issue
66-
class BoxItem extends CollectionWidgetItem {
67-
_renderVisible(value, oldValue) {
67+
class BoxItem extends CollectionWidgetItem<Item> {
68+
_options!: ItemExtraOption<Item> & {
69+
fireItemStateChangedAction: ((args: {
70+
name: string;
71+
state: unknown;
72+
oldState: unknown;
73+
}) => void);
74+
};
75+
76+
_renderVisible(
77+
value: boolean | undefined,
78+
oldValue: boolean | undefined,
79+
): void {
6880
super._renderVisible(value);
6981
if (isDefined(oldValue)) {
70-
// @ts-expect-error
7182
this._options.fireItemStateChangedAction({
7283
name: 'visible',
7384
state: value,

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,7 @@ class Splitter extends CollectionWidget<Properties> {
314314
}
315315

316316
_getItemInstance($item: dxElementWrapper): SplitterItem {
317-
// @ts-expect-error badly typed base class
318-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
319-
return Splitter.ItemClass.getInstance($item);
317+
return SplitterItem.getInstance<SplitterItem>($item);
320318
}
321319

322320
_updateResizeHandlesResizableState(): void {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import CollectionWidgetItem from '@ts/ui/collection/m_item';
77
import ResizeHandle from './resize_handle';
88
import type Splitter from './splitter';
99

10-
// @ts-expect-error dxClass inheritance issue
11-
class SplitterItem extends CollectionWidgetItem {
12-
private readonly _$element?: dxElementWrapper;
13-
10+
class SplitterItem extends CollectionWidgetItem<Item> {
1411
_owner: Splitter;
1512

1613
_rawData?: Item;
@@ -24,6 +21,7 @@ class SplitterItem extends CollectionWidgetItem {
2421
},
2522
rawData: Item,
2623
) {
24+
// @ts-expect-error
2725
super($element, options, rawData);
2826

2927
this._owner = options.owner;
@@ -46,7 +44,7 @@ class SplitterItem extends CollectionWidgetItem {
4644
}
4745

4846
_setIdAttr(id: string): void {
49-
this._$element?.attr('id', id);
47+
this._$element.attr('id', id);
5048
}
5149

5250
getIndex(): number {
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { noop } from '@js/core/utils/common';
2+
import type { Item } from '@js/ui/tab_panel';
23
import CollectionWidgetItem from '@ts/ui/collection/m_item';
34

4-
// @ts-expect-error dxClass inheritance issue
5-
export default class TabPanelItem extends CollectionWidgetItem {
6-
_renderWatchers() {
7-
// @ts-expect-error
5+
export default class TabPanelItem extends CollectionWidgetItem<Item> {
6+
_renderWatchers(): void {
87
this._startWatcher('badge', noop);
98

10-
return super._renderWatchers();
9+
super._renderWatchers();
1110
}
1211
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import CollectionWidgetItem from '@ts/ui/collection/m_item';
33

44
const TABS_ITEM_BADGE_CLASS = 'dx-tabs-item-badge';
55
const BADGE_CLASS = 'dx-badge';
6-
6+
// @ts-expect-error
77
const TabsItem = CollectionWidgetItem.inherit({
88

99
_renderWatchers() {

0 commit comments

Comments
 (0)