Skip to content

Commit

Permalink
Merge pull request #267 from ghiscoding/fix/date-filter-unsupported-l…
Browse files Browse the repository at this point in the history
…ocales

fix(filter): Date Filters using Flatpickr throw error w/invalid locale
  • Loading branch information
ghiscoding authored Nov 30, 2019
2 parents f331da4 + 2e6a7cc commit 376d852
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ describe('AutoCompleteEditor', () => {
setTimeout(() => {
expect(focusSpy).toHaveBeenCalled();
done();
}, 51);
}, 52);
});
});
});
Expand Down
23 changes: 23 additions & 0 deletions src/aurelia-slickgrid/filters/__tests__/compoundDateFilter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'jest-extended';
import { DOM } from 'aurelia-pal';
import { EventAggregator } from 'aurelia-event-aggregator';
import { I18N } from 'aurelia-i18n';
Expand Down Expand Up @@ -256,6 +257,28 @@ describe('CompoundDateFilter', () => {
expect(selectonOptionElms[0].textContent).toBe('janvier');
});

it('should throw an error and use English locale when user tries to load an unsupported Flatpickr locale', () => {
i18n.setLocale('zx');
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z'];
mockColumn.filter.operator = '<=';

filter.init(filterArguments);
const filterInputElm = divContainer.querySelector<HTMLInputElement>('.search-filter.filter-finish .flatpickr input.flatpickr');
const calendarElm = document.body.querySelector<HTMLDivElement>('.flatpickr-calendar');
const selectonOptionElms = calendarElm.querySelectorAll<HTMLSelectElement>(' .flatpickr-monthDropdown-months option');

filter.show();

filterInputElm.focus();
filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(consoleSpy).toHaveBeenCalledWith(expect.toInclude('[Aurelia-Slickgrid - CompoundDate Filter] It seems that "zx" is not a locale supported by Flatpickr'));
expect(selectonOptionElms.length).toBe(12);
expect(selectonOptionElms[0].textContent).toBe('January');
});

it('should trigger a callback with the clear filter set when calling the "clear" method', () => {
filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z'];
const spyCallback = jest.spyOn(filterArguments, 'callback');
Expand Down
23 changes: 23 additions & 0 deletions src/aurelia-slickgrid/filters/__tests__/dateRangeFilter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'jest-extended';
import { I18N } from 'aurelia-i18n';
import { DOM } from 'aurelia-pal';
import { EventAggregator } from 'aurelia-event-aggregator';
Expand Down Expand Up @@ -245,6 +246,28 @@ describe('DateRangeFilter', () => {
expect(selectonOptionElms[0].textContent).toBe('janvier');
});

it('should throw an error and use English locale when user tries to load an unsupported Flatpickr locale', () => {
i18n.setLocale('zx');
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z'];
mockColumn.filter.operator = 'RangeInclusive';

filter.init(filterArguments);
const filterInputElm = divContainer.querySelector<HTMLInputElement>('input.flatpickr.search-filter.filter-finish');
const calendarElm = document.body.querySelector<HTMLDivElement>('.flatpickr-calendar');
const selectonOptionElms = calendarElm.querySelectorAll<HTMLSelectElement>(' .flatpickr-monthDropdown-months option');

filter.show();

filterInputElm.focus();
filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(consoleSpy).toHaveBeenCalledWith(expect.toInclude('[Aurelia-Slickgrid - DateRange Filter] It seems that "zx" is not a locale supported by Flatpickr'));
expect(selectonOptionElms.length).toBe(12);
expect(selectonOptionElms[0].textContent).toBe('January');
});

it('should trigger a callback with the clear filter set when calling the "clear" method', () => {
filterArguments.searchTerms = ['2000-01-01', '2000-01-31'];
const spyCallback = jest.spyOn(filterArguments, 'callback');
Expand Down
21 changes: 15 additions & 6 deletions src/aurelia-slickgrid/filters/compoundDateFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ export class CompoundDateFilter implements Filter {
private buildDatePickerInput(searchTerm?: SearchTerm) {
const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.type || FieldType.dateIso);
const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnDef.type || FieldType.dateUtc);
let currentLocale = this.i18n && this.i18n.getLocale && this.i18n.getLocale() || 'en';
const userFilterOptions = (this.columnFilter && 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 && userFilterOptions.locale) || (this.i18n && this.i18n.getLocale && this.i18n.getLocale()) || 'en';
if (currentLocale && currentLocale.length > 2) {
currentLocale = currentLocale.substring(0, 2);
}
Expand Down Expand Up @@ -203,7 +206,7 @@ export class CompoundDateFilter implements Filter {
}

// merge options with optional user's custom options
this._flatpickrOptions = { ...pickerOptions, ...(this.columnFilter.filterOptions as FlatpickrOption) };
this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions };

let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
if (this.columnFilter && this.columnFilter.placeholder) {
Expand Down Expand Up @@ -293,10 +296,16 @@ export class CompoundDateFilter implements Filter {
private loadFlatpickrLocale(language: string) {
let locales = 'en';

if (language !== 'en') {
// change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
const localeDefault: any = require(`flatpickr/dist/l10n/${language}.js`).default;
locales = (localeDefault && localeDefault[language]) ? localeDefault[language] : 'en';
try {
if (language !== 'en') {
// change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
const localeDefault: any = require(`flatpickr/dist/l10n/${language}.js`).default;
locales = (localeDefault && localeDefault[language]) ? localeDefault[language] : 'en';
}
} catch (e) {
console.warn(`[Aurelia-Slickgrid - CompoundDate Filter] It seems that "${language}" is not a locale supported by Flatpickr, we will use "en" instead. `
+ `To avoid seeing this message, you can specifically set "filter: { filterOptions: { locale: 'en' } }" in your column definition.`);
return 'en';
}
return locales;
}
Expand Down
21 changes: 15 additions & 6 deletions src/aurelia-slickgrid/filters/dateRangeFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,10 @@ export class DateRangeFilter implements Filter {
const columnId = this.columnDef && this.columnDef.id;
const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.type || FieldType.dateIso);
const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnDef.type || FieldType.dateUtc);
let currentLocale = this.i18n && this.i18n.getLocale && this.i18n.getLocale() || 'en';
const userFilterOptions = (this.columnFilter && 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 && userFilterOptions.locale) || (this.i18n && this.i18n.getLocale && this.i18n.getLocale()) || 'en';
if (currentLocale.length > 2) {
currentLocale = currentLocale.substring(0, 2);
}
Expand Down Expand Up @@ -217,7 +220,7 @@ export class DateRangeFilter implements Filter {
}

// merge options with optional user's custom options
this._flatpickrOptions = { ...pickerOptions, ...(this.columnFilter.filterOptions as FlatpickrOption) };
this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions };

let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
if (this.columnFilter && this.columnFilter.placeholder) {
Expand Down Expand Up @@ -269,10 +272,16 @@ export class DateRangeFilter implements Filter {
private loadFlatpickrLocale(language: string) {
let locales = 'en';

if (language !== 'en') {
// change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
const localeDefault: any = require(`flatpickr/dist/l10n/${language}.js`).default;
locales = (localeDefault && localeDefault[language]) ? localeDefault[language] : 'en';
try {
if (language !== 'en') {
// change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
const localeDefault: any = require(`flatpickr/dist/l10n/${language}.js`).default;
locales = (localeDefault && localeDefault[language]) ? localeDefault[language] : 'en';
}
} catch (e) {
console.warn(`[Aurelia-Slickgrid - DateRange Filter] It seems that "${language}" is not a locale supported by Flatpickr, we will use "en" instead. `
+ `To avoid seeing this message, you can specifically set "filter: { filterOptions: { locale: 'en' } }" in your column definition.`);
return 'en';
}
return locales;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { Column, GridOption } from '../../models';
import { decimalFormatter } from '../decimalFormatter';

describe('the Decimal Formatter', () => {
let consoleSpy;
const gridStub = {
getOptions: jest.fn()
};

beforeEach(() => {
consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();
});

it('should display an empty string when no value is provided', () => {
const output = decimalFormatter(1, 1, '', {} as Column, {});
expect(output).toBe('');
Expand Down Expand Up @@ -58,6 +63,7 @@ describe('the Decimal Formatter', () => {
expect(output2).toBe('12345678.10');
expect(output3).toBe('12,345,678.10');
expect(output4).toBe('12 345 678,10');
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid] please consider using "minDecimal" (instead of "minDecimalPlaces" or "decimalPlaces").');
});

it('should display a number with dollar sign and use "maxDecimal" params', () => {
Expand All @@ -70,6 +76,7 @@ describe('the Decimal Formatter', () => {
const input = 88.156789;
const output = decimalFormatter(1, 1, input, { params: { maxDecimalPlaces: 3 } } as Column, {});
expect(output).toBe(`88.157`);
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid] please consider using "maxDecimal" (instead of "maxDecimalPlaces").');
});

it('should display a negative number with parentheses when "displayNegativeNumberWithParentheses" is enabled in the "params"', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ describe('FilterService', () => {
let service: FilterService;
let sharedService: SharedService;
let slickgridEventHandler: SlickEventHandler;
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

beforeEach(() => {
// define a <div> container to simulate a row detail DOM element
Expand Down Expand Up @@ -454,7 +455,7 @@ describe('FilterService', () => {
expect(spyEmitter).not.toHaveBeenCalled();
});

it('should clear all the Filters when the query response is a Promise', (done) => {
it('should clear all the Filters when the query response is a Promise (will be deprecated in future)', (done) => {
gridOptionMock.backendServiceApi.service.processOnFilterChanged = () => Promise.resolve('filter query from Promise');
const spyClear = jest.spyOn(service.getFiltersMetadata()[0], 'clear');
const spyFilterChange = jest.spyOn(service, 'onBackendFilterChange');
Expand All @@ -471,6 +472,7 @@ describe('FilterService', () => {
expect(service.getColumnFilters()).toEqual({});
expect(spyFilterChange).not.toHaveBeenCalled();
expect(spyEmitter).not.toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith(expect.toInclude('[Aurelia-Slickgrid] please note that the "processOnFilterChanged" method signature, from Backend Service'));
done();
});
});
Expand Down
15 changes: 15 additions & 0 deletions src/aurelia-slickgrid/services/__tests__/grid.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,18 +1029,22 @@ describe('Grid Service', () => {
// ----------------------

describe('deprecated methods', () => {
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

it('should call "addItem" when "addItemToDatagrid" is originally called', () => {
const mockItem = { id: 0 };
const spy = jest.spyOn(service, 'addItem');
service.addItemToDatagrid(mockItem);
expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "addItem" method since "addItemToDatagrid" will be deprecated in the future.');
});

it('should call "addItem" when "addItemsToDatagrid" is originally called', () => {
const mockItems = [{ id: 0 }];
const spy = jest.spyOn(service, 'addItems');
service.addItemsToDatagrid(mockItems);
expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "addItems" method since "addItemsToDatagrid" will be deprecated in the future.');
});

it('should call "updateItem" when "updateDataGridItem" is originally called', () => {
Expand All @@ -1052,6 +1056,7 @@ describe('Grid Service', () => {
service.updateDataGridItem(mockItem);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "updateItem" method since "updateDataGridItem" will be deprecated in the future.');
});

it('should call "updateItems" when "updateDataGridItems" is originally called', () => {
Expand All @@ -1063,6 +1068,7 @@ describe('Grid Service', () => {
service.updateDataGridItems([mockItem]);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "updateItems" method since "updateDataGridItems" will be deprecated in the future.');
});

it('should call "updateItemById" when "updateDataGridItemById" is originally called', () => {
Expand All @@ -1074,30 +1080,39 @@ describe('Grid Service', () => {
service.updateDataGridItemById(0, mockItem);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "updateItemById" method since "updateDataGridItemById" will be deprecated in the future.');
});

it('should call "deleteItem" when "deleteDataGridItem" is originally called', () => {
const spy = jest.spyOn(service, 'deleteItem');
service.deleteDataGridItem({ id: 0 });

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "deleteItem" method since "deleteDataGridItem" will be deprecated in the future.');
});

it('should call "deleteItems" when "deleteDataGridItems" is originally called', () => {
const spy = jest.spyOn(service, 'deleteItems');
service.deleteDataGridItems([{ id: 0 }]);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "deleteItems" method since "deleteDataGridItems" will be deprecated in the future.');
});

it('should call "deleteItemById" when "deleteDataGridItemById" is originally called', () => {
const spy = jest.spyOn(service, 'deleteItemById');
service.deleteDataGridItemById(5);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "deleteItemById" method since "deleteDataGridItemById" will be deprecated in the future.');
});

it('should call "deleteItemByIds" when "deleteDataGridItemByIds" is originally called', () => {
const spy = jest.spyOn(service, 'deleteItemByIds');
service.deleteDataGridItemByIds([5]);

expect(spy).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('[Aurelia-Slickgrid - GridService] please consider using the new "deleteItemByIds" method since "deleteDataGridItemByIds" will be deprecated in the future.');
});
});
});
Loading

0 comments on commit 376d852

Please sign in to comment.