Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions packages/devextreme/js/__internal/grids/grid_core/m_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export function isDateType(dataType: string | undefined): boolean {
return dataType === 'date' || dataType === 'datetime';
}

export interface SelectionRange {
selectionStart: number;
selectionEnd: number;
}

const getIntervalSelector = function () {
const data = arguments[1];
const value = this.calculateCellValue(data);
Expand Down Expand Up @@ -562,22 +567,25 @@ export default {

isDateType,

getSelectionRange(focusedElement) {
getSelectionRange(focusedElement): SelectionRange {
try {
if (focusedElement) {
return {
selectionStart: focusedElement.selectionStart,
selectionEnd: focusedElement.selectionEnd,
selectionStart: isNumeric(focusedElement.selectionStart) ? focusedElement.selectionStart : -1,
selectionEnd: isNumeric(focusedElement.selectionEnd) ? focusedElement.selectionEnd : -1,
};
Comment thread
nightskylark marked this conversation as resolved.
}
} catch (e) { /* empty */ }

return {};
return {
selectionStart: -1,
selectionEnd: -1,
};
},

setSelectionRange(focusedElement, selectionRange) {
setSelectionRange(focusedElement, selectionRange: SelectionRange): void {
try {
if (focusedElement && focusedElement.setSelectionRange) {
if (focusedElement && focusedElement.setSelectionRange && selectionRange.selectionStart >= 0 && selectionRange.selectionEnd >= 0) {
focusedElement.setSelectionRange(selectionRange.selectionStart, selectionRange.selectionEnd);
}
} catch (e) { /* empty */ }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { ColumnHeadersView } from '../column_headers/m_column_headers';
import type { ColumnsController } from '../columns_controller/m_columns_controller';
import type { DataController } from '../data_controller/data_controller';
import modules from '../m_modules';
import gridCoreUtils from '../m_utils';
import gridCoreUtils, { type SelectionRange } from '../m_utils';
import type { RowsView } from './m_rows_view';

const BORDERS_CLASS = 'borders';
Expand Down Expand Up @@ -78,11 +78,17 @@ const calculateFreeWidthWithCurrentMinWidth = function (that, columnIndex, curre
return calculateFreeWidth(that, widths.map((width, index) => (index === columnIndex ? currentMinWidth : width)));
};

const restoreFocus = function (focusedElement, selectionRange) {
const restoreFocus = (focusedElement: Element, selectionRange: SelectionRange): void => {
accessibility.hiddenFocus(focusedElement, true);
gridCoreUtils.setSelectionRange(focusedElement, selectionRange);
};

interface MaxWidthController {
isModified: boolean;
set: (value: number) => void;
clear: () => void;
}

export class ResizingController extends modules.ViewController {
private _refreshSizesHandler: any;

Expand All @@ -100,8 +106,6 @@ export class ResizingController extends modules.ViewController {

private _prevContentMinHeight: any;

private _maxWidth: any;

private _hasWidth: any;

private _hasHeight: any;
Expand All @@ -122,6 +126,26 @@ export class ResizingController extends modules.ViewController {

public resizeCompleted!: Callback;

private readonly _maxWidth: MaxWidthController = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach is a bit unusual for the Grid. Having two regular private methods, _setMaxWidth and _clearMaxWidth, along with a boolean flag, would be more consistent with the existing codebase.

isModified: false,
set: (value): void => {
const $element = this.component.$element();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we also check whether $element exists here, just like we do in the clear method?


this._maxWidth.isModified = true;
$element.css('maxWidth', value);
},
clear: (): void => {
const $element = this.component.$element();

if (!this._maxWidth.isModified || !$element || !$element.get(0)) {
return;
}

this._maxWidth.isModified = false;
$element[0].style.maxWidth = '';
},
};

protected callbackNames() {
return ['resizeCompleted'];
}
Expand Down Expand Up @@ -338,85 +362,55 @@ export class ResizingController extends modules.ViewController {
}
}

private _synchronizeColumns() {
const columnsController = this._columnsController;
const visibleColumns = columnsController.getVisibleColumns();
const columnAutoWidth = this.option('columnAutoWidth');
const hasUndefinedColumnWidth = visibleColumns.some((column) => !isDefined(column.width));
let needBestFit = this._needBestFit();
let hasMinWidth = false;
let resetBestFitMode;
let isColumnWidthsCorrected = false;
let resultWidths: any[] = [];
let focusedElement;
let selectionRange;
private _enableTemporaryBestFitMode(): () => void {
const $element = this.component.$element();
const focusedElement = domAdapter.getActiveElement($element.get(0) as HTMLElement | null);
const selectionRange = gridCoreUtils.getSelectionRange(focusedElement);

const normalizeWidthsByExpandColumns = function () {
let expandColumnWidth;
this._toggleBestFitMode(true);

each(visibleColumns, (index, column) => {
if (column.type === 'groupExpand') {
expandColumnWidth = resultWidths[index];
}
});
return (): void => {
this._toggleBestFitMode(false);

each(visibleColumns, (index, column) => {
if (column.type === 'groupExpand' && expandColumnWidth) {
resultWidths[index] = expandColumnWidth;
}
});
};
if (focusedElement && focusedElement !== domAdapter.getActiveElement()) {
const isFocusOutsideWindow = getBoundingRect(focusedElement).bottom < 0;

!needBestFit && each(visibleColumns, (index, column) => {
if (column.width === 'auto') {
needBestFit = true;
return false;
if (!isFocusOutsideWindow) {
restoreFocus(focusedElement, selectionRange);
}
}
return undefined;
});
};
}

each(visibleColumns, (index, column) => {
if (column.minWidth) {
hasMinWidth = true;
return false;
}
return undefined;
});
private _synchronizeColumns(): void {
const columnsController = this._columnsController;
const visibleColumns = columnsController.getVisibleColumns();
const columnAutoWidth = this.option('columnAutoWidth') as boolean;
const hasUndefinedColumnWidth = visibleColumns.some((column) => !isDefined(column.width));
const needBestFit = this._needBestFit() || visibleColumns.some((column) => column.width === 'auto');
const hasMinWidth = visibleColumns.some((column) => !!column.minWidth);

// Prepare for measurement
this._toggleContentMinHeight(this._hasHeight); // T1047239, T1270354

this._setVisibleWidths(visibleColumns, []);

const $element = this.component.$element();

if (needBestFit) {
// @ts-expect-error
focusedElement = domAdapter.getActiveElement($element.get(0));
selectionRange = gridCoreUtils.getSelectionRange(focusedElement);
this._toggleBestFitMode(true);
resetBestFitMode = true;
}

if ($element && $element.get(0) && this._maxWidth) {
delete this._maxWidth;
$element[0].style.maxWidth = '';
}
const restoreAfterBestFitMode = needBestFit && this._enableTemporaryBestFitMode();
this._maxWidth.clear();

// eslint-disable-next-line @typescript-eslint/no-floating-promises
deferUpdate(() => {
if (needBestFit) {
let resultWidths: (number | string | undefined)[] = [];

if (needBestFit || hasMinWidth) {
resultWidths = this._getBestFitWidths();
}

each(visibleColumns, (index, column) => {
each(visibleColumns, (index, column) => {
if (needBestFit) {
const columnId = columnsController.getColumnId(column);
columnsController.columnOption(columnId, 'bestFitWidth', resultWidths[index], true);
});
} else if (hasMinWidth) {
resultWidths = this._getBestFitWidths();
}
}

each(visibleColumns, function (index) {
const { width } = this;
const { width } = column;
if (width !== 'auto') {
if (isDefined(width)) {
resultWidths[index] = isNumeric(width) || isPixelWidth(width) ? parseFloat(width) : width;
Expand All @@ -426,21 +420,14 @@ export class ResizingController extends modules.ViewController {
}
});

if (resetBestFitMode) {
this._toggleBestFitMode(false);
resetBestFitMode = false;
if (focusedElement && focusedElement !== domAdapter.getActiveElement()) {
const isFocusOutsideWindow = getBoundingRect(focusedElement).bottom < 0;
if (!isFocusOutsideWindow) {
restoreFocus(focusedElement, selectionRange);
}
}
if (restoreAfterBestFitMode) {
restoreAfterBestFitMode();
}

isColumnWidthsCorrected = this._correctColumnWidths(resultWidths, visibleColumns);
const isColumnWidthsCorrected = this._correctColumnWidths(resultWidths, visibleColumns);

if (columnAutoWidth) {
normalizeWidthsByExpandColumns();
this._normalizeWidthsByExpandColumns(resultWidths, visibleColumns);
if (this._needStretch()) {
this._processStretch(resultWidths, visibleColumns);
}
Expand Down Expand Up @@ -478,6 +465,21 @@ export class ResizingController extends modules.ViewController {
return freeWidth / columnCountWithoutWidth;
}

private readonly _normalizeWidthsByExpandColumns = (resultWidths, visibleColumns): void => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear why this method is marked as readonly. In this case, we're explicitly preventing it from being overridden without any clear reason. That goes against the Grid's architecture, which is built around inheritance and @Extended overrides.

Also, the method parameters are untyped.

const expandColumnIndex = visibleColumns.findIndex((column) => column.type === 'groupExpand');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the Grid uses the width of the first expand column it encounters. Previously, it used the width of the last expand column.

const expandColumnWidth = resultWidths[expandColumnIndex];

if (!isDefined(expandColumnWidth)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer ignore the value 0. Is this intentional?

return;
}

each(visibleColumns, (index, column) => {
if (column.type === 'groupExpand') {
resultWidths[index] = expandColumnWidth;
}
});
};

/**
* @extended: adaptivity
*/
Expand All @@ -487,7 +489,6 @@ export class ResizingController extends modules.ViewController {
let hasPercentWidth = false;
let hasAutoWidth = false;
let isColumnWidthsCorrected = false;
const $element = that.component.$element();
const hasWidth = that._hasWidth;

for (i = 0; i < visibleColumns.length; i++) {
Expand Down Expand Up @@ -540,9 +541,7 @@ export class ResizingController extends modules.ViewController {
if (hasWidth === false && !hasPercentWidth) {
const borderWidth = gridCoreUtils.getComponentBorderWidth(this, $rowsViewElement);

that._maxWidth = totalWidth + scrollbarWidth + borderWidth;

$element.css('maxWidth', that._maxWidth);
that._maxWidth.set(totalWidth + scrollbarWidth + borderWidth);
}
}
}
Expand Down
Loading