diff --git a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts index ff38622d4..be3da690f 100644 --- a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts @@ -112,6 +112,7 @@ describe('CompoundDateFilter', () => { defaultDate: '', errorHandler: expect.toBeFunction(), locale: 'en', + mode: 'single', onChange: expect.anything(), wrap: true, }); @@ -121,14 +122,14 @@ describe('CompoundDateFilter', () => { const mockDate = '2001-01-02T16:02:02.239Z'; filter.init(filterArguments); filter.setValues(mockDate); - expect(filter.currentDate).toEqual(mockDate); + expect(filter.currentDateOrDates).toEqual(mockDate); }); it('should be able to call "setValues" as an array and have that value set in the picker', () => { const mockDate = '2001-01-02T16:02:02.239Z'; filter.init(filterArguments); filter.setValues([mockDate]); - expect(filter.currentDate).toEqual(mockDate); + expect(filter.currentDateOrDates).toEqual(mockDate); }); it('should be able to call "setValues" with a value and an extra operator and expect it to be set as new operator', () => { @@ -138,7 +139,7 @@ describe('CompoundDateFilter', () => { const filterOperatorElm = divContainer.querySelector('.input-group-prepend.operator select') as HTMLInputElement; - expect(filter.currentDate).toEqual(mockDate); + expect(filter.currentDateOrDates).toEqual(mockDate); expect(filterOperatorElm.value).toBe('>='); }); @@ -218,7 +219,7 @@ describe('CompoundDateFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDate).toBe('2000-01-01T05:00:00.000Z'); + expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); expect(filterInputElm.value).toBe('2000-01-01'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); }); @@ -245,7 +246,7 @@ describe('CompoundDateFilter', () => { filter.setValues(mockDate); let filledInputElm = divContainer.querySelector('.search-filter.filter-finish .filled') as HTMLInputElement; - expect(filter.currentDate).toEqual(mockDate); + expect(filter.currentDateOrDates).toEqual(mockDate); expect(filledInputElm).toBeTruthy(); filter.setValues(''); @@ -273,7 +274,7 @@ describe('CompoundDateFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDate).toBe('2000-01-01T05:00:00.000Z'); + expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); expect(filterInputElm.value).toBe('2000-01-01'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); expect(calendarElm).toBeTruthy(); @@ -347,7 +348,7 @@ describe('CompoundDateFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - // expect(filter.currentDate.toISOString()).toBe('2001-01-02T21:02:02.000Z'); + // expect(filter.currentDateOrDates.toISOString()).toBe('2001-01-02T21:02:02.000Z'); expect(filterInputElm.value).toBe('2001-01-02 4:02:02 PM'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02'], shouldTriggerQuery: true @@ -368,7 +369,7 @@ describe('CompoundDateFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDate).toBe('2000-01-01T05:00:00.000Z'); + expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); }); diff --git a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts index e52917dc8..a496b442f 100644 --- a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts +++ b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts @@ -1,3 +1,4 @@ +import 'jest-extended'; import { FieldType } from '../../enums/index'; import { Column, FilterArguments, GridOption, SlickGrid } from '../../interfaces/index'; import { Filters } from '../filters.index'; @@ -117,14 +118,14 @@ describe('DateRangeFilter', () => { const mockDates = ['2001-01-02T16:02:02.239Z', '2001-01-31T16:02:02.239Z']; filter.init(filterArguments); filter.setValues(mockDates); - expect(filter.currentDates).toEqual(mockDates); + expect(filter.currentDateOrDates).toEqual(mockDates); }); it('should be able to call "setValues" with 2 dots (..) notation and have them set in the picker', () => { const mockDate = '2001-01-02T16:02:02.239Z..2001-01-31T16:02:02.239Z'; filter.init(filterArguments); filter.setValues([mockDate]); - expect(filter.currentDates).toEqual(mockDate.split('..')); + expect(filter.currentDateOrDates).toEqual(mockDate.split('..')); }); it('should trigger input change event and expect the callback to be called with the date provided in the input', () => { @@ -199,7 +200,7 @@ describe('DateRangeFilter', () => { filter.setValues(mockDates); let filledInputElm = divContainer.querySelector('.search-filter.filter-finish.filled') as HTMLInputElement; - expect(filter.currentDates).toEqual(mockDates); + expect(filter.currentDateOrDates).toEqual(mockDates); expect(filledInputElm).toBeTruthy(); filter.setValues(''); @@ -300,7 +301,7 @@ describe('DateRangeFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - // expect(filter.currentDates.map((date) => date.toISOString())).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); + // expect(filter.currentDateOrDates.map((date) => date.toISOString())).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); expect(filterInputElm.value).toBe('2000-01-01 5:00:00 AM to 2000-01-31 5:00:00 AM'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '>', searchTerms: ['2000-01-01 05:00:00 am', '2000-01-31 05:00:00 am'], shouldTriggerQuery: true @@ -321,7 +322,7 @@ describe('DateRangeFilter', () => { const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDates).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); + expect(filter.currentDateOrDates).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); expect(filterInputElm.value).toBe('2000-01-01 to 2000-01-31'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true }); }); diff --git a/packages/common/src/filters/compoundDateFilter.ts b/packages/common/src/filters/compoundDateFilter.ts index 27e4199d6..a3f8cfa75 100644 --- a/packages/common/src/filters/compoundDateFilter.ts +++ b/packages/common/src/filters/compoundDateFilter.ts @@ -1,329 +1,10 @@ -import * as flatpickr_ from 'flatpickr'; -import { BaseOptions as FlatpickrBaseOptions } from 'flatpickr/dist/types/options'; -import { Instance as FlatpickrInstance, FlatpickrFn } from 'flatpickr/dist/types/instance'; -const flatpickr: FlatpickrFn = (flatpickr_?.['default'] ?? flatpickr_) as any; // patch for rollup - -import { - Column, - ColumnFilter, - Filter, - FilterArguments, - FilterCallback, - FlatpickrOption, - GridOption, - OperatorDetail, - SlickGrid, -} from '../interfaces/index'; -import { FieldType, OperatorString, OperatorType, SearchTerm } from '../enums/index'; -import { buildSelectOperator, compoundOperatorNumeric } from './filterUtilities'; -import { createDomElement, destroyObjectDomElementProps, emptyElement, } from '../services/domUtilities'; -import { mapFlatpickrDateFormatWithFieldType, mapOperatorToShorthandDesignation } from '../services/utilities'; -import { TranslaterService } from '../services/translater.service'; -import { BindingEventService } from '../services/bindingEvent.service'; - -export class CompoundDateFilter implements Filter { - protected _bindEventService: BindingEventService; - protected _clearFilterTriggered = false; - protected _currentDate: Date | undefined; - protected _currentValue?: string; - protected _flatpickrOptions!: FlatpickrOption; - protected _filterElm!: HTMLDivElement; - protected _filterDivInputElm!: HTMLDivElement; - protected _operator!: OperatorType | OperatorString; - protected _selectOperatorElm!: HTMLSelectElement; - protected _shouldTriggerQuery = true; - flatInstance!: FlatpickrInstance; - grid!: SlickGrid; - searchTerms: SearchTerm[] = []; - columnDef!: Column; - callback!: FilterCallback; - filterContainerElm!: HTMLDivElement; +import { TranslaterService } from '../services'; +import { DateFilter } from './dateFilter'; +export class CompoundDateFilter extends DateFilter { + /** Initialize the Filter */ constructor(protected readonly translaterService: TranslaterService) { - this._bindEventService = new BindingEventService(); - } - - /** Getter for the Grid Options pulled through the Grid Object */ - protected get gridOptions(): GridOption { - return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {}; - } - - /** Getter for the Column Filter */ - get columnFilter(): ColumnFilter { - return this.columnDef && this.columnDef.filter || {}; - } - - /** Getter for the Current Dates selected */ - get currentDate(): Date | undefined { - return this._currentDate; - } - - /** Getter to know what would be the default operator when none is specified */ - get defaultOperator(): OperatorType | OperatorString { - return OperatorType.empty; - } - - /** Getter for the Flatpickr Options */ - get flatpickrOptions(): FlatpickrOption { - return this._flatpickrOptions || {}; - } - - /** Getter for the Filter Operator */ - get operator(): OperatorType | OperatorString { - return this._operator || this.columnFilter.operator || this.defaultOperator; - } - - /** Setter for the Filter Operator */ - set operator(op: OperatorType | OperatorString) { - this._operator = op; - } - - /** - * Initialize the Filter - */ - init(args: FilterArguments) { - if (!args) { - throw new Error('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); - } - this.grid = args.grid; - this.callback = args.callback; - this.columnDef = args.columnDef; - this.operator = args.operator || ''; - this.searchTerms = args?.searchTerms ?? []; - this.filterContainerElm = args.filterContainerElm; - - // date input can only have 1 search term, so we will use the 1st array index if it exist - const searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms.length >= 0) ? this.searchTerms[0] : ''; - - // step 1, create the DOM Element of the filter which contain the compound Operator+Input - // and initialize it if searchTerm is filled - this._filterElm = this.createDomFilterElement(searchTerm); - - // step 3, subscribe to the keyup event and run the callback when that happens - // also add/remove "filled" class for styling purposes - this._bindEventService.bind(this._filterDivInputElm, 'keyup', this.onTriggerEvent.bind(this)); - this._bindEventService.bind(this._selectOperatorElm, 'change', this.onTriggerEvent.bind(this)); - } - - /** - * Clear the filter value - */ - clear(shouldTriggerQuery = true) { - if (this.flatInstance && this._selectOperatorElm) { - this._clearFilterTriggered = true; - this._shouldTriggerQuery = shouldTriggerQuery; - this.searchTerms = []; - this._selectOperatorElm.selectedIndex = 0; - if (this.flatInstance.input) { - this.flatInstance.clear(); - } - } - this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); - } - - /** - * destroy the filter - */ - destroy() { - this._bindEventService.unbindAll(); - - if (typeof this.flatInstance?.destroy === 'function') { - this.flatInstance.destroy(); - if (this.flatInstance.element) { - destroyObjectDomElementProps(this.flatInstance); - } - } - emptyElement(this.filterContainerElm); - emptyElement(this._filterDivInputElm); - this._filterDivInputElm?.remove(); - this.filterContainerElm?.remove(); - this._selectOperatorElm?.remove(); - this._filterElm?.remove(); - this.grid = null as any; - } - - hide() { - if (typeof this.flatInstance?.close === 'function') { - this.flatInstance.close(); - } - } - - show() { - if (typeof this.flatInstance?.open === 'function') { - this.flatInstance.open(); - } - } - - getValues() { - return this._currentDate; - } - - /** Set value(s) in the DOM element, we can optionally pass an operator and/or trigger a change event */ - setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString) { - if (this.flatInstance) { - const newValue = Array.isArray(values) ? values[0] : values; - this._currentDate = (values && newValue) ? newValue as Date : undefined; - this.flatInstance.setDate(this._currentDate || ''); - } - - if (this.getValues()) { - this._filterElm.classList.add('filled'); - this._filterDivInputElm.classList.add('filled'); - } else { - this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); - } - - // set the operator when defined - this.operator = operator || this.defaultOperator; - if (operator && this._selectOperatorElm) { - const operatorShorthand = mapOperatorToShorthandDesignation(this.operator); - this._selectOperatorElm.value = operatorShorthand; - } - } - - // - // protected functions - // ------------------ - - protected buildDatePickerInput(searchTerm?: SearchTerm): HTMLDivElement { - const columnId = this.columnDef?.id ?? ''; - const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateUtc); - const userFilterOptions = this.columnFilter?.filterOptions ?? {} as FlatpickrOption; - - // get current locale, if user defined a custom locale just use or get it the Translate Service if it exist else just use English - let currentLocale = (userFilterOptions?.locale ?? this.translaterService?.getCurrentLanguage?.()) || this.gridOptions.locale || 'en'; - if (currentLocale?.length > 2) { - currentLocale = currentLocale.substring(0, 2); - } - - // if we are preloading searchTerms, we'll keep them for reference - if (searchTerm) { - this._currentDate = searchTerm as Date; - } - - const pickerOptions: FlatpickrOption = { - defaultDate: (searchTerm as string) || '', - altInput: true, - altFormat: outputFormat, - dateFormat: inputFormat, - wrap: true, - closeOnSelect: true, - locale: currentLocale, - onChange: (selectedDates: Date[] | Date, dateStr: string) => { - this._currentDate = Array.isArray(selectedDates) && selectedDates[0] || undefined; - this._currentValue = dateStr; - - // when using the time picker, we can simulate a keyup event to avoid multiple backend request - // since backend request are only executed after user start typing, changing the time should be treated the same way - const newEvent = pickerOptions.enableTime ? new Event('keyup') : undefined; - this.onTriggerEvent(newEvent); - }, - errorHandler: (error) => { - if (error.toString().includes('invalid locale')) { - console.warn(`[Slickgrid-Universal] Flatpickr missing locale imports (${currentLocale}), will revert to English as the default locale. - See Flatpickr Localization for more info, for example if we want to use French, then we can import it with: import 'flatpickr/dist/l10n/fr';`); - } - } - }; - - // add the time picker when format is UTC (Z) or has the 'h' (meaning hours) - if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) { - pickerOptions.enableTime = true; - } - - // merge options with optional user's custom options - this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions }; - - // create the DOM element & add an ID and filter class - let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? ''; - if (this.columnFilter?.placeholder) { - placeholder = this.columnFilter.placeholder; - } - - const filterDivInputElm = createDomElement('div', { className: 'flatpickr' }); - filterDivInputElm.appendChild( - createDomElement('input', { - type: 'text', className: 'form-control', - placeholder, - dataset: { input: '', columnid: `${columnId}` } - }) - ); - this.flatInstance = flatpickr(filterDivInputElm, this._flatpickrOptions as unknown as Partial); - - return filterDivInputElm; - } - - /** 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 compoundOperatorNumeric(this.gridOptions, this.translaterService); - } - } - - /** - * Create the DOM element - */ - protected createDomFilterElement(searchTerm?: SearchTerm): HTMLDivElement { - const columnId = this.columnDef?.id ?? ''; - emptyElement(this.filterContainerElm); - - - // create the DOM element filter container & operator - this._filterDivInputElm = this.buildDatePickerInput(searchTerm); - this._selectOperatorElm = buildSelectOperator(this.getOperatorOptionValues(), this.gridOptions); - const filterContainerElm = createDomElement('div', { className: `form-group search-filter filter-${columnId}` }); - const containerInputGroupElm = createDomElement('div', { className: 'input-group flatpickr' }); - const operatorInputGroupAddonElm = createDomElement('div', { className: 'input-group-addon input-group-prepend operator' }); - - operatorInputGroupAddonElm.appendChild(this._selectOperatorElm); - containerInputGroupElm.appendChild(operatorInputGroupAddonElm); - containerInputGroupElm.appendChild(this._filterDivInputElm); - - // create the DOM element & add an ID and filter class - filterContainerElm.appendChild(containerInputGroupElm); - - if (this.operator) { - const operatorShorthand = mapOperatorToShorthandDesignation(this.operator); - this._selectOperatorElm.value = operatorShorthand; - } - - // if there's a search term, we will add the "filled" class for styling purposes - if (searchTerm !== '') { - this._filterDivInputElm.classList.add('filled'); - this._currentDate = searchTerm as Date; - this._currentValue = searchTerm as string; - } - - // append the new DOM element to the header row - if (filterContainerElm) { - this.filterContainerElm.appendChild(filterContainerElm); - } - - return filterContainerElm; - } - - protected onTriggerEvent(e: Event | undefined) { - if (this._clearFilterTriggered) { - this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery }); - this._filterElm.classList.remove('filled'); - } else { - const selectedOperator = this._selectOperatorElm.value as OperatorString; - (this._currentValue) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); - - // when changing compound operator, we don't want to trigger the filter callback unless the date input is also provided - const skipCompoundOperatorFilterWithNullInput = this.columnFilter.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput === undefined; - if (!skipCompoundOperatorFilterWithNullInput || this._currentDate !== undefined) { - this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentValue ? [this._currentValue] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery }); - } - } - - // reset both flags for next use - this._clearFilterTriggered = false; - this._shouldTriggerQuery = true; + super(translaterService); + this.inputFilterType = 'compound'; } } diff --git a/packages/common/src/filters/dateFilter.ts b/packages/common/src/filters/dateFilter.ts new file mode 100644 index 000000000..378b561ce --- /dev/null +++ b/packages/common/src/filters/dateFilter.ts @@ -0,0 +1,423 @@ +import * as flatpickr_ from 'flatpickr'; +import * as moment_ from 'moment-mini'; +import { BaseOptions as FlatpickrBaseOptions } from 'flatpickr/dist/types/options'; +import { Instance as FlatpickrInstance, FlatpickrFn } from 'flatpickr/dist/types/instance'; +const flatpickr: FlatpickrFn = (flatpickr_?.['default'] ?? flatpickr_) as any; // patch for rollup +const moment = (moment_ as any)?.['default'] ?? moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670 + +import { + FieldType, + OperatorString, + OperatorType, + SearchTerm, +} from '../enums/index'; +import { + Column, + ColumnFilter, + Filter, + FilterArguments, + FilterCallback, + FlatpickrOption, + GridOption, + OperatorDetail, + SlickGrid, +} from '../interfaces/index'; +import { buildSelectOperator, compoundOperatorNumeric } from './filterUtilities'; +import { createDomElement, destroyObjectDomElementProps, emptyElement, } from '../services/domUtilities'; +import { mapFlatpickrDateFormatWithFieldType, mapMomentDateFormatWithFieldType, mapOperatorToShorthandDesignation } from '../services/utilities'; +import { BindingEventService } from '../services/bindingEvent.service'; +import { TranslaterService } from '../services/translater.service'; + +export class DateFilter implements Filter { + protected _bindEventService: BindingEventService; + protected _clearFilterTriggered = false; + protected _currentValue?: string; + protected _currentDateOrDates?: Date | Date[] | string[]; + protected _currentDateStrings?: string[]; + protected _flatpickrOptions!: FlatpickrOption; + protected _filterElm!: HTMLDivElement; + protected _filterDivInputElm!: HTMLDivElement; + protected _operator!: OperatorType | OperatorString; + protected _selectOperatorElm?: HTMLSelectElement; + protected _shouldTriggerQuery = true; + inputFilterType: 'compound' | 'range' = 'range'; + flatInstance!: FlatpickrInstance; + grid!: SlickGrid; + searchTerms: SearchTerm[] = []; + columnDef!: Column; + callback!: FilterCallback; + filterContainerElm!: HTMLDivElement; + + constructor(protected readonly translaterService: TranslaterService) { + this._bindEventService = new BindingEventService(); + } + + /** Getter for the Grid Options pulled through the Grid Object */ + protected get gridOptions(): GridOption { + return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {}; + } + + /** Getter for the Column Filter */ + get columnFilter(): ColumnFilter { + return this.columnDef && this.columnDef.filter || {}; + } + + /** Getter for the Current Date(s) selected */ + get currentDateOrDates() { + return this._currentDateOrDates; + } + + /** Getter to know what would be the default operator when none is specified */ + get defaultOperator(): OperatorType | OperatorString { + return this.inputFilterType === 'compound' + ? OperatorType.empty + : (this.gridOptions.defaultFilterRangeOperator || OperatorType.rangeInclusive); + } + + /** Getter for the Flatpickr Options */ + get flatpickrOptions(): FlatpickrOption { + return this._flatpickrOptions || {}; + } + + /** Getter for the Filter Operator */ + get operator(): OperatorType | OperatorString { + if (this.inputFilterType === 'compound') { + return this._operator || this.columnFilter.operator || this.defaultOperator; + } + return this.columnFilter?.operator ?? this.defaultOperator; + } + + /** Setter for the filter operator */ + set operator(operator: OperatorType | OperatorString) { + if (this.inputFilterType === 'compound') { + this._operator = operator; + } else if (this.columnFilter) { + this.columnFilter.operator = operator; + } + } + + /** + * Initialize the Filter + */ + init(args: FilterArguments) { + if (!args) { + throw new Error('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); + } + + this.grid = args.grid; + this.callback = args.callback; + this.columnDef = args.columnDef; + if (this.inputFilterType === 'compound') { + this.operator = args.operator || ''; + } + this.searchTerms = args?.searchTerms ?? []; + this.filterContainerElm = args.filterContainerElm; + + // date input can only have 1 search term, so we will use the 1st array index if it exist + const searchValues = this.inputFilterType === 'compound' + ? (Array.isArray(this.searchTerms) && this.searchTerms.length >= 0) ? this.searchTerms[0] : '' + : this.searchTerms; + + // step 1, create the DOM Element of the filter which contain the compound Operator+Input + this._filterElm = this.createDomFilterElement(searchValues); + + // step 3, subscribe to the keyup event and run the callback when that happens + // also add/remove "filled" class for styling purposes + this._bindEventService.bind(this._filterDivInputElm, 'keyup', this.onTriggerEvent.bind(this)); + if (this._selectOperatorElm) { + this._bindEventService.bind(this._selectOperatorElm, 'change', this.onTriggerEvent.bind(this)); + } + } + + /** + * Clear the filter value + */ + clear(shouldTriggerQuery = true) { + if (this.flatInstance) { + this._clearFilterTriggered = true; + this._shouldTriggerQuery = shouldTriggerQuery; + this.searchTerms = []; + if (this._selectOperatorElm) { + this._selectOperatorElm.selectedIndex = 0; + } + if (this.flatInstance.input) { + this.flatInstance.clear(); + } + } + this._filterElm.classList.remove('filled'); + this._filterDivInputElm.classList.remove('filled'); + } + + /** + * destroy the filter + */ + destroy() { + this._bindEventService.unbindAll(); + + if (typeof this.flatInstance?.destroy === 'function') { + this.flatInstance.destroy(); + if (this.flatInstance.element) { + destroyObjectDomElementProps(this.flatInstance); + } + } + emptyElement(this.filterContainerElm); + emptyElement(this._filterDivInputElm); + this._filterDivInputElm?.remove(); + this.filterContainerElm?.remove(); + this._selectOperatorElm?.remove(); + this._filterElm?.remove(); + this.grid = null as any; + } + + hide() { + if (typeof this.flatInstance?.close === 'function') { + this.flatInstance.close(); + } + } + + show() { + if (typeof this.flatInstance?.open === 'function') { + this.flatInstance.open(); + } + } + + getValues() { + return this._currentDateOrDates; + } + + /** + * Set value(s) on the DOM element + * @params searchTerms + */ + setValues(values?: SearchTerm[] | SearchTerm, operator?: OperatorType | OperatorString) { + let pickerValues: any | any[]; + + if (this.inputFilterType === 'compound') { + pickerValues = Array.isArray(values) ? values[0] : values; + + } else { + // get the picker values, if it's a string with the "..", we'll do the split else we'll use the array of search terms + if (typeof values === 'string' || (Array.isArray(values) && typeof values[0] === 'string') && (values[0] as string).indexOf('..') > 0) { + pickerValues = (typeof values === 'string') ? [(values as string)] : (values[0] as string).split('..'); + } else if (Array.isArray(values)) { + pickerValues = values; + } + } + + if (this.flatInstance) { + this._currentDateOrDates = (values && pickerValues) ? pickerValues : undefined; + this.flatInstance.setDate(this._currentDateOrDates || ''); + } + + const currentValueOrValues = this.getValues() || []; + if (this.getValues() || (Array.isArray(currentValueOrValues) && currentValueOrValues.length > 0 && values)) { + this._filterElm.classList.add('filled'); + this._filterDivInputElm.classList.add('filled'); + } else { + this._filterElm.classList.remove('filled'); + this._filterDivInputElm.classList.remove('filled'); + } + + // set the operator when defined + this.operator = operator || this.defaultOperator; + if (operator && this._selectOperatorElm) { + const operatorShorthand = mapOperatorToShorthandDesignation(this.operator); + this._selectOperatorElm.value = operatorShorthand; + } + } + + // + // protected functions + // ------------------ + protected buildDatePickerInput(searchTerms?: SearchTerm | SearchTerm[]): HTMLDivElement { + const columnId = this.columnDef?.id ?? ''; + const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); + const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateUtc); + const userFilterOptions = this.columnFilter?.filterOptions ?? {} as FlatpickrOption; + + // get current locale, if user defined a custom locale just use or get it the Translate Service if it exist else just use English + let currentLocale = (userFilterOptions?.locale ?? this.translaterService?.getCurrentLanguage?.()) || this.gridOptions.locale || 'en'; + if (currentLocale?.length > 2) { + currentLocale = currentLocale.substring(0, 2); + } + + let pickerValues: any | any[]; + + if (this.inputFilterType === 'compound') { + if (searchTerms) { + pickerValues = searchTerms; + this._currentDateOrDates = searchTerms as Date; + } + } else { + // get the picker values, if it's a string with the "..", we'll do the split else we'll use the array of search terms + if (typeof searchTerms === 'string' || (Array.isArray(searchTerms) && typeof searchTerms[0] === 'string') && (searchTerms[0] as string).indexOf('..') > 0) { + pickerValues = (typeof searchTerms === 'string') ? [(searchTerms as string)] : (searchTerms[0] as string).split('..'); + } else if (Array.isArray(searchTerms)) { + pickerValues = searchTerms; + } + + // if we are preloading searchTerms, we'll keep them for reference + if (Array.isArray(pickerValues)) { + this._currentDateOrDates = pickerValues as Date[]; + const outFormat = mapMomentDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); + this._currentDateStrings = pickerValues.map(date => moment(date).format(outFormat)); + } + } + + const pickerOptions: FlatpickrOption = { + defaultDate: (pickerValues || '') as string | string[], + altInput: true, + altFormat: outputFormat, + dateFormat: inputFormat, + mode: this.inputFilterType === 'range' ? 'range' : 'single', + wrap: true, + closeOnSelect: true, + locale: currentLocale, + onChange: (selectedDates: Date[] | Date, dateStr: string) => { + if (this.inputFilterType === 'compound') { + this._currentValue = dateStr; + this._currentDateOrDates = Array.isArray(selectedDates) && selectedDates[0] || undefined; + } else { + if (Array.isArray(selectedDates)) { + this._currentDateOrDates = selectedDates; + const outFormat = mapMomentDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateIso); + this._currentDateStrings = selectedDates.map(date => moment(date).format(outFormat)); + this._currentValue = this._currentDateStrings.join('..'); + } + } + + // when using the time picker, we can simulate a keyup event to avoid multiple backend request + // since backend request are only executed after user start typing, changing the time should be treated the same way + const newEvent = pickerOptions.enableTime ? new Event('keyup') : undefined; + this.onTriggerEvent(newEvent); + }, + errorHandler: (error) => { + if (error.toString().includes('invalid locale')) { + console.warn(`[Slickgrid-Universal] Flatpickr missing locale imports (${currentLocale}), will revert to English as the default locale. + See Flatpickr Localization for more info, for example if we want to use French, then we can import it with: import 'flatpickr/dist/l10n/fr';`); + } + } + }; + + // add the time picker when format is UTC (Z) or has the 'h' (meaning hours) + if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) { + pickerOptions.enableTime = true; + } + + // merge options with optional user's custom options + this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions }; + + let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? ''; + if (this.columnFilter?.placeholder) { + placeholder = this.columnFilter.placeholder; + } + + const filterDivInputElm = createDomElement('div', { className: 'flatpickr' }); + if (this.inputFilterType === 'range') { + filterDivInputElm.classList.add('search-filter', `filter-${columnId}`); + } + filterDivInputElm.appendChild( + createDomElement('input', { + type: 'text', className: 'form-control', + placeholder, + dataset: { input: '', columnid: `${columnId}` } + }) + ); + this.flatInstance = flatpickr(filterDivInputElm, this._flatpickrOptions as unknown as Partial); + + return filterDivInputElm; + } + + /** 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 compoundOperatorNumeric(this.gridOptions, this.translaterService); + } + } + + /** + * Create the DOM element + * @params searchTerms + */ + protected createDomFilterElement(searchTerms?: SearchTerm | SearchTerm[]): HTMLDivElement { + const columnId = this.columnDef?.id ?? ''; + emptyElement(this.filterContainerElm); + + // create the DOM element filter container + this._filterDivInputElm = this.buildDatePickerInput(searchTerms); + + if (this.inputFilterType === 'range') { + // if there's a search term, we will add the "filled" class for styling purposes + if (Array.isArray(searchTerms) && searchTerms.length > 0 && searchTerms[0] !== '') { + this._filterDivInputElm.classList.add('filled'); + this._currentDateOrDates = searchTerms as Date[]; + this._currentValue = searchTerms[0] as string; + } + + // append the new DOM element to the header row + if (this._filterDivInputElm) { + this.filterContainerElm.appendChild(this._filterDivInputElm); + } + + return this._filterDivInputElm; + } else { + this._selectOperatorElm = buildSelectOperator(this.getOperatorOptionValues(), this.gridOptions); + const filterContainerElm = createDomElement('div', { className: `form-group search-filter filter-${columnId}` }); + const containerInputGroupElm = createDomElement('div', { className: 'input-group flatpickr' }); + const operatorInputGroupAddonElm = createDomElement('div', { className: 'input-group-addon input-group-prepend operator' }); + + operatorInputGroupAddonElm.appendChild(this._selectOperatorElm); + containerInputGroupElm.appendChild(operatorInputGroupAddonElm); + containerInputGroupElm.appendChild(this._filterDivInputElm); + + // create the DOM element & add an ID and filter class + filterContainerElm.appendChild(containerInputGroupElm); + + if (this.operator) { + const operatorShorthand = mapOperatorToShorthandDesignation(this.operator); + this._selectOperatorElm.value = operatorShorthand; + } + + // if there's a search term, we will add the "filled" class for styling purposes + if (searchTerms !== '') { + this._filterDivInputElm.classList.add('filled'); + this._currentDateOrDates = searchTerms as Date; + this._currentValue = searchTerms as string; + } + + // append the new DOM element to the header row + if (filterContainerElm) { + this.filterContainerElm.appendChild(filterContainerElm); + } + + return filterContainerElm; + } + } + + protected onTriggerEvent(e: Event | undefined) { + if (this._clearFilterTriggered) { + this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery }); + this._filterElm.classList.remove('filled'); + } else { + if (this.inputFilterType === 'range') { + (this._currentDateStrings) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); + this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentDateStrings ? this._currentDateStrings : [this._currentValue as string]), operator: this.operator || '', shouldTriggerQuery: this._shouldTriggerQuery }); + } else if (this.inputFilterType === 'compound' && this._selectOperatorElm) { + const selectedOperator = this._selectOperatorElm.value as OperatorString; + (this._currentValue) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); + + // when changing compound operator, we don't want to trigger the filter callback unless the date input is also provided + const skipCompoundOperatorFilterWithNullInput = this.columnFilter.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput === undefined; + if (!skipCompoundOperatorFilterWithNullInput || this._currentDateOrDates !== undefined) { + this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentValue ? [this._currentValue] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery }); + } + } + } + + // reset both flags for next use + this._clearFilterTriggered = false; + this._shouldTriggerQuery = true; + } +} diff --git a/packages/common/src/filters/dateRangeFilter.ts b/packages/common/src/filters/dateRangeFilter.ts index 8984b4b72..1dca3eebb 100644 --- a/packages/common/src/filters/dateRangeFilter.ts +++ b/packages/common/src/filters/dateRangeFilter.ts @@ -1,318 +1,10 @@ -import * as flatpickr_ from 'flatpickr'; -import * as moment_ from 'moment-mini'; -import { BaseOptions as FlatpickrBaseOptions } from 'flatpickr/dist/types/options'; -import { Instance as FlatpickrInstance, FlatpickrFn } from 'flatpickr/dist/types/instance'; -const flatpickr: FlatpickrFn = (flatpickr_?.['default'] ?? flatpickr_) as any; // patch for rollup -const moment = (moment_ as any)?.['default'] ?? moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670 - -import { - FieldType, - OperatorString, - OperatorType, - SearchTerm, -} from '../enums/index'; -import { - Column, - ColumnFilter, - Filter, - FilterArguments, - FilterCallback, - FlatpickrOption, - GridOption, - SlickGrid, -} from '../interfaces/index'; -import { createDomElement, destroyObjectDomElementProps, emptyElement, } from '../services/domUtilities'; -import { mapFlatpickrDateFormatWithFieldType, mapMomentDateFormatWithFieldType } from '../services/utilities'; -import { BindingEventService } from '../services/bindingEvent.service'; -import { TranslaterService } from '../services/translater.service'; - -export class DateRangeFilter implements Filter { - protected _bindEventService: BindingEventService; - protected _clearFilterTriggered = false; - protected _currentValue?: string; - protected _currentDates?: Date[] | string[]; - protected _currentDateStrings?: string[]; - protected _flatpickrOptions!: FlatpickrOption; - protected _filterElm!: HTMLDivElement; - protected _filterDivInputElm!: HTMLDivElement; - protected _shouldTriggerQuery = true; - flatInstance!: FlatpickrInstance; - grid!: SlickGrid; - searchTerms: SearchTerm[] = []; - columnDef!: Column; - callback!: FilterCallback; - filterContainerElm!: HTMLDivElement; +import { TranslaterService } from '../services'; +import { DateFilter } from './dateFilter'; +export class DateRangeFilter extends DateFilter { + /** Initialize the Filter */ constructor(protected readonly translaterService: TranslaterService) { - this._bindEventService = new BindingEventService(); - } - - /** Getter for the Grid Options pulled through the Grid Object */ - protected get gridOptions(): GridOption { - return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {}; - } - - /** Getter for the Column Filter */ - get columnFilter(): ColumnFilter { - return this.columnDef && this.columnDef.filter || {}; - } - - /** Getter for the Current Dates selected */ - get currentDates() { - return this._currentDates; - } - - /** Getter to know what would be the default operator when none is specified */ - get defaultOperator(): OperatorType | OperatorString { - return this.gridOptions.defaultFilterRangeOperator || OperatorType.rangeInclusive; - } - - /** Getter for the Flatpickr Options */ - get flatpickrOptions(): FlatpickrOption { - return this._flatpickrOptions || {}; - } - - /** Getter for the Filter Operator */ - get operator(): OperatorType | OperatorString { - return this.columnFilter?.operator ?? this.defaultOperator; - } - - /** Setter for the filter operator */ - set operator(operator: OperatorType | OperatorString) { - if (this.columnFilter) { - this.columnFilter.operator = operator; - } - } - - /** - * Initialize the Filter - */ - init(args: FilterArguments) { - if (!args) { - throw new Error('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); - } - - this.grid = args.grid; - this.callback = args.callback; - this.columnDef = args.columnDef; - this.searchTerms = args?.searchTerms ?? []; - this.filterContainerElm = args.filterContainerElm; - - // step 1, create the DOM Element of the filter which contain the compound Operator+Input - this._filterElm = this.createDomFilterElement(this.searchTerms); - - // step 3, subscribe to the keyup event and run the callback when that happens - // also add/remove "filled" class for styling purposes - this._bindEventService.bind(this._filterDivInputElm, 'keyup', this.onTriggerEvent.bind(this)); - } - - /** - * Clear the filter value - */ - clear(shouldTriggerQuery = true) { - if (this.flatInstance) { - this._clearFilterTriggered = true; - this._shouldTriggerQuery = shouldTriggerQuery; - this.searchTerms = []; - if (this.flatInstance.input) { - this.flatInstance.clear(); - } - } - this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); - } - - /** - * destroy the filter - */ - destroy() { - this._bindEventService.unbindAll(); - - if (typeof this.flatInstance?.destroy === 'function') { - this.flatInstance.destroy(); - if (this.flatInstance.element) { - destroyObjectDomElementProps(this.flatInstance); - } - } - emptyElement(this.filterContainerElm); - emptyElement(this._filterDivInputElm); - this._filterDivInputElm?.remove(); - this.filterContainerElm?.remove(); - this._filterElm?.remove(); - this.grid = null as any; - } - - hide() { - if (typeof this.flatInstance?.close === 'function') { - this.flatInstance.close(); - } - } - - show() { - if (typeof this.flatInstance?.open === 'function') { - this.flatInstance.open(); - } - } - - getValues() { - return this._currentDates; - } - - /** - * Set value(s) on the DOM element - * @params searchTerms - */ - setValues(searchTerms: SearchTerm[] | SearchTerm | undefined, operator?: OperatorType | OperatorString) { - let pickerValues: any[] = []; - - // get the picker values, if it's a string with the "..", we'll do the split else we'll use the array of search terms - if (typeof searchTerms === 'string' || (Array.isArray(searchTerms) && typeof searchTerms[0] === 'string') && (searchTerms[0] as string).indexOf('..') > 0) { - pickerValues = (typeof searchTerms === 'string') ? [(searchTerms as string)] : (searchTerms[0] as string).split('..'); - } else if (Array.isArray(searchTerms)) { - pickerValues = searchTerms; - } - - if (this.flatInstance) { - this._currentDates = (searchTerms && pickerValues) ? pickerValues : undefined; - this.flatInstance.setDate(this._currentDates || ''); - } - - const currentValues = this.getValues() || []; - if (currentValues.length > 0 && searchTerms) { - this._filterElm.classList.add('filled'); - this._filterDivInputElm.classList.add('filled'); - } else { - this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); - } - - // set the operator when defined - this.operator = operator || this.defaultOperator; - } - - // - // protected functions - // ------------------ - protected buildDatePickerInput(searchTerms?: SearchTerm | SearchTerm[]): HTMLDivElement { - const columnId = this.columnDef?.id ?? ''; - const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateUtc); - const userFilterOptions = this.columnFilter?.filterOptions ?? {} as FlatpickrOption; - - // get current locale, if user defined a custom locale just use or get it the Translate Service if it exist else just use English - let currentLocale = (userFilterOptions?.locale ?? this.translaterService?.getCurrentLanguage?.()) || this.gridOptions.locale || 'en'; - if (currentLocale.length > 2) { - currentLocale = currentLocale.substring(0, 2); - } - - let pickerValues: any[] = []; - - // get the picker values, if it's a string with the "..", we'll do the split else we'll use the array of search terms - if (typeof searchTerms === 'string' || (Array.isArray(searchTerms) && typeof searchTerms[0] === 'string') && (searchTerms[0] as string).indexOf('..') > 0) { - pickerValues = (typeof searchTerms === 'string') ? [(searchTerms as string)] : (searchTerms[0] as string).split('..'); - } else if (Array.isArray(searchTerms)) { - pickerValues = searchTerms; - } - - // if we are preloading searchTerms, we'll keep them for reference - if (pickerValues) { - this._currentDates = pickerValues as Date[]; - const outFormat = mapMomentDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - this._currentDateStrings = pickerValues.map(date => moment(date).format(outFormat)); - } - - const pickerOptions: FlatpickrOption = { - defaultDate: (pickerValues || '') as string | string[], - altInput: true, - altFormat: outputFormat, - dateFormat: inputFormat, - mode: 'range', - wrap: true, - closeOnSelect: true, - locale: currentLocale, - onChange: (selectedDates: Date[] | Date) => { - if (Array.isArray(selectedDates)) { - this._currentDates = selectedDates; - const outFormat = mapMomentDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - this._currentDateStrings = selectedDates.map(date => moment(date).format(outFormat)); - this._currentValue = this._currentDateStrings.join('..'); - } - - // when using the time picker, we can simulate a keyup event to avoid multiple backend request - // since backend request are only executed after user start typing, changing the time should be treated the same way - const newEvent = pickerOptions.enableTime ? new Event('keyup') : undefined; - this.onTriggerEvent(newEvent); - }, - errorHandler: (error) => { - if (error.toString().includes('invalid locale')) { - console.warn(`[Slickgrid-Universal] Flatpickr missing locale imports (${currentLocale}), will revert to English as the default locale. - See Flatpickr Localization for more info, for example if we want to use French, then we can import it with: import 'flatpickr/dist/l10n/fr';`); - } - } - }; - - // add the time picker when format is UTC (Z) or has the 'h' (meaning hours) - if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) { - pickerOptions.enableTime = true; - } - - // merge options with optional user's custom options - this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions }; - - let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? ''; - if (this.columnFilter?.placeholder) { - placeholder = this.columnFilter.placeholder; - } - - const filterDivInputElm = createDomElement('div', { className: `flatpickr search-filter filter-${columnId}` }); - filterDivInputElm.appendChild( - createDomElement('input', { - type: 'text', className: 'form-control', - placeholder, - dataset: { input: '', columnid: `${columnId}` } - }) - ); - this.flatInstance = flatpickr(filterDivInputElm, this._flatpickrOptions as unknown as Partial); - - return filterDivInputElm; - } - - /** - * Create the DOM element - * @params searchTerms - */ - protected createDomFilterElement(searchTerms?: SearchTerm[]): HTMLDivElement { - emptyElement(this.filterContainerElm); - - // create the DOM element filter container - this._filterDivInputElm = this.buildDatePickerInput(searchTerms); - - // if there's a search term, we will add the "filled" class for styling purposes - if (Array.isArray(searchTerms) && searchTerms.length > 0 && searchTerms[0] !== '') { - this._filterDivInputElm.classList.add('filled'); - this._currentDates = searchTerms as Date[]; - this._currentValue = searchTerms[0] as string; - } - - // append the new DOM element to the header row - if (this._filterDivInputElm) { - this.filterContainerElm.appendChild(this._filterDivInputElm); - } - - return this._filterDivInputElm; - } - - protected onTriggerEvent(e: Event | undefined) { - if (this._clearFilterTriggered) { - this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery }); - this._filterElm.classList.remove('filled'); - } else { - (this._currentDateStrings) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); - this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentDateStrings ? this._currentDateStrings : [this._currentValue as string]), operator: this.operator || '', shouldTriggerQuery: this._shouldTriggerQuery }); - } - - // reset both flags for next use - this._clearFilterTriggered = false; - this._shouldTriggerQuery = true; + super(translaterService); + this.inputFilterType = 'range'; } } diff --git a/packages/common/src/filters/index.ts b/packages/common/src/filters/index.ts index 0f83b8348..7a21b0bea 100644 --- a/packages/common/src/filters/index.ts +++ b/packages/common/src/filters/index.ts @@ -4,6 +4,7 @@ export * from './compoundInputFilter'; export * from './compoundInputNumberFilter'; export * from './compoundInputPasswordFilter'; export * from './compoundSliderFilter'; +export * from './dateFilter'; export * from './dateRangeFilter'; export * from './filters.index'; export * from './filterFactory';