From 2333d5132637c6077b1b1d91e5e56bbcce79de9e Mon Sep 17 00:00:00 2001 From: EugeniyKiyashko Date: Wed, 29 Jan 2025 15:44:09 +0400 Subject: [PATCH] Collection[Edit, Async, LiveUpdate, Hierarchical] & selection strategies: convert into ES6 classes (#28836) --- .../js/__internal/core/widget/component.ts | 13 +- .../appointments/m_appointment_collection.ts | 2 +- .../devextreme/js/__internal/ui/chat/chat.ts | 17 +- .../js/__internal/ui/chat/messagelist.ts | 13 +- .../js/__internal/ui/collection/async.ts | 26 - .../ui/collection/collection_widget.base.ts | 42 +- .../js/__internal/ui/collection/edit.ts | 23 - .../__internal/ui/collection/hierarchical.ts | 49 -- .../__internal/ui/collection/live_update.ts | 20 - .../collection/m_collection_widget.async.ts | 83 ++- ...m_collection_widget.edit.strategy.plain.ts | 60 +- .../m_collection_widget.edit.strategy.ts | 147 +++-- .../ui/collection/m_collection_widget.edit.ts | 567 +++++++++++------- .../m_collection_widget.live_update.ts | 132 ++-- .../ui/context_menu/m_context_menu.ts | 12 +- .../context_menu/m_menu_base.edit.strategy.ts | 3 +- .../__internal/ui/context_menu/m_menu_base.ts | 15 +- .../m_hierarchical_collection_widget.ts | 150 +++-- .../js/__internal/ui/list/m_list.base.ts | 2 +- .../ui/list/m_list.edit.strategy.grouped.ts | 88 +-- .../js/__internal/ui/m_accordion.ts | 2 +- .../js/__internal/ui/m_action_sheet.ts | 2 +- packages/devextreme/js/__internal/ui/m_box.ts | 43 +- .../js/__internal/ui/m_button_group.ts | 2 +- .../devextreme/js/__internal/ui/m_gallery.ts | 2 +- .../js/__internal/ui/m_multi_view.ts | 2 +- .../js/__internal/ui/m_responsive_box.ts | 2 +- .../js/__internal/ui/m_tile_view.ts | 2 +- .../js/__internal/ui/m_validation_summary.ts | 2 +- .../js/__internal/ui/menu/m_menu.ts | 3 +- .../ui/radio_group/m_radio_collection.ts | 2 +- .../js/__internal/ui/selection/m_selection.ts | 4 +- .../js/__internal/ui/splitter/splitter.ts | 19 +- .../__internal/ui/splitter/splitter_item.ts | 1 - .../js/__internal/ui/tabs/m_tabs.ts | 2 +- .../__internal/ui/toolbar/m_toolbar.base.ts | 4 +- 36 files changed, 872 insertions(+), 686 deletions(-) delete mode 100644 packages/devextreme/js/__internal/ui/collection/async.ts delete mode 100644 packages/devextreme/js/__internal/ui/collection/edit.ts delete mode 100644 packages/devextreme/js/__internal/ui/collection/hierarchical.ts delete mode 100644 packages/devextreme/js/__internal/ui/collection/live_update.ts diff --git a/packages/devextreme/js/__internal/core/widget/component.ts b/packages/devextreme/js/__internal/core/widget/component.ts index 243e676404e6..09c5cd19eb18 100644 --- a/packages/devextreme/js/__internal/core/widget/component.ts +++ b/packages/devextreme/js/__internal/core/widget/component.ts @@ -29,6 +29,15 @@ const getEventName = (actionName): string => actionName.charAt(2).toLowerCase() const isInnerOption = (optionName): boolean => optionName.indexOf('_', 0) === 0; +export interface ActionConfig { + beforeExecute?: (e: Record) => void; + afterExecute?: (e: Record) => void; + excludeValidators?: ('disabled' | 'readOnly')[]; + element?: Element; + validatingTargetName?: string; + category?: 'rendering'; +} + export interface Properties extends ComponentOptions< EventInfo, InitializedEventInfo, @@ -350,7 +359,7 @@ export class Component< } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - _createAction(actionSource, config): (e) => void { + _createAction(actionSource, config?: ActionConfig): (e) => void { // eslint-disable-next-line @typescript-eslint/init-declarations let action; @@ -373,7 +382,7 @@ export class Component< _createActionByOption( optionName: string, - config?: Record, + config?: ActionConfig, ): (event?: Record) => void { // eslint-disable-next-line @typescript-eslint/init-declarations let action; diff --git a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts index e32d32f4ced6..a9451bcd6b68 100644 --- a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts +++ b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts @@ -42,7 +42,7 @@ const COMPONENT_CLASS = 'dx-scheduler-scrollable-appointments'; const DBLCLICK_EVENT_NAME = addNamespace(dblclickEvent, 'dxSchedulerAppointment'); const toMs = dateUtils.dateToMilliseconds; - +// @ts-expect-error class SchedulerAppointments extends CollectionWidget { _virtualAppointments: any; diff --git a/packages/devextreme/js/__internal/ui/chat/chat.ts b/packages/devextreme/js/__internal/ui/chat/chat.ts index fa9b0b4f20bc..e7f5163fb6cd 100644 --- a/packages/devextreme/js/__internal/ui/chat/chat.ts +++ b/packages/devextreme/js/__internal/ui/chat/chat.ts @@ -15,16 +15,16 @@ import type { } from '@js/ui/chat'; import type { OptionChanged } from '@ts/core/widget/types'; import Widget from '@ts/core/widget/widget'; - -import AlertList from './alertlist'; +import AlertList from '@ts/ui/chat/alertlist'; import type { MessageEnteredEvent as MessageBoxMessageEnteredEvent, Properties as MessageBoxProperties, TypingStartEvent as MessageBoxTypingStartEvent, -} from './messagebox'; -import MessageBox from './messagebox'; -import type { Change, MessageTemplate, Properties as MessageListProperties } from './messagelist'; -import MessageList from './messagelist'; +} from '@ts/ui/chat/messagebox'; +import MessageBox from '@ts/ui/chat/messagebox'; +import type { MessageTemplate, Properties as MessageListProperties } from '@ts/ui/chat/messagelist'; +import MessageList from '@ts/ui/chat/messagelist'; +import type { DataChange } from '@ts/ui/collection/collection_widget.base'; const CHAT_CLASS = 'dx-chat'; const TEXTEDITOR_INPUT_CLASS = 'dx-texteditor-input'; @@ -84,7 +84,10 @@ class Chat extends Widget { this.option('items', []); } - _dataSourceChangedHandler(newItems: Message[], e?: { changes?: Change[] }): void { + _dataSourceChangedHandler( + newItems: Message[], + e?: { changes?: DataChange[] }, + ): void { if (e?.changes) { this._messageList._modifyByChanges(e.changes); diff --git a/packages/devextreme/js/__internal/ui/chat/messagelist.ts b/packages/devextreme/js/__internal/ui/chat/messagelist.ts index 8651083b49a9..a4e5eac5560a 100644 --- a/packages/devextreme/js/__internal/ui/chat/messagelist.ts +++ b/packages/devextreme/js/__internal/ui/chat/messagelist.ts @@ -2,9 +2,6 @@ import { Guid } from '@js/common'; import type { Format } from '@js/common/core/localization'; import dateLocalization from '@js/common/core/localization/date'; import messageLocalization from '@js/common/core/localization/message'; -import type { - DeepPartial, -} from '@js/core/index'; import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import resizeObserverSingleton from '@js/core/resize_observer'; @@ -21,6 +18,7 @@ import type { OptionChanged } from '@ts/core/widget/types'; import Widget from '@ts/core/widget/widget'; import { getScrollTopMax } from '@ts/ui/scroll_view/utils/get_scroll_top_max'; +import type { DataChange } from '../collection/collection_widget.base'; import { isElementVisible } from '../splitter/utils/layout'; import MessageBubble, { CHAT_MESSAGEBUBBLE_CLASS } from './messagebubble'; import type { MessageGroupAlignment } from './messagegroup'; @@ -50,13 +48,6 @@ const SCROLLABLE_CONTAINER_CLASS = 'dx-scrollable-container'; export const MESSAGEGROUP_TIMEOUT = 5 * 1000 * 60; export type MessageTemplate = ((data: Message, messageBubbleContainer: Element) => void) | null; - -export interface Change { - type: 'insert' | 'update' | 'remove'; - data?: DeepPartial; - key?: string | number; - index?: number; -} export interface Properties extends WidgetOptions { items: Message[]; currentUserId: number | string | undefined; @@ -624,7 +615,7 @@ class MessageList extends Widget { super._clean(); } - _modifyByChanges(changes: Change[]): void { + _modifyByChanges(changes: DataChange[]): void { changes.forEach((change) => { switch (change.type) { case 'update': diff --git a/packages/devextreme/js/__internal/ui/collection/async.ts b/packages/devextreme/js/__internal/ui/collection/async.ts deleted file mode 100644 index ce28fc78e113..000000000000 --- a/packages/devextreme/js/__internal/ui/collection/async.ts +++ /dev/null @@ -1,26 +0,0 @@ -import CollectionWidgetAsync from '@js/ui/collection/ui.collection_widget.async'; -import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; -import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; - -import CollectionWidgetEdit from './edit'; - -declare class Async< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetBaseProperties, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends CollectionWidgetEdit { - _onItemTemplateRendered( - itemTemplate: { source: () => unknown }, - args: { itemData: unknown } - ): () => void; - - _planPostRenderActions(...args: unknown[]): void; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TypedCollectionWidget: typeof Async = CollectionWidgetAsync as any; - -export default TypedCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts b/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts index b76054dd6e14..6d37f6e33384 100644 --- a/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts +++ b/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts @@ -9,6 +9,9 @@ import messageLocalization from '@js/common/core/localization/message'; import Action from '@js/core/action'; import domAdapter from '@js/core/dom_adapter'; import Guid from '@js/core/guid'; +import type { + DeepPartial, +} from '@js/core/index'; import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { BindableTemplate } from '@js/core/templates/bindable_template'; @@ -33,8 +36,10 @@ import type { import type { CollectionWidgetItem as CollectionWidgetItemProperties, CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import { focusable } from '@js/ui/widget/selectors'; import { getPublicElement } from '@ts/core/m_element'; +import type { ActionConfig } from '@ts/core/widget/component'; import type { OptionChanged } from '@ts/core/widget/types'; import Widget from '@ts/core/widget/widget'; +import type CollectionItem from '@ts/ui/collection/m_item'; import CollectionWidgetItem from '@ts/ui/collection/m_item'; const COLLECTION_CLASS = 'dx-collection'; @@ -62,10 +67,12 @@ const FOCUS_PAGE_DOWN = 'pagedown'; const FOCUS_LAST = 'last'; const FOCUS_FIRST = 'first'; -interface ActionConfig { - beforeExecute?: (e: DxEvent) => void; - afterExecute?: (e: DxEvent) => void; - excludeValidators?: ('disabled' | 'readOnly')[]; +export type DataChangeType = 'insert' | 'update' | 'remove'; + +export interface DataChange { + key: TKey; + type: DataChangeType; + data: DeepPartial; } type ItemTemplate = template | ( @@ -77,8 +84,17 @@ export interface ItemRenderInfo { container: dxElementWrapper; contentClass: string; defaultTemplateName: ItemTemplate | undefined; + uniqueKey?: string; templateProperty?: string; } + +export interface PostprocessRenderItemInfo { + itemElement: dxElementWrapper; + itemContent: dxElementWrapper; + itemData: TItem; + itemIndex: number; +} + export interface CollectionWidgetBaseProperties< // eslint-disable-next-line @typescript-eslint/no-explicit-any TComponent extends CollectionWidget | any, @@ -617,7 +633,7 @@ class CollectionWidget< property: string, value: unknown, // eslint-disable-next-line @typescript-eslint/no-unused-vars - prevValue: unknown, + prevValue?: unknown, ): void { const $item = this._findItemElementByItem(item); if (!$item.length) { @@ -761,7 +777,11 @@ class CollectionWidget< this._startIndexForAppendedItems = null; } - _dataSourceChangedHandler(newItems: TItem[]): void { + _dataSourceChangedHandler( + newItems: TItem[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + e?: { changes?: DataChange[] }, + ): void { const items = this.option('items'); if (this._initialized && items && this._shouldAppendItems()) { // @ts-expect-error ts-error @@ -1081,7 +1101,6 @@ class CollectionWidget< _renderItems(items: TItem[]): void { if (items.length) { each(items, (index, itemData) => { - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/restrict-plus-operands this._renderItem(this._renderedItemsCount + index, itemData); }); @@ -1110,7 +1129,7 @@ class CollectionWidget< _renderItem( index: { group: number; item: number } | number, itemData: TItem, - $container: dxElementWrapper | null, + $container?: dxElementWrapper | null, $itemToReplace?: dxElementWrapper, ): dxElementWrapper { // @ts-expect-error ts-error @@ -1264,12 +1283,7 @@ class CollectionWidget< // eslint-disable-next-line class-methods-use-this _postprocessRenderItem( // eslint-disable-next-line @typescript-eslint/no-unused-vars - args: { - itemElement: dxElementWrapper; - itemContent: dxElementWrapper; - itemData: TItem; - itemIndex: number; - }, + args: PostprocessRenderItemInfo, ): void {} _executeItemRenderAction( diff --git a/packages/devextreme/js/__internal/ui/collection/edit.ts b/packages/devextreme/js/__internal/ui/collection/edit.ts deleted file mode 100644 index 7078843a2d36..000000000000 --- a/packages/devextreme/js/__internal/ui/collection/edit.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { dxElementWrapper } from '@js/core/renderer'; -import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; -import CollectionWidgetEdit from '@js/ui/collection/ui.collection_widget.edit'; -import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; -import CollectionWidgetBase from '@ts/ui/collection/collection_widget.base'; - -declare class Edit< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetBaseProperties, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends CollectionWidgetBase { - _processSelectableItem($itemElement: dxElementWrapper, isSelected: boolean): void; - _setAriaSelectionAttribute($itemElement: dxElementWrapper, isSelected: string): void; - _clearSelectedItems(): void; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TypedCollectionWidget: typeof Edit = CollectionWidgetEdit as any; - -export default TypedCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/hierarchical.ts b/packages/devextreme/js/__internal/ui/collection/hierarchical.ts deleted file mode 100644 index 79f01834fb87..000000000000 --- a/packages/devextreme/js/__internal/ui/collection/hierarchical.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { dxElementWrapper } from '@js/core/renderer'; -import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; -import type { HierarchicalCollectionWidgetOptions } from '@js/ui/hierarchical_collection/ui.hierarchical_collection_widget'; -import HierarchicalCollectionWidget from '@js/ui/hierarchical_collection/ui.hierarchical_collection_widget'; - -import AsyncCollectionWidget from './async'; - -export interface TypedCollectionWidgetOptions< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TComponent extends HierarchicalCollectionWidget, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends HierarchicalCollectionWidgetOptions { -} - -declare class Hierarchical< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends TypedCollectionWidgetOptions, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends AsyncCollectionWidget { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - _dataAdapter?: any; - - _initDataAdapter(): void; - - _getIconContainer(itemData: TItem): dxElementWrapper; - _getTextContainer(itemData: TItem): dxElementWrapper; - _getLinkContainer( - iconContainer: dxElementWrapper, - textContainer: dxElementWrapper, - itemData: TItem, - ): dxElementWrapper; - _addContent($container: dxElementWrapper, itemData: TItem): void; - - _addWidgetClass(): void; - - _getChildNodes(node: TItem): TItem[]; - _hasChildren(node: TItem): number | undefined; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TypedCollectionWidget: typeof Hierarchical = HierarchicalCollectionWidget as any; - -export default TypedCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/live_update.ts b/packages/devextreme/js/__internal/ui/collection/live_update.ts deleted file mode 100644 index 5cdd691bd8a2..000000000000 --- a/packages/devextreme/js/__internal/ui/collection/live_update.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; -import CollectionWidgetLiveUpdate from '@js/ui/collection/ui.collection_widget.live_update'; -import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; - -import CollectionWidgetAsync from './async'; - -declare class LiveUpdate< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetBaseProperties, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends CollectionWidgetAsync { -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TypedCollectionWidget: typeof LiveUpdate = CollectionWidgetLiveUpdate as any; - -export default TypedCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.async.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.async.ts index e4c3dc9f1365..1f0e067d4f37 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.async.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.async.ts @@ -1,70 +1,97 @@ import Guid from '@js/core/guid'; -import { noop } from '@js/core/utils/common'; +import type { dxElementWrapper } from '@js/core/renderer'; import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred, when } from '@js/core/utils/deferred'; - -import CollectionWidgetEdit from './m_collection_widget.edit'; - -const AsyncCollectionWidget = CollectionWidgetEdit.inherit({ - _initMarkup() { +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { ItemRenderInfo } from '@ts/ui/collection/collection_widget.base'; +import type { CollectionWidgetEditProperties } from '@ts/ui/collection/m_collection_widget.edit'; +import CollectionWidgetEdit from '@ts/ui/collection/m_collection_widget.edit'; + +class CollectionWidgetAsync< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TProperties extends CollectionWidgetEditProperties, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends CollectionWidgetEdit { + _asyncTemplateItemsMap!: Record>; + + _initMarkup(): void { this._asyncTemplateItemsMap = {}; - this.callBase(); - }, + super._initMarkup(); + } - _render() { - this.callBase(arguments); + _render(): void { + super._render(); + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._planPostRenderActions(); - }, + } - _renderItemContent(args) { + _renderItemContent(args: ItemRenderInfo): DeferredObj { const renderContentDeferred = Deferred(); const itemDeferred = Deferred(); const uniqueKey = `dx${new Guid()}`; this._asyncTemplateItemsMap[uniqueKey] = itemDeferred; - const $itemContent = this.callBase({ ...args, uniqueKey }); + const $itemContent = super._renderItemContent({ ...args, uniqueKey }); + // eslint-disable-next-line @typescript-eslint/no-floating-promises itemDeferred.done(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises renderContentDeferred.resolve($itemContent); }); - + // @ts-expect-error ts-error return renderContentDeferred.promise(); - }, - - _onItemTemplateRendered(itemTemplate, renderArgs) { - return () => { - this._asyncTemplateItemsMap[renderArgs.uniqueKey]?.resolve(); + } + + _onItemTemplateRendered( + itemTemplate: { source: () => unknown }, + renderArgs: ItemRenderInfo, + ) { + return (): void => { + const { uniqueKey } = renderArgs; + + if (uniqueKey) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this._asyncTemplateItemsMap[uniqueKey]?.resolve(); + } }; - }, + } - _postProcessRenderItems: noop, + // eslint-disable-next-line class-methods-use-this + _postProcessRenderItems(): void {} - _planPostRenderActions(...args: unknown[]) { + _planPostRenderActions(...args: unknown[]): Promise { const d = Deferred(); const asyncTemplateItems = Object.values>(this._asyncTemplateItemsMap); + // eslint-disable-next-line @typescript-eslint/no-floating-promises when.apply(this, asyncTemplateItems).done(() => { + // @ts-expect-error ts-error this._postProcessRenderItems(...args); + // eslint-disable-next-line @typescript-eslint/no-floating-promises d.resolve().done(() => { this._asyncTemplateItemsMap = {}; }); }); return d.promise(); - }, + } - _clean() { - this.callBase(); + _clean(): void { + super._clean(); const asyncTemplateItems = Object.values>(this._asyncTemplateItemsMap); asyncTemplateItems.forEach((item) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises item.reject(); }); this._asyncTemplateItemsMap = {}; - }, -}); + } +} -export default AsyncCollectionWidget; +export default CollectionWidgetAsync; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.plain.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.plain.ts index 54fef1992b8d..2229a324316d 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.plain.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.plain.ts @@ -1,10 +1,16 @@ -import EditStrategy from './m_collection_widget.edit.strategy'; +import type { dxElementWrapper } from '@js/core/renderer'; +import type CollectionWidget from '@ts/ui/collection/m_collection_widget.edit'; +import type { CollectionWidgetEditProperties } from '@ts/ui/collection/m_collection_widget.edit'; -const PlainEditStrategy = EditStrategy.inherit({ +import EditStrategy from './m_collection_widget.edit.strategy'; +class PlainEditStrategy< + // @ts-expect-error + TComponent extends CollectionWidget = CollectionWidget, +> extends EditStrategy { _getPlainItems() { return this._collectionWidget.option('items') || []; - }, + } getIndexByItemData(itemData) { const keyOf = this._collectionWidget.keyOf.bind(this._collectionWidget); @@ -12,19 +18,19 @@ const PlainEditStrategy = EditStrategy.inherit({ return this.getIndexByKey(keyOf(itemData)); } return this._getPlainItems().indexOf(itemData); - }, + } getItemDataByIndex(index) { return this._getPlainItems()[index]; - }, + } - deleteItemAtIndex(index) { + deleteItemAtIndex(index: number): void { this._getPlainItems().splice(index, 1); - }, + } itemsGetter() { return this._getPlainItems(); - }, + } getKeysByItems(items) { const keyOf = this._collectionWidget.keyOf.bind(this._collectionWidget); @@ -36,9 +42,9 @@ const PlainEditStrategy = EditStrategy.inherit({ } } return result; - }, + } - getIndexByKey(key) { + getIndexByKey(key): number { const cache = this._cache; const keys = cache && cache.keys || this.getKeysByItems(this._getPlainItems()); @@ -55,44 +61,46 @@ const PlainEditStrategy = EditStrategy.inherit({ } return -1; - }, + } getItemsByKeys(keys, items) { return (items || keys).slice(); - }, + } - moveItemAtIndexToIndex(movingIndex, destinationIndex) { + moveItemAtIndexToIndex(movingIndex, destinationIndex): void { const items = this._getPlainItems(); const movedItemData = items[movingIndex]; items.splice(movingIndex, 1); items.splice(destinationIndex, 0, movedItemData); - }, + } - _isItemIndex(index) { + // eslint-disable-next-line class-methods-use-this + _isItemIndex(index: Element | number): boolean { return (typeof index === 'number') && Math.round(index) === index; - }, + } - _getNormalizedItemIndex(itemElement) { + _getNormalizedItemIndex(itemElement: Element): number { return this._collectionWidget._itemElements().index(itemElement); - }, + } _normalizeItemIndex(index) { return index; - }, + } _denormalizeItemIndex(index) { return index; - }, + } - _getItemByNormalizedIndex(index) { + _getItemByNormalizedIndex(index: number): dxElementWrapper { + // @ts-expect-error ts-error return index > -1 ? this._collectionWidget._itemElements().eq(index) : null; - }, + } - _itemsFromSameParent() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _itemsFromSameParent(firstIndex, secondIndex): boolean { return true; - }, - -}); + } +} export default PlainEditStrategy; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.ts index b9799225e8f0..1c0c786931a8 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.strategy.ts @@ -1,53 +1,83 @@ import Class from '@js/core/class'; import domAdapter from '@js/core/dom_adapter'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { equalByValue } from '@js/core/utils/common'; import { isRenderer } from '@js/core/utils/type'; +import type CollectionWidget from '@ts/ui/collection/m_collection_widget.edit'; +import type { CollectionWidgetEditProperties } from '@ts/ui/collection/m_collection_widget.edit'; -const { abstract } = Class; +class EditStrategy< + // @ts-expect-error ts-error + TComponent extends CollectionWidget, + // @ts-expect-error dxClass inheritance issue + // eslint-disable-next-line @typescript-eslint/ban-types +> extends (Class.inherit({}) as new() => {}) { + _collectionWidget!: TComponent; -const EditStrategy = Class.inherit({ + _cache?: Record | null; + + constructor(collectionWidget: TComponent) { + super(); - ctor(collectionWidget) { this._collectionWidget = collectionWidget; - }, + } - getIndexByItemData: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getIndexByItemData(value): number { + return Class.abstract(); + } - getItemDataByIndex: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getItemDataByIndex(index) { + Class.abstract(); + } - getKeysByItems: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getKeysByItems(items) { + Class.abstract(); + } - getItemsByKeys: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getItemsByKeys(keys, items) { + Class.abstract(); + } - itemsGetter: abstract, + itemsGetter() { + Class.abstract(); + } getKeyByIndex(index) { const resultIndex = this._denormalizeItemIndex(index); return this.getKeysByItems([this.getItemDataByIndex(resultIndex)])[0]; - }, + } - _equalKeys(key1, key2) { + _equalKeys(key1, key2): boolean { if (this._collectionWidget._isKeySpecified()) { return equalByValue(key1, key2); } return key1 === key2; - }, + } - beginCache() { + beginCache(): void { this._cache = {}; - }, + } - endCache() { + endCache(): void { this._cache = null; - }, + } - getIndexByKey: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getIndexByKey(key): number { + return Class.abstract(); + } - getNormalizedIndex(value) { + getNormalizedIndex( + value: number | Element, + ): number { if (this._isNormalizedItemIndex(value)) { - return value; + return value as number; } if (this._isItemIndex(value)) { @@ -59,7 +89,7 @@ const EditStrategy = Class.inherit({ } return this._normalizeItemIndex(this.getIndexByItemData(value)); - }, + } getIndex(value) { if (this._isNormalizedItemIndex(value)) { @@ -75,9 +105,9 @@ const EditStrategy = Class.inherit({ } return this.getIndexByItemData(value); - }, + } - getItemElement(value) { + getItemElement(value: Element | number): dxElementWrapper { if (this._isNormalizedItemIndex(value)) { return this._getItemByNormalizedIndex(value); } @@ -87,39 +117,68 @@ const EditStrategy = Class.inherit({ } if (this._isNode(value)) { + // @ts-expect-error ts-error return $(value); } const normalizedItemIndex = this._normalizeItemIndex(this.getIndexByItemData(value)); return this._getItemByNormalizedIndex(normalizedItemIndex); - }, + } - _isNode: (el) => domAdapter.isNode(el && isRenderer(el) ? el.get(0) : el), + _isNode(el) { + return domAdapter.isNode(el && isRenderer(el) ? el.get(0) : el); + } - deleteItemAtIndex: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + deleteItemAtIndex(index: number) { + Class.abstract(); + } - itemPlacementFunc(movingIndex, destinationIndex) { + itemPlacementFunc(movingIndex, destinationIndex): 'after' | 'before' { return this._itemsFromSameParent(movingIndex, destinationIndex) && movingIndex < destinationIndex ? 'after' : 'before'; - }, + } - moveItemAtIndexToIndex: abstract, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + moveItemAtIndexToIndex(movingIndex, destinationIndex): void { + Class.abstract(); + } - _isNormalizedItemIndex(index) { + // eslint-disable-next-line class-methods-use-this + _isNormalizedItemIndex(index: number | Element): boolean { return (typeof index === 'number') && Math.round(index) === index; - }, - - _isItemIndex: abstract, - - _getNormalizedItemIndex: abstract, - - _normalizeItemIndex: abstract, - - _denormalizeItemIndex: abstract, - - _getItemByNormalizedIndex: abstract, - - _itemsFromSameParent: abstract, - -}); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this + _isItemIndex(index: number | Element): boolean { + return Class.abstract(); + } + + _getNormalizedItemIndex( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + value: number | Element, + ): number { + return Class.abstract(); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _normalizeItemIndex(index: number | Element): number { + return Class.abstract(); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this + _denormalizeItemIndex(index: number): number { + return Class.abstract(); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _getItemByNormalizedIndex(value: number | Element): dxElementWrapper { + return Class.abstract(); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _itemsFromSameParent(movingIndex, destinationIndex): boolean { + return Class.abstract(); + } +} export default EditStrategy; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts index c06ae4c23bc5..e499f7ab9682 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts @@ -1,43 +1,81 @@ +import type { SingleMultipleOrNone } from '@js/common'; +import type { ItemInfo } from '@js/common/core/events'; import eventsEngine from '@js/common/core/events/core/events_engine'; import { DataSource } from '@js/common/data/data_source/data_source'; import { normalizeLoadResult } from '@js/common/data/data_source/utils'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { noop } from '@js/core/utils/common'; import { compileGetter } from '@js/core/utils/data'; +import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred, - // @ts-expect-error + // @ts-expect-error ts-error fromPromise, when, } from '@js/core/utils/deferred'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { isDefined } from '@js/core/utils/type'; +import type { DxEvent } from '@js/events/events.types'; +import type { ItemLike, SelectionChangeInfo } from '@js/ui/collection/ui.collection_widget.base'; import errors from '@js/ui/widget/ui.errors'; +import type { ActionConfig } from '@ts/core/widget/component'; +import type { OptionChanged } from '@ts/core/widget/types'; +import type { CollectionWidgetBaseProperties, PostprocessRenderItemInfo } from '@ts/ui/collection/collection_widget.base'; import BaseCollectionWidget from '@ts/ui/collection/collection_widget.base'; +import PlainEditStrategy from '@ts/ui/collection/m_collection_widget.edit.strategy.plain'; import Selection from '@ts/ui/selection/m_selection'; -import PlainEditStrategy from './m_collection_widget.edit.strategy.plain'; +import type MenuBaseEditStrategy from '../context_menu/m_menu_base.edit.strategy'; const ITEM_DELETING_DATA_KEY = 'dxItemDeleting'; const NOT_EXISTING_INDEX = -1; -const indexExists = function (index) { - return index !== NOT_EXISTING_INDEX; -}; -// @ts-expect-error -const CollectionWidget = BaseCollectionWidget.inherit({ +const indexExists = (index): boolean => index !== NOT_EXISTING_INDEX; - _setOptionsByReference() { - this.callBase(); +export interface CollectionWidgetEditProperties< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TComponent extends CollectionWidget | any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends CollectionWidgetBaseProperties { + selectionMode?: SingleMultipleOrNone; +} + +class CollectionWidget< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TProperties extends CollectionWidgetEditProperties, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends BaseCollectionWidget { + _userOptions?: TProperties; + + _selection!: Selection; + + _editStrategy!: PlainEditStrategy | MenuBaseEditStrategy; + + _actions!: Record) => void>; + + _rendered?: boolean; + + _rendering?: boolean; + + _setOptionsByReference(): void { + super._setOptionsByReference(); extend(this._optionsByReference, { selectedItem: true, }); - }, + } - _getDefaultOptions() { - return extend(this.callBase(), { + _getDefaultOptions(): TProperties { + return { + ...super._getDefaultOptions(), selectionMode: 'none', selectionRequired: false, selectByClick: true, @@ -52,36 +90,38 @@ const CollectionWidget = BaseCollectionWidget.inherit({ onItemReordered: null, onItemDeleting: null, onItemDeleted: null, - }); - }, + }; + } - ctor(element, options) { + ctor(element: Element, options: TProperties): void { this._userOptions = options || {}; - this.callBase(element, options); - }, + super.ctor(element, options); + } - _init() { + _init(): void { this._initEditStrategy(); - this.callBase(); + super._init(); this._initKeyGetter(); this._initActions(); this._initSelectionModule(); - }, + } - _initKeyGetter() { + _initKeyGetter(): void { + // @ts-expect-error ts-error this._keyGetter = compileGetter(this.option('keyExpr')); - }, + } - _getActionsList() { + // eslint-disable-next-line class-methods-use-this + _getActionsList(): ('onSelectionChanging' | 'onSelectionChanged')[] { return ['onSelectionChanging', 'onSelectionChanged']; - }, + } - _initActions() { + _initActions(): void { this._actions = {}; const actions = this._getActionsList(); @@ -90,60 +130,69 @@ const CollectionWidget = BaseCollectionWidget.inherit({ excludeValidators: ['disabled', 'readOnly'], }) ?? noop; }); - }, + } _getKeysByItems(selectedItems) { return this._editStrategy.getKeysByItems(selectedItems); - }, + } _getItemsByKeys(selectedItemKeys, selectedItems) { return this._editStrategy.getItemsByKeys(selectedItemKeys, selectedItems); - }, + } - _getKeyByIndex(index) { + _getKeyByIndex(index: number): unknown { return this._editStrategy.getKeyByIndex(index); - }, + } - _getIndexByKey(key) { + _getIndexByKey(key: unknown): number { return this._editStrategy.getIndexByKey(key); - }, + } _getIndexByItemData(itemData) { return this._editStrategy.getIndexByItemData(itemData); - }, + } _isKeySpecified() { + // @ts-expect-error ts-error return !!this._dataController.key(); - }, + } _getCombinedFilter() { + // @ts-expect-error ts-error return this._dataController.filter(); - }, + } key() { - if (this.option('keyExpr')) return this.option('keyExpr'); + const { keyExpr } = this.option(); + if (keyExpr) return keyExpr; + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._dataController.key(); - }, + } keyOf(item) { let key = item; if (this.option('keyExpr')) { + // @ts-expect-error ts-error key = this._keyGetter(item); + // @ts-expect-error ts-error } else if (this._dataController.store()) { + // @ts-expect-error ts-error key = this._dataController.keyOf(item); } return key; - }, + } - _nullValueSelectionSupported() { + // eslint-disable-next-line class-methods-use-this + _nullValueSelectionSupported(): boolean { return false; - }, + } - _initSelectionModule() { + _initSelectionModule(): void { const that = this; - const { itemsGetter } = that._editStrategy; + const { itemsGetter } = this._editStrategy; this._selection = new Selection({ allowNullValue: this._nullValueSelectionSupported(), @@ -170,17 +219,20 @@ const CollectionWidget = BaseCollectionWidget.inherit({ this._updateSelectedItems(args); } }, - filter: that._getCombinedFilter.bind(that), - totalCount() { - const items = that.option('items'); - const totalCount = that._dataController.totalCount(); + filter: this._getCombinedFilter.bind(this), + totalCount: (): number => { + const { items } = this.option(); + // @ts-expect-error ts-error + const totalCount: number = this._dataController.totalCount(); return totalCount >= 0 ? totalCount - : that._getItemsCount(items); + // @ts-expect-error ts-error + : this._getItemsCount(items); }, - key: that.key.bind(that), - keyOf: that.keyOf.bind(that), - load(options) { + key: this.key.bind(this), + keyOf: this.keyOf.bind(this), + load(options): DeferredObj { + // @ts-expect-error ts-error const dataController = that._dataController; options.customQueryParams = dataController.loadOptions()?.customQueryParams; options.userData = dataController.userData(); @@ -198,70 +250,71 @@ const CollectionWidget = BaseCollectionWidget.inherit({ } return Deferred().resolve(this.plainItems()); }, - dataFields() { - return that._dataController.select(); - }, - plainItems: itemsGetter.bind(that._editStrategy), + // @ts-expect-error ts-error + dataFields: () => this._dataController.select(), + plainItems: itemsGetter.bind(this._editStrategy), }); - }, + } - _getItemsCount(items) { + _getItemsCount(items: TItem[]): number { + // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unsafe-return, no-return-assign return items.reduce((itemsCount, item) => itemsCount += item.items + // @ts-expect-error ts-error ? this._getItemsCount(item.items) : 1, 0); - }, + } - _initEditStrategy() { - const Strategy = PlainEditStrategy; - this._editStrategy = new Strategy(this); - }, + _initEditStrategy(): void { + this._editStrategy = new PlainEditStrategy(this); + } - _getSelectedItemIndices(keys) { - const that = this; - const indices = []; + _getSelectedItemIndices(keys): number[] { + const indices: number[] = []; keys = keys || this._selection.getSelectedItemKeys(); - that._editStrategy.beginCache(); + this._editStrategy.beginCache(); each(keys, (_, key) => { - const selectedIndex = that._getIndexByKey(key); + const selectedIndex = this._getIndexByKey(key); if (indexExists(selectedIndex)) { - // @ts-expect-error indices.push(selectedIndex); } }); - that._editStrategy.endCache(); + this._editStrategy.endCache(); return indices; - }, + } - _initMarkup() { + _initMarkup(): void { this._rendering = true; - + // @ts-expect-error ts-error if (!this._dataController.isLoading()) { this._syncSelectionOptions().done(() => this._normalizeSelectedItems()); } - this.callBase(); - }, - _render() { - this.callBase(); + super._initMarkup(); + } + + _render(): void { + super._render(); this._rendering = false; - }, + } - _fireContentReadyAction() { + _fireContentReadyAction(): void { this._rendering = false; this._rendered = true; - this.callBase.apply(this, arguments); - }, - _syncSelectionOptions(byOption) { - byOption = byOption || this._chooseSelectOption(); + // eslint-disable-next-line @typescript-eslint/no-floating-promises + super._fireContentReadyAction(); + } + + _syncSelectionOptions(byOption?: string) { + byOption = byOption ?? this._chooseSelectOption(); let selectedItem; let selectedIndex; @@ -331,16 +384,21 @@ const CollectionWidget = BaseCollectionWidget.inherit({ } return Deferred().resolve().promise(); - }, + } - _chooseSelectOption() { + _chooseSelectOption(): string { let optionName = 'selectedIndex'; - const isOptionDefined = function (optionName) { - const optionValue = this.option(optionName); + const isOptionDefined = ( + name: 'selectedItems' | 'selectedItem' | 'selectedItemKeys', + ): boolean => { + const optionValue = this.option(name); + // @ts-expect-error ts-error const length = isDefined(optionValue) && optionValue.length; - return length || optionName in this._userOptions; - }.bind(this); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return length || name in this._userOptions; + }; if (isOptionDefined('selectedItems')) { optionName = 'selectedItems'; @@ -351,9 +409,9 @@ const CollectionWidget = BaseCollectionWidget.inherit({ } return optionName; - }, + } - _compareKeys(oldKeys, newKeys) { + _compareKeys(oldKeys, newKeys): boolean { if (oldKeys.length !== newKeys.length) { return false; } @@ -365,18 +423,23 @@ const CollectionWidget = BaseCollectionWidget.inherit({ } return true; - }, + } - _normalizeSelectedItems() { - if (this.option('selectionMode') === 'none') { + _normalizeSelectedItems(): Promise { + const { selectionMode, selectedItems, items } = this.option(); + + if (selectionMode === 'none') { this._setOptionWithoutOptionChange('selectedItems', []); this._syncSelectionOptions('selectedItems'); - } else if (this.option('selectionMode') === 'single') { - const newSelection = this.option('selectedItems'); + } else if (selectionMode === 'single') { + const newSelection = selectedItems ?? []; - if (newSelection.length > 1 || !newSelection.length && this.option('selectionRequired') && this.option('items') && this.option('items').length) { + // eslint-disable-next-line no-mixed-operators + if (newSelection.length > 1 || !newSelection.length && this.option('selectionRequired') && items && items.length) { const currentSelection = this._selection.getSelectedItems(); - let normalizedSelection = newSelection[0] === undefined ? currentSelection[0] : newSelection[0]; + let normalizedSelection = newSelection[0] === undefined + ? currentSelection[0] + : newSelection[0]; if (normalizedSelection === undefined) { // eslint-disable-next-line prefer-destructuring @@ -403,11 +466,14 @@ const CollectionWidget = BaseCollectionWidget.inherit({ } return Deferred().resolve().promise(); - }, + } - _itemClickHandler(e) { + _itemClickHandler( + e: DxEvent, + args?: Record, + config?: ActionConfig, + ): void { let itemSelectPromise = Deferred().resolve(); - const { callBase } = this; this._createAction((e) => { itemSelectPromise = this._itemSelectHandler(e.event) ?? itemSelectPromise; @@ -417,82 +483,98 @@ const CollectionWidget = BaseCollectionWidget.inherit({ itemElement: $(e.currentTarget), event: e, }); - + // const parentItemClickHandler = super._itemClickHandler.bind(this); + // eslint-disable-next-line @typescript-eslint/no-floating-promises itemSelectPromise.always(() => { - callBase.apply(this, arguments); + super._itemClickHandler(e, args, config); }); - }, - - _itemSelectHandler(e, shouldIgnoreSelectByClick) { - let itemSelectPromise; + } + _itemSelectHandler( + e: DxEvent, + shouldIgnoreSelectByClick?: boolean, + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + ): DeferredObj | void { if (!shouldIgnoreSelectByClick && !this.option('selectByClick')) { return; } const $itemElement = e.currentTarget; + // @ts-expect-error ts-error if (this.isItemSelected($itemElement)) { this.unselectItem(e.currentTarget); } else { - itemSelectPromise = this.selectItem(e.currentTarget); - } + const itemSelectPromise = this.selectItem(e.currentTarget); - return itemSelectPromise?.promise(); - }, + // @ts-expect-error ts-error + // eslint-disable-next-line consistent-return + return itemSelectPromise?.promise(); + } + } - _selectedItemElement(index) { + _selectedItemElement(index: number): dxElementWrapper { return this._itemElements().eq(index); - }, + } + + _postprocessRenderItem(args: PostprocessRenderItemInfo): void { + const { selectionMode } = this.option(); - _postprocessRenderItem(args) { - if (this.option('selectionMode') !== 'none') { + if (selectionMode !== 'none') { const $itemElement = $(args.itemElement); + // @ts-expect-error ts-error const normalizedItemIndex = this._editStrategy.getNormalizedIndex($itemElement); const isItemSelected = this._isItemSelected(normalizedItemIndex); this._processSelectableItem($itemElement, isItemSelected); } - }, + } - _processSelectableItem($itemElement, isSelected) { + _processSelectableItem( + $itemElement: dxElementWrapper, + isSelected: boolean, + ): void { $itemElement.toggleClass(this._selectedItemClass(), isSelected); this._setAriaSelectionAttribute($itemElement, String(isSelected)); - }, - - _updateSelectedItems(args) { - const that = this; - const { addedItemKeys } = args; - const { removedItemKeys } = args; - - if (that._rendered && (addedItemKeys.length || removedItemKeys.length)) { - const selectionChangePromise = that._selectionChangePromise; - if (!that._rendering) { + } + + _updateSelectedItems(args: SelectionChangeInfo & { + addedItemKeys: unknown[]; + removedItemKeys: unknown[]; + }): void { + const { addedItemKeys, removedItemKeys } = args; + + if (this._rendered && (addedItemKeys.length || removedItemKeys.length)) { + // @ts-expect-error ts-error + const selectionChangePromise = this._selectionChangePromise; + if (!this._rendering) { const addedSelection = []; - let normalizedIndex; const removedSelection = []; - that._editStrategy.beginCache(); + this._editStrategy.beginCache(); - for (let i = 0; i < addedItemKeys.length; i++) { - normalizedIndex = that._getIndexByKey(addedItemKeys[i]); - // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < addedItemKeys.length; i += 1) { + const normalizedIndex = this._getIndexByKey(addedItemKeys[i]); + // @ts-expect-error ts-error addedSelection.push(normalizedIndex); - that._addSelection(normalizedIndex); + this._addSelection(normalizedIndex); } - for (let i = 0; i < removedItemKeys.length; i++) { - normalizedIndex = that._getIndexByKey(removedItemKeys[i]); - // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < removedItemKeys.length; i += 1) { + const normalizedIndex = this._getIndexByKey(removedItemKeys[i]); + // @ts-expect-error ts-error removedSelection.push(normalizedIndex); - that._removeSelection(normalizedIndex); + this._removeSelection(normalizedIndex); } - that._editStrategy.endCache(); + this._editStrategy.endCache(); - that._updateSelection(addedSelection, removedSelection); + this._updateSelection(addedSelection, removedSelection); } + // eslint-disable-next-line @typescript-eslint/no-floating-promises when(selectionChangePromise).done(() => { this._actions.onSelectionChanged({ addedItems: args.addedItems, @@ -500,50 +582,56 @@ const CollectionWidget = BaseCollectionWidget.inherit({ }); }); } - }, + } - _updateSelection: noop, + // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this + _updateSelection(addedSelection: unknown[], removedSelection: unknown[]): void {} - _setAriaSelectionAttribute($target, value) { + _setAriaSelectionAttribute( + $target: dxElementWrapper, + value: string, + ): void { this.setAria('selected', value, $target); - }, + } - _removeSelection(normalizedIndex) { + _removeSelection(normalizedIndex: number): void { const $itemElement = this._editStrategy.getItemElement(normalizedIndex); if (indexExists(normalizedIndex)) { this._processSelectableItem($itemElement, false); - // @ts-expect-error + // @ts-expect-error ts-error eventsEngine.triggerHandler($itemElement, 'stateChanged', false); } - }, + } - _addSelection(normalizedIndex) { + _addSelection(normalizedIndex: number): void { const $itemElement = this._editStrategy.getItemElement(normalizedIndex); if (indexExists(normalizedIndex)) { this._processSelectableItem($itemElement, true); - // @ts-expect-error + // @ts-expect-error ts-error eventsEngine.triggerHandler($itemElement, 'stateChanged', true); } - }, + } - _isItemSelected(index) { + _isItemSelected(index: number): boolean { const key = this._getKeyByIndex(index); + return this._selection.isItemSelected(key, { checkPending: true }); - }, + } - _optionChanged(args) { + _optionChanged(args: OptionChanged): void { switch (args.name) { case 'selectionMode': this._invalidate(); break; case 'dataSource': + // eslint-disable-next-line no-mixed-operators if (!args.value || Array.isArray(args.value) && !args.value.length) { this.option('selectedItemKeys', []); } - this.callBase(args); + super._optionChanged(args); break; case 'selectedIndex': case 'selectedItem': @@ -555,6 +643,7 @@ const CollectionWidget = BaseCollectionWidget.inherit({ this._initKeyGetter(); break; case 'selectionRequired': + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._normalizeSelectedItems(); break; case 'onSelectionChanging': @@ -568,16 +657,16 @@ const CollectionWidget = BaseCollectionWidget.inherit({ case 'maxFilterLengthInRequest': break; default: - this.callBase(args); + super._optionChanged(args); } - }, + } - _clearSelectedItems() { + _clearSelectedItems(): void { this._setOptionWithoutOptionChange('selectedItems', []); this._syncSelectionOptions('selectedItems'); - }, + } - _waitDeletingPrepare($itemElement) { + _waitDeletingPrepare($itemElement: dxElementWrapper): Promise { if ($itemElement.data(ITEM_DELETING_DATA_KEY)) { return Deferred().resolve().promise(); } @@ -588,28 +677,44 @@ const CollectionWidget = BaseCollectionWidget.inherit({ const deletingActionArgs = { cancel: false }; const deletePromise = this._itemEventHandler($itemElement, 'onItemDeleting', deletingActionArgs, { excludeValidators: ['disabled', 'readOnly'] }); + // eslint-disable-next-line @typescript-eslint/no-floating-promises, func-names when(deletePromise).always(function (value) { + // @ts-expect-error ts-error const deletePromiseExists = !deletePromise; + // @ts-expect-error ts-error const deletePromiseResolved = !deletePromiseExists && deletePromise.state() === 'resolved'; const argumentsSpecified = !!arguments.length; - const shouldDelete = deletePromiseExists || deletePromiseResolved && !argumentsSpecified || deletePromiseResolved && value; + // eslint-disable-next-line no-mixed-operators + const shouldDelete = deletePromiseExists || deletePromiseResolved + // eslint-disable-next-line no-mixed-operators + && !argumentsSpecified || deletePromiseResolved + // eslint-disable-next-line no-mixed-operators + && value; + // eslint-disable-next-line @typescript-eslint/no-floating-promises when(fromPromise(deletingActionArgs.cancel)) .always(() => { $itemElement.data(ITEM_DELETING_DATA_KEY, false); }) .done((cancel) => { - shouldDelete && !cancel ? deferred.resolve() : deferred.reject(); + if (shouldDelete && !cancel) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.resolve(); + } else { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.reject(); + } }) // eslint-disable-next-line @typescript-eslint/no-misused-promises .fail(deferred.reject); }); return deferred.promise(); - }, + } - _deleteItemFromDS($item) { + _deleteItemFromDS($item: dxElementWrapper): Promise | DeferredObj { + // @ts-expect-error ts-error const dataController = this._dataController; const deferred = Deferred(); const disabledState = this.option('disabled'); @@ -628,69 +733,83 @@ const CollectionWidget = BaseCollectionWidget.inherit({ dataStore.remove(dataController.keyOf(this._getItemData($item))) .done((key) => { if (key !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.resolve(); } else { + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.reject(); } }) .fail(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.reject(); }); - deferred.always(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.always((): void => { this.option('disabled', disabledState); }); return deferred; - }, + } - _tryRefreshLastPage() { + _tryRefreshLastPage(): Promise { const deferred = Deferred(); - + // @ts-expect-error ts-error if (this._isLastPage() || this.option('grouped')) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.resolve(); } else { + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._refreshLastPage().done(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.resolve(); }); } return deferred.promise(); - }, + } - _refreshLastPage() { + _refreshLastPage(): DeferredObj { this._expectLastItemLoading(); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._dataController.load(); - }, + } - _updateSelectionAfterDelete(index) { + _updateSelectionAfterDelete(index: number): void { const key = this._getKeyByIndex(index); + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._selection.deselect([key]); - }, + } - _updateIndicesAfterIndex(index) { + _updateIndicesAfterIndex(index: number): void { const itemElements = this._itemElements(); - for (let i = index + 1; i < itemElements.length; i++) { + for (let i = index + 1; i < itemElements.length; i += 1) { $(itemElements[i]).data(this._itemIndexKey(), i - 1); } - }, + } - _simulateOptionChange(optionName) { + _simulateOptionChange(optionName: keyof TProperties): void { const optionValue = this.option(optionName); if (optionValue instanceof DataSource) { return; } - this._optionChangedAction({ name: optionName, fullName: optionName, value: optionValue }); - }, + this._optionChangedAction?.({ name: optionName, fullName: optionName, value: optionValue }); + } - isItemSelected(itemElement) { + isItemSelected(itemElement: dxElementWrapper | number): boolean { + // @ts-expect-error ts-error return this._isItemSelected(this._editStrategy.getNormalizedIndex(itemElement)); - }, + } - selectItem(itemElement) { - if (this.option('selectionMode') === 'none') return Deferred().resolve(); + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + selectItem(itemElement: Element): DeferredObj | void { + const { selectionMode } = this.option(); + + if (selectionMode === 'none') return Deferred().resolve(); const itemIndex = this._editStrategy.getNormalizedIndex(itemElement); if (!indexExists(itemIndex)) { @@ -703,15 +822,16 @@ const CollectionWidget = BaseCollectionWidget.inherit({ return Deferred().resolve(); } - if (this.option('selectionMode') === 'single') { + if (selectionMode === 'single') { return this._selection.setSelection([key]); } - const selectedItemKeys = this.option('selectedItemKeys') || []; - return this._selection.setSelection([...selectedItemKeys, key], [key]); - }, + const { selectedItemKeys } = this.option(); + + return this._selection.setSelection([...selectedItemKeys ?? [], key], [key]); + } - unselectItem(itemElement) { + unselectItem(itemElement: Element): void { const itemIndex = this._editStrategy.getNormalizedIndex(itemElement); if (!indexExists(itemIndex)) { return; @@ -729,16 +849,21 @@ const CollectionWidget = BaseCollectionWidget.inherit({ return; } + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._selection.deselect([key]); - }, + } - _deleteItemElementByIndex(index) { + _deleteItemElementByIndex(index: number): void { this._updateSelectionAfterDelete(index); this._updateIndicesAfterIndex(index); this._editStrategy.deleteItemAtIndex(index); - }, + } - _afterItemElementDeleted($item, deletedActionArgs) { + _afterItemElementDeleted( + $item: dxElementWrapper, + deletedActionArgs: ItemInfo, + ): void { + // @ts-expect-error ts-error const changingOption = this._dataController.getDataSource() ? 'dataSource' : 'items'; @@ -750,80 +875,94 @@ const CollectionWidget = BaseCollectionWidget.inherit({ excludeValidators: ['disabled', 'readOnly'], }); this._renderEmptyMessage(); - }, - - deleteItem(itemElement) { - const that = this; + } + deleteItem(itemElement: Element): Promise { const deferred = Deferred(); const $item = this._editStrategy.getItemElement(itemElement); const index = this._editStrategy.getNormalizedIndex(itemElement); const itemResponseWaitClass = this._itemResponseWaitClass(); if (indexExists(index)) { + // @ts-expect-error ts-error this._waitDeletingPrepare($item).done(() => { $item.addClass(itemResponseWaitClass); - const deletedActionArgs = that._extendActionArgs($item); - that._deleteItemFromDS($item).done(() => { - that._deleteItemElementByIndex(index); - that._afterItemElementDeleted($item, deletedActionArgs); - that._tryRefreshLastPage().done(() => { - deferred.resolveWith(that); + const deletedActionArgs = this._extendActionArgs($item); + // @ts-expect-error ts-error + this._deleteItemFromDS($item).done(() => { + this._deleteItemElementByIndex(index); + this._afterItemElementDeleted($item, deletedActionArgs); + // @ts-expect-error ts-error + this._tryRefreshLastPage().done(() => { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.resolveWith(this); }); }).fail(() => { $item.removeClass(itemResponseWaitClass); - deferred.rejectWith(that); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.rejectWith(this); }); }).fail(() => { - deferred.rejectWith(that); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.rejectWith(this); }); } else { - deferred.rejectWith(that); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises + deferred.rejectWith(this); } return deferred.promise(); - }, + } - reorderItem(itemElement, toItemElement) { + reorderItem(itemElement: Element, toItemElement: Element): DeferredObj { const deferred = Deferred(); - - const that = this; const strategy = this._editStrategy; const $movingItem = strategy.getItemElement(itemElement); const $destinationItem = strategy.getItemElement(toItemElement); const movingIndex = strategy.getNormalizedIndex(itemElement); const destinationIndex = strategy.getNormalizedIndex(toItemElement); - + // @ts-expect-error ts-error const changingOption = this._dataController.getDataSource() ? 'dataSource' : 'items'; - const canMoveItems = indexExists(movingIndex) && indexExists(destinationIndex) && movingIndex !== destinationIndex; + const canMoveItems = indexExists(movingIndex) + && indexExists(destinationIndex) + && movingIndex !== destinationIndex; if (canMoveItems) { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.resolveWith(this); } else { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-floating-promises deferred.rejectWith(this); } - // @ts-expect-error - return deferred.promise().done(function () { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return deferred.promise().done(() => { $destinationItem[strategy.itemPlacementFunc(movingIndex, destinationIndex)]($movingItem); strategy.moveItemAtIndexToIndex(movingIndex, destinationIndex); this._updateIndicesAfterIndex(movingIndex); - that.option('selectedItems', that._getItemsByKeys(that._selection.getSelectedItemKeys(), that._selection.getSelectedItems())); + this.option('selectedItems', this._getItemsByKeys(this._selection.getSelectedItemKeys(), this._selection.getSelectedItems())); if (changingOption === 'items') { - that._simulateOptionChange(changingOption); + this._simulateOptionChange(changingOption); } - that._itemEventHandler($movingItem, 'onItemReordered', { + this._itemEventHandler($movingItem, 'onItemReordered', { fromIndex: strategy.getIndex(movingIndex), toIndex: strategy.getIndex(destinationIndex), }, { excludeValidators: ['disabled', 'readOnly'], }); }); - }, -}); + } +} export default CollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.live_update.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.live_update.ts index db85a0ae025d..4fe1ff2deccf 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.live_update.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.live_update.ts @@ -3,43 +3,57 @@ import { keysEqual } from '@js/common/data/utils'; import domAdapter from '@js/core/dom_adapter'; import $ from '@js/core/renderer'; import { findChanges } from '@js/core/utils/array_compare'; -import { noop } from '@js/core/utils/common'; import { when } from '@js/core/utils/deferred'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; - -import CollectionWidget from './m_collection_widget.async'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { OptionChanged } from '@ts/core/widget/types'; +import CollectionWidgetAsync from '@ts/ui/collection/m_collection_widget.async'; +import type { CollectionWidgetEditProperties } from '@ts/ui/collection/m_collection_widget.edit'; const PRIVATE_KEY_FIELD = '__dx_key__'; -export default CollectionWidget.inherit({ - _getDefaultOptions() { - return extend(this.callBase(), { +class CollectionWidgetLiveUpdate< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TProperties extends CollectionWidgetEditProperties, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends CollectionWidgetAsync { + _correctionIndex!: number; + + _itemsCache!: TItem[]; + + _getDefaultOptions(): TProperties { + return { + ...super._getDefaultOptions(), repaintChangesOnly: false, - }); - }, + }; + } _customizeStoreLoadOptions(e) { + // @ts-expect-error ts-error const dataController = this._dataController; - + // @ts-expect-error ts-error if (dataController.getDataSource() && !this._dataController.isLoaded()) { this._correctionIndex = 0; } if (this._correctionIndex && e.storeLoadOptions) { e.storeLoadOptions.skip += this._correctionIndex; } - }, + } - reload() { + reload(): void { this._correctionIndex = 0; - }, + } - _init() { - this.callBase(); + _init(): void { + super._init(); this._refreshItemsCache(); this._correctionIndex = 0; this._subscribeLoadOptionsCustomization(true); - }, + } _findItemElementByKey(key) { let result = $(); @@ -54,16 +68,16 @@ export default CollectionWidget.inherit({ } }); return result; - }, + } _dataSourceChangedHandler(newItems, e) { if (e?.changes) { this._modifyByChanges(e.changes); } else { - this.callBase(newItems, e); + super._dataSourceChangedHandler(newItems, e); this._refreshItemsCache(); } - }, + } _isItemEquals(item1, item2) { if (item1 && item1[PRIVATE_KEY_FIELD]) { @@ -75,11 +89,11 @@ export default CollectionWidget.inherit({ } catch (e) { return item1 === item2; } - }, + } _isItemStrictEquals(item1, item2) { return this._isItemEquals(item1, item2); - }, + } _shouldAddNewGroup(changes, items) { let result = false; @@ -102,7 +116,7 @@ export default CollectionWidget.inherit({ } return result; - }, + } _partialRefresh() { if (this.option('repaintChangesOnly')) { @@ -121,14 +135,15 @@ export default CollectionWidget.inherit({ this._refreshItemsCache(); } return false; - }, + } - _refreshItemsCache() { + _refreshItemsCache(): void { if (this.option('repaintChangesOnly')) { const items = this._editStrategy.itemsGetter(); try { this._itemsCache = extend(true, [], items); if (!this.key()) { + // @ts-expect-error this._itemsCache = this._itemsCache.map((itemCache, index) => ({ [PRIVATE_KEY_FIELD]: items[index], data: itemCache, @@ -138,14 +153,14 @@ export default CollectionWidget.inherit({ this._itemsCache = extend([], items); } } - }, + } - _dispose() { + _dispose(): void { this._subscribeLoadOptionsCustomization(false); - this.callBase(); - }, + super._dispose(); + } - _updateByChange(keyInfo, items, change, isPartialRefresh) { + _updateByChange(keyInfo, items, change, isPartialRefresh): void { if (isPartialRefresh) { this._renderItem(change.index, change.data, null, this._findItemElementByKey(change.key)); } else { @@ -157,9 +172,9 @@ export default CollectionWidget.inherit({ }); } } - }, + } - _insertByChange(keyInfo, items, change, isPartialRefresh) { + _insertByChange(keyInfo, items, change, isPartialRefresh): void { // @ts-expect-error when(isPartialRefresh || insert(keyInfo, items, change.data, change.index)).done(() => { this._beforeItemElementInserted(change); @@ -169,37 +184,41 @@ export default CollectionWidget.inherit({ this._afterItemElementInserted(); this._correctionIndex++; }); - }, - - _updateSelectionAfterRemoveByChange(removeIndex) { - const selectedIndex = this.option('selectedIndex'); + } + _updateSelectionAfterRemoveByChange(removeIndex): void { + const { selectedIndex, selectedItems } = this.option(); + // @ts-expect-error if (selectedIndex > removeIndex) { + // @ts-expect-error this.option('selectedIndex', selectedIndex - 1); - } else if (selectedIndex === removeIndex && this.option('selectedItems').length === 1) { + // @ts-expect-error + } else if (selectedIndex === removeIndex && selectedItems.length === 1) { this.option('selectedItems', []); } else { this._normalizeSelectedItems(); } - }, + } - _beforeItemElementInserted(change) { - const selectedIndex = this.option('selectedIndex'); + _beforeItemElementInserted(change): void { + const { selectedIndex } = this.option(); + // @ts-expect-error if (change.index <= selectedIndex) { + // @ts-expect-error this.option('selectedIndex', selectedIndex + 1); } - }, + } - _afterItemElementInserted: noop, + _afterItemElementInserted(): void {} - _removeByChange(keyInfo, items, change, isPartialRefresh) { + _removeByChange(keyInfo, items, change, isPartialRefresh): void { const index = isPartialRefresh ? change.index : indexByKey(keyInfo, items, change.key); const removedItem = isPartialRefresh ? change.oldItem : items[index]; if (removedItem) { const $removedItemElement = this._findItemElementByKey(change.key); const deletedActionArgs = this._extendActionArgs($removedItemElement); - + // @ts-expect-error this._waitDeletingPrepare($removedItemElement).done(() => { if (isPartialRefresh) { this._updateIndicesAfterIndex(index - 1); @@ -213,11 +232,12 @@ export default CollectionWidget.inherit({ this._correctionIndex--; } - }, + } - _modifyByChanges(changes, isPartialRefresh) { + _modifyByChanges(changes, isPartialRefresh?): void { const items = this._editStrategy.itemsGetter(); const keyInfo = { key: this.key.bind(this), keyOf: this.keyOf.bind(this) }; + // @ts-expect-error const dataController = this._dataController; const paginate = dataController.paginate(); const group = dataController.group(); @@ -230,32 +250,36 @@ export default CollectionWidget.inherit({ this._renderedItemsCount = items.length; this._refreshItemsCache(); this._fireContentReadyAction(); - }, + } _appendItemToContainer($container, $itemFrame, index) { const nextSiblingElement = $container.children(this._itemSelector()).get(index); domAdapter.insertElement($container.get(0), $itemFrame.get(0), nextSiblingElement); - }, + } _subscribeLoadOptionsCustomization(enable: boolean): void { + // @ts-expect-error ts-error if (!this._dataController) { return; } if (enable) { this._correctionIndex = 0; + // @ts-expect-error ts-error this._dataController.on('customizeStoreLoadOptions', this._customizeStoreLoadOptions.bind(this)); } else { + // @ts-expect-error ts-error this._dataController.off('customizeStoreLoadOptions', this._customizeStoreLoadOptions.bind(this)); } - }, + } - _optionChanged(args) { + _optionChanged(args: OptionChanged): void { switch (args.name) { case 'items': { + // @ts-expect-error excess argument const isItemsUpdated = this._partialRefresh(args.value); if (!isItemsUpdated) { - this.callBase(args); + super._optionChanged(args); } break; } @@ -265,13 +289,15 @@ export default CollectionWidget.inherit({ } this._subscribeLoadOptionsCustomization(false); - this.callBase(args); + super._optionChanged(args); this._subscribeLoadOptionsCustomization(true); break; case 'repaintChangesOnly': break; default: - this.callBase(args); + super._optionChanged(args); } - }, -}); + } +} + +export default CollectionWidgetLiveUpdate; diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts index a7568ab671a9..9e1005a02831 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts @@ -76,8 +76,6 @@ class ContextMenu extends MenuBase { _overlayContentId?: string; - _actions?: any; - _showContextMenuEventHandler?: (event: unknown) => any; getShowEvent(showEventOption: { @@ -230,6 +228,7 @@ class ContextMenu extends MenuBase { $newTarget = $activeItemHighlighted ? this._prevItem($items) : $oldTarget; this._setFocusedElement($newTarget); if ($oldTarget.is($items.first())) { + // @ts-expect-error this._actions.onLeftFirstItem($oldTarget); } break; @@ -237,6 +236,7 @@ class ContextMenu extends MenuBase { $newTarget = $activeItemHighlighted ? this._nextItem($items) : $oldTarget; this._setFocusedElement($newTarget); if ($oldTarget.is($items.last())) { + // @ts-expect-error this._actions.onLeftLastItem($oldTarget); } break; @@ -313,11 +313,11 @@ class ContextMenu extends MenuBase { this._hideSubmenu($curItem.closest(`.${DX_SUBMENU_CLASS}`)); return $parentItem; } - + // @ts-expect-error this._actions.onCloseRootSubmenu($curItem); } - _expandSubmenuHandler($items, location) { + _expandSubmenuHandler($items, location): dxElementWrapper | undefined { const $curItem = this._getActiveItem(true); const itemData = this._getItemData($curItem); const node = this._dataAdapter.getNodeByItem(itemData); @@ -332,7 +332,7 @@ class ContextMenu extends MenuBase { return this._nextItem(this._getItemsByLocation(location)); } - + // @ts-expect-error this._actions.onExpandLastSubmenu($curItem); return undefined; } @@ -480,7 +480,7 @@ class ContextMenu extends MenuBase { }, { validatingTargetName: 'target' }); const handler = (e) => contextMenuAction({ event: e, target: $(e.currentTarget) }); - // @ts-expect-error + contextMenuAction = this._createAction(contextMenuAction); // @ts-expect-error if (isRenderer(target) || target.nodeType || isWindow(target)) { diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.edit.strategy.ts b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.edit.strategy.ts index 248c6a0aa771..c46f4dc54f4a 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.edit.strategy.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.edit.strategy.ts @@ -2,8 +2,9 @@ import $ from '@js/core/renderer'; import { map } from '@js/core/utils/iterator'; import type { Item } from '@js/ui/context_menu'; import PlainEditStrategy from '@ts/ui/collection/m_collection_widget.edit.strategy.plain'; +import type MenuBase from '@ts/ui/context_menu/m_menu_base'; -class MenuBaseEditStrategy extends PlainEditStrategy { +class MenuBaseEditStrategy extends PlainEditStrategy { _getPlainItems(): Item { return map(this._collectionWidget.option('items'), function getMenuItems(item) { return item.items ? [item].concat(map(item.items, getMenuItems)) : item; diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts index 97f36ada33a3..31f00eb0cb31 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts @@ -9,9 +9,9 @@ import { isDefined, isObject, isPlainObject } from '@js/core/utils/type'; import type { dxMenuBaseOptions } from '@js/ui/context_menu/ui.menu_base'; import type { Item, SubmenuShowMode } from '@js/ui/menu'; import { render } from '@js/ui/widget/utils.ink_ripple'; -import HierarchicalCollectionWidget from '@ts/ui/collection/hierarchical'; import MenuItem from '@ts/ui/collection/m_item'; import MenuBaseEditStrategy from '@ts/ui/context_menu/m_menu_base.edit.strategy'; +import HierarchicalCollectionWidget from '@ts/ui/hierarchical_collection/m_hierarchical_collection_widget'; const DX_MENU_CLASS = 'dx-menu'; const DX_MENU_NO_ICONS_CLASS = `${DX_MENU_CLASS}-no-icons`; @@ -42,8 +42,6 @@ export type Properties = dxMenuBaseOptions; class MenuBase extends HierarchicalCollectionWidget { static ItemClass = MenuItem; - _editStrategy?: MenuBaseEditStrategy; - hasIcons?: boolean; _showSubmenusTimeout?: ReturnType; @@ -166,6 +164,7 @@ class MenuBase extends HierarchicalCollectionWidget { if (url) { $container.html(html); const link = this._getLinkContainer( + // @ts-expect-error this._getIconContainer(itemData), this._getTextContainer(itemData), itemData, @@ -296,7 +295,7 @@ class MenuBase extends HierarchicalCollectionWidget { _initEditStrategy() { const Strategy = MenuBaseEditStrategy; - // @ts-expect-error dxClass inheritance issue + this._editStrategy = new Strategy(this); } @@ -445,13 +444,12 @@ class MenuBase extends HierarchicalCollectionWidget { .addClass(DX_MENU_ITEM_WRAPPER_CLASS); } - // @ts-expect-error _renderItem( index: number, - node: any, + node: Item, $nodeContainer: dxElementWrapper, $nodeElement?: dxElementWrapper, - ): void { + ): dxElementWrapper { const { items = [] } = this.option(); const $node = $nodeElement ?? this._createDOMElement($nodeContainer); @@ -469,6 +467,8 @@ class MenuBase extends HierarchicalCollectionWidget { $itemFrame.attr('tabIndex', -1); if (this._hasSubmenu(node)) this.setAria('haspopup', 'true', $itemFrame); + + return $itemFrame; } _renderItemFrame( @@ -550,7 +550,6 @@ class MenuBase extends HierarchicalCollectionWidget { _itemClickHandler(e) { if (e._skipHandling) return; - // @ts-expect-error const itemClickActionHandler = this._createAction(this._updateSubmenuVisibilityOnClick.bind(this)); this._itemDXEventHandler(e, 'onItemClick', {}, { beforeExecute: this._itemClick, diff --git a/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts b/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts index 9d894e8ddfb5..5c483cf5ea8c 100644 --- a/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts +++ b/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts @@ -1,4 +1,6 @@ import devices from '@js/core/devices'; +import type { DefaultOptionsRule } from '@js/core/options/utils'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { BindableTemplate } from '@js/core/templates/bindable_template'; import { noop } from '@js/core/utils/common'; @@ -7,17 +9,29 @@ import { extend } from '@js/core/utils/extend'; import { getImageContainer } from '@js/core/utils/icon'; import { each } from '@js/core/utils/iterator'; import { isFunction, isObject } from '@js/core/utils/type'; -import CollectionWidget from '@js/ui/collection/ui.collection_widget.async'; +import CollectionWidgetAsync from '@js/ui/collection/ui.collection_widget.async'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { OptionChanged } from '@ts/core/widget/types'; +import type { CollectionWidgetEditProperties } from '@ts/ui/collection/m_collection_widget.edit'; import HierarchicalDataAdapter from './m_data_adapter'; const DISABLED_STATE_CLASS = 'dx-state-disabled'; const ITEM_URL_CLASS = 'dx-item-url'; -const HierarchicalCollectionWidget = CollectionWidget.inherit({ - - _getDefaultOptions() { - return extend(this.callBase(), { +class HierarchicalCollectionWidget< +// eslint-disable-next-line @typescript-eslint/no-explicit-any +TProperties extends CollectionWidgetEditProperties, +// eslint-disable-next-line @typescript-eslint/no-explicit-any +TItem extends ItemLike = any, +// eslint-disable-next-line @typescript-eslint/no-explicit-any +TKey = any, +> extends CollectionWidgetAsync { + _dataAdapter?: any; + + _getDefaultOptions(): TProperties { + return { + ...super._getDefaultOptions(), keyExpr: 'id', displayExpr: 'text', selectedExpr: 'selected', @@ -26,34 +40,37 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ hoverStateEnabled: true, parentIdExpr: 'parentId', expandedExpr: 'expanded', - }); - }, + }; + } - _defaultOptionsRules() { - return this.callBase().concat([ + _defaultOptionsRules(): DefaultOptionsRule[] { + return super._defaultOptionsRules().concat([ { device() { return devices.real().deviceType === 'desktop' && !devices.isSimulator(); }, + // @ts-expect-error ts-error options: { focusStateEnabled: true, }, }, ]); - }, + } _init() { - this.callBase(); + super._init(); this._initAccessors(); this._initDataAdapter(); this._initDynamicTemplates(); - }, + } _initDataSource() { - this.callBase(); + // @ts-expect-error ts-error + super._initDataSource(); + // @ts-expect-error ts-error this._dataSource && this._dataSource.paginate(false); - }, + } _initDataAdapter() { const accessors = this._createDataAdapterAccessors(); @@ -67,11 +84,12 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ items: this.option('items'), }, this._getDataAdapterOptions()), ); - }, + } - _getDataAdapterOptions: noop, + _getDataAdapterOptions() {} - _getItemExtraPropNames: noop, + // @ts-expect-error + _getItemExtraPropNames(): string[] {} _initDynamicTemplates() { const fields = ['text', 'html', 'items', 'icon'].concat(this._getItemExtraPropNames()); @@ -79,19 +97,29 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ this._templateManager.addDefaultTemplates({ item: new BindableTemplate(this._addContent.bind(this), fields, this.option('integrationOptions.watchMethod'), { text: this._displayGetter, + // @ts-expect-error items: this._itemsGetter, }), }); - }, + } - _addContent($container, itemData) { + _addContent($container: dxElementWrapper, itemData: TItem): void { $container + // @ts-expect-error .html(itemData.html) + // @ts-expect-error .append(this._getIconContainer(itemData)) .append(this._getTextContainer(itemData)); - }, + } + + _getLinkContainer( + iconContainer: dxElementWrapper, + textContainer: dxElementWrapper, + itemData: TItem, + ): dxElementWrapper { + // @ts-expect-error + const { linkAttr, url } = itemData; - _getLinkContainer(iconContainer, textContainer, { linkAttr, url }) { const linkAttributes = isObject(linkAttr) ? linkAttr : {}; return $('') .addClass(ITEM_URL_CLASS) @@ -99,17 +127,18 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ .attr({ ...linkAttributes, href: url }) .append(iconContainer) .append(textContainer); - }, + } - _getIconContainer(itemData) { + _getIconContainer(itemData: TItem): dxElementWrapper | undefined | null { + // @ts-expect-error if (!itemData.icon) { return undefined; } - + // @ts-expect-error const $imageContainer = getImageContainer(itemData.icon); // @ts-expect-error if ($imageContainer.is('img')) { - const componentName = this.NAME.startsWith('dxPrivateComponent') + const componentName = this.NAME?.startsWith('dxPrivateComponent') ? '' : `${this.NAME} `; // @ts-expect-error @@ -117,39 +146,42 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ } return $imageContainer; - }, + } - _getTextContainer(itemData) { + _getTextContainer(itemData: TItem): dxElementWrapper { + // @ts-expect-error return $('').text(itemData.text); - }, + } - _initAccessors() { + _initAccessors(): void { const that = this; each(this._getAccessors(), (_, accessor) => { that._compileAccessor(accessor); }); this._compileDisplayGetter(); - }, + } _getAccessors() { return ['key', 'selected', 'items', 'disabled', 'parentId', 'expanded']; - }, + } - _getChildNodes(node) { + _getChildNodes(node: TItem): TItem[] { const that = this; const arr = []; + // @ts-expect-error each(node.internalFields.childrenKeys, (_, key) => { const childNode = that._dataAdapter.getNodeByKey(key); // @ts-expect-error arr.push(childNode); }); return arr; - }, + } - _hasChildren(node) { + _hasChildren(node: TItem): number | undefined { + // @ts-expect-error return node && node.internalFields.childrenKeys.length; - }, + } _compileAccessor(optionName) { const getter = `_${optionName}Getter`; @@ -165,10 +197,11 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ this[getter] = function (obj) { return obj[optionExpr()]; }; return; } - + // @ts-expect-error this[getter] = compileGetter(optionExpr); + // @ts-expect-error this[setter] = compileSetter(optionExpr); - }, + } _createDataAdapterAccessors() { const that = this; @@ -189,27 +222,34 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ accessors.getters.display = !this._displayGetter ? (itemData) => itemData.text : this._displayGetter; return accessors; - }, + } - _initMarkup() { - this.callBase(); + _initMarkup(): void { + super._initMarkup(); this._addWidgetClass(); - }, + } - _addWidgetClass() { + _addWidgetClass(): void { this._focusTarget().addClass(this._widgetClass()); - }, - - _widgetClass: noop, - - _renderItemFrame(index, itemData) { - const $itemFrame = this.callBase.apply(this, arguments); - + } + + // @ts-expect-error ts-error + _widgetClass(): string {} + + _renderItemFrame( + index: number, + itemData: TItem, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + $itemContainer: dxElementWrapper, + ): dxElementWrapper { + // @ts-expect-error ts-error + const $itemFrame = super._renderItemFrame.apply(this, arguments); + // @ts-expect-error ts-error $itemFrame.toggleClass(DISABLED_STATE_CLASS, !!this._disabledGetter(itemData)); return $itemFrame; - }, + } - _optionChanged(args) { + _optionChanged(args: OptionChanged): void { switch (args.name) { case 'displayExpr': case 'keyExpr': @@ -228,12 +268,12 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({ break; case 'items': this._initDataAdapter(); - this.callBase(args); + super._optionChanged(args); break; default: - this.callBase(args); + super._optionChanged(args); } - }, -}); + } +} export default HierarchicalCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/list/m_list.base.ts b/packages/devextreme/js/__internal/ui/list/m_list.base.ts index 048ce80b73c2..4940c64b8c33 100644 --- a/packages/devextreme/js/__internal/ui/list/m_list.base.ts +++ b/packages/devextreme/js/__internal/ui/list/m_list.base.ts @@ -56,7 +56,7 @@ const groupItemsGetter = compileGetter('items'); // eslint-disable-next-line @typescript-eslint/naming-convention let _scrollView; - +// @ts-expect-error export const ListBase = CollectionWidget.inherit({ _supportedKeys() { const that = this; diff --git a/packages/devextreme/js/__internal/ui/list/m_list.edit.strategy.grouped.ts b/packages/devextreme/js/__internal/ui/list/m_list.edit.strategy.grouped.ts index 9dc94180c61f..840ad8fe3a1d 100644 --- a/packages/devextreme/js/__internal/ui/list/m_list.edit.strategy.grouped.ts +++ b/packages/devextreme/js/__internal/ui/list/m_list.edit.strategy.grouped.ts @@ -1,5 +1,6 @@ import query from '@js/common/data/query'; import storeHelper from '@js/common/data/store_helper'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { each } from '@js/core/utils/iterator'; import { isNumeric } from '@js/core/utils/type'; @@ -11,26 +12,23 @@ const LIST_GROUP_CLASS = 'dx-list-group'; const SELECTION_SHIFT = 20; const SELECTION_MASK = (1 << SELECTION_SHIFT) - 1; -const combineIndex = function (indices) { - return (indices.group << SELECTION_SHIFT) + indices.item; -}; - -const splitIndex = function (combinedIndex) { - return { - group: combinedIndex >> SELECTION_SHIFT, - item: combinedIndex & SELECTION_MASK, - }; -}; - -const GroupedEditStrategy = EditStrategy.inherit({ +const combineIndex = ( + indices: { group: number; item: number }, +): number => (indices.group << SELECTION_SHIFT) + indices.item; +const splitIndex = (combinedIndex: number): { group: number; item: number } => ({ + group: combinedIndex >> SELECTION_SHIFT, + item: combinedIndex & SELECTION_MASK, +}); +class GroupedEditStrategy extends EditStrategy { _groupElements() { return this._collectionWidget._itemContainer().find(`.${LIST_GROUP_CLASS}`); - }, + } - _groupItemElements($group) { + // eslint-disable-next-line class-methods-use-this + _groupItemElements($group: dxElementWrapper): dxElementWrapper { return $group.find(`.${LIST_ITEM_CLASS}`); - }, + } getIndexByItemData(itemData) { const groups = this._collectionWidget.option('items'); @@ -65,7 +63,7 @@ const GroupedEditStrategy = EditStrategy.inherit({ }); return index; - }, + } getItemDataByIndex(index) { const items = this._collectionWidget.option('items'); @@ -73,13 +71,12 @@ const GroupedEditStrategy = EditStrategy.inherit({ if (isNumeric(index)) { return this.itemsGetter()[index]; } - return (index && items[index.group] && items[index.group].items[index.item]) || null; - }, + } itemsGetter() { let resultItems = []; - const items = this._collectionWidget.option('items'); + const { items } = this._collectionWidget.option(); for (let i = 0; i < items.length; i++) { if (items[i] && items[i].items) { @@ -90,14 +87,14 @@ const GroupedEditStrategy = EditStrategy.inherit({ } } return resultItems; - }, + } - deleteItemAtIndex(index) { + deleteItemAtIndex(index: number): void { const indices = splitIndex(index); const itemGroup = this._collectionWidget.option('items')[indices.group].items; itemGroup.splice(indices.item, 1); - }, + } getKeysByItems(items) { let plainItems = []; @@ -119,8 +116,9 @@ const GroupedEditStrategy = EditStrategy.inherit({ } return result; - }, + } + // @ts-expect-error getIndexByKey(key, items) { const groups = items || this._collectionWidget.option('items'); let index = -1; @@ -147,9 +145,10 @@ const GroupedEditStrategy = EditStrategy.inherit({ }); return index; - }, + } _getGroups(items) { + // @ts-expect-error const dataController = this._collectionWidget._dataController; const group = dataController.group(); @@ -159,7 +158,7 @@ const GroupedEditStrategy = EditStrategy.inherit({ } return this._collectionWidget.option('items'); - }, + } getItemsByKeys(keys, items) { const result = []; @@ -168,12 +167,14 @@ const GroupedEditStrategy = EditStrategy.inherit({ const getItemMeta = (key) => { const index = this.getIndexByKey(key, groups); + // @ts-expect-error const group = index && groups[index.group]; if (!group) return; return { groupKey: group.key, + // @ts-expect-error item: group.items[index.item], }; }; @@ -198,14 +199,13 @@ const GroupedEditStrategy = EditStrategy.inherit({ }); return result; - }, + } moveItemAtIndexToIndex(movingIndex, destinationIndex) { const items = this._collectionWidget.option('items'); const movingIndices = splitIndex(movingIndex); const destinationIndices = splitIndex(destinationIndex); - const movingItemGroup = items[movingIndices.group].items; const destinationItemGroup = items[destinationIndices.group].items; @@ -213,13 +213,16 @@ const GroupedEditStrategy = EditStrategy.inherit({ movingItemGroup.splice(movingIndices.item, 1); destinationItemGroup.splice(destinationIndices.item, 0, movedItemData); - }, + } - _isItemIndex(index) { + // @ts-expect-error + // eslint-disable-next-line class-methods-use-this + _isItemIndex(index: { group: number; item: number }): boolean { return index && isNumeric(index.group) && isNumeric(index.item); - }, + } - _getNormalizedItemIndex(itemElement) { + // @ts-expect-error + _getNormalizedItemIndex(itemElement: Element): number | { group: number; index: number } { const $item = $(itemElement); const $group = $item.closest(`.${LIST_GROUP_CLASS}`); @@ -231,27 +234,28 @@ const GroupedEditStrategy = EditStrategy.inherit({ group: this._groupElements().index($group), item: this._groupItemElements($group).index($item), }); - }, + } - _normalizeItemIndex(index) { + // eslint-disable-next-line class-methods-use-this + _normalizeItemIndex(index: { group: number; item: number }): number { return combineIndex(index); - }, + } - _denormalizeItemIndex(index) { + // eslint-disable-next-line class-methods-use-this + _denormalizeItemIndex(index: number): { group: number; item: number } { return splitIndex(index); - }, + } - _getItemByNormalizedIndex(index) { + _getItemByNormalizedIndex(index: number): dxElementWrapper { const indices = splitIndex(index); const $group = this._groupElements().eq(indices.group); return this._groupItemElements($group).eq(indices.item); - }, + } - _itemsFromSameParent(firstIndex, secondIndex) { + _itemsFromSameParent(firstIndex, secondIndex): boolean { return splitIndex(firstIndex).group === splitIndex(secondIndex).group; - }, - -}); + } +} export default GroupedEditStrategy; diff --git a/packages/devextreme/js/__internal/ui/m_accordion.ts b/packages/devextreme/js/__internal/ui/m_accordion.ts index 63e6a649639f..a36c10748411 100644 --- a/packages/devextreme/js/__internal/ui/m_accordion.ts +++ b/packages/devextreme/js/__internal/ui/m_accordion.ts @@ -28,7 +28,7 @@ const ACCORDION_ITEM_BODY_CLASS = 'dx-accordion-item-body'; const ACCORDION_ITEM_TITLE_CAPTION_CLASS = 'dx-accordion-item-title-caption'; const ACCORDION_ITEM_DATA_KEY = 'dxAccordionItemData'; - +// @ts-expect-error const Accordion = CollectionWidget.inherit({ _getDefaultOptions() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/m_action_sheet.ts b/packages/devextreme/js/__internal/ui/m_action_sheet.ts index 754c9e6d72eb..ec49bc714220 100644 --- a/packages/devextreme/js/__internal/ui/m_action_sheet.ts +++ b/packages/devextreme/js/__internal/ui/m_action_sheet.ts @@ -22,7 +22,7 @@ const ACTION_SHEET_ITEM_CLASS = 'dx-actionsheet-item'; const ACTION_SHEET_ITEM_DATA_KEY = 'dxActionSheetItemData'; const ACTION_SHEET_WITHOUT_TITLE_CLASS = 'dx-actionsheet-without-title'; const ACTION_SHEET_BUTTON_DEFAULT_STYLING_MODE = 'outlined'; - +// @ts-expect-error const ActionSheet = CollectionWidget.inherit({ _getDefaultOptions() { diff --git a/packages/devextreme/js/__internal/ui/m_box.ts b/packages/devextreme/js/__internal/ui/m_box.ts index 5434c68ca401..4e88385a5cf6 100644 --- a/packages/devextreme/js/__internal/ui/m_box.ts +++ b/packages/devextreme/js/__internal/ui/m_box.ts @@ -1,5 +1,6 @@ // eslint-disable-next-line max-classes-per-file import registerComponent from '@js/core/component_registrator'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { extend } from '@js/core/utils/extend'; import { dasherize } from '@js/core/utils/inflector'; @@ -10,7 +11,7 @@ import { import { isDefined } from '@js/core/utils/type'; import { hasWindow } from '@js/core/utils/window'; import CollectionWidget from '@js/ui//collection/ui.collection_widget.edit'; -import type { Item } from '@js/ui/box'; +import type { Item, Properties } from '@js/ui/box'; import type { ItemExtraOption } from '@ts/ui/collection/m_item'; import CollectionWidgetItem from '@ts/ui/collection/m_item'; @@ -159,7 +160,7 @@ class LayoutStrategy { } } -class Box extends CollectionWidget { +class Box extends CollectionWidget { private _layout: any; private _queue: any; @@ -191,31 +192,27 @@ class Box extends CollectionWidget { return BOX_ITEM_DATA_KEY; } - _itemElements() { - // @ts-expect-error + _itemElements(): dxElementWrapper { return this._itemContainer().children(this._itemSelector()); } - _init() { + _init(): void { super._init(); - // @ts-expect-error + this.$element().addClass(BOX_FLEX_CLASS); this._initLayout(); this._initBoxQueue(); } - _initLayout() { - // @ts-expect-error + _initLayout(): void { this._layout = new LayoutStrategy(this.$element(), this.option.bind(this)); } - _initBoxQueue() { - // @ts-expect-error + _initBoxQueue(): void { this._queue = this.option('_queue') || []; } - _queueIsNotEmpty() { - // @ts-expect-error + _queueIsNotEmpty(): boolean { return this.option('_queue') ? false : !!this._queue.length; } @@ -227,8 +224,7 @@ class Box extends CollectionWidget { return this._queue.shift(); } - _initMarkup() { - // @ts-expect-error + _initMarkup(): void { this.$element().addClass(BOX_CLASS); this._layout.renderBox(); super._initMarkup(); @@ -251,20 +247,13 @@ class Box extends CollectionWidget { while (this._queueIsNotEmpty()) { const item = this._shiftItemFromQueue(); - // @ts-expect-error this._createComponent(item.$item, Box, extend({ - // @ts-expect-error itemTemplate: this.option('itemTemplate'), - // @ts-expect-error itemHoldTimeout: this.option('itemHoldTimeout'), - // @ts-expect-error onItemHold: this.option('onItemHold'), - // @ts-expect-error onItemClick: this.option('onItemClick'), - // @ts-expect-error onItemContextMenu: this.option('onItemContextMenu'), - // @ts-expect-error onItemRendered: this.option('onItemRendered'), _queue: this._queue, }, item.config)); @@ -276,7 +265,6 @@ class Box extends CollectionWidget { _renderItemContent(args) { const $itemNode = args.itemData && args.itemData.node; if ($itemNode) { - // @ts-expect-error return this._renderItemContentByNode(args, $itemNode); } @@ -299,13 +287,18 @@ class Box extends CollectionWidget { return super._createItemByTemplate(itemTemplate, args); } - _itemOptionChanged(item, property, value, oldValue) { + _itemOptionChanged( + item: Item, + property: string, + value: unknown, + prevValue, + ): void { if (property === 'visible') { // @ts-expect-error this._onItemStateChanged({ name: property, state: value, - oldState: oldValue !== false, + oldState: prevValue !== false, }); } super._itemOptionChanged(item, property, value); @@ -315,7 +308,6 @@ class Box extends CollectionWidget { switch (args.name) { case '_queue': case 'direction': - // @ts-expect-error this._invalidate(); break; case 'align': @@ -344,7 +336,6 @@ class Box extends CollectionWidget { // @ts-expect-error Box.ItemClass = BoxItem; -// @ts-expect-error registerComponent('dxBox', Box); export default Box; diff --git a/packages/devextreme/js/__internal/ui/m_button_group.ts b/packages/devextreme/js/__internal/ui/m_button_group.ts index 7b0362020783..f6846c6ae3e4 100644 --- a/packages/devextreme/js/__internal/ui/m_button_group.ts +++ b/packages/devextreme/js/__internal/ui/m_button_group.ts @@ -20,7 +20,7 @@ const BUTTON_GROUP_STYLING_MODE_CLASS = { outlined: 'dx-buttongroup-mode-outlined', text: 'dx-buttongroup-mode-text', }; - +// @ts-expect-error const ButtonCollection = CollectionWidget.inherit({ _initTemplates() { this.callBase(); diff --git a/packages/devextreme/js/__internal/ui/m_gallery.ts b/packages/devextreme/js/__internal/ui/m_gallery.ts index bebb9d2df665..d33d954277dc 100644 --- a/packages/devextreme/js/__internal/ui/m_gallery.ts +++ b/packages/devextreme/js/__internal/ui/m_gallery.ts @@ -89,7 +89,7 @@ const GalleryNavButton = Widget.inherit({ } }, }); - +// @ts-expect-error const Gallery = CollectionWidget.inherit({ _wasAnyItemTemplateRendered: false, diff --git a/packages/devextreme/js/__internal/ui/m_multi_view.ts b/packages/devextreme/js/__internal/ui/m_multi_view.ts index d8014ddce78d..1cf7158d460c 100644 --- a/packages/devextreme/js/__internal/ui/m_multi_view.ts +++ b/packages/devextreme/js/__internal/ui/m_multi_view.ts @@ -28,7 +28,7 @@ const MULTIVIEW_ANIMATION_DURATION = 200; const toNumber = (value) => +value; const position = ($element) => locate($element).left; - +// @ts-expect-error const MultiView = CollectionWidget.inherit({ _supportedKeys() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/m_responsive_box.ts b/packages/devextreme/js/__internal/ui/m_responsive_box.ts index 8c8e2f3a4810..5fe72686fed6 100644 --- a/packages/devextreme/js/__internal/ui/m_responsive_box.ts +++ b/packages/devextreme/js/__internal/ui/m_responsive_box.ts @@ -18,7 +18,7 @@ const BOX_ITEM_CLASS = 'dx-box-item'; const BOX_ITEM_DATA_KEY = 'dxBoxItemData'; const HD_SCREEN_WIDTH = 1920; - +// @ts-expect-error const ResponsiveBox = CollectionWidget.inherit({ _getDefaultOptions() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/m_tile_view.ts b/packages/devextreme/js/__internal/ui/m_tile_view.ts index f57753a1e769..8965ecd51401 100644 --- a/packages/devextreme/js/__internal/ui/m_tile_view.ts +++ b/packages/devextreme/js/__internal/ui/m_tile_view.ts @@ -49,7 +49,7 @@ const CONFIGS = { crossPosition: 'left', }, }; - +// @ts-expect-error const TileView = CollectionWidget.inherit({ _getDefaultOptions() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/m_validation_summary.ts b/packages/devextreme/js/__internal/ui/m_validation_summary.ts index d3c7ea85d50c..8f14e126dcc0 100644 --- a/packages/devextreme/js/__internal/ui/m_validation_summary.ts +++ b/packages/devextreme/js/__internal/ui/m_validation_summary.ts @@ -11,7 +11,7 @@ import ValidationEngine from './m_validation_engine'; const VALIDATION_SUMMARY_CLASS = 'dx-validationsummary'; const ITEM_CLASS = `${VALIDATION_SUMMARY_CLASS}-item`; const ITEM_DATA_KEY = `${VALIDATION_SUMMARY_CLASS}-item-data`; - +// @ts-expect-error const ValidationSummary = CollectionWidget.inherit({ _getDefaultOptions() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/menu/m_menu.ts b/packages/devextreme/js/__internal/ui/menu/m_menu.ts index 57e61d6be877..0fe22ff9b122 100644 --- a/packages/devextreme/js/__internal/ui/menu/m_menu.ts +++ b/packages/devextreme/js/__internal/ui/menu/m_menu.ts @@ -78,8 +78,6 @@ class Menu extends MenuBase { _hoveredRootItem?: dxElementWrapper; - _actions?: any; - _showSubmenuTimer?: any; _hideSubmenuTimer?: any; @@ -948,6 +946,7 @@ class Menu extends MenuBase { return submenu; } itemData = itemData ?? this._getItemData($itemElement); + const node = this._dataAdapter.getNodeByItem(itemData); // @ts-expect-error return this._hasChildren(node) && this._renderSubmenuItems(node, $itemElement); diff --git a/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts b/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts index d2fde9b38c2a..d52a687b7a34 100644 --- a/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts +++ b/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts @@ -4,7 +4,7 @@ import { deferRender } from '@js/core/utils/common'; import { extend } from '@js/core/utils/extend'; import DataExpressionMixin from '@js/ui/editor/ui.data_expression'; import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; -import CollectionWidget from '@ts/ui/collection/edit'; +import CollectionWidget from '@ts/ui/collection/m_collection_widget.edit'; const RADIO_BUTTON_CHECKED_CLASS = 'dx-radiobutton-checked'; const RADIO_BUTTON_ICON_CHECKED_CLASS = 'dx-radiobutton-icon-checked'; diff --git a/packages/devextreme/js/__internal/ui/selection/m_selection.ts b/packages/devextreme/js/__internal/ui/selection/m_selection.ts index e8fedc7281d8..a5f7e7fd32ea 100644 --- a/packages/devextreme/js/__internal/ui/selection/m_selection.ts +++ b/packages/devextreme/js/__internal/ui/selection/m_selection.ts @@ -79,7 +79,7 @@ export default class Selection { filterIsChanged && this.onSelectionChanged(); } - setSelection(keys, updatedKeys) { + setSelection(keys, updatedKeys?) { return this.selectedItemKeys(keys, false, false, false, updatedKeys); } @@ -221,7 +221,7 @@ export default class Selection { return this._selectionStrategy.isItemDataSelected(data, { checkPending: true }); } - isItemSelected(arg, options?: any) { + isItemSelected(arg, options?: any): boolean { return this._selectionStrategy.isItemKeySelected(arg, options); } diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter.ts b/packages/devextreme/js/__internal/ui/splitter/splitter.ts index f70ee6dedec0..bc48a2dfde86 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter.ts @@ -26,9 +26,10 @@ import type { ResizeStartEvent, } from '@js/ui/splitter'; import type { OptionChanged } from '@ts/core/widget/types'; -import type { CollectionWidgetBaseProperties, ItemRenderInfo } from '@ts/ui/collection/collection_widget.base'; -import CollectionWidget from '@ts/ui/collection/live_update'; +import type { ItemRenderInfo, PostprocessRenderItemInfo } from '@ts/ui/collection/collection_widget.base'; +import CollectionWidgetLiveUpdate from '@ts/ui/collection/m_collection_widget.live_update'; +import type { CollectionWidgetEditProperties } from '../collection/m_collection_widget.edit'; import type ResizeHandle from './resize_handle'; import type { ResizeHandleOptions } from './resize_handle'; import { RESIZE_HANDLE_CLASS } from './resize_handle'; @@ -97,8 +98,8 @@ export interface Properties< TKey = any, > extends PublicProperties, Omit< - CollectionWidgetBaseProperties, - keyof PublicProperties & keyof CollectionWidgetBaseProperties + CollectionWidgetEditProperties, + keyof PublicProperties & keyof CollectionWidgetEditProperties > { _renderQueue?: RenderQueueItem[]; } @@ -108,7 +109,7 @@ interface PaneCache { direction: CollapseExpandDirection; } -class Splitter extends CollectionWidget { +class Splitter extends CollectionWidgetLiveUpdate { static ItemClass = SplitterItem; private _renderQueue: RenderQueueItem[] = []; @@ -386,7 +387,6 @@ class Splitter extends CollectionWidget { } _getItemDataByIndex(index: number): Item { - // @ts-expect-error badly typed base class // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._editStrategy.getItemDataByIndex(index); } @@ -618,12 +618,7 @@ class Splitter extends CollectionWidget { return super._createItemByTemplate(itemTemplate, args); } - _postprocessRenderItem(args: { - itemElement: dxElementWrapper; - itemContent: dxElementWrapper; - itemData: Item; - itemIndex: number; - }): void { + _postprocessRenderItem(args: PostprocessRenderItemInfo): void { const splitterConfig = args.itemData.splitter; if (!splitterConfig) { return; diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts b/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts index 0cab3f00541e..b5d9ecf06a5f 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts @@ -48,7 +48,6 @@ class SplitterItem extends CollectionWidgetItem { } getIndex(): number { - // @ts-expect-error // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._owner._getIndexByItemData(this._rawData); } diff --git a/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts b/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts index a384712cf9a3..4869438aa9f4 100644 --- a/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts +++ b/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts @@ -112,7 +112,7 @@ const STYLING_MODE = { primary: 'primary', secondary: 'secondary', }; - +// @ts-expect-error const Tabs = CollectionWidget.inherit({ _getDefaultOptions() { return extend(this.callBase(), { diff --git a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts index 3dde7eef7ae0..d9aa7c6c892a 100644 --- a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts +++ b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts @@ -15,8 +15,8 @@ import { } from '@js/ui/themes'; import type { Item, Properties } from '@js/ui/toolbar'; import type { OptionChanged } from '@ts/core/widget/types'; -import AsyncCollectionWidget from '@ts/ui/collection/async'; import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; +import CollectionWidgetAsync from '@ts/ui/collection/m_collection_widget.async'; import { TOOLBAR_CLASS } from './m_constants'; @@ -57,7 +57,7 @@ export interface ToolbarBaseProperties< compactMode: boolean; } -class ToolbarBase extends AsyncCollectionWidget { +class ToolbarBase extends CollectionWidgetAsync { _$toolbarItemsContainer?: any; _$beforeSection?: dxElementWrapper;