Skip to content

Commit

Permalink
GridCore: Refactoring of the fluent borders related code. (#26393)
Browse files Browse the repository at this point in the history
  • Loading branch information
williamvinogradov authored Jan 2, 2024
1 parent d136b0f commit fd8c47d
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 82 deletions.
94 changes: 12 additions & 82 deletions packages/devextreme/js/__internal/grids/grid_core/m_modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Callbacks from '@js/core/utils/callbacks';
// @ts-expect-error
import { grep } from '@js/core/utils/common';
import { each } from '@js/core/utils/iterator';
import { isDefined, isFunction } from '@js/core/utils/type';
import { isFunction } from '@js/core/utils/type';
import { hasWindow } from '@js/core/utils/window';
import messageLocalization from '@js/localization/message';
import errors from '@js/ui/widget/ui.errors';
Expand All @@ -16,11 +16,11 @@ import type {
View as ViewType,
ViewController as ViewControllerType,
} from './m_types';
import type { ViewsWithBorder } from './views/utils/update_views_borders';
import { updateViewsBorders } from './views/utils/update_views_borders';

const WIDGET_WITH_LEGACY_CONTAINER_NAME = 'dxDataGrid';

const BORDERED_VIEWS = ['columnHeadersView', 'rowsView', 'footerView', 'filterPanelView'];

const ModuleItem = Class.inherit({
_endUpdateCore() { },

Expand Down Expand Up @@ -262,83 +262,13 @@ const View: ModuleType<ViewType> = ModuleItem.inherit({
return this.component._views[name];
},

getFirstVisibleViewElement() {
const columnHeaderView = this.getView('columnHeadersView');
if (columnHeaderView && columnHeaderView.isVisible()) {
return columnHeaderView.element();
}

return this.getView('rowsView').element();
},

getLastVisibleViewElement() {
const filterPanelView = this.getView('filterPanelView');
if (filterPanelView && filterPanelView.isVisible()) {
return filterPanelView.element();
}

const footerView = this.getView('footerView');
if (footerView && footerView.isVisible()) {
return footerView.element();
}

return this.getView('rowsView').element();
},

getViewElementWithClass(className) {
const borderedView = BORDERED_VIEWS.map((viewName) => this.getView(viewName))
.filter((view) => view && view.element())
.find((view) => view.element().hasClass(className));

return borderedView && borderedView.element();
},

updateBorderedViews() {
const BORDERED_TOP_VIEW_CLASS = 'dx-bordered-top-view';
const BORDERED_BOTTOM_VIEW_CLASS = 'dx-bordered-bottom-view';

const oldFirstBorderedElement = this.getViewElementWithClass(BORDERED_TOP_VIEW_CLASS);
const oldLastBorderedElement = this.getViewElementWithClass(BORDERED_BOTTOM_VIEW_CLASS);
const newFirstBorderedElement = this.getFirstVisibleViewElement();
const newLastBorderedElement = this.getLastVisibleViewElement();

if (oldFirstBorderedElement && !oldFirstBorderedElement.is(newFirstBorderedElement)) {
oldFirstBorderedElement.removeClass(BORDERED_TOP_VIEW_CLASS);
}

if (oldLastBorderedElement && !oldLastBorderedElement.is(newLastBorderedElement)) {
oldLastBorderedElement.removeClass(BORDERED_BOTTOM_VIEW_CLASS);
}

if (!newFirstBorderedElement.hasClass(BORDERED_TOP_VIEW_CLASS)) {
newFirstBorderedElement.addClass(BORDERED_TOP_VIEW_CLASS);
}

if (!newLastBorderedElement.hasClass(BORDERED_BOTTOM_VIEW_CLASS)) {
newLastBorderedElement.addClass(BORDERED_BOTTOM_VIEW_CLASS);
}
},

isViewsStateValid() {
if (this.component._views) {
if (!BORDERED_VIEWS.includes(this.name)) {
return false;
}

const rowsView = this.getView('rowsView');
if (!(rowsView && isDefined(rowsView.element?.()))) {
return false;
}

const optionalViews = ['columnHeadersView', 'footerView', 'filterPanelView']
.map((viewName) => this.getView(viewName))
.filter((view) => view && view.isVisible?.());
const isOptionalViewsRendered = optionalViews.every((view) => view && isDefined(view.element()));

return isOptionalViewsRendered;
}

return false;
_getBorderedViews(): ViewsWithBorder {
return {
columnHeadersView: this.component._views.columnHeadersView,
rowsView: this.component._views.rowsView,
filterPanelView: this.component._views.filterPanelView,
footerView: this.component._views.footerView,
};
},

render($parent, options) {
Expand All @@ -356,8 +286,8 @@ const View: ModuleType<ViewType> = ModuleItem.inherit({

$element.toggleClass('dx-hidden', !isVisible);

if (this.isViewsStateValid()) {
this.updateBorderedViews();
if (this.component._views) {
updateViewsBorders(this.name, this._getBorderedViews());
}

if (isVisible) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { dxElementWrapper } from '@js/core/renderer';
import { isDefined } from '@js/core/utils/type';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type View = any;

// TODO: Move to the grid_core/m_types views interface.
export interface ViewsWithBorder {
columnHeadersView: View;
rowsView: View;
filterPanelView: View;
footerView: View;
}

const CLASSES = {
borderedTop: 'dx-bordered-top-view',
borderedBottom: 'dx-bordered-bottom-view',
};

const getFirstVisibleViewElement = ({
columnHeadersView,
rowsView,
}: ViewsWithBorder): dxElementWrapper => {
if (columnHeadersView?.isVisible()) {
return columnHeadersView.element();
}

return rowsView.element();
};

const getLastVisibleViewElement = ({
filterPanelView,
footerView,
rowsView,
}: ViewsWithBorder): dxElementWrapper => {
if (filterPanelView?.isVisible()) {
return filterPanelView.element();
}

if (footerView?.isVisible()) {
return footerView.element();
}

return rowsView.element();
};

const getViewElementWithClass = (
viewsWithBorder: ViewsWithBorder,
className: string,
): dxElementWrapper | null => {
const borderedView = Object.values(viewsWithBorder)
.find((view) => view?.element()?.hasClass(className));

return borderedView?.element() ?? null;
};

const shouldUpdateBorders = (
viewName: string,
viewsWithBorder: ViewsWithBorder,
): boolean => {
if (!Object.keys(viewsWithBorder).includes(viewName)) {
return false;
}

const { rowsView, ...otherViews } = viewsWithBorder;
if (!isDefined(rowsView?.element?.())) {
return false;
}

return Object.values(otherViews)
.filter((view) => view?.isVisible?.())
.every((view) => isDefined(view?.element()));
};

export const updateViewsBorders = (
viewName: string,
viewsWithBorder: ViewsWithBorder,
): void => {
if (!shouldUpdateBorders(viewName, viewsWithBorder)) {
return;
}

const $oldFirst = getViewElementWithClass(viewsWithBorder, CLASSES.borderedTop);
const $oldLast = getViewElementWithClass(viewsWithBorder, CLASSES.borderedBottom);
const $newFirst = getFirstVisibleViewElement(viewsWithBorder);
const $newLast = getLastVisibleViewElement(viewsWithBorder);

// @ts-expect-error The dxElementWrapper's "is" method is badly typed.
if ($oldFirst && !$oldFirst.is($newFirst)) {
$oldFirst.removeClass(CLASSES.borderedTop);
}

// @ts-expect-error The dxElementWrapper's "is" method is badly typed.
if ($oldLast && !$oldLast.is($newLast)) {
$oldLast.removeClass(CLASSES.borderedBottom);
}

if (!$newFirst.hasClass(CLASSES.borderedTop)) {
$newFirst.addClass(CLASSES.borderedTop);
}

if (!$newLast.hasClass(CLASSES.borderedBottom)) {
$newLast.addClass(CLASSES.borderedBottom);
}
};

0 comments on commit fd8c47d

Please sign in to comment.