diff --git a/src/app/modules/angular-slickgrid/filters/__tests__/compoundDateFilter.spec.ts b/src/app/modules/angular-slickgrid/filters/__tests__/compoundDateFilter.spec.ts index 547a7d5b8..75468e02c 100644 --- a/src/app/modules/angular-slickgrid/filters/__tests__/compoundDateFilter.spec.ts +++ b/src/app/modules/angular-slickgrid/filters/__tests__/compoundDateFilter.spec.ts @@ -30,7 +30,7 @@ describe('CompoundDateFilter', () => { let divContainer: HTMLDivElement; let filter: CompoundDateFilter; let filterArguments: FilterArguments; - let spyGetHeaderRow; + let spyGetHeaderRow: any; let mockColumn: Column; let translate: TranslateService; @@ -88,7 +88,7 @@ describe('CompoundDateFilter', () => { }); it('should throw an error when trying to call init without any arguments', () => { - expect(() => filter.init(null)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); + expect(() => filter.init(null as any)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); }); it('should initialize the filter', () => { @@ -101,10 +101,10 @@ describe('CompoundDateFilter', () => { it('should have a placeholder when defined in its column definition', () => { const testValue = 'test placeholder'; - mockColumn.filter.placeholder = testValue; + mockColumn.filter!.placeholder = testValue; filter.init(filterArguments); - const filterElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; expect(filterElm.placeholder).toBe(testValue); }); @@ -165,19 +165,19 @@ describe('CompoundDateFilter', () => { filter.init(filterArguments); filter.setValues([mockDate], OperatorType.greaterThanOrEqual); - const filterOperatorElm = divContainer.querySelector('.input-group-prepend.operator select'); + const filterOperatorElm = divContainer.querySelector('.input-group-prepend.operator select') as HTMLInputElement; expect(filter.currentDate).toEqual(mockDate); expect(filterOperatorElm.value).toBe('>='); }); it('should trigger input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes - mockColumn.filter.operator = '>'; + mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes + mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; filterInputElm.value = '2001-01-02T16:02:02.239Z'; filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); @@ -189,12 +189,12 @@ describe('CompoundDateFilter', () => { }); it('should pass a different operator then trigger an input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes - mockColumn.filter.operator = '>'; + mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes + mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; filterInputElm.value = '2001-01-02T16:02:02.239Z'; filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); @@ -205,11 +205,11 @@ describe('CompoundDateFilter', () => { it('should create the input filter with a default search term when passed as a filter argument', () => { filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter.operator = '<='; + mockColumn.filter!.operator = '<='; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); @@ -223,11 +223,11 @@ describe('CompoundDateFilter', () => { it('should trigger an operator change event and expect the callback to be called with the searchTerms and operator defined', () => { filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter.operator = '>'; + mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector('.search-filter.filter-finish select'); + const filterSelectElm = divContainer.querySelector('.search-filter.filter-finish select') as HTMLInputElement; filterSelectElm.value = '<='; filterSelectElm.dispatchEvent(new Event('change')); @@ -242,12 +242,12 @@ describe('CompoundDateFilter', () => { translate.use('fr'); filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter.operator = '<='; + mockColumn.filter!.operator = '<='; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; const selectonOptionElms = calendarElm.querySelectorAll('.flatpickr-monthDropdown-months option'); filter.show(); @@ -270,11 +270,11 @@ describe('CompoundDateFilter', () => { translate.use('zz-yy'); // will be trimmed to 2 chars "zz" filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter.operator = '<='; + mockColumn.filter!.operator = '<='; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); filter.show(); @@ -296,7 +296,7 @@ describe('CompoundDateFilter', () => { filter.init(filterArguments); filter.clear(); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); @@ -310,7 +310,7 @@ describe('CompoundDateFilter', () => { filter.init(filterArguments); filter.clear(false); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); @@ -319,13 +319,13 @@ describe('CompoundDateFilter', () => { }); it('should have a value with date & time in the picker when "enableTime" option is set and we trigger a change', () => { - mockColumn.filter.filterOptions = { enableTime: true, allowInput: true }; // change to allow input value only for testing purposes + mockColumn.filter!.filterOptions = { enableTime: true, allowInput: true }; // change to allow input value only for testing purposes mockColumn.outputType = FieldType.dateTimeIsoAmPm; - mockColumn.filter.operator = '>'; + mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; filterInputElm.value = '2001-01-02T16:02:02.000+05:00'; filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); @@ -339,13 +339,13 @@ describe('CompoundDateFilter', () => { }); it('should have a value with date & time in the picker when using no "outputType" which will default to UTC date', () => { - mockColumn.outputType = null; + mockColumn.outputType = null as any; filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter.operator = '<='; + mockColumn.filter!.operator = '<='; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); @@ -358,19 +358,38 @@ describe('CompoundDateFilter', () => { }); it('should have default English text with operator dropdown options related to dates', () => { - mockColumn.outputType = null; + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.input-group-prepend.operator select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Less than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Greater than'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Greater than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Not equal to'); + }); + + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; + mockColumn.filter!.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; filter.init(filterArguments); const filterOperatorElm = divContainer.querySelectorAll('.input-group-prepend.operator select'); expect(filterOperatorElm[0][0].title).toBe(''); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Less than'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Less than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Greater than'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Greater than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Not equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); }); describe('with French I18N translations', () => { @@ -380,19 +399,19 @@ describe('CompoundDateFilter', () => { }); it('should have French text translated with operator dropdown options related to dates', () => { - mockColumn.outputType = null; + mockColumn.outputType = null as any; filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; filter.init(filterArguments); const filterOperatorElm = divContainer.querySelectorAll('.input-group-prepend.operator select'); expect(filterOperatorElm[0][0].title).toBe(''); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Plus petit que'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Plus petit ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Plus grand que'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Plus grand ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Non égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Plus petit que'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Plus petit ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Plus grand que'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Plus grand ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Non égal à'); }); }); }); diff --git a/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts b/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts index 17c33332c..a81ff2f6c 100644 --- a/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts +++ b/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts @@ -355,6 +355,25 @@ describe('CompoundInputFilter', () => { expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false }); }); + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['xyz']; + mockColumn.filter!.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); + }); + describe('with French I18N translations', () => { beforeEach(() => { gridOptionMock.enableTranslate = true; diff --git a/src/app/modules/angular-slickgrid/filters/__tests__/compoundSliderFilter.spec.ts b/src/app/modules/angular-slickgrid/filters/__tests__/compoundSliderFilter.spec.ts index c2f21748a..19223ddfb 100644 --- a/src/app/modules/angular-slickgrid/filters/__tests__/compoundSliderFilter.spec.ts +++ b/src/app/modules/angular-slickgrid/filters/__tests__/compoundSliderFilter.spec.ts @@ -30,7 +30,7 @@ describe('CompoundSliderFilter', () => { let divContainer: HTMLDivElement; let filter: CompoundSliderFilter; let filterArguments: FilterArguments; - let spyGetHeaderRow; + let spyGetHeaderRow: any; let mockColumn: Column; let translate: TranslateService; @@ -88,7 +88,7 @@ describe('CompoundSliderFilter', () => { }); it('should throw an error when trying to call init without any arguments', () => { - expect(() => filter.init(null)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); + expect(() => filter.init(null as any)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); }); it('should initialize the filter', () => { @@ -105,7 +105,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArgs); filter.setValues(['2']); - const filterElm = divContainer.querySelector('.input-group.search-filter.filter-duration input'); + const filterElm = divContainer.querySelector('.input-group.search-filter.filter-duration input') as HTMLInputElement; filterElm.dispatchEvent(new CustomEvent('change')); expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, operator: '>', searchTerms: ['2'], shouldTriggerQuery: true }); @@ -117,7 +117,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArgs); filter.setValues(3); - const filterElm = divContainer.querySelector('.input-group.search-filter.filter-duration input'); + const filterElm = divContainer.querySelector('.input-group.search-filter.filter-duration input') as HTMLInputElement; filterElm.dispatchEvent(new CustomEvent('change')); const filterFilledElms = divContainer.querySelectorAll('.slider-container.search-filter.filter-duration.filled'); @@ -130,7 +130,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArguments); filter.setValues(9); - const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select'); + const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select') as HTMLInputElement; filterOperatorElm.value = '<='; filterOperatorElm.dispatchEvent(new Event('change')); @@ -144,7 +144,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArguments); filter.setValues(['9'], OperatorType.greaterThanOrEqual); - const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select'); + const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select') as HTMLInputElement; filterOperatorElm.dispatchEvent(new Event('change')); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '>=', searchTerms: ['9'], shouldTriggerQuery: true }); @@ -154,7 +154,7 @@ describe('CompoundSliderFilter', () => { const filterArgs = { ...filterArguments, operator: '<=', searchTerms: [3] } as FilterArguments; filter.init(filterArgs); - const filterNumberElm = divContainer.querySelector('.input-group-text'); + const filterNumberElm = divContainer.querySelector('.input-group-text') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.slider-container.search-filter.filter-duration.filled'); expect(filterFilledElms.length).toBe(1); @@ -164,11 +164,11 @@ describe('CompoundSliderFilter', () => { it('should create the input filter with default search terms and a different step size when "valueStep" is provided', () => { const filterArgs = { ...filterArguments, operator: '<=', searchTerms: [15] } as FilterArguments; - mockColumn.filter.valueStep = 5; + mockColumn.filter!.valueStep = 5; filter.init(filterArgs); - const filterNumberElm = divContainer.querySelector('.input-group-text'); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterNumberElm = divContainer.querySelector('.input-group-text') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; expect(filterInputElm.step).toBe('5'); expect(filterNumberElm.textContent).toBe('15'); @@ -183,7 +183,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArguments); - const filterNumberElm = divContainer.querySelector('.input-group-text'); + const filterNumberElm = divContainer.querySelector('.input-group-text') as HTMLInputElement; expect(filterNumberElm.textContent).toBe('4'); expect(filter.getValues()).toEqual(4); @@ -199,7 +199,7 @@ describe('CompoundSliderFilter', () => { filter.init(filterArguments); - const filterNumberElm = divContainer.querySelector('.input-group-text'); + const filterNumberElm = divContainer.querySelector('.input-group-text') as HTMLInputElement; expect(filterNumberElm.textContent).toBe('4'); expect(filter.getValues()).toEqual(4); @@ -207,7 +207,7 @@ describe('CompoundSliderFilter', () => { it('should create the input filter with default search terms range but without showing side numbers when "hideSliderNumber" is set in params', () => { filterArguments.searchTerms = [3]; - mockColumn.filter.params = { hideSliderNumber: true }; + mockColumn.filter!.params = { hideSliderNumber: true }; filter.init(filterArguments); @@ -260,16 +260,35 @@ describe('CompoundSliderFilter', () => { filterArguments.searchTerms = ['9']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.input-group.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.input-group.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('9'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Less than'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Less than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Greater than'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Greater than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Not equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Less than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Greater than'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Greater than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Not equal to'); + }); + + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['9']; + mockColumn.filter!.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); }); describe('with French I18N translations', () => { @@ -283,16 +302,16 @@ describe('CompoundSliderFilter', () => { filterArguments.searchTerms = [9]; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.input-group.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.input-group.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('9'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Plus petit que'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Plus petit ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Plus grand que'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Plus grand ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Non égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Plus petit que'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Plus petit ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Plus grand que'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Plus grand ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Non égal à'); }); }); }); diff --git a/src/app/modules/angular-slickgrid/filters/compoundDateFilter.ts b/src/app/modules/angular-slickgrid/filters/compoundDateFilter.ts index 5fc2d68f5..ef9f5d232 100644 --- a/src/app/modules/angular-slickgrid/filters/compoundDateFilter.ts +++ b/src/app/modules/angular-slickgrid/filters/compoundDateFilter.ts @@ -16,6 +16,7 @@ import { FlatpickrOption, GridOption, Locale, + OperatorDetail, OperatorString, OperatorType, SearchTerm, @@ -243,16 +244,21 @@ export class CompoundDateFilter implements Filter { return $filterInputElm; } - protected getOptionValues(): { operator: OperatorString, description: string }[] { - return [ - { operator: '', description: '' }, - { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + return [ + { operator: '', description: '' }, + { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + } } /** Get Locale, Translated or a Default Text if first two aren't detected */ @@ -273,7 +279,7 @@ export class CompoundDateFilter implements Filter { $($headerElm).empty(); // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = this.buildDatePickerInput(searchTerm); const $filterContainerElm = $(`
`); diff --git a/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts b/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts index dbe4e6c04..9b2d152ec 100644 --- a/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts +++ b/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts @@ -9,6 +9,7 @@ import { FilterCallback, Locale, GridOption, + OperatorDetail, OperatorString, OperatorType, SearchTerm, @@ -163,35 +164,40 @@ export class CompoundInputFilter implements Filter { return ``; } - protected getOptionValues(): { operator: OperatorString, description: string }[] { + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { const type = (this.columnDef.type && this.columnDef.type) ? this.columnDef.type : FieldType.string; let optionValues = []; - switch (type) { - case FieldType.string: - case FieldType.text: - case FieldType.readonly: - case FieldType.password: - optionValues = [ - { operator: '' as OperatorString, description: this.getOutputText('CONTAINS', 'TEXT_CONTAINS', 'Contains') }, - { operator: '<>' as OperatorString, description: this.getOutputText('NOT_CONTAINS', 'TEXT_NOT_CONTAINS', 'Not Contains') }, - { operator: '=' as OperatorString, description: this.getOutputText('EQUALS', 'TEXT_EQUALS', 'Equals') }, - { operator: '!=' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') }, - { operator: 'a*' as OperatorString, description: this.getOutputText('STARTS_WITH', 'TEXT_STARTS_WITH', 'Starts with') }, - { operator: '*z' as OperatorString, description: this.getOutputText('ENDS_WITH', 'TEXT_ENDS_WITH', 'Ends with') }, - ]; - break; - default: - optionValues = [ - { operator: '' as OperatorString, description: '' }, - { operator: '=' as OperatorString, description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<' as OperatorString, description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=' as OperatorString, description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>' as OperatorString, description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=' as OperatorString, description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; - break; + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + switch (type) { + case FieldType.string: + case FieldType.text: + case FieldType.readonly: + case FieldType.password: + optionValues = [ + { operator: '' as OperatorString, description: this.getOutputText('CONTAINS', 'TEXT_CONTAINS', 'Contains') }, + { operator: '<>' as OperatorString, description: this.getOutputText('NOT_CONTAINS', 'TEXT_NOT_CONTAINS', 'Not Contains') }, + { operator: '=' as OperatorString, description: this.getOutputText('EQUALS', 'TEXT_EQUALS', 'Equals') }, + { operator: '!=' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') }, + { operator: 'a*' as OperatorString, description: this.getOutputText('STARTS_WITH', 'TEXT_STARTS_WITH', 'Starts with') }, + { operator: '*z' as OperatorString, description: this.getOutputText('ENDS_WITH', 'TEXT_ENDS_WITH', 'Ends with') }, + ]; + break; + default: + optionValues = [ + { operator: '' as OperatorString, description: '' }, + { operator: '=' as OperatorString, description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<' as OperatorString, description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=' as OperatorString, description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>' as OperatorString, description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=' as OperatorString, description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + break; + } } return optionValues; @@ -215,7 +221,7 @@ export class CompoundInputFilter implements Filter { $($headerElm).empty(); // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = $(this.buildInputHtmlString()); const $filterContainerElm = $(`
`); diff --git a/src/app/modules/angular-slickgrid/filters/compoundSliderFilter.ts b/src/app/modules/angular-slickgrid/filters/compoundSliderFilter.ts index adb6b65e2..eb55a02f4 100644 --- a/src/app/modules/angular-slickgrid/filters/compoundSliderFilter.ts +++ b/src/app/modules/angular-slickgrid/filters/compoundSliderFilter.ts @@ -8,6 +8,7 @@ import { FilterCallback, GridOption, Locale, + OperatorDetail, OperatorString, OperatorType, SearchTerm, @@ -206,17 +207,21 @@ export class CompoundSliderFilter implements Filter { return `
${defaultValue}
`; } - /** Get the available operator option values */ - protected getOptionValues(): { operator: OperatorString, description: string }[] { - return [ - { operator: '', description: '' }, - { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + return [ + { operator: '', description: '' }, + { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + } } /** Get Locale, Translated or a Default Text if first two aren't detected */ @@ -248,7 +253,7 @@ export class CompoundSliderFilter implements Filter { this._currentValue = +searchTermInput; // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = $(this.buildTemplateHtmlString()); const $filterContainerElm = $(`
`); diff --git a/src/app/modules/angular-slickgrid/models/columnFilter.interface.ts b/src/app/modules/angular-slickgrid/models/columnFilter.interface.ts index 2accbb18f..9d796ff26 100644 --- a/src/app/modules/angular-slickgrid/models/columnFilter.interface.ts +++ b/src/app/modules/angular-slickgrid/models/columnFilter.interface.ts @@ -9,6 +9,7 @@ import { FieldType, Filter, MultipleSelectOption, + OperatorDetail, OperatorString, OperatorType, SearchTerm, @@ -33,6 +34,9 @@ export interface ColumnFilter { /** Column Definition */ columnDef?: Column; + /** Optional operator list to override the full list of Compound Operator select dropdown list. */ + compoundOperatorList?: OperatorDetail[]; + /** Custom Filter */ customFilter?: Filter; diff --git a/src/app/modules/angular-slickgrid/models/index.ts b/src/app/modules/angular-slickgrid/models/index.ts index 2ea67bd91..2579355c9 100644 --- a/src/app/modules/angular-slickgrid/models/index.ts +++ b/src/app/modules/angular-slickgrid/models/index.ts @@ -122,6 +122,7 @@ export * from './odataOption.interface'; export * from './odataServiceApi.interface'; export * from './odataSortingOption.interface'; export * from './onEventArgs.interface'; +export * from './operatorDetail.interface'; export * from './operatorString'; export * from './operatorType.enum'; export * from './pagination.interface'; diff --git a/src/app/modules/angular-slickgrid/models/operatorDetail.interface.ts b/src/app/modules/angular-slickgrid/models/operatorDetail.interface.ts new file mode 100644 index 000000000..93b87c58d --- /dev/null +++ b/src/app/modules/angular-slickgrid/models/operatorDetail.interface.ts @@ -0,0 +1,7 @@ +import { OperatorString, OperatorType } from './index'; + +/** Operator with its Description */ +export interface OperatorDetail { + operator: OperatorString | OperatorType; + description: string; +}