Skip to content

Commit c4dd6df

Browse files
authored
T1312423 - CardView – Missing translation for Filter Panel title and related texts (DevExpress#32705)
1 parent ad338d3 commit c4dd6df

48 files changed

Lines changed: 1376 additions & 263 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { PopupModel } from '@ts/ui/__tests__/__mock__/model/popup';
2+
import { TreeViewModel } from '@ts/ui/__tests__/__mock__/model/tree_view';
3+
4+
const CLASSES = {
5+
filterBuilder: 'dx-filterbuilder',
6+
groupOperation: 'dx-filterbuilder-group-operation',
7+
treeView: 'dx-treeview',
8+
popupWrapper: 'dx-popup-wrapper',
9+
itemField: 'dx-filterbuilder-item-field',
10+
itemOperation: 'dx-filterbuilder-item-operation',
11+
};
12+
13+
export class FilterBuilderModel extends PopupModel {
14+
public getElement(): HTMLElement {
15+
const content = this.getOverlayContent();
16+
return content?.querySelector<HTMLElement>(`.${CLASSES.filterBuilder}`) as HTMLElement;
17+
}
18+
19+
public getGroupOperationButton(): HTMLElement {
20+
const element = this.getElement();
21+
return element.querySelector<HTMLElement>(`.${CLASSES.groupOperation}`) as HTMLElement;
22+
}
23+
24+
public getFieldButton(): HTMLElement {
25+
const element = this.getElement();
26+
return element.querySelector<HTMLElement>(`.${CLASSES.itemField}`) as HTMLElement;
27+
}
28+
29+
public getOperationButton(): HTMLElement {
30+
const element = this.getElement();
31+
return element.querySelector<HTMLElement>(`.${CLASSES.itemOperation}`) as HTMLElement;
32+
}
33+
34+
public getTreeView(): TreeViewModel {
35+
const popups = Array.from(document.body.querySelectorAll<HTMLElement>(`.${CLASSES.popupWrapper}`));
36+
const treeViewPopup = popups.find((popup) => popup.querySelector(`.${CLASSES.treeView}`));
37+
const treeViewElement = treeViewPopup?.querySelector<HTMLElement>(`.${CLASSES.treeView}`);
38+
39+
return new TreeViewModel(treeViewElement as HTMLElement);
40+
}
41+
}

packages/devextreme/js/__internal/filter_builder/m_filter_builder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,12 @@ class FilterBuilder extends Widget<any> {
608608

609609
_getGroupOperations(criteria) {
610610
let groupOperations = this.option('groupOperations');
611-
const groupOperationDescriptions = this.option('groupOperationDescriptions');
611+
const groupOperationDescriptions = {
612+
and: this.option('groupOperationDescriptions.and') ?? messageLocalization.format('dxFilterBuilder-and'),
613+
or: this.option('groupOperationDescriptions.or') ?? messageLocalization.format('dxFilterBuilder-or'),
614+
notAnd: this.option('groupOperationDescriptions.notAnd') ?? messageLocalization.format('dxFilterBuilder-notAnd'),
615+
notOr: this.option('groupOperationDescriptions.notOr') ?? messageLocalization.format('dxFilterBuilder-notOr'),
616+
};
612617

613618
if (!groupOperations || !groupOperations.length) {
614619
groupOperations = [getGroupValue(criteria).replace('!', 'not')];

packages/devextreme/js/__internal/grids/data_grid/__tests__/__mock__/model/data_grid.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { Column } from '@js/ui/data_grid';
22
import DataGrid from '@js/ui/data_grid';
3+
import { DataGridBaseModel } from '@ts/grids/grid_core/__tests__/__mock__/model/data_grid_base';
34

4-
import { GridCoreModel } from '../../../../grid_core/__tests__/__mock__/model/grid_core';
5-
6-
export class DataGridModel extends GridCoreModel<DataGrid> {
5+
export class DataGridModel extends DataGridBaseModel<DataGrid> {
76
protected NAME = 'dxDataGrid';
87

98
public getInstance(): DataGrid {

packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/column_chooser.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,22 @@
1+
import { PopupModel } from '@ts/ui/__tests__/__mock__/model/popup';
12
import { TreeViewModel } from '@ts/ui/__tests__/__mock__/model/tree_view';
23

3-
const CLASSES = {
4-
columnChooser: 'dx-datagrid-column-chooser',
5-
columnChooserList: 'dx-datagrid-column-chooser-list',
6-
popupWrapper: 'dx-popup-wrapper',
7-
};
4+
export class ColumnChooserModel extends PopupModel {
5+
private readonly columnChooserListClass: string;
86

9-
export class ColumnChooserModel {
10-
constructor(protected readonly root: HTMLElement) {}
11-
12-
private getPopupWrapper(): HTMLElement | null {
13-
return document.body.querySelector(`.${CLASSES.popupWrapper}.${CLASSES.columnChooser}`);
14-
}
15-
16-
private getOverlay(): HTMLElement | null {
17-
const wrapper = this.getPopupWrapper();
18-
return wrapper?.querySelector('.dx-overlay-content') ?? null;
7+
constructor(widgetName: string) {
8+
super();
9+
this.columnChooserListClass = `dx-${widgetName}-column-chooser-list`;
1910
}
2011

2112
private getTreeView(): TreeViewModel | null {
22-
const overlay = this.getOverlay();
13+
const overlay = this.getOverlayContent();
2314
if (!overlay) return null;
2415

25-
const treeViewElement = overlay.querySelector(`.${CLASSES.columnChooserList}`) as HTMLElement;
16+
const treeViewElement = overlay.querySelector(`.${this.columnChooserListClass}`) as HTMLElement;
2617
return treeViewElement ? new TreeViewModel(treeViewElement) : null;
2718
}
2819

29-
public isVisible(): boolean {
30-
return this.getOverlay() !== null;
31-
}
32-
3320
public searchColumn(text: string): void {
3421
const treeView = this.getTreeView();
3522
treeView?.setSearchValue(text);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { PopupModel } from '@ts/ui/__tests__/__mock__/model/popup';
2+
3+
const SELECTORS = {
4+
dialogMessage: 'dx-dialog-message',
5+
cancelButton: '[aria-label="No"]',
6+
};
7+
8+
export class ConfirmationDialogModel extends PopupModel {
9+
public getMessage(): string {
10+
const overlay = this.getOverlayContent();
11+
const messageElement = overlay.querySelector(`.${SELECTORS.dialogMessage}`) as HTMLElement;
12+
return messageElement.textContent ?? '';
13+
}
14+
15+
public getCancelButton(): HTMLElement {
16+
const element = this.getElement();
17+
return element.querySelector(SELECTORS.cancelButton) as HTMLElement;
18+
}
19+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
import type { GridBase } from '@js/common/grids';
4+
5+
import { GridCoreModel } from './grid_core';
6+
7+
export abstract class DataGridBaseModel<
8+
TInstance extends GridBase = GridBase,
9+
> extends GridCoreModel<TInstance> {
10+
public apiColumnOption(id: string, name?: string, value?: any): any {
11+
const instance = this.getInstance();
12+
13+
switch (arguments.length) {
14+
case 1:
15+
return instance.columnOption(id);
16+
case 2:
17+
return instance.columnOption(id, name);
18+
default:
19+
instance.columnOption(id, name as string, value);
20+
return undefined;
21+
}
22+
}
23+
24+
public async apiRefresh(): Promise<void> {
25+
await this.getInstance().refresh();
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { PopupModel } from '../../../../../ui/__tests__/__mock__/model/popup';
2+
3+
const SELECTORS = {
4+
textEditorInput: 'dx-texteditor-input',
5+
item: 'dx-item',
6+
toolbar: 'dx-toolbar',
7+
saveButton: '[aria-label*="Save"]',
8+
};
9+
10+
export class EditFormModel extends PopupModel {
11+
constructor(protected readonly root: HTMLElement | null) {
12+
super();
13+
}
14+
15+
public getSaveButton(): HTMLElement {
16+
const overlay = this.getOverlayContent();
17+
const toolbar = overlay?.querySelector(`.${SELECTORS.toolbar}`);
18+
return toolbar?.querySelector(SELECTORS.saveButton) as HTMLElement;
19+
}
20+
21+
public getItem(id: string): HTMLElement | null {
22+
return this.root?.querySelector(`.${SELECTORS.textEditorInput}[id*=_${id}]`) ?? null;
23+
}
24+
25+
public getItems(): NodeListOf<HTMLElement> | null {
26+
return this.root?.querySelectorAll(`.${SELECTORS.item}`) ?? null;
27+
}
28+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { CheckBoxModel } from '../../../../../ui/__tests__/__mock__/model/checkbox';
2+
3+
export class FilterPanelModel {
4+
private readonly filterPanelClass: string;
5+
6+
private readonly filterPanelTextClass: string;
7+
8+
private readonly filterPanelClearFilterClass: string;
9+
10+
private readonly filterPanelCheckboxClass: string;
11+
12+
private readonly root: HTMLElement;
13+
14+
constructor(root: HTMLElement, prefix: string) {
15+
this.filterPanelClass = `dx-${prefix}-filter-panel`;
16+
this.filterPanelTextClass = `dx-${prefix}-filter-panel-text`;
17+
this.filterPanelClearFilterClass = `dx-${prefix}-filter-panel-clear-filter`;
18+
this.filterPanelCheckboxClass = `dx-${prefix}-filter-panel-checkbox`;
19+
this.root = root;
20+
}
21+
22+
public getElement(): HTMLElement {
23+
return this.root.querySelector(`.${this.filterPanelClass}`) as HTMLElement;
24+
}
25+
26+
public getCreateFilterButton(): HTMLElement {
27+
return this.getElement().querySelector(`.${this.filterPanelTextClass}`) as HTMLElement;
28+
}
29+
30+
public getClearFilterButton(): HTMLElement {
31+
return this.getElement().querySelector(`.${this.filterPanelClearFilterClass}`) as HTMLElement;
32+
}
33+
34+
public getEnableFilterCheckbox(): CheckBoxModel {
35+
const checkboxElement = this.getElement().querySelector(`.${this.filterPanelCheckboxClass}`) as HTMLElement;
36+
return new CheckBoxModel(checkboxElement);
37+
}
38+
39+
public isVisible(): boolean {
40+
const element = this.getElement();
41+
return element !== null && element.style.display !== 'none';
42+
}
43+
}

packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/grid_core.ts

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
1-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2-
/* eslint-disable @typescript-eslint/no-explicit-any */
31
import type { GridBase } from '@js/common/grids';
42
import type { dxElementWrapper } from '@js/core/renderer';
53
import $ from '@js/core/renderer';
4+
import type CardView from '@js/ui/card_view';
5+
import { FilterBuilderModel } from '@ts/filter_builder/__tests__/__mock__/model/filter_builder';
6+
import { PagerModel } from '@ts/pagination/__tests__/__mock__/model/pager';
7+
import { LoadPanelModel } from '@ts/ui/__tests__/__mock__/model/load_panel';
68

79
import { DataCellModel } from './cell/data_cell';
810
import { HeaderCellModel } from './cell/header_cell';
911
import { ColumnChooserModel } from './column_chooser';
12+
import { ConfirmationDialogModel } from './confirmation_dialog';
13+
import { EditFormModel } from './edit_form';
14+
import { FilterPanelModel } from './filter_panel';
1015
import { DataRowModel } from './row/data_row';
1116

1217
const SELECTORS = {
1318
headerRowClass: 'dx-header-row',
1419
dataRowClass: 'dx-data-row',
1520
groupRowClass: 'dx-group-row',
21+
loadPanel: 'dx-loadpanel',
22+
editForm: 'edit-form',
1623
headerCellIndicators: 'dx-column-indicators',
1724
headerCellFilter: 'dx-header-filter',
1825
revertButton: 'dx-revert-button',
1926
};
2027

21-
export abstract class GridCoreModel<TInstance extends GridBase = GridBase> {
28+
export abstract class GridCoreModel<TInstance = GridBase | CardView> {
2229
protected abstract NAME: string;
2330

2431
constructor(protected readonly root: HTMLElement) {}
2532

33+
private getWidgetName(): string {
34+
return this.NAME.slice(2).toLowerCase();
35+
}
36+
37+
protected getFilterPanelPrefix(): string {
38+
return this.getWidgetName();
39+
}
40+
2641
public getHeaderCells(): NodeListOf<HTMLElement> {
2742
return this.root.querySelectorAll(`.${SELECTORS.headerRowClass} > td`);
2843
}
@@ -39,18 +54,6 @@ export abstract class GridCoreModel<TInstance extends GridBase = GridBase> {
3954
return this.root.querySelectorAll(`.${SELECTORS.groupRowClass}`);
4055
}
4156

42-
public apiColumnOption(id: string, name?: string, value?: any): any {
43-
switch (arguments.length) {
44-
case 1:
45-
return this.getInstance().columnOption(id);
46-
case 2:
47-
return this.getInstance().columnOption(id, name);
48-
default:
49-
this.getInstance().columnOption(id, name as string, value);
50-
return undefined;
51-
}
52-
}
53-
5457
public getHeaderByText(text: string): dxElementWrapper {
5558
return $(Array.from(this.getHeaderCells()).find((el) => $(el).text().includes(text)));
5659
}
@@ -79,13 +82,50 @@ export abstract class GridCoreModel<TInstance extends GridBase = GridBase> {
7982
}
8083

8184
public addWidgetPrefix(classNames: string): string {
82-
const componentName = this.NAME;
85+
const widgetName = this.getWidgetName();
86+
return `dx-${widgetName}${classNames ? `-${classNames}` : ''}`;
87+
}
88+
89+
public getLoadPanel(): LoadPanelModel {
90+
return new LoadPanelModel(document.body.querySelector(`.${SELECTORS.loadPanel}`));
91+
}
8392

84-
return `dx-${componentName.slice(2).toLowerCase()}${classNames ? `-${classNames}` : ''}`;
93+
public getEditForm(): EditFormModel {
94+
return new EditFormModel(this.root.querySelector(`.${this.addWidgetPrefix(SELECTORS.editForm)}`));
8595
}
8696

8797
public getColumnChooser(): ColumnChooserModel {
88-
return new ColumnChooserModel(this.root);
98+
return new ColumnChooserModel(this.getWidgetName());
99+
}
100+
101+
public getFilterPanel(): FilterPanelModel {
102+
return new FilterPanelModel(this.root, this.getFilterPanelPrefix());
103+
}
104+
105+
public getFilterBuilder(): FilterBuilderModel {
106+
return new FilterBuilderModel();
107+
}
108+
109+
public getPager(): PagerModel {
110+
return new PagerModel(this.root);
111+
}
112+
113+
public getConfirmationDialog(): ConfirmationDialogModel {
114+
return new ConfirmationDialogModel();
115+
}
116+
117+
public apiOption(name: string): unknown;
118+
public apiOption(name: string, value: unknown): void;
119+
public apiOption(name: string, value?: unknown): unknown {
120+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
121+
const instance = this.getInstance() as any;
122+
123+
if (arguments.length === 1) {
124+
return instance.option(name);
125+
}
126+
127+
instance.option(name, value);
128+
return undefined;
89129
}
90130

91131
public getHeaderCellFilter(columnIndex: number): dxElementWrapper {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { PopupModel } from '@ts/ui/__tests__/__mock__/model/popup';
2+
3+
const CLASSES = {
4+
headerFilterMenu: 'dx-header-filter-menu',
5+
listItemContent: 'dx-list-item-content',
6+
};
7+
8+
const SELECTORS = {
9+
okButton: '[role="button"][aria-label*="OK"]',
10+
};
11+
12+
export class HeaderFilterModel extends PopupModel {
13+
public getOKButton(): HTMLElement {
14+
const popup = this.getPopupWrapper();
15+
return popup?.querySelector(SELECTORS.okButton) as HTMLElement;
16+
}
17+
18+
public getListItems(): HTMLElement[] {
19+
const popup = this.getPopupWrapper();
20+
const listItems = popup?.querySelectorAll(`.${CLASSES.listItemContent}`);
21+
return Array.from(listItems ?? []) as HTMLElement[];
22+
}
23+
24+
public getListItem(index: number): HTMLElement {
25+
const listItems = this.getListItems();
26+
return listItems[index];
27+
}
28+
}

0 commit comments

Comments
 (0)