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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from '@jest/globals';
import type { CustomOperation, Field } from '@js/ui/filter_builder';

import { getCurrentValueText } from '../m_utils';
import { getCurrentValueText, getFilterOperations } from '../m_utils';

describe('Formatting', () => {
it('empty string', () => {
Expand Down Expand Up @@ -107,3 +107,47 @@ describe('Formatting', () => {
expect(getCurrentValueText(field, value, null)).toBe('9/5/2017, 12:30 PM');
});
});

describe('getFilterOperations', () => {
it('returns the default operations of the data type', () => {
expect(getFilterOperations({ dataType: 'boolean' })).toEqual(['=', '<>', 'isblank', 'isnotblank']);
});

it('returns a copy of the default operations', () => {
getFilterOperations({ dataType: 'boolean' }).push('custom');

expect(getFilterOperations({ dataType: 'boolean' })).toEqual(['=', '<>', 'isblank', 'isnotblank']);
});

it('returns a copy of the field operations', () => {
const filterOperations = ['=', '<>'];

const result = getFilterOperations({ filterOperations });
result.push('custom');

expect(result).not.toBe(filterOperations);
expect(filterOperations).toEqual(['=', '<>']);
});

it('falls back to the default operations for an empty list', () => {
expect(getFilterOperations({ dataType: 'object', filterOperations: [] })).toEqual(['isblank', 'isnotblank']);
});

it('returns an empty list for an unknown data type', () => {
expect(getFilterOperations({ dataType: 'unknown' })).toEqual([]);
expect(getFilterOperations({ dataType: 'unknown', filterOperations: [] })).toEqual([]);
expect(getFilterOperations({ dataType: 'unknown', filterOperations: null })).toEqual([]);
});

it('keeps null operations', () => {
const filterOperations = ['=', null, '<>'] as string[];

expect(getFilterOperations({ filterOperations })).toEqual(['=', null, '<>']);
});

it('skips undefined operations', () => {
const filterOperations = ['=', undefined, '<>'] as string[];

expect(getFilterOperations({ filterOperations })).toEqual(['=', '<>']);
});
});
93 changes: 68 additions & 25 deletions packages/devextreme/js/__internal/filter_builder/m_between.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { dxElementWrapper } from '@js/core/renderer';
import $ from '@js/core/renderer';
import { extend } from '@js/core/utils/extend';
import type { CustomOperation, Field } from '@js/ui/filter_builder';

const FILTER_BUILDER_RANGE_CLASS = 'dx-filterbuilder-range';
const FILTER_BUILDER_RANGE_START_CLASS = `${FILTER_BUILDER_RANGE_CLASS}-start`;
Expand All @@ -8,42 +10,83 @@ const FILTER_BUILDER_RANGE_SEPARATOR_CLASS = `${FILTER_BUILDER_RANGE_CLASS}-sepa

const SEPARATOR = '\u2013';

function editorTemplate(conditionInfo, container) {
type RangeValue = (string | number | Date | null | undefined)[];

interface RangeConditionInfo {
field: Field;
value?: RangeValue;
setValue: (value: RangeValue) => void;
}

export interface EditorFactoryOwner {
_editorFactory: {
createEditor: (
this: EditorFactoryOwner,
container: dxElementWrapper,
options: object,
) => void;
};
}

export type BetweenOperation = CustomOperation & {
name: string;
notForLookup: boolean;
valueSeparator: string;
};

function editorTemplate(
this: EditorFactoryOwner,
conditionInfo: RangeConditionInfo,
container: dxElementWrapper,
): void {
const $editorStart = $('<div>').addClass(FILTER_BUILDER_RANGE_START_CLASS);
const $editorEnd = $('<div>').addClass(FILTER_BUILDER_RANGE_END_CLASS);
let values = conditionInfo.value || [];
const getStartValue = function (values) {
return values && values.length > 0 ? values[0] : null;
let values: RangeValue = conditionInfo.value || [];
const getStartValue = function (rangeValues: RangeValue | undefined): RangeValue[number] {
return rangeValues && rangeValues.length > 0 ? rangeValues[0] : null;
};
const getEndValue = function (values) {
return values && values.length === 2 ? values[1] : null;
const getEndValue = function (rangeValues: RangeValue | undefined): RangeValue[number] {
return rangeValues && rangeValues.length === 2 ? rangeValues[1] : null;
};

container.append($editorStart);
container.append($('<span>').addClass(FILTER_BUILDER_RANGE_SEPARATOR_CLASS).text(SEPARATOR));
container.append(
$('<span>').addClass(FILTER_BUILDER_RANGE_SEPARATOR_CLASS).text(SEPARATOR),
);
container.append($editorEnd);
container.addClass(FILTER_BUILDER_RANGE_CLASS);

this._editorFactory.createEditor.call(this, $editorStart, extend({}, conditionInfo.field, conditionInfo, {
value: getStartValue(values),
parentType: 'filterBuilder',
setValue(value) {
values = [value, getEndValue(values)];
conditionInfo.setValue(values);
},
}));

this._editorFactory.createEditor.call(this, $editorEnd, extend({}, conditionInfo.field, conditionInfo, {
value: getEndValue(values),
parentType: 'filterBuilder',
setValue(value) {
values = [getStartValue(values), value];
conditionInfo.setValue(values);
},
}));
this._editorFactory.createEditor.call(
this,
$editorStart,
extend({}, conditionInfo.field, conditionInfo, {
value: getStartValue(values),
parentType: 'filterBuilder',
setValue(value: RangeValue[number]) {
values = [value, getEndValue(values)];
conditionInfo.setValue(values);
},
}),
);

this._editorFactory.createEditor.call(
this,
$editorEnd,
extend({}, conditionInfo.field, conditionInfo, {
value: getEndValue(values),
parentType: 'filterBuilder',
setValue(value: RangeValue[number]) {
values = [getStartValue(values), value];
conditionInfo.setValue(values);
},
}),
);
}

export function getConfig(caption, context) {
export function getConfig(
caption: string | undefined,
context: EditorFactoryOwner,
): BetweenOperation {
return {
name: 'between',
caption,
Expand Down
Loading
Loading