Skip to content
Merged
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 14 additions & 5 deletions packages/devextreme-scss/scss/widgets/base/_gridBase.scss
Original file line number Diff line number Diff line change
Expand Up @@ -971,12 +971,21 @@
&:focus {
outline: 0;
}
}

&.dx-#{$widget-name}-sticky-column-left {
display: inline-block;
overflow: hidden;
left: 0;
right: 0;
&.dx-#{$widget-name}-sticky-columns {
.dx-row > .dx-master-detail-cell {
overflow: visible;

.dx-#{$widget-name}-master-detail-container {
overflow: hidden;
text-overflow: ellipsis;

&.dx-#{$widget-name}-sticky-column-left {
left: 0;
right: 0;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,7 @@ $fluent-grid-base-group-panel-message-line-height: $fluent-button-text-line-heig
> .dx-master-detail-cell {
padding: $grid-masterdetail-padding;
}

> .dx-#{$widget-name}-group-space,
.dx-master-detail-cell:not(.dx-row-lines) {
border-top: $datagrid-border;
Expand Down Expand Up @@ -1178,6 +1179,14 @@ $fluent-grid-base-group-panel-message-line-height: $fluent-button-text-line-heig
.dx-row-removed.dx-row-lines > td {
border-top-width: 0;
}

.dx-master-detail-row > .dx-master-detail-cell {
padding: 0;

> .dx-#{$widget-name}-master-detail-container {
padding: $grid-masterdetail-padding;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ $generic-grid-base-cell-input-height: round($generic-base-line-height * $generic
> .dx-master-detail-cell {
padding: $grid-masterdetail-padding;
}

> .dx-#{$widget-name}-group-space,
.dx-master-detail-cell:not(.dx-row-lines) {
border-top: $datagrid-border;
Expand Down Expand Up @@ -1064,6 +1065,14 @@ $generic-grid-base-cell-input-height: round($generic-base-line-height * $generic
.dx-row-removed.dx-row-lines > td {
border-top-width: 0;
}

.dx-master-detail-row > .dx-master-detail-cell {
padding: 0;

> .dx-#{$widget-name}-master-detail-container {
padding: $grid-masterdetail-padding;
}
}
}

.dx-#{$widget-name}-sticky-columns .dx-#{$widget-name}-draggable-column {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ $material-grid-base-group-panel-message-line-height: $material-button-text-line-
> .dx-master-detail-cell {
padding: $grid-masterdetail-padding;
}

> .dx-#{$widget-name}-group-space,
.dx-master-detail-cell:not(.dx-row-lines) {
border-top: $datagrid-border;
Expand Down Expand Up @@ -1160,6 +1161,14 @@ $material-grid-base-group-panel-message-line-height: $material-button-text-line-
.dx-row-removed.dx-row-lines > td {
border-top-width: 0;
}

.dx-master-detail-row > .dx-master-detail-cell {
padding: 0;

> .dx-#{$widget-name}-master-detail-container {
padding: $grid-masterdetail-padding;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const CLASSES = {
detailRow: 'dx-master-detail-row',
detailCell: 'dx-master-detail-cell',
detailContainer: 'master-detail-container',
cellFocusDisabledClass: 'dx-cell-focus-disabled',
rowLines: 'dx-row-lines',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { afterEach } from 'node:test';

import { describe, expect, it } from '@jest/globals';
import $ from 'jquery';

import type { Properties as DataGridProperties } from '../../../../ui/data_grid';
import DataGrid from '../../../../ui/data_grid';

const SELECTORS = {
gridContainer: '#gridContainer',
detailCell: 'dx-master-detail-cell',
detailContainer: 'dx-datagrid-master-detail-container',
};

const GRID_CONTAINER_ID = 'gridContainer';

const createDataGrid = async (
options: DataGridProperties = {},
): Promise<{ $container: JQuery; instance: DataGrid }> => new Promise((resolve) => {
const $container = $('<div>')
.attr('id', GRID_CONTAINER_ID)
.appendTo(document.body);

const instance = new DataGrid($container.get(0) as HTMLDivElement, options);

const contentReadyHandler = (): void => {
resolve({ $container, instance });
instance.off('contentReady', contentReadyHandler);
};

instance.on('contentReady', contentReadyHandler);
});

describe('GridCore master_detail', () => {
afterEach(() => {
const $container = $(SELECTORS.gridContainer);
const dataGrid = ($container as any).dxDataGrid('instance') as DataGrid;

dataGrid.dispose();
$container.remove();
});

describe('master detail container', () => {
it('container is td element', async () => {
let containerElement: HTMLElement | undefined;

await createDataGrid({
columns: ['field1', 'field2'],
dataSource: [{ field1: 'value1', field2: 'value2' }],
masterDetail: {
enabled: true,
autoExpandAll: true,
template: (container) => {
containerElement = container;
},
},
});

expect(containerElement?.tagName).toBe('TD');
expect(containerElement?.classList).toContain(SELECTORS.detailCell);
});

it('container is div element when sticky columns enabled', async () => {
let containerElement: HTMLElement | undefined;

await createDataGrid({
columns: [{ dataField: 'field1', fixed: true }, 'field2'],
dataSource: [{ field1: 'value1', field2: 'value2' }],
masterDetail: {
enabled: true,
autoExpandAll: true,
template: (container) => {
containerElement = container;
},
},
});

expect(containerElement?.parentElement?.tagName).toBe('TD');
expect(containerElement?.parentElement?.classList).toContain(SELECTORS.detailCell);
expect(containerElement?.tagName).toBe('DIV');
expect(containerElement?.classList).toContain(SELECTORS.detailContainer);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ import type { ResizingController } from '@ts/grids/grid_core/views/m_grid_view';
import type { RowsView } from '@ts/grids/grid_core/views/m_rows_view';

import gridCoreUtils from '../m_utils';

const MASTER_DETAIL_CELL_CLASS = 'dx-master-detail-cell';
const MASTER_DETAIL_ROW_CLASS = 'dx-master-detail-row';
const CELL_FOCUS_DISABLED_CLASS = 'dx-cell-focus-disabled';
const ROW_LINES_CLASS = 'dx-row-lines';
import { CLASSES } from './const';
import { isDetailRow } from './utils';

const columns = (Base: ModuleType<ColumnsController>) => class ColumnsMasterDetailExtender extends Base {
protected _getExpandColumnsCore() {
Expand Down Expand Up @@ -238,7 +235,7 @@ const resizing = (Base: ModuleType<ResizingController>) => class ResizingMasterD
}

private _updateParentDataGrids($element) {
const $masterDetailRow = $element.closest(`.${MASTER_DETAIL_ROW_CLASS}`);
const $masterDetailRow = $element.closest(`.${CLASSES.detailRow}`);

if ($masterDetailRow.length) {
when(this._updateMasterDataGrid($masterDetailRow, $element)).done(() => {
Expand Down Expand Up @@ -312,13 +309,21 @@ const resizing = (Base: ModuleType<ResizingController>) => class ResizingMasterD

protected _toggleBestFitMode(isBestFit) {
super._toggleBestFitMode.apply(this, arguments as any);
if (this.option('masterDetail.template')) {
const $rowsTable = this._rowsView.getTableElement();
if ($rowsTable) {
$rowsTable
.find('.dx-master-detail-cell')
.css('maxWidth', isBestFit ? 0 : '');
}

const hasMasterDetailTemplate = this.option('masterDetail.template');

if (!hasMasterDetailTemplate) {
return;
}

const $rowsTable = this._rowsView.getTableElement();

if ($rowsTable) {
const detailSelector = `.${this.addWidgetPrefix(CLASSES.detailContainer)}, .${CLASSES.detailCell}`;

$rowsTable
.find(detailSelector)
.css('maxWidth', isBestFit ? 0 : '');
}
}
};
Expand All @@ -340,16 +345,16 @@ const rowsView = (Base: ModuleType<RowsView>) => class RowsViewMasterDetailExten
return template;
}

protected _isDetailRow(row) {
return row?.rowType && row.rowType.indexOf('detail') === 0;
}

protected _createRow(row) {
const $row = super._createRow.apply(this, arguments as any);
const isDetailRowResult = isDetailRow(row);

if (isDetailRowResult) {
const showRowLines = this.option('showRowLines');

if (row && this._isDetailRow(row)) {
this.option('showRowLines') && $row.addClass(ROW_LINES_CLASS);
$row.addClass(MASTER_DETAIL_ROW_CLASS);
$row
.addClass(CLASSES.detailRow)
.toggleClass(CLASSES.rowLines, showRowLines);

if (isDefined(row.visible)) {
$row.toggle(row.visible);
Expand All @@ -360,8 +365,9 @@ const rowsView = (Base: ModuleType<RowsView>) => class RowsViewMasterDetailExten

protected _renderCells($row, options) {
const { row } = options;
const isDetailRowResult = isDetailRow(row);

if (row.rowType && this._isDetailRow(row)) {
if (isDetailRowResult) {
if (this._needRenderCell(0, options.columnIndices)) {
this._renderMasterDetailCell($row, row, options);
}
Expand All @@ -383,8 +389,8 @@ const rowsView = (Base: ModuleType<RowsView>) => class RowsViewMasterDetailExten
});

$detailCell
.addClass(CELL_FOCUS_DISABLED_CLASS)
.addClass(MASTER_DETAIL_CELL_CLASS)
.addClass(CLASSES.cellFocusDisabledClass)
.addClass(CLASSES.detailCell)
.attr('colSpan', visibleColumns.length);

const isEditForm = row.isEditing;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function isDetailRow(row): boolean {
const rowType = row?.rowType;
return rowType === 'detail' || rowType === 'detailAdaptive';
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import type { ModuleType } from '../m_types';
import gridCoreUtils from '../m_utils';
import { CLASSES as MASTER_DETAIL_CLASSES } from '../master_detail/const';
import { isDetailRow } from '../master_detail/utils';
import type { ColumnsView } from '../views/m_columns_view';
import type { RowsView } from '../views/m_rows_view';
import { isGroupRow } from '../views/m_rows_view';
Expand Down Expand Up @@ -341,7 +342,6 @@ const columnHeadersView = (
});
}

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
items = items || [];
items.push(
{
Expand Down Expand Up @@ -379,19 +379,26 @@ const rowsView = (
const $detailCell: dxElementWrapper = super._renderMasterDetailCell($row, row, options);

if (this.hasStickyColumns()) {
$detailCell.addClass(this.addWidgetPrefix(CLASSES.stickyColumnLeft));
setWidth($detailCell, this._getMasterDetailWidth());
const detailContainerSelector = `.${this.addWidgetPrefix(MASTER_DETAIL_CLASSES.detailContainer)}`;
const $detailContainer = $detailCell.find(detailContainerSelector);

$detailContainer.addClass(this.addWidgetPrefix(CLASSES.stickyColumnLeft));

setWidth($detailContainer, this._getMasterDetailWidth());
}

return $detailCell;
}

private _updateMasterDetailWidths() {
const $detailContainers = this._getRowElements()
.children(`.${MASTER_DETAIL_CLASSES.detailCell}`)
.children(`.${this.addWidgetPrefix(MASTER_DETAIL_CLASSES.detailContainer)}`);

const width = this._getMasterDetailWidth();
const $masterDetailCells = this._getRowElements().children('.dx-master-detail-cell');

setWidth(
$masterDetailCells,
$detailContainers,
`${width}px`,
);
}
Expand Down Expand Up @@ -446,12 +453,18 @@ const rowsView = (
}

protected _renderCellContent($cell, options, renderOptions) {
if (!isGroupRow(options) || !this.hasStickyColumns()) {
const hasStickyColumns = this.hasStickyColumns();
const isGroupRowResult = isGroupRow(options);
const isDetailRowResult = isDetailRow(options);
const needWrapContent = isGroupRowResult || isDetailRowResult;

if (!hasStickyColumns || !needWrapContent) {
return super._renderCellContent($cell, options, renderOptions);
}

const $container = $('<div>')
.addClass(this.addWidgetPrefix(CLASSES.groupRowContainer))
.toggleClass(this.addWidgetPrefix(CLASSES.groupRowContainer), isGroupRowResult)
.toggleClass(this.addWidgetPrefix(MASTER_DETAIL_CLASSES.detailContainer), isDetailRowResult)
.appendTo($cell);

return super._renderCellContent($container, options, renderOptions);
Expand Down
Loading