Skip to content

Commit

Permalink
fix(build): import Flatpickr Locale on demand via regular imports
Browse files Browse the repository at this point in the history
- we shouldn't use require(locale) because they all end up being part of the final bundle, it's better to let the user import whichever Flatpickr Locale he wants to use and that will end up being a much smaller bundle with only the locale we really need
  • Loading branch information
ghiscoding committed Jan 5, 2021
1 parent 0ae6363 commit ef06543
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 80 deletions.
3 changes: 3 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ import { SwtCommonGridComponent } from './examples/swt-common-grid.component';
import { AngularSlickgridModule } from './modules/angular-slickgrid/modules/angular-slickgrid.module';
// import { SlickgridModule } from 'angular-slickgrid';

// load necessary Flatpickr Locale(s), but make sure it's imported AFTER the SlickgridModule import
import 'flatpickr/dist/l10n/fr';

// AoT requires an exported function for factories
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing';
import { TranslateService, TranslateModule } from '@ngx-translate/core';
import { Editors } from '../index';
import { DateEditor } from '../dateEditor';
import { AutocompleteOption, Column, EditorArgs, EditorArguments, GridOption, KeyCode, FieldType } from '../../models';
import { Column, EditorArguments, GridOption, FieldType } from '../../models';
import * as moment from 'moment-mini';

const KEY_CHAR_A = 97;
Expand Down Expand Up @@ -423,14 +423,27 @@ describe('DateEditor', () => {
});

describe('with different locale', () => {
it('should display text in new locale', (done) => {
it('should display a console warning when locale is not previously imported', (done) => {
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

gridOptionMock.i18n = translate;
translate.use('zz-yy'); // will be trimmed to 2 chars "zz"
editor = new DateEditor(editorArguments);
setTimeout(() => {
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Angular-Slickgrid] Flatpickr missing locale imports (zz), will revert to English as the default locale.`));
done();
});
});

translate.use('fr-CA'); // will be trimmed to "fr"
it('should display text in new locale', async () => {
await (await import('flatpickr/dist/l10n/fr')).French;

gridOptionMock.i18n = translate;
translate.use('fr');
editor = new DateEditor(editorArguments);

const spy = jest.spyOn(editor.flatInstance, 'open');
const calendarElm = document.body.querySelector<HTMLDivElement>('.flatpickr-calendar');
const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement;
const selectonOptionElms = calendarElm.querySelectorAll<HTMLSelectElement>(' .flatpickr-monthDropdown-months option');

editor.show();
Expand All @@ -439,7 +452,6 @@ describe('DateEditor', () => {
expect(selectonOptionElms.length).toBe(12);
expect(selectonOptionElms[0].textContent).toBe('janvier');
expect(spy).toHaveBeenCalled();
done();
});
});
});
Expand Down
27 changes: 8 additions & 19 deletions src/app/modules/angular-slickgrid/editors/dateEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,15 @@ export class DateEditor implements Editor {
dateFormat: inputFormat,
closeOnSelect: true,
wrap: true,
locale: (currentLocale !== 'en') ? this.loadFlatpickrLocale(currentLocale) : 'en',
locale: currentLocale,
onChange: () => this.save(),
errorHandler: () => {
// do nothing, Flatpickr is a little too sensitive and will throw an error when provided date is lower than minDate so just disregard the error completely
errorHandler: (error: Error) => {
if (error.toString().includes('invalid locale')) {
console.warn(`[Angular-Slickgrid] 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';`);
}
// for any other error do nothing
// Flatpickr is a little too sensitive and will throw an error when provided date is lower than minDate so just disregard the error completely
}
};

Expand Down Expand Up @@ -301,20 +306,4 @@ export class DateEditor implements Editor {
msg: null
};
}

//
// private functions
// ------------------

/** Load a different set of locales for Flatpickr to be localized */
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';
}
return locales;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ describe('CompoundDateFilter', () => {
closeOnSelect: true,
dateFormat: 'Y-m-d',
defaultDate: '',
errorHandler: expect.toBeFunction(),
locale: 'en',
onChange: expect.anything(),
wrap: true,
Expand Down Expand Up @@ -236,16 +237,18 @@ describe('CompoundDateFilter', () => {
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true });
});

it('should work with different locale when locale is changed', () => {
translate.use('fr-CA'); // will be trimmed to "fr"
it('should work with different locale when locale is changed', async () => {
await (await import('flatpickr/dist/l10n/fr')).French;

translate.use('fr');
filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z'];
mockColumn.filter.operator = '<=';
const spyCallback = jest.spyOn(filterArguments, 'callback');

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

filter.show();

Expand All @@ -262,10 +265,10 @@ 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', () => {
translate.use('zx');
it('should display a console warning when locale is not previously imported', (done) => {
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

translate.use('zz-yy'); // will be trimmed to 2 chars "zz"
filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z'];
mockColumn.filter.operator = '<=';

Expand All @@ -279,9 +282,12 @@ describe('CompoundDateFilter', () => {
filterInputElm.focus();
filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(consoleSpy).toHaveBeenCalledWith(expect.toInclude('[Angular-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');
setTimeout(() => {
expect(selectonOptionElms.length).toBe(12);
expect(selectonOptionElms[0].textContent).toBe('January');
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Angular-Slickgrid] Flatpickr missing locale imports (zz), will revert to English as the default locale.`));
done();
});
});

it('should trigger a callback with the clear filter set when calling the "clear" method', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ describe('DateRangeFilter', () => {
dateFormat: 'Y-m-d',
defaultDate: [],
enableTime: true,
errorHandler: expect.toBeFunction(),
locale: 'en',
mode: 'range',
onChange: expect.anything(),
Expand Down Expand Up @@ -211,8 +212,9 @@ describe('DateRangeFilter', () => {
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true });
});

it('should work with different locale when locale is changed', () => {
translate.use('fr-CA'); // will be trimmed to "fr"
it('should work with different locale when locale is changed', async () => {
await (await import('flatpickr/dist/l10n/fr')).French;
translate.use('fr');
filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z'];
mockColumn.filter.operator = 'RangeInclusive';
const spyCallback = jest.spyOn(filterArguments, 'callback');
Expand All @@ -236,26 +238,29 @@ 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', () => {
translate.use('zx');
it('should display a console warning when locale is not previously imported', (done) => {
const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue();

translate.use('zz-yy'); // will be trimmed to 2 chars "zz"
filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z'];
mockColumn.filter.operator = 'RangeInclusive';
mockColumn.filter!.operator = 'RangeInclusive';

filter.init(filterArguments);
const filterInputElm = divContainer.querySelector<HTMLInputElement>('.flatpickr.search-filter.filter-finish input.input');
const calendarElm = document.body.querySelector<HTMLDivElement>('.flatpickr-calendar');
const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement;
const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement;
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('[Angular-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');
setTimeout(() => {
expect(selectonOptionElms.length).toBe(12);
expect(selectonOptionElms[0].textContent).toBe('January');
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Angular-Slickgrid] Flatpickr missing locale imports (zz), will revert to English as the default locale.`));
done();
});
});

it('should trigger a callback with the clear filter set when calling the "clear" method', () => {
Expand Down
26 changes: 7 additions & 19 deletions src/app/modules/angular-slickgrid/filters/compoundDateFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export class CompoundDateFilter implements Filter {
dateFormat: inputFormat,
wrap: true,
closeOnSelect: true,
locale: (currentLocale !== 'en') ? this.loadFlatpickrLocale(currentLocale) : 'en',
locale: currentLocale,
onChange: (selectedDates: Date[] | Date, dateStr: string) => {
this._currentValue = dateStr;
this._currentDate = Array.isArray(selectedDates) && selectedDates[0];
Expand All @@ -217,6 +217,12 @@ export class CompoundDateFilter implements Filter {
customEvent = new CustomEvent('keyup');
}
this.onTriggerEvent(customEvent);
},
errorHandler: (error) => {
if (error.toString().includes('invalid locale')) {
console.warn(`[Angular-Slickgrid] 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';`);
}
}
};

Expand Down Expand Up @@ -312,24 +318,6 @@ export class CompoundDateFilter implements Filter {
return $filterContainerElm;
}

/** Load a different set of locales for Flatpickr to be localized */
private loadFlatpickrLocale(language: string) {
let locales = '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(`[Angular-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;
}

private onTriggerEvent(e: Event | undefined) {
if (this._clearFilterTriggered) {
this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
Expand Down
26 changes: 7 additions & 19 deletions src/app/modules/angular-slickgrid/filters/dateRangeFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export class DateRangeFilter implements Filter {
mode: 'range',
wrap: true,
closeOnSelect: true,
locale: (currentLocale !== 'en') ? this.loadFlatpickrLocale(currentLocale) : 'en',
locale: currentLocale,
onChange: (selectedDates: Date[] | Date, dateStr: string, instance: any) => {
if (Array.isArray(selectedDates)) {
this._currentDates = selectedDates;
Expand All @@ -221,6 +221,12 @@ export class DateRangeFilter implements Filter {
// since backend request are only executed after user start typing, changing the time should be treated the same way
const newEvent = pickerOptions.enableTime ? new CustomEvent('keyup') : undefined;
this.onTriggerEvent(newEvent);
},
errorHandler: (error) => {
if (error.toString().includes('invalid locale')) {
console.warn(`[Angular-Slickgrid] 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';`);
}
}
};

Expand Down Expand Up @@ -277,24 +283,6 @@ export class DateRangeFilter implements Filter {
return this.$filterInputElm;
}

/** Load a different set of locales for Flatpickr to be localized */
private loadFlatpickrLocale(language: string) {
let locales = '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(`[Angular-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;
}

private onTriggerEvent(e: Event | undefined) {
if (this._clearFilterTriggered) {
this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
Expand Down

0 comments on commit ef06543

Please sign in to comment.