diff --git a/packages/devextreme/js/__internal/data/data_source/data_source.ts b/packages/devextreme/js/__internal/data/data_source/data_source.ts index 79350d094d78..72aae3df3fab 100644 --- a/packages/devextreme/js/__internal/data/data_source/data_source.ts +++ b/packages/devextreme/js/__internal/data/data_source/data_source.ts @@ -788,21 +788,3 @@ export class DataSource { return this; } } - -/* - * `Class.inherit()` defined prototype members as enumerable, and consumers still rely on - * that: the grid's DataSourceAdapter copies a data source's members with a `for…in` loop - * (see its "remove copying dataSource's members" TODO). ES6 class methods are not - * enumerable, so restore the descriptors a data source used to expose. - */ -Object.getOwnPropertyNames(DataSource.prototype).forEach((memberName) => { - if (memberName === 'constructor') { - return; - } - - const descriptor = Object.getOwnPropertyDescriptor(DataSource.prototype, memberName); - - if (descriptor) { - Object.defineProperty(DataSource.prototype, memberName, { ...descriptor, enumerable: true }); - } -}); diff --git a/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts b/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts index 3cbdec732579..4a8226c4538c 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/export/m_export.ts @@ -701,7 +701,7 @@ export class ExportController extends dataGridCore.ViewController { private needLoadItemsOnExportingSelectedItems(): boolean { return this.option('loadItemsOnExportingSelectedItems') - ?? this._dataController._dataSource.remoteOperations().filtering; + ?? (this._dataController._dataSource?.remoteOperations().filtering ?? false); } } diff --git a/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts b/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts index 95ad327d2018..3aa4315f72de 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/focus/m_focus.ts @@ -93,12 +93,14 @@ const data = (Base: DataControllerBase) => class FocusDataControllerExtender ext // @ts-expect-error const deferred = new Deferred(); const isGroupKey = Array.isArray(key); - const group = dataSource.group(); - if (isGroupKey) { + if (isGroupKey || !dataSource) { return deferred.resolve(-1).promise(); } + const group = dataSource.group(); + + // @ts-expect-error badly typed DataSourceAdapter if (!dataSource._grouping._updatePagingOptions) { this._calculateGlobalRowIndexByFlatData(key, null, true) .done(deferred.resolve) @@ -110,12 +112,14 @@ const data = (Base: DataControllerBase) => class FocusDataControllerExtender ext filter: this._concatWithCombinedFilter(filter), group, }).done((data) => { + // @ts-expect-error badly typed DataSourceAdapter const hasData = isDefined(data) && data.length > 0; if (this._dataSource !== dataSource || !hasData) { return deferred.resolve(-1).promise(); } + // @ts-expect-error badly typed DataSourceAdapter const groupPath = this._getGroupPath(data, group.length); this._expandGroupByPath(this, groupPath, 0).done(() => { diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts index 82d91ef7dcb8..916507cb79dc 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/extenders/grouping_data_controller.ts @@ -148,17 +148,19 @@ export const groupingDataControllerExtender = ( private collapseAll(groupIndex: number): void { const dataSource = this._dataSource; + // @ts-expect-error badly typed DataSourceAdapter if (dataSource?.collapseAll(groupIndex)) { - dataSource.pageIndex(0); - dataSource.reload(); + dataSource?.pageIndex(0); + dataSource?.reload(); } } private expandAll(groupIndex: number): void { const dataSource = this._dataSource; + // @ts-expect-error badly typed DataSourceAdapter if (dataSource?.expandAll(groupIndex)) { - dataSource.pageIndex(0); - dataSource.reload(); + dataSource?.pageIndex(0); + dataSource?.reload(); } } @@ -199,6 +201,7 @@ export const groupingDataControllerExtender = ( } private isRowExpanded(key: RowKey): boolean { + // @ts-expect-error badly typed DataSourceAdapter return !!this._dataSource?.isRowExpanded(key); } diff --git a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts index 456cded7a7f6..815fc4e1ed7e 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/grouping/m_grouping.ts @@ -58,13 +58,13 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class } } - protected totalItemsCount() { + public totalItemsCount() { const totalCount = super.totalItemsCount(); return totalCount > 0 && this._dataSource.group() && this._dataSource.requireTotalCount() ? totalCount + this._grouping.totalCountCorrection() : totalCount; } - protected itemsCount() { + public itemsCount() { return this._dataSource.group() ? this._grouping.itemsCount() || 0 : super.itemsCount.apply(this, arguments as any); } @@ -121,7 +121,7 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class return this._grouping.refresh.apply(this._grouping, arguments); } - protected changeRowExpand(path) { + public changeRowExpand(path) { const that = this; const dataSource = that._dataSource; @@ -183,7 +183,7 @@ const dataSourceAdapterExtender = (Base: ModuleType) => class return this._grouping.handleDataLoading(options); } - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { return this._grouping.handleDataLoaded(options, super.customizeLoadResultHandler.bind(this)); } diff --git a/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts b/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts index 7a3594a6b081..8cf597ad96f3 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts @@ -43,6 +43,7 @@ export const summaryDataControllerExtender = ( public getTotalSummaryValue(summaryItemName?: string | number | null): unknown { const summaryItemIndex = getSummaryItemIndex(this.option('summary.totalItems'), summaryItemName); + // @ts-expect-error badly typed DataSourceAdapter const aggregates = this._dataSource.totalAggregates(); if (aggregates.length && summaryItemIndex > -1) { @@ -293,6 +294,7 @@ export const summaryDataControllerExtender = ( this._footerItems = []; if (dataSource && summaryTotalItems?.length) { + // @ts-expect-error badly typed DataSourceAdapter const totalAggregates = dataSource.totalAggregates(); const summaryCells = this._getSummaryCells(summaryTotalItems, totalAggregates); diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts index 5771e049533a..4539569f7922 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts @@ -33,7 +33,6 @@ import type { CallbackFlags, DataChange, DataFilter, - DataSourceAdapterLike, GeneratedItem, ItemChange, ItemProcessingOptions, @@ -70,8 +69,7 @@ import { import { generateRowValues } from './utils/row_values'; export class DataController extends modules.Controller { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _dataSource?: any; + public _dataSource?: DataSourceAdapter | null; protected isSharedDataSource?: boolean; @@ -192,7 +190,8 @@ export class DataController extends modules.Controller { * @extended: virtual_scrolling */ protected _getPagingOptionValue(optionName: PagingOptionName): number { - return this._dataSource[optionName]() as number; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this._dataSource![optionName]() as number; } protected callbackNames(): string[] { @@ -336,9 +335,8 @@ export class DataController extends modules.Controller { return !this._isLoading; } - public getDataSource(): DataSource | null | undefined { - const adapter: DataSourceAdapterLike | null | undefined = this._dataSource; - return adapter ? adapter._dataSource : null; + public getDataSource(): DataSource | null { + return this._dataSource?._dataSource ?? null; } public getCombinedFilter(returnDataField?: boolean): DataFilter { @@ -422,6 +420,9 @@ export class DataController extends modules.Controller { private readonly customizeStoreLoadOptionsHandler = (e: LoadOperation): void => { const columnsController = this._columnsController; const dataSource = this._dataSource; + if (!dataSource) { + return; + } const { storeLoadOptions } = e; if (e.isCustomLoading && !storeLoadOptions.isLoadingAll) { @@ -730,7 +731,7 @@ export class DataController extends modules.Controller { dataSource.load().done((...args: unknown[]) => { this._isPaging = false; result.resolve(...args); - }).fail(result.reject); + }).fail((...args: unknown[]) => { result.reject(...args); }); } else { result.resolve(); } @@ -1181,7 +1182,8 @@ export class DataController extends modules.Controller { // change.items at this stage is defined only if virtualScrolling // + legacyScrollingMode enabled - const dataItems = this._beforeProcessItems(change.items ?? this._dataSource.items()); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const dataItems = this._beforeProcessItems(change.items ?? this._dataSource!.items()); const processedItems = this._processItems(dataItems, change); this._cachedProcessedItems = processedItems; @@ -1470,7 +1472,7 @@ export class DataController extends modules.Controller { } public pageCount(): number { - return this._dataSource ? this._dataSource.pageCount() as number : 1; + return this._dataSource ? this._dataSource.pageCount() : 1; } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1509,10 +1511,12 @@ export class DataController extends modules.Controller { group: dataSource.group(), sort: dataSource.sort(), }) + // @ts-expect-error badly typed CustomLoadResult .done(resolveWithProcessedItems) .fail(d.reject as (...args: unknown[]) => void); } else if (!dataSource.isLoading()) { dataSource.customLoadAll() + // @ts-expect-error badly typed CustomLoadResult .done(resolveWithProcessedItems) .fail(d.reject as (...args: unknown[]) => void); } else { @@ -1606,7 +1610,8 @@ export class DataController extends modules.Controller { this._skipProcessingPagingChange = false; } - const pageIndex = dataSource.pageIndex(); + // @ts-expect-error badly typed DataSourceAdapter + const pageIndex: number = dataSource.pageIndex(); this._isPaging = optionName === 'pageIndex'; const loadResult: DeferredObj = dataSource[optionName === 'pageIndex' ? 'load' : 'reload'](); @@ -1757,19 +1762,20 @@ export class DataController extends modules.Controller { } public push(...args: unknown[]): unknown { + // @ts-expect-error badly typed DataSourceAdapter return this._dataSource?.push(...args); } private itemsCount(): number { - return (this._dataSource ? this._dataSource.itemsCount() : 0) as number; + return (this._dataSource ? this._dataSource.itemsCount() : 0); } public totalItemsCount(): number { - return (this._dataSource ? this._dataSource.totalItemsCount() : 0) as number; + return (this._dataSource ? this._dataSource.totalItemsCount() : 0); } public hasKnownLastPage(): boolean { - return (this._dataSource ? this._dataSource.hasKnownLastPage() : true) as boolean; + return (this._dataSource ? this._dataSource.hasKnownLastPage() : true); } /** @@ -1780,7 +1786,7 @@ export class DataController extends modules.Controller { } public totalCount(): number { - return (this._dataSource ? this._dataSource.totalCount() : 0) as number; + return (this._dataSource ? this._dataSource.totalCount() : 0); } public hasLoadOperation(): boolean { diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts index 23c4014ca398..e25b4bc85757 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_source_adapter/m_data_source_adapter.ts @@ -8,7 +8,7 @@ import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred, when } from '@js/core/utils/deferred'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; -import { isDefined, isFunction, isPlainObject } from '@js/core/utils/type'; +import { isDefined, isPlainObject } from '@js/core/utils/type'; import type { StoreChange } from '@js/data/store'; import type { ChangingEvent, DataSource, StoreLoadOptions } from '@ts/data/data_source/types'; import type { BeforePushEvent } from '@ts/data/types'; @@ -30,7 +30,7 @@ import type { import { normalizeRemoteOperations } from './utils/remoteOperations'; export default class DataSourceAdapter extends modules.Controller { - protected _dataSource!: DataSource; + public _dataSource!: DataSource; private _remoteOperations!: RemoteOperationsOptions; @@ -96,10 +96,6 @@ export default class DataSourceAdapter extends modules.Controller { private changingHandlerProxy!: (e: ChangingEvent) => void; - protected store!: () => any; - - private readonly group!: (args?: any) => any; - private customLoader!: CustomLoader; public init(dataSource?: DataSource): void { @@ -107,59 +103,48 @@ export default class DataSourceAdapter extends modules.Controller { return; } - const that = this; - - that._dataSource = dataSource; - that._remoteOperations = normalizeRemoteOperations( + this._dataSource = dataSource; + this._remoteOperations = normalizeRemoteOperations( this.option('remoteOperations'), dataSource.store(), ); - that._isLastPage = !dataSource.isLastPage(); - that._hasLastPage = false; - that._currentTotalCount = 0; - that._cachedData = createEmptyCachedData(); - that._lastOperationTypes = {}; - that._eventsStrategy = dataSource._eventsStrategy; - that._totalCountCorrection = 0; - that.customLoader = new CustomLoader( + this._isLastPage = !dataSource.isLastPage(); + this._hasLastPage = false; + this._currentTotalCount = 0; + this._cachedData = createEmptyCachedData(); + this._lastOperationTypes = {}; + this._eventsStrategy = dataSource._eventsStrategy; + this._totalCountCorrection = 0; + this.customLoader = new CustomLoader( dataSource, () => this.option('loadingTimeout'), (operation) => this.customizeStoreLoadOptionsHandler(operation), (operation) => this.customizeLoadResultHandler(operation), ); - that.changed = Callbacks(); - that.loadingChanged = Callbacks(); - that.loadError = Callbacks(); - that.customizeStoreLoadOptions = Callbacks(); - that.changing = Callbacks(); - that.pushed = Callbacks(); - - that.dataChangedHandlerProxy = that.dataChangedHandler.bind(that); - that.customizeStoreLoadOptionsHandlerProxy = that.customizeStoreLoadOptionsHandler.bind(that); - that.customizeLoadResultHandlerProxy = that.customizeLoadResultHandler.bind(that); - that.loadingChangedHandlerProxy = that.loadingChangedHandler.bind(that); - that.loadErrorHandlerProxy = that.loadErrorHandler.bind(that); - that.pushHandlerProxy = that.pushHandler.bind(that); - that.changingHandlerProxy = that.changingHandler.bind(that); - - dataSource.on('changed', that.dataChangedHandlerProxy); - dataSource.on('customizeStoreLoadOptions', that.customizeStoreLoadOptionsHandlerProxy); - dataSource.on('customizeLoadResult', that.customizeLoadResultHandlerProxy); - dataSource.on('loadingChanged', that.loadingChangedHandlerProxy); - dataSource.on('loadError', that.loadErrorHandlerProxy); - dataSource.on('changing', that.changingHandlerProxy); - dataSource.store().on('beforePush', that.pushHandlerProxy); - - // TODO: remove copying dataSource's members - each(dataSource, (memberName, member) => { - if (!that[memberName] && isFunction(member)) { - that[memberName] = function () { - return this._dataSource[memberName].apply(this._dataSource, arguments); - }; - } - }); + this.changed = Callbacks(); + this.loadingChanged = Callbacks(); + this.loadError = Callbacks(); + this.customizeStoreLoadOptions = Callbacks(); + this.changing = Callbacks(); + this.pushed = Callbacks(); + + this.dataChangedHandlerProxy = this.dataChangedHandler.bind(this); + this.customizeStoreLoadOptionsHandlerProxy = this.customizeStoreLoadOptionsHandler.bind(this); + this.customizeLoadResultHandlerProxy = this.customizeLoadResultHandler.bind(this); + this.loadingChangedHandlerProxy = this.loadingChangedHandler.bind(this); + this.loadErrorHandlerProxy = this.loadErrorHandler.bind(this); + this.pushHandlerProxy = this.pushHandler.bind(this); + this.changingHandlerProxy = this.changingHandler.bind(this); + + dataSource.on('changed', this.dataChangedHandlerProxy); + dataSource.on('customizeStoreLoadOptions', this.customizeStoreLoadOptionsHandlerProxy); + dataSource.on('customizeLoadResult', this.customizeLoadResultHandlerProxy); + dataSource.on('loadingChanged', this.loadingChangedHandlerProxy); + dataSource.on('loadError', this.loadErrorHandlerProxy); + dataSource.on('changing', this.changingHandlerProxy); + dataSource.store().on('beforePush', this.pushHandlerProxy); } public dispose(isSharedDataSource?: boolean): void { @@ -182,6 +167,76 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: TreeLists's data_source_adapter */ + public filter(): StoreLoadOptions['filter']; + public filter(filterExpr: StoreLoadOptions['filter']): void; + public filter(...args: unknown[]): unknown { + return (this._dataSource.filter as (...a: unknown[]) => unknown)(...args); + } + + public sort(): StoreLoadOptions['sort']; + public sort(sortExpr: StoreLoadOptions['sort']): void; + public sort(...args: unknown[]): unknown { + return (this._dataSource.sort as (...a: unknown[]) => unknown)(...args); + } + + public group(): StoreLoadOptions['group']; + public group(groupExpr: StoreLoadOptions['group']): void; + public group(...args: unknown[]): unknown { + return (this._dataSource.group as (...a: unknown[]) => unknown)(...args); + } + + public select(): StoreLoadOptions['select']; + public select(selectExpr: StoreLoadOptions['select']): void; + public select(...args: unknown[]): unknown { + return (this._dataSource.select as (...a: unknown[]) => unknown)(...args); + } + + public paginate(): boolean | undefined; + public paginate(value: boolean): void; + public paginate(value?: boolean): boolean | undefined { + return (this._dataSource.paginate as (...a: unknown[]) => boolean | undefined)(value); + } + + public requireTotalCount(): StoreLoadOptions['requireTotalCount']; + public requireTotalCount(value: boolean): void; + public requireTotalCount(value?: boolean): unknown { + return (this._dataSource.requireTotalCount as (...a: unknown[]) => unknown)(value); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public store(): any { + return this._dataSource.store(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public key(): any { + return this._dataSource.key(); + } + + public isLoading(): boolean { + return this._dataSource.isLoading(); + } + + public beginLoading(): void { + this._dataSource.beginLoading(); + } + + public endLoading(): void { + this._dataSource.endLoading(); + } + + public loadOptions(): StoreLoadOptions { + return this._dataSource.loadOptions(); + } + + public cancel(operationId: number): boolean { + return this._dataSource.cancel(operationId); + } + + public cancelAll(): void { + (this._dataSource as unknown as { cancelAll: () => void }).cancelAll(); + } + public remoteOperations(): RemoteOperationsOptions { return this._remoteOperations; } @@ -190,17 +245,16 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling */ public refresh(options, operationTypes) { - const that = this; - const dataSource = that._dataSource; + const dataSource = this._dataSource; if (operationTypes.reload) { - that.resetCurrentTotalCount(); - that._isLastPage = !dataSource.paginate(); - that._hasLastPage = that._isLastPage; + this.resetCurrentTotalCount(); + this._isLastPage = !dataSource.paginate(); + this._hasLastPage = this._isLastPage; } } - private resetCurrentTotalCount() { + public resetCurrentTotalCount() { this._currentTotalCount = 0; this._totalCountCorrection = 0; } @@ -231,7 +285,7 @@ export default class DataSourceAdapter extends modules.Controller { return !isLocalOperations; } - private push(changes: StoreChange[], fromStore: boolean): void { + public push(changes: StoreChange[], fromStore: boolean): void { const store = this.store(); if (this._needClearStoreDataCache()) { @@ -260,7 +314,7 @@ export default class DataSourceAdapter extends modules.Controller { this.pushed.fire(changes); } - private getDataIndexGetter() { + public getDataIndexGetter() { if (!this._dataIndexGetter) { const store = this.store(); @@ -520,7 +574,7 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: TreeLists's data_source_adapter */ - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { const { loadOptions } = options; const localPaging = options.remoteOperations && !options.remoteOperations.paging; const { cachedData } = options; @@ -716,11 +770,11 @@ export default class DataSourceAdapter extends modules.Controller { return this._loadingOperationTypes; } - public operationTypes(): OperationTypes | undefined { - return this._operationTypes; + public operationTypes(): OperationTypes | null { + return this._operationTypes ?? null; } - private lastLoadOptions() { + public lastLoadOptions() { return this._lastLoadOptions || {}; } @@ -745,14 +799,14 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: TreeLists's data_source_adapter */ // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected changeRowExpand(path?: any): any {} + public changeRowExpand(path?: any): any {} - private totalCount() { + public totalCount() { // eslint-disable-next-line radix return parseInt((this._currentTotalCount || this._dataSourceTotalCount()) + this._totalCountCorrection); } - private totalCountCorrection() { + public totalCountCorrection() { return this._totalCountCorrection; } @@ -760,19 +814,19 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling * @protected */ - protected items(): any {} + public items(): any {} /** * @extended: virtual_scrolling */ - protected itemsCount() { + public itemsCount() { return this._dataSource.items().length; } /** * @extended: TreeLists's data_source_adapter */ - protected totalItemsCount() { + public totalItemsCount() { return this.totalCount(); } @@ -787,10 +841,9 @@ export default class DataSourceAdapter extends modules.Controller { return this._dataSource.pageSize(value); } - protected pageCount() { - const that = this; - const count = that.totalItemsCount() - that._totalCountCorrection; - const pageSize = that.pageSize(); + public pageCount() { + const count = this.totalItemsCount() - this._totalCountCorrection; + const pageSize = this.pageSize(); if (pageSize && count > 0) { return Math.max(1, Math.ceil(count / pageSize)); @@ -798,7 +851,7 @@ export default class DataSourceAdapter extends modules.Controller { return 1; } - protected hasKnownLastPage() { + public hasKnownLastPage() { return this._hasLastPage || this._dataSource.totalCount() >= 0; } @@ -806,7 +859,7 @@ export default class DataSourceAdapter extends modules.Controller { return this.customLoader.loadFromStore(loadOptions); } - protected isCustomLoading(): boolean { + public isCustomLoading(): boolean { return this.customLoader.isLoading(); } @@ -817,7 +870,7 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: virtual_scrolling */ - protected load(options?: CustomLoadOptions): DeferredObj { + public load(options?: CustomLoadOptions): DeferredObj { if (options) { return this.customLoader.load(options); } @@ -839,12 +892,13 @@ export default class DataSourceAdapter extends modules.Controller { /** * @extended: virtual_scrolling */ - protected reload(full: boolean): DeferredObj { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public reload(full?: boolean, changesOnly?: boolean): DeferredObj { const result = full ? this._dataSource.reload() : this._dataSource.load(); return result as unknown as DeferredObj; } - private getCachedStoreData() { + public getCachedStoreData() { return this._cachedStoreData; } @@ -857,5 +911,5 @@ export default class DataSourceAdapter extends modules.Controller { * @extended: virtual_scrolling */ // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected pageIndex(pageIndex?) {} + public pageIndex(pageIndex?) {} } diff --git a/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts b/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts index 39fb37dd160b..aa3d5fe659dc 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/focus/m_focus.ts @@ -546,7 +546,7 @@ const columns = (Base: ModuleType) => class FocusColumnsExten if (notSortedKeys.length) { result = result || []; if (isLocalOperations) { - result.push({ selector: dataSource.getDataIndexGetter(), desc: false }); + result.push({ selector: dataSource?.getDataIndexGetter(), desc: false }); } else { notSortedKeys.forEach((notSortedKey) => result.push({ selector: notSortedKey, desc: false })); } @@ -708,7 +708,7 @@ const focusDataControllerExtender = ( } private getGlobalRowIndexByKey(key) { - if (this._dataSource.group()) { + if (this._dataSource!.group()) { // @ts-expect-error return this._calculateGlobalRowIndexByGroupedData(key); } @@ -719,7 +719,7 @@ const focusDataControllerExtender = ( protected _calculateGlobalRowIndexByFlatData(key, groupFilter, useGroup) { // @ts-expect-error const deferred = new Deferred(); - const dataSource = this._dataSource; + const dataSource = this._dataSource!; if (Array.isArray(key) || isNewRowTempKey(key)) { return deferred.resolve(-1).promise(); @@ -736,8 +736,8 @@ const focusDataControllerExtender = ( deferred.resolve(-1); return; } - if (data.length > 0) { - filter = this._generateOperationFilterByKey(key, data[0], useGroup); + if ((data as unknown[]).length > 0) { + filter = this._generateOperationFilterByKey(key, (data as unknown[])[0], useGroup); dataSource.load({ filter: this._concatWithCombinedFilter(filter, groupFilter), skip: 0, @@ -748,7 +748,7 @@ const focusDataControllerExtender = ( deferred.resolve(-1); return; } - deferred.resolve(extra.totalCount); + deferred.resolve((extra as { totalCount: number }).totalCount); }); } else { deferred.resolve(-1); @@ -784,8 +784,8 @@ const focusDataControllerExtender = ( private _generateOperationFilterByKey(key, rowData, useGroup) { const that = this; const dateSerializationFormat = that.option('dateSerializationFormat'); - const isRemoteFiltering = that._dataSource.remoteOperations().filtering; - const isRemoteSorting = that._dataSource.remoteOperations().sorting; + const isRemoteFiltering = that._dataSource!.remoteOperations().filtering; + const isRemoteSorting = that._dataSource!.remoteOperations().sorting; let filter = that._generateFilterByKey(key, '<'); // @ts-expect-error @@ -846,7 +846,7 @@ const focusDataControllerExtender = ( } protected _generateFilterByKey(key, operation?) { - const dataSourceKey = this._dataSource.key(); + const dataSourceKey = this._dataSource!.key(); let filter: any = []; if (!operation) { diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts index 8903563cd5e9..ed08c807aeda 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/extenders/virtual_scrolling_data_controller.ts @@ -34,8 +34,10 @@ import { LOAD_TIMEOUT, VISIBLE_PAGE_INDEX, } from '../const'; +import type { dataSourceAdapterExtender } from '../m_virtual_scrolling'; import { VirtualScrollController } from '../m_virtual_scrolling_core'; import type { ChangedLoadParams } from '../types'; +import type { GroupCountableDataSource } from '../utils/items'; import { correctCount, isItemCountableByDataSource, @@ -51,11 +53,15 @@ export interface VirtualScrollingDataControllerExtension { virtualItemsCount: () => VirtualItemsCount | undefined; } +type VirtualScrollingDataSourceAdapter = InstanceType>; + export const virtualScrollingDataControllerExtender = ( Base: ModuleType, ): ModuleType< DataController & VirtualScrollingDataControllerExtension > => class VirtualScrollingDataControllerExtender extends Base { + public declare _dataSource?: VirtualScrollingDataSourceAdapter | null; + private _loadViewportParams: any; private _allItems: any; @@ -106,6 +112,7 @@ export const virtualScrollingDataControllerExtender = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars public reload(reload?: boolean, changesOnly?: boolean): DeferredObj { const rowsScrollController = this._rowsScrollController || this._dataSource; + // @ts-expect-error badly typed DataSourceAdapter const itemIndex = rowsScrollController?.getItemIndexByPosition(); const result = super.reload.apply(this, arguments as any); return result?.done(() => { @@ -175,7 +182,7 @@ export const virtualScrollingDataControllerExtender = ( private _getRowsScrollDataOptions() { const that = this; const isItemCountable = function (item) { - return isItemCountableByDataSource(item, that._dataSource); + return isItemCountableByDataSource(item, that._dataSource as unknown as GroupCountableDataSource); }; return { @@ -369,7 +376,7 @@ export const virtualScrollingDataControllerExtender = ( processedItems.forEach((item) => { const { rowType } = item; - const itemCountable = isItemCountableByDataSource(item, dataSource); + const itemCountable = isItemCountableByDataSource(item, dataSource as unknown as GroupCountableDataSource); const isNextGroupItem = rowType === 'group' && (prevCountable || (prevRowType !== 'group' && currentIndex > 0)); const isNextDataItem = rowType === 'data' && itemCountable && (prevCountable || prevRowType !== 'group'); @@ -403,7 +410,7 @@ export const virtualScrollingDataControllerExtender = ( } protected _afterProcessItems(processedItems: ProcessedItem[]): ProcessedItem[] { - this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource)).length; + this._itemCount = processedItems.filter((item) => isItemCountableByDataSource(item, this._dataSource as unknown as GroupCountableDataSource)).length; if (isDefined(this._loadViewportParams)) { this._updateLoadViewportParams(); @@ -438,7 +445,7 @@ export const virtualScrollingDataControllerExtender = ( if (removeCount) { const fromEnd = changeType === 'prepend'; - removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource) || (item.rowType === 'group' && isNextAfterLast)); + removeCount = correctCount(that._items, removeCount, fromEnd, (item, isNextAfterLast) => isItemCountableByDataSource(item, that._dataSource as unknown as GroupCountableDataSource) || (item.rowType === 'group' && isNextAfterLast)); change.removeCount = removeCount; } @@ -527,46 +534,46 @@ export const virtualScrollingDataControllerExtender = ( return isDefined(lastVisibleItem?.dataIndex) ? lastVisibleItem!.dataIndex + 1 : 0; } - private viewportSize() { + private viewportSize(size?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; // @ts-expect-error - const result = rowsScrollController?.viewportSize.apply(rowsScrollController, arguments); + const result = rowsScrollController?.viewportSize(size); if (this.option(LEGACY_SCROLLING_MODE) === false) { return result; } - return dataSource?.viewportSize.apply(dataSource, arguments); + return dataSource?.viewportSize(size); } private viewportHeight(height, scrollTop) { this._rowsScrollController?.viewportHeight(height, scrollTop); } - private viewportItemSize() { + private viewportItemSize(size?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; // @ts-expect-error - const result = rowsScrollController?.viewportItemSize.apply(rowsScrollController, arguments); + const result = rowsScrollController?.viewportItemSize(size); if (this.option(LEGACY_SCROLLING_MODE) === false) { return result; } - return dataSource?.viewportItemSize.apply(dataSource, arguments); + return dataSource?.viewportItemSize(size); } - private setViewportPosition() { + private setViewportPosition(position?) { const rowsScrollController = this._rowsScrollController; const dataSource = this._dataSource; this._isPaging = false; if (rowsScrollController) { // @ts-expect-error - rowsScrollController.setViewportPosition.apply(rowsScrollController, arguments); + rowsScrollController.setViewportPosition(position); } else { - dataSource?.setViewportPosition.apply(dataSource, arguments); + dataSource?.setViewportPosition(position); } } @@ -738,8 +745,8 @@ export const virtualScrollingDataControllerExtender = ( } private loadPages(changedParams: ChangedLoadParams): void { - this._dataSource.pageIndex(changedParams.pageIndex); - this._dataSource.loadPageCount(changedParams.loadPageCount); + this._dataSource!.pageIndex(changedParams.pageIndex); + this._dataSource!.loadPageCount(changedParams.loadPageCount); this._repaintChangesOnly = true; this._needUpdateDimensions = true; @@ -827,11 +834,11 @@ export const virtualScrollingDataControllerExtender = ( if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getItemSize.apply(rowsScrollController, arguments); + return rowsScrollController.getItemSize(); } const dataSource = this._dataSource; - return dataSource?.getItemSize.apply(dataSource, arguments); + return dataSource?.getItemSize(); } private getItemSizes() { @@ -839,23 +846,23 @@ export const virtualScrollingDataControllerExtender = ( if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getItemSizes.apply(rowsScrollController, arguments); + return rowsScrollController.getItemSizes(); } const dataSource = this._dataSource; - return dataSource?.getItemSizes.apply(dataSource, arguments); + return dataSource?.getItemSizes(); } - private getContentOffset() { + private getContentOffset(type?) { const rowsScrollController = this._rowsScrollController; if (rowsScrollController) { // @ts-expect-error - return rowsScrollController.getContentOffset.apply(rowsScrollController, arguments); + return rowsScrollController.getContentOffset(type); } const dataSource = this._dataSource; - return dataSource?.getContentOffset.apply(dataSource, arguments); + return dataSource?.getContentOffset(type); } public refresh(options?: boolean | RefreshOptions): DeferredObj { @@ -908,7 +915,7 @@ export const virtualScrollingDataControllerExtender = ( const { fullReload, pageIndex } = operationTypes; if (e.isDataChanged && !fullReload && pageIndex) { - this._updateVisiblePageIndex(this._dataSource.pageIndex()); + this._updateVisiblePageIndex(this._dataSource!.pageIndex()); } } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts index 5315499f0d30..094de621b840 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/m_virtual_scrolling.ts @@ -33,6 +33,7 @@ import { VIRTUAL_ROW_CLASS, } from './const'; import { subscribeToExternalScrollers, VirtualScrollController } from './m_virtual_scrolling_core'; +import type { GroupCountableDataSource } from './utils/items'; import { isItemCountableByDataSource } from './utils/items'; import { isInfiniteMode, isVirtualMode, isVirtualPaging } from './utils/scrolling_mode'; @@ -216,7 +217,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = super._customizeRemoteOperations.apply(this, arguments as any); } - protected items() { + public items() { return this._items; } @@ -224,21 +225,21 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return this.option(LEGACY_SCROLLING_MODE) === false && isVirtualMode(this) && !isBase ? this._totalCount : super._dataSourceTotalCount(); } - protected itemsCount(isBase?) { + public itemsCount(isBase?) { if (isBase || this.option(LEGACY_SCROLLING_MODE) === false) { return super.itemsCount(); } return this._virtualScrollController.itemsCount(); } - protected load(loadOptions) { + public load(loadOptions) { if (this.option(LEGACY_SCROLLING_MODE) === false || loadOptions) { return super.load(loadOptions); } return this._virtualScrollController.load(); } - private isLoading() { + public isLoading() { return this.option(LEGACY_SCROLLING_MODE) === false ? this._dataSource.isLoading() : this._isLoading; } @@ -266,7 +267,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return result; } - protected reload() { + public reload() { this._dataSource.pageIndex(this.pageIndex()); const virtualScrollController = this._virtualScrollController; @@ -320,7 +321,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return super.refresh.apply(this, arguments as any); } - private loadPageCount(count?) { + public loadPageCount(count?) { if (!isDefined(count)) { return this._loadPageCount; } @@ -354,27 +355,30 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = } // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected pageIndex(pageIndex?): any { + public pageIndex(pageIndex?): any { return proxyDataSourceAdapterMethod(this, 'pageIndex', [...arguments]); } - private virtualItemsCount(): any { + public virtualItemsCount(): any { return proxyDataSourceAdapterMethod(this, 'virtualItemsCount', [...arguments]); } - private getContentOffset(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public getContentOffset(type?): any { return proxyDataSourceAdapterMethod(this, 'getContentOffset', [...arguments]); } - private getVirtualContentSize(): any { + public getVirtualContentSize(): any { return proxyDataSourceAdapterMethod(this, 'getVirtualContentSize', [...arguments]); } - private setContentItemSizes(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setContentItemSizes(sizes?): any { return proxyDataSourceAdapterMethod(this, 'setContentItemSizes', [...arguments]); } - private setViewportPosition(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setViewportPosition(position?): any { return proxyDataSourceAdapterMethod(this, 'setViewportPosition', [...arguments]); } @@ -387,27 +391,29 @@ export const dataSourceAdapterExtender = (Base: ModuleType) = return proxyDataSourceAdapterMethod(this, 'setViewportItemIndex', [...arguments]); } - private getItemIndexByPosition(): any { + public getItemIndexByPosition(): any { return proxyDataSourceAdapterMethod(this, 'getItemIndexByPosition', [...arguments]); } - private viewportSize(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public viewportSize(size?): any { return proxyDataSourceAdapterMethod(this, 'viewportSize', [...arguments]); } - private viewportItemSize(): any { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public viewportItemSize(size?): any { return proxyDataSourceAdapterMethod(this, 'viewportItemSize', [...arguments]); } - private getItemSize(): any { + public getItemSize(): any { return proxyDataSourceAdapterMethod(this, 'getItemSize', [...arguments]); } - private getItemSizes(): any { + public getItemSizes(): any { return proxyDataSourceAdapterMethod(this, 'getItemSizes', [...arguments]); } - private loadIfNeed(): any { + public loadIfNeed(): any { return proxyDataSourceAdapterMethod(this, 'loadIfNeed', [...arguments]); } }; @@ -569,7 +575,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo } protected _renderCore(e) { - const startRenderTime: any = new Date(); + const startRenderTime = Date.now(); const deferred = super._renderCore.apply(this, arguments as any); @@ -582,9 +588,11 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo .viewportSize() || 20; if (gridCoreUtils.isVirtualRowRendering(this) && itemCount > 0 && this.option(LEGACY_SCROLLING_MODE) !== false) { - dataSource._renderTime = ((new Date()) as any - startRenderTime) * viewportSize / itemCount; + // @ts-expect-error badly typed DataSourceAdapter + dataSource._renderTime = (Date.now() - startRenderTime) * viewportSize / itemCount; } else { - dataSource._renderTime = ((new Date()) as any - startRenderTime); + // @ts-expect-error badly typed DataSourceAdapter + dataSource._renderTime = Date.now() - startRenderTime; } } return deferred; @@ -718,7 +726,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo itemSize = 0; } lastLoadIndex = currentItem.loadIndex; - } else if (isItemCountableByDataSource(currentItem, dataSource)) { + } else if (isItemCountableByDataSource(currentItem, dataSource as unknown as GroupCountableDataSource)) { if (firstCountableItem) { firstCountableItem = false; } else { @@ -964,7 +972,7 @@ export const rowsView = (Base: ModuleType) => class VirtualScrollingRo } } - private loadIfNeed() { + public loadIfNeed() { this._dataController // @ts-expect-error ?.loadIfNeed?.(); diff --git a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts index fc8b52d079dc..28412664c581 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/virtual_scrolling/utils/items.ts @@ -1,6 +1,6 @@ import type { ProcessedItem } from '@ts/grids/grid_core/data_controller/types'; -interface GroupCountableDataSource { +export interface GroupCountableDataSource { isGroupItemCountable: (data: unknown) => boolean; } diff --git a/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts b/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts index f0fa6c4d443e..55c9e35e78fa 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts @@ -5,10 +5,13 @@ import { DataController, dataControllerModule } from '@ts/grids/grid_core/data_c import type { DataSourceAdapterProvider } from '@ts/grids/grid_core/data_source_adapter/types'; import type { RowKey } from '@ts/grids/grid_core/m_types'; +import type { DataSourceAdapterTreeList } from '../data_source_adapter/m_data_source_adapter'; import dataSourceAdapterProvider from '../data_source_adapter/m_data_source_adapter'; import treeListCore from '../m_core'; export class TreeListDataController extends DataController { + public declare _dataSource?: DataSourceAdapterTreeList | null; + protected _getDataSourceAdapterProvider(): DataSourceAdapterProvider { return dataSourceAdapterProvider; } @@ -36,7 +39,7 @@ export class TreeListDataController extends DataController { } private _loadOnOptionChange() { - this._dataSource.load(); + this._dataSource!.load(); } protected isSameRowState(item1, item2): boolean { @@ -163,6 +166,7 @@ export class TreeListDataController extends DataController { break; case 'expandedRowKeys': case 'onNodesInitialized': + // @ts-expect-error badly typed DataSourceAdapter if (this._dataSource && !this._dataSource._isNodesInitializing && !equalByValue(args.value, args.previousValue)) { this._loadOnOptionChange(); } @@ -201,7 +205,7 @@ export class TreeListDataController extends DataController { } private forEachNode() { - this._dataSource.forEachNode.apply(this, arguments); + this._dataSource!.forEachNode.apply(this, arguments as any); } // Collect keys by walking the loaded node tree (depth-first, parent before diff --git a/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts b/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts index 722fdef004b4..794e20ebb1bd 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts @@ -617,7 +617,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return baseChanges; } - protected customizeLoadResultHandler(options) { + public customizeLoadResultHandler(options) { const data = options.data = this._convertDataToPlainStructure(options.data); if (!options.remoteOperations.filtering && options.loadOptions.filter) { // @ts-expect-error @@ -773,7 +773,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { this.createAction('onNodesInitialized'); } - private getKeyExpr() { + public getKeyExpr() { const store = this.store(); const key = store && store.key(); const keyExpr = this.option('keyExpr'); @@ -787,23 +787,23 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return key || keyExpr || DEFAULT_KEY_EXPRESSION; } - private keyOf(data) { + public keyOf(data) { return this._keyGetter && this._keyGetter(data); } - private parentKeyOf(data) { + public parentKeyOf(data) { return this._parentIdGetter && this._parentIdGetter(data); } - private getRootNode() { + public getRootNode() { return this._rootNode; } - protected totalItemsCount() { + public totalItemsCount() { return this._totalItemsCount + this._totalCountCorrection; } - private isRowExpanded(key, cache?) { + public isRowExpanded(key, cache?) { if (cache) { let { isExpandedByKey } = cache; if (!isExpandedByKey) { @@ -836,13 +836,13 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { this.option('expandedRowKeys', expandedRowKeys); } - protected changeRowExpand(key) { + public changeRowExpand(key) { this._changeRowExpandCore(key); // @ts-expect-error return this._isNodesInitializing ? new Deferred().resolve() : this.load(); } - private getNodeByKey(key) { + public getNodeByKey(key) { if (this._nodeByKey) { return this._nodeByKey[key]; } @@ -864,7 +864,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return result; } - private getChildNodeKeys(parentKey) { + public getChildNodeKeys(parentKey) { const node = this.getNodeByKey(parentKey); const childrenKeys: any[] = []; @@ -875,7 +875,7 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return childrenKeys; } - private loadDescendants(keys, childrenOnly) { + public loadDescendants(keys, childrenOnly) { const that = this; // @ts-expect-error const d = new Deferred(); @@ -911,7 +911,8 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter { return d.promise(); } - private forEachNode() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any + public forEachNode(nodeCallback?: (node: any) => void) { let nodes = []; let callback; diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts b/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts index f65678a32c3c..976b33b0d7d0 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_focus.ts @@ -3,6 +3,7 @@ import { focusModule } from '@ts/grids/grid_core/focus/m_focus'; import type { DataController } from '../grid_core/data_controller/data_controller'; import type { ModuleType } from '../grid_core/m_types'; +import type { DataSourceAdapterTreeList } from './data_source_adapter/m_data_source_adapter'; import core from './m_core'; function findIndex(items, callback) { @@ -51,7 +52,7 @@ const data = ( private getParentKey(key) { const that = this; - const dataSource = that._dataSource; + const dataSource = that._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const node = that.getNodeByKey(key); // @ts-expect-error @@ -63,7 +64,7 @@ const data = ( dataSource.load({ filter: [dataSource.getKeyExpr(), '=', key], }).done((items) => { - const parentData = items[0]; + const parentData = (items as unknown[])[0]; if (parentData) { d.resolve(dataSource.parentKeyOf(parentData)); @@ -78,15 +79,17 @@ const data = ( private expandAscendants(key) { const that = this; - const dataSource = that._dataSource; + const dataSource = that._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const d = new Deferred(); that.getParentKey(key).done((parentKey) => { if (dataSource && parentKey !== undefined && parentKey !== that.option('rootValue')) { + // @ts-expect-error badly typed DataSourceAdapter dataSource._isNodesInitializing = true; // @ts-expect-error that.expandRow(parentKey); + // @ts-expect-error badly typed DataSourceAdapter dataSource._isNodesInitializing = false; that.expandAscendants(parentKey).done(d.resolve).fail(d.reject); } else { @@ -98,7 +101,7 @@ const data = ( } protected getPageIndexByKey(key) { - const dataSource = this._dataSource; + const dataSource = this._dataSource as unknown as DataSourceAdapterTreeList; // @ts-expect-error const d = new Deferred(); @@ -106,7 +109,7 @@ const data = ( dataSource.load({ parentIds: [], }).done((nodes) => { - if (this._dataSource !== dataSource) { + if ((this._dataSource as unknown) !== (dataSource as unknown)) { d.resolve(-1); return; } diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts b/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts index 087fcd9315ca..169ec0172d0a 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts @@ -35,6 +35,7 @@ virtualScrollingModule.extenders.views.rowsView = (Base: ModuleType) = virtualScrollingModule.extenders.controllers.data = (Base: ModuleType) => class TreeListVirtualScrollingDataControllerExtender extends virtualScrollingDataControllerExtender(Base) { protected _loadOnOptionChange() { + // @ts-expect-error badly typed DataSourceAdapter const virtualScrollController = this._dataSource?._virtualScrollController; virtualScrollController?.reset(); @@ -44,7 +45,7 @@ virtualScrollingModule.extenders.controllers.data = (Base: ModuleType) => class VirtualScrollingDataSourceAdapterExtender extends virtualScrollingDataSourceAdapterExtender(Base) { - protected changeRowExpand() { + public changeRowExpand() { return super.changeRowExpand.apply(this, arguments as any).done(() => { const viewportItemIndex = this.getViewportItemIndex(); diff --git a/packages/devextreme/testing/helpers/gridBaseMocks.js b/packages/devextreme/testing/helpers/gridBaseMocks.js index 029e59537099..9f4eb8f29e91 100644 --- a/packages/devextreme/testing/helpers/gridBaseMocks.js +++ b/packages/devextreme/testing/helpers/gridBaseMocks.js @@ -808,6 +808,21 @@ module.exports = function($, gridCore, columnResizingReordering, domUtils, commo cancelAll: commonUtils.noop, + loadOptions: function() { + return {}; + }, + beginLoading: commonUtils.noop, + endLoading: commonUtils.noop, + key: function() { + return options.key; + }, + select: function() { + return options.select; + }, + cancel: function() { + return false; + }, + on(eventName, eventHandler) { this[eventName].add(eventHandler); }, diff --git a/packages/devextreme/testing/helpers/vizMocks.js b/packages/devextreme/testing/helpers/vizMocks.js index 8a6838ea73a5..ae1a8310d41b 100644 --- a/packages/devextreme/testing/helpers/vizMocks.js +++ b/packages/devextreme/testing/helpers/vizMocks.js @@ -259,14 +259,24 @@ function stubClass(target, members, settings) { settings = settings || {}; proto.prototype = typeof target === 'function' ? target.prototype : target; const stubPrototype = stub.prototype = new proto(); - $.each(stubPrototype, function(name, member) { - if(typeof member === 'function' && name !== 'constructor') { - stubPrototype[name] = function() { - createStub(this, name); - return this[name].apply(this, arguments); - }; - } - }); + // Walk the prototype chain so non-enumerable methods (ES6 class methods) are + // stubbed too; a plain `for...in`/`$.each` only sees enumerable members. + const stubbedNames = {}; + for(let currentProto = stubPrototype; currentProto && currentProto !== Object.prototype; currentProto = Object.getPrototypeOf(currentProto)) { + Object.getOwnPropertyNames(currentProto).forEach(function(name) { + if(name === 'constructor' || stubbedNames[name]) { + return; + } + const descriptor = Object.getOwnPropertyDescriptor(currentProto, name); + if(descriptor && typeof descriptor.value === 'function') { + stubbedNames[name] = true; + stubPrototype[name] = function() { + createStub(this, name); + return this[name].apply(this, arguments); + }; + } + }); + } settings.$extraFunctions && $.each(settings.$extraFunctions, function(_, name) { _members[name] = 'name' in _members ? _members[name] : function() { }; });