From 43d0da5d144e5ed34b8241221bd42571cce9293d Mon Sep 17 00:00:00 2001 From: tumit Date: Tue, 21 Jan 2020 22:33:56 +0700 Subject: [PATCH] feat(datepicker): Implement Thai Buddish calendar in Datepicker #3893 (#5470) * style(datepicker): change Thai 'weekdaysShort' format for look better in datepicker * feat(datepicker): enable to modify date value after input and before format - add 'preinput' method to LocaleData interface (for after input) - add 'postvalue' method to LocaleData interface (for before format) feat(datepicker): add th-be for Thai Buddish caleder for #3893 --- .../+datepicker/demo-datepicker.module.ts | 4 +- demo/src/ng-api-doc.ts | 83 +++++++++++++++++++ src/chronos/format/format.ts | 5 +- src/chronos/i18n/th-be.ts | 76 +++++++++++++++++ src/chronos/locale/locale.class.ts | 12 +++ src/chronos/public_api.ts | 1 + src/chronos/test/locale/th-be.spec.ts | 16 ++++ .../bs-datepicker-input.directive.ts | 21 ++++- .../bs-daterangepicker-input.directive.ts | 23 +++-- src/locale.ts | 1 + src/locale/public_api.ts | 1 + 11 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 src/chronos/i18n/th-be.ts create mode 100644 src/chronos/test/locale/th-be.spec.ts diff --git a/demo/src/app/components/+datepicker/demo-datepicker.module.ts b/demo/src/app/components/+datepicker/demo-datepicker.module.ts index 1816188f04..189cb51c70 100644 --- a/demo/src/app/components/+datepicker/demo-datepicker.module.ts +++ b/demo/src/app/components/+datepicker/demo-datepicker.module.ts @@ -9,7 +9,7 @@ import { BsDatepickerModule, DatepickerModule } from 'ngx-bootstrap/datepicker'; import { arLocale, bgLocale, caLocale, csLocale, daLocale, deLocale, enGbLocale, esDoLocale, esLocale, esUsLocale, etLocale, frLocale, heLocale, hiLocale, hrLocale, fiLocale, glLocale, huLocale, idLocale, itLocale, jaLocale, kaLocale, koLocale, ltLocale, lvLocale, mnLocale, nbLocale, - nlBeLocale, nlLocale, plLocale, ptBrLocale, ruLocale, roLocale, skLocale, slLocale, svLocale, thLocale, trLocale, viLocale, + nlBeLocale, nlLocale, plLocale, ptBrLocale, ruLocale, roLocale, skLocale, slLocale, svLocale, thLocale, thBeLocale, trLocale, viLocale, zhCnLocale, ukLocale } from 'ngx-bootstrap/locale'; @@ -23,7 +23,7 @@ import { DEMO_COMPONENTS } from './demos'; const locales = [ arLocale, bgLocale, caLocale, csLocale, daLocale, deLocale, enGbLocale, esDoLocale, esLocale, esUsLocale, etLocale, frLocale, heLocale, hiLocale, hrLocale, fiLocale, glLocale, huLocale, idLocale, itLocale, jaLocale, kaLocale, koLocale, ltLocale, lvLocale, mnLocale, - nbLocale, nlBeLocale, nlLocale, plLocale, ptBrLocale, ruLocale, roLocale, skLocale, slLocale, svLocale, thLocale, + nbLocale, nlBeLocale, nlLocale, plLocale, ptBrLocale, ruLocale, roLocale, skLocale, slLocale, svLocale, thLocale, thBeLocale, trLocale, ukLocale, viLocale, zhCnLocale ]; diff --git a/demo/src/ng-api-doc.ts b/demo/src/ng-api-doc.ts index e76e774e1d..79934a5d4d 100644 --- a/demo/src/ng-api-doc.ts +++ b/demo/src/ng-api-doc.ts @@ -1054,6 +1054,79 @@ export const ngdoc: any = { } ] }, + "BsDaterangepickerInlineDirective": { + "fileName": "src/datepicker/bs-daterangepicker-inline.component.ts", + "className": "BsDaterangepickerInlineDirective", + "description": "", + "selector": "bs-daterangepicker-inline", + "exportAs": "bsDaterangepickerInline", + "inputs": [ + { + "name": "bsConfig", + "type": "Partial", + "description": "

Config object for datepicker

\n" + }, + { + "name": "bsValue", + "type": "Date[]", + "description": "

Initial value of datepicker

\n" + }, + { + "name": "dateCustomClasses", + "type": "DatepickerDateCustomClasses[]", + "description": "

Date custom classes

\n" + }, + { + "name": "datesDisabled", + "type": "Date[]", + "description": "

Disable specific dates

\n" + }, + { + "name": "isDisabled", + "type": "boolean", + "description": "

Indicates whether datepicker is enabled or not

\n" + }, + { + "name": "maxDate", + "type": "Date", + "description": "

Maximum date which is available for selection

\n" + }, + { + "name": "minDate", + "type": "Date", + "description": "

Minimum date which is available for selection

\n" + } + ], + "outputs": [ + { + "name": "bsValueChange", + "description": "

Emits when daterangepicker value has been changed

\n" + } + ], + "properties": [], + "methods": [ + { + "name": "setConfig", + "description": "

Set config for datepicker

\n", + "args": [], + "returnType": "void" + } + ] + }, + "BsDaterangepickerInlineConfig": { + "fileName": "src/datepicker/bs-daterangepicker-inline.config.ts", + "className": "BsDaterangepickerInlineConfig", + "description": "", + "methods": [], + "properties": [ + { + "name": "isAnimated", + "defaultValue": "false", + "type": "boolean", + "description": "

turn on/off animation

\n" + } + ] + }, "BsDaterangepickerInputDirective": { "fileName": "src/datepicker/bs-daterangepicker-input.directive.ts", "className": "BsDaterangepickerInputDirective", @@ -1826,6 +1899,16 @@ export const ngdoc: any = { "properties": [], "methods": [] }, + "BsDaterangepickerInlineContainerComponent": { + "fileName": "src/datepicker/themes/bs/bs-daterangepicker-inline-container.component.ts", + "className": "BsDaterangepickerInlineContainerComponent", + "description": "", + "selector": "bs-daterangepicker-inline-container", + "inputs": [], + "outputs": [], + "properties": [], + "methods": [] + }, "BsDaysCalendarViewComponent": { "fileName": "src/datepicker/themes/bs/bs-days-calendar-view.component.ts", "className": "BsDaysCalendarViewComponent", diff --git a/src/chronos/format/format.ts b/src/chronos/format/format.ts index cb852a6d79..6ece95dd53 100644 --- a/src/chronos/format/format.ts +++ b/src/chronos/format/format.ts @@ -52,10 +52,13 @@ export function makeFormatFunction(format: string): } return function (date: Date, locale: Locale, isUTC: boolean, offset = 0): string { + + const postValue = locale.postvalue(date); + let output = ''; for (let j = 0; j < length; j++) { output += isFunction(formatArr[j]) - ? (formatArr[j] as DateFormatterFn).call(null, date, {format, locale, isUTC, offset}) + ? (formatArr[j] as DateFormatterFn).call(null, postValue, {format, locale, isUTC, offset}) : formatArr[j]; } diff --git a/src/chronos/i18n/th-be.ts b/src/chronos/i18n/th-be.ts new file mode 100644 index 0000000000..60f12dd9eb --- /dev/null +++ b/src/chronos/i18n/th-be.ts @@ -0,0 +1,76 @@ +// tslint:disable:comment-format binary-expression-operand-order max-line-length +// tslint:disable:no-bitwise prefer-template cyclomatic-complexity +// tslint:disable:no-shadowed-variable switch-default prefer-const +// tslint:disable:one-variable-per-declaration newline-before-return + +// moment.js locale configuration +// locale : Thai-Buddhist Era [th-be] +// author : Watcharapol Sanitwong : https://github.com/tumit + +import { LocaleData } from '../locale/locale.class'; + +export const thBeLocale: LocaleData = { + abbr: 'th-be', + months: 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'), + monthsShort: 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'), + monthsParseExact: true, + weekdays: 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'), + weekdaysShort: 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), + weekdaysMin: 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY เวลา H:mm', + LLLL: 'วันddddที่ D MMMM YYYY เวลา H:mm' + }, + meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/, + isPM(input) { + return input === 'หลังเที่ยง'; + }, + meridiem(hour, minute, isLower) { + if (hour < 12) { + return 'ก่อนเที่ยง'; + } else { + return 'หลังเที่ยง'; + } + }, + calendar: { + sameDay: '[วันนี้ เวลา] LT', + nextDay: '[พรุ่งนี้ เวลา] LT', + nextWeek: 'dddd[หน้า เวลา] LT', + lastDay: '[เมื่อวานนี้ เวลา] LT', + lastWeek: '[วัน]dddd[ที่แล้ว เวลา] LT', + sameElse: 'L' + }, + relativeTime: { + future: 'อีก %s', + past: '%sที่แล้ว', + s: 'ไม่กี่วินาที', + ss: '%d วินาที', + m: '1 นาที', + mm: '%d นาที', + h: '1 ชั่วโมง', + hh: '%d ชั่วโมง', + d: '1 วัน', + dd: '%d วัน', + M: '1 เดือน', + MM: '%d เดือน', + y: '1 ปี', + yy: '%d ปี' + }, + preinput(input: Date): Date { + // just year-543 of input before next step + let preinputDate = new Date(input); + preinputDate.setFullYear(input.getFullYear()-543); + return preinputDate; + }, + postvalue(value: Date): Date { + // just year+543 of value before display on ui + let preinputDate = new Date(value); + preinputDate.setFullYear(value.getFullYear()+543); + return preinputDate; + } +}; diff --git a/src/chronos/locale/locale.class.ts b/src/chronos/locale/locale.class.ts index a36d9e7662..4348e9a9db 100644 --- a/src/chronos/locale/locale.class.ts +++ b/src/chronos/locale/locale.class.ts @@ -89,6 +89,10 @@ export interface LocaleData { preparse?(str: string): string; + preinput?(input: Date): Date; + + postvalue?(value: Date): Date; + postformat?(str: string | number): string; meridiem?(hour: number, minute?: number, isLower?: boolean): string; @@ -198,6 +202,14 @@ export class Locale { return str; } + preinput(input: Date) { + return input; + } + + postvalue(value: Date) { + return value; + } + postformat(str: string) { return str; } diff --git a/src/chronos/public_api.ts b/src/chronos/public_api.ts index 1646fccf6e..c021cfa161 100644 --- a/src/chronos/public_api.ts +++ b/src/chronos/public_api.ts @@ -71,6 +71,7 @@ export { skLocale } from './i18n/sk'; export { slLocale } from './i18n/sl'; export { svLocale } from './i18n/sv'; export { thLocale } from './i18n/th'; +export { thBeLocale } from './i18n/th-be'; export { trLocale } from './i18n/tr'; export { ukLocale } from './i18n/uk'; export { viLocale } from './i18n/vi'; diff --git a/src/chronos/test/locale/th-be.spec.ts b/src/chronos/test/locale/th-be.spec.ts new file mode 100644 index 0000000000..4cce290b42 --- /dev/null +++ b/src/chronos/test/locale/th-be.spec.ts @@ -0,0 +1,16 @@ +// tslint:disable:max-line-length max-file-line-count prefer-const forin prefer-template one-variable-per-declaration newline-before-return +// tslint:disable:binary-expression-operand-order comment-format one-line no-var-keyword object-literal-shorthand +// tslint:disable:variable-name no-shadowed-variable + +import { assertEq } from '../test-helpers'; +import { thBeLocale } from '../../i18n/th-be'; + +describe('locale: th-be', () => { + it('prevalue should -543 of years', function () { + assertEq(thBeLocale.preinput(new Date(2553, 1, 14)).getTime(), new Date(2010, 1, 14).getTime()); + }); + + it('postvalue should +543 of years', function () { + assertEq(thBeLocale.postvalue(new Date(2010, 1, 14)).getTime(), new Date(2553, 1, 14).getTime()); + }); +}); diff --git a/src/datepicker/bs-datepicker-input.directive.ts b/src/datepicker/bs-datepicker-input.directive.ts index d821719f46..12eef83235 100644 --- a/src/datepicker/bs-datepicker-input.directive.ts +++ b/src/datepicker/bs-datepicker-input.directive.ts @@ -69,10 +69,23 @@ export class BsDatepickerInputDirective private changeDetection: ChangeDetectorRef) { // update input value on datepicker value update this._picker.bsValueChange.subscribe((value: Date) => { - this._setInputValue(value); - if (this._value !== value) { - this._value = value; - this._onChange(value); + + let preValue = value; + if (value) { + const _localeKey = this._localeService.currentLocale; + const _locale = getLocale(_localeKey); + if (!_locale) { + throw new Error( + `Locale "${_localeKey}" is not defined, please add it with "defineLocale(...)"` + ); + } + preValue = _locale.preinput(value); + } + + this._setInputValue(preValue); + if (this._value !== preValue) { + this._value = preValue; + this._onChange(preValue); this._onTouched(); } this.changeDetection.markForCheck(); diff --git a/src/datepicker/bs-daterangepicker-input.directive.ts b/src/datepicker/bs-daterangepicker-input.directive.ts index 9a7d1aa763..c9f4963f45 100644 --- a/src/datepicker/bs-daterangepicker-input.directive.ts +++ b/src/datepicker/bs-daterangepicker-input.directive.ts @@ -70,10 +70,24 @@ export class BsDaterangepickerInputDirective private changeDetection: ChangeDetectorRef) { // update input value on datepicker value update this._picker.bsValueChange.subscribe((value: Date[]) => { - this._setInputValue(value); - if (this._value !== value) { - this._value = value; - this._onChange(value); + + let preValue = value; + + if (value) { + const _localeKey = this._localeService.currentLocale; + const _locale = getLocale(_localeKey); + if (!_locale) { + throw new Error( + `Locale "${_localeKey}" is not defined, please add it with "defineLocale(...)"` + ); + } + preValue = value.map(v => _locale.preinput(v)); + } + + this._setInputValue(preValue); + if (this._value !== preValue) { + this._value = preValue; + this._onChange(preValue); this._onTouched(); } this.changeDetection.markForCheck(); @@ -174,7 +188,6 @@ export class BsDaterangepickerInputDirective _input = value; } - this._value = (_input as string[]) .map((_val: string): Date => { if (this._picker._config.useUtc) { diff --git a/src/locale.ts b/src/locale.ts index ca5b89667e..c6d99e9ff1 100644 --- a/src/locale.ts +++ b/src/locale.ts @@ -36,6 +36,7 @@ export { slLocale, svLocale, thLocale, + thBeLocale, trLocale, ukLocale, viLocale, diff --git a/src/locale/public_api.ts b/src/locale/public_api.ts index 9f08f6f94c..4502914d85 100644 --- a/src/locale/public_api.ts +++ b/src/locale/public_api.ts @@ -35,6 +35,7 @@ export { skLocale } from 'ngx-bootstrap/chronos'; export { slLocale } from 'ngx-bootstrap/chronos'; export { svLocale } from 'ngx-bootstrap/chronos'; export { thLocale } from 'ngx-bootstrap/chronos'; +export { thBeLocale } from 'ngx-bootstrap/chronos'; export { trLocale } from 'ngx-bootstrap/chronos'; export { ukLocale } from 'ngx-bootstrap/chronos'; export { viLocale } from 'ngx-bootstrap/chronos';