ngx-bootstrap
Version:
Native Angular Bootstrap Components
1,648 lines (1,630 loc) • 171 kB
JavaScript
import { Injectable, EventEmitter, Component, Renderer2, ElementRef, Directive, ViewContainerRef, Input, Output, forwardRef, Host, ChangeDetectorRef, ChangeDetectionStrategy, NgModule, ViewChild } from '@angular/core';
import { filter, map, take } from 'rxjs/operators';
import { getMonth, getFullYear, isFirstDayOfWeek, getDay, shiftDate, isBefore, endOf, isAfter, startOf, isSame, getFirstDayOfMonth, formatDate, getLocale, isSameMonth, isSameDay, isDisabledDay, isSameYear, setFullDate, isDateValid, isArray, isDate, parseDate, utcAsLocal } from 'ngx-bootstrap/chronos';
import { BehaviorSubject } from 'rxjs';
import { MiniStore, MiniState } from 'ngx-bootstrap/mini-ngrx';
import { PositioningService } from 'ngx-bootstrap/positioning';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { isBs3 } from 'ngx-bootstrap/utils';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* For date range picker there are `BsDaterangepickerConfig` which inherits all properties,
* except `displayMonths`, for range picker it default to `2`
*/
class BsDatepickerConfig {
constructor() {
/**
* sets use adaptive position
*/
this.adaptivePosition = false;
/**
* turn on/off animation
*/
this.isAnimated = false;
/**
* CSS class which will be applied to datepicker container,
* usually used to set color theme
*/
this.containerClass = 'theme-green';
// DatepickerRenderOptions
this.displayMonths = 1;
/**
* Allows to hide week numbers in datepicker
*/
this.showWeekNumbers = true;
this.dateInputFormat = 'L';
// range picker
this.rangeSeparator = ' - ';
/**
* Date format for date range input field
*/
this.rangeInputFormat = 'L';
// DatepickerFormatOptions
this.monthTitle = 'MMMM';
this.yearTitle = 'YYYY';
this.dayLabel = 'D';
this.monthLabel = 'MMMM';
this.yearLabel = 'YYYY';
this.weekNumbers = 'w';
}
}
BsDatepickerConfig.decorators = [
{ type: Injectable }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @abstract
*/
class BsDatepickerAbstractComponent {
constructor() {
this._customRangesFish = [];
}
/**
* @param {?} value
* @return {?}
*/
set minDate(value) {
this._effects.setMinDate(value);
}
/**
* @param {?} value
* @return {?}
*/
set maxDate(value) {
this._effects.setMaxDate(value);
}
/**
* @param {?} value
* @return {?}
*/
set daysDisabled(value) {
this._effects.setDaysDisabled(value);
}
/**
* @param {?} value
* @return {?}
*/
set datesDisabled(value) {
this._effects.setDatesDisabled(value);
}
/**
* @param {?} value
* @return {?}
*/
set isDisabled(value) {
this._effects.setDisabled(value);
}
/**
* @param {?} value
* @return {?}
*/
set dateCustomClasses(value) {
this._effects.setDateCustomClasses(value);
}
/**
* @param {?} event
* @return {?}
*/
setViewMode(event) { }
/**
* @param {?} event
* @return {?}
*/
navigateTo(event) { }
/**
* @param {?} event
* @return {?}
*/
dayHoverHandler(event) { }
/**
* @param {?} event
* @return {?}
*/
weekHoverHandler(event) { }
/**
* @param {?} event
* @return {?}
*/
monthHoverHandler(event) { }
/**
* @param {?} event
* @return {?}
*/
yearHoverHandler(event) { }
/**
* @param {?} day
* @return {?}
*/
daySelectHandler(day) { }
/**
* @param {?} event
* @return {?}
*/
monthSelectHandler(event) { }
/**
* @param {?} event
* @return {?}
*/
yearSelectHandler(event) { }
/* tslint:disable-next-line: no-any */
/**
* @param {?} event
* @return {?}
*/
_stopPropagation(event) {
event.stopPropagation();
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class BsDatepickerActions {
/**
* @return {?}
*/
calculate() {
return { type: BsDatepickerActions.CALCULATE };
}
/**
* @return {?}
*/
format() {
return { type: BsDatepickerActions.FORMAT };
}
/**
* @return {?}
*/
flag() {
return { type: BsDatepickerActions.FLAG };
}
/**
* @param {?} date
* @return {?}
*/
select(date) {
return {
type: BsDatepickerActions.SELECT,
payload: date
};
}
/**
* @param {?} event
* @return {?}
*/
changeViewMode(event) {
return {
type: BsDatepickerActions.CHANGE_VIEWMODE,
payload: event
};
}
/**
* @param {?} event
* @return {?}
*/
navigateTo(event) {
return {
type: BsDatepickerActions.NAVIGATE_TO,
payload: event
};
}
/**
* @param {?} step
* @return {?}
*/
navigateStep(step) {
return {
type: BsDatepickerActions.NAVIGATE_OFFSET,
payload: step
};
}
/**
* @param {?} options
* @return {?}
*/
setOptions(options) {
return {
type: BsDatepickerActions.SET_OPTIONS,
payload: options
};
}
// date range picker
/**
* @param {?} value
* @return {?}
*/
selectRange(value) {
return {
type: BsDatepickerActions.SELECT_RANGE,
payload: value
};
}
/**
* @param {?} event
* @return {?}
*/
hoverDay(event) {
return {
type: BsDatepickerActions.HOVER,
payload: event.isHovered ? event.cell.date : null
};
}
/**
* @param {?} date
* @return {?}
*/
minDate(date) {
return {
type: BsDatepickerActions.SET_MIN_DATE,
payload: date
};
}
/**
* @param {?} date
* @return {?}
*/
maxDate(date) {
return {
type: BsDatepickerActions.SET_MAX_DATE,
payload: date
};
}
/**
* @param {?} days
* @return {?}
*/
daysDisabled(days) {
return {
type: BsDatepickerActions.SET_DAYSDISABLED,
payload: days
};
}
/**
* @param {?} dates
* @return {?}
*/
datesDisabled(dates) {
return {
type: BsDatepickerActions.SET_DATESDISABLED,
payload: dates
};
}
/**
* @param {?} value
* @return {?}
*/
isDisabled(value) {
return {
type: BsDatepickerActions.SET_IS_DISABLED,
payload: value
};
}
/**
* @param {?} value
* @return {?}
*/
setDateCustomClasses(value) {
return {
type: BsDatepickerActions.SET_DATE_CUSTOM_CLASSES,
payload: value
};
}
/**
* @param {?} locale
* @return {?}
*/
setLocale(locale) {
return {
type: BsDatepickerActions.SET_LOCALE,
payload: locale
};
}
}
BsDatepickerActions.CALCULATE = '[datepicker] calculate dates matrix';
BsDatepickerActions.FORMAT = '[datepicker] format datepicker values';
BsDatepickerActions.FLAG = '[datepicker] set flags';
BsDatepickerActions.SELECT = '[datepicker] select date';
BsDatepickerActions.NAVIGATE_OFFSET = '[datepicker] shift view date';
BsDatepickerActions.NAVIGATE_TO = '[datepicker] change view date';
BsDatepickerActions.SET_OPTIONS = '[datepicker] update render options';
BsDatepickerActions.HOVER = '[datepicker] hover date';
BsDatepickerActions.CHANGE_VIEWMODE = '[datepicker] switch view mode';
BsDatepickerActions.SET_MIN_DATE = '[datepicker] set min date';
BsDatepickerActions.SET_MAX_DATE = '[datepicker] set max date';
BsDatepickerActions.SET_DAYSDISABLED = '[datepicker] set days disabled';
BsDatepickerActions.SET_DATESDISABLED = '[datepicker] set dates disabled';
BsDatepickerActions.SET_IS_DISABLED = '[datepicker] set is disabled';
BsDatepickerActions.SET_DATE_CUSTOM_CLASSES = '[datepicker] set date custom classes';
BsDatepickerActions.SET_LOCALE = '[datepicker] set datepicker locale';
BsDatepickerActions.SELECT_RANGE = '[daterangepicker] select dates range';
BsDatepickerActions.decorators = [
{ type: Injectable }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class BsLocaleService {
constructor() {
this._defaultLocale = 'en';
this._locale = new BehaviorSubject(this._defaultLocale);
this._localeChange = this._locale.asObservable();
}
/**
* @return {?}
*/
get locale() {
return this._locale;
}
/**
* @return {?}
*/
get localeChange() {
return this._localeChange;
}
/**
* @return {?}
*/
get currentLocale() {
return this._locale.getValue();
}
/**
* @param {?} locale
* @return {?}
*/
use(locale) {
if (locale === this.currentLocale) {
return;
}
this._locale.next(locale);
}
}
BsLocaleService.decorators = [
{ type: Injectable }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class BsDatepickerEffects {
/**
* @param {?} _actions
* @param {?} _localeService
*/
constructor(_actions, _localeService) {
this._actions = _actions;
this._localeService = _localeService;
this._subs = [];
}
/**
* @param {?} _bsDatepickerStore
* @return {?}
*/
init(_bsDatepickerStore) {
this._store = _bsDatepickerStore;
return this;
}
/**
* setters
* @param {?} value
* @return {?}
*/
setValue(value) {
this._store.dispatch(this._actions.select(value));
}
/**
* @param {?} value
* @return {?}
*/
setRangeValue(value) {
this._store.dispatch(this._actions.selectRange(value));
}
/**
* @param {?} value
* @return {?}
*/
setMinDate(value) {
this._store.dispatch(this._actions.minDate(value));
return this;
}
/**
* @param {?} value
* @return {?}
*/
setMaxDate(value) {
this._store.dispatch(this._actions.maxDate(value));
return this;
}
/**
* @template THIS
* @this {THIS}
* @param {?} value
* @return {THIS}
*/
setDaysDisabled(value) {
(/** @type {?} */ (this))._store.dispatch((/** @type {?} */ (this))._actions.daysDisabled(value));
return (/** @type {?} */ (this));
}
/**
* @template THIS
* @this {THIS}
* @param {?} value
* @return {THIS}
*/
setDatesDisabled(value) {
(/** @type {?} */ (this))._store.dispatch((/** @type {?} */ (this))._actions.datesDisabled(value));
return (/** @type {?} */ (this));
}
/**
* @param {?} value
* @return {?}
*/
setDisabled(value) {
this._store.dispatch(this._actions.isDisabled(value));
return this;
}
/**
* @param {?} value
* @return {?}
*/
setDateCustomClasses(value) {
this._store.dispatch(this._actions.setDateCustomClasses(value));
return this;
}
/* Set rendering options */
/**
* @param {?} _config
* @return {?}
*/
setOptions(_config) {
/** @type {?} */
const _options = Object.assign({ locale: this._localeService.currentLocale }, _config);
this._store.dispatch(this._actions.setOptions(_options));
return this;
}
/**
* view to mode bindings
* @param {?} container
* @return {?}
*/
setBindings(container) {
container.daysCalendar = this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.flaggedMonths))
.pipe(filter((/**
* @param {?} months
* @return {?}
*/
months => !!months)));
// month calendar
container.monthsCalendar = this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.flaggedMonthsCalendar))
.pipe(filter((/**
* @param {?} months
* @return {?}
*/
months => !!months)));
// year calendar
container.yearsCalendar = this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.yearsCalendarFlagged))
.pipe(filter((/**
* @param {?} years
* @return {?}
*/
years => !!years)));
container.viewMode = this._store.select((/**
* @param {?} state
* @return {?}
*/
state => state.view.mode));
container.options = this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.showWeekNumbers))
.pipe(map((/**
* @param {?} showWeekNumbers
* @return {?}
*/
showWeekNumbers => ({ showWeekNumbers }))));
return this;
}
/**
* event handlers
* @param {?} container
* @return {?}
*/
setEventHandlers(container) {
container.setViewMode = (/**
* @param {?} event
* @return {?}
*/
(event) => {
this._store.dispatch(this._actions.changeViewMode(event));
});
container.navigateTo = (/**
* @param {?} event
* @return {?}
*/
(event) => {
this._store.dispatch(this._actions.navigateStep(event.step));
});
container.dayHoverHandler = (/**
* @param {?} event
* @return {?}
*/
(event) => {
/** @type {?} */
const _cell = (/** @type {?} */ (event.cell));
if (_cell.isOtherMonth || _cell.isDisabled) {
return;
}
this._store.dispatch(this._actions.hoverDay(event));
_cell.isHovered = event.isHovered;
});
container.monthHoverHandler = (/**
* @param {?} event
* @return {?}
*/
(event) => {
event.cell.isHovered = event.isHovered;
});
container.yearHoverHandler = (/**
* @param {?} event
* @return {?}
*/
(event) => {
event.cell.isHovered = event.isHovered;
});
container.monthSelectHandler = (/**
* @param {?} event
* @return {?}
*/
(event) => {
if (event.isDisabled) {
return;
}
this._store.dispatch(this._actions.navigateTo({
unit: {
month: getMonth(event.date),
year: getFullYear(event.date)
},
viewMode: 'day'
}));
});
container.yearSelectHandler = (/**
* @param {?} event
* @return {?}
*/
(event) => {
if (event.isDisabled) {
return;
}
this._store.dispatch(this._actions.navigateTo({
unit: {
year: getFullYear(event.date)
},
viewMode: 'month'
}));
});
return this;
}
/**
* @return {?}
*/
registerDatepickerSideEffects() {
this._subs.push(this._store.select((/**
* @param {?} state
* @return {?}
*/
state => state.view)).subscribe((/**
* @param {?} view
* @return {?}
*/
view => {
this._store.dispatch(this._actions.calculate());
})));
// format calendar values on month model change
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.monthsModel))
.pipe(filter((/**
* @param {?} monthModel
* @return {?}
*/
monthModel => !!monthModel)))
.subscribe((/**
* @param {?} month
* @return {?}
*/
month => this._store.dispatch(this._actions.format()))));
// flag day values
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.formattedMonths))
.pipe(filter((/**
* @param {?} month
* @return {?}
*/
month => !!month)))
.subscribe((/**
* @param {?} month
* @return {?}
*/
month => this._store.dispatch(this._actions.flag()))));
// flag day values
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.selectedDate))
.pipe(filter((/**
* @param {?} selectedDate
* @return {?}
*/
selectedDate => !!selectedDate)))
.subscribe((/**
* @param {?} selectedDate
* @return {?}
*/
selectedDate => this._store.dispatch(this._actions.flag()))));
// flag for date range picker
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.selectedRange))
.pipe(filter((/**
* @param {?} selectedRange
* @return {?}
*/
selectedRange => !!selectedRange)))
.subscribe((/**
* @param {?} selectedRange
* @return {?}
*/
selectedRange => this._store.dispatch(this._actions.flag()))));
// monthsCalendar
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.monthsCalendar))
.subscribe((/**
* @return {?}
*/
() => this._store.dispatch(this._actions.flag()))));
// years calendar
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.yearsCalendarModel))
.pipe(filter((/**
* @param {?} state
* @return {?}
*/
state => !!state)))
.subscribe((/**
* @return {?}
*/
() => this._store.dispatch(this._actions.flag()))));
// on hover
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.hoveredDate))
.pipe(filter((/**
* @param {?} hoveredDate
* @return {?}
*/
hoveredDate => !!hoveredDate)))
.subscribe((/**
* @param {?} hoveredDate
* @return {?}
*/
hoveredDate => this._store.dispatch(this._actions.flag()))));
// date custom classes
this._subs.push(this._store
.select((/**
* @param {?} state
* @return {?}
*/
state => state.dateCustomClasses))
.pipe(filter((/**
* @param {?} dateCustomClasses
* @return {?}
*/
dateCustomClasses => !!dateCustomClasses)))
.subscribe((/**
* @param {?} dateCustomClasses
* @return {?}
*/
dateCustomClasses => this._store.dispatch(this._actions.flag()))));
// on locale change
this._subs.push(this._localeService.localeChange
.subscribe((/**
* @param {?} locale
* @return {?}
*/
locale => this._store.dispatch(this._actions.setLocale(locale)))));
return this;
}
/**
* @return {?}
*/
destroy() {
for (const sub of this._subs) {
sub.unsubscribe();
}
}
}
BsDatepickerEffects.decorators = [
{ type: Injectable }
];
/** @nocollapse */
BsDatepickerEffects.ctorParameters = () => [
{ type: BsDatepickerActions },
{ type: BsLocaleService }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const defaultMonthOptions = {
width: 7,
height: 6
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const _initialView = { date: new Date(), mode: 'day' };
/** @type {?} */
const initialDatepickerState = Object.assign(new BsDatepickerConfig(), {
locale: 'en',
view: _initialView,
selectedRange: [],
monthViewOptions: defaultMonthOptions
});
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} date
* @param {?} options
* @return {?}
*/
function getStartingDayOfCalendar(date, options) {
if (isFirstDayOfWeek(date, options.firstDayOfWeek)) {
return date;
}
/** @type {?} */
const weekDay = getDay(date);
/** @type {?} */
const offset = calculateDateOffset(weekDay, options.firstDayOfWeek);
return shiftDate(date, { day: -offset });
}
/**
* @param {?} weekday
* @param {?} startingDayOffset
* @return {?}
*/
function calculateDateOffset(weekday, startingDayOffset) {
if (startingDayOffset === 0) {
return weekday;
}
/** @type {?} */
const offset = weekday - startingDayOffset % 7;
return offset < 0 ? offset + 7 : offset;
}
/**
* @param {?} date
* @param {?} min
* @param {?} max
* @return {?}
*/
function isMonthDisabled(date, min, max) {
/** @type {?} */
const minBound = min && isBefore(endOf(date, 'month'), min, 'day');
/** @type {?} */
const maxBound = max && isAfter(startOf(date, 'month'), max, 'day');
return minBound || maxBound;
}
/**
* @param {?} date
* @param {?} min
* @param {?} max
* @return {?}
*/
function isYearDisabled(date, min, max) {
/** @type {?} */
const minBound = min && isBefore(endOf(date, 'year'), min, 'day');
/** @type {?} */
const maxBound = max && isAfter(startOf(date, 'year'), max, 'day');
return minBound || maxBound;
}
/**
* @param {?} date
* @param {?} datesDisabled
* @return {?}
*/
function isDisabledDate(date, datesDisabled) {
if (datesDisabled === undefined || !datesDisabled || !datesDisabled.length) {
return false;
}
return datesDisabled.some((/**
* @param {?} dateDisabled
* @return {?}
*/
(dateDisabled) => isSame(date, dateDisabled, 'date')));
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template T
* @param {?} options
* @param {?} fn
* @return {?}
*/
function createMatrix(options, fn) {
/** @type {?} */
let prevValue = options.initialDate;
/** @type {?} */
const matrix = new Array(options.height);
for (let i = 0; i < options.height; i++) {
matrix[i] = new Array(options.width);
for (let j = 0; j < options.width; j++) {
matrix[i][j] = fn(prevValue);
prevValue = shiftDate(prevValue, options.shift);
}
}
return matrix;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} startingDate
* @param {?} options
* @return {?}
*/
function calcDaysCalendar(startingDate, options) {
/** @type {?} */
const firstDay = getFirstDayOfMonth(startingDate);
/** @type {?} */
const initialDate = getStartingDayOfCalendar(firstDay, options);
/** @type {?} */
const matrixOptions = {
width: options.width,
height: options.height,
initialDate,
shift: { day: 1 }
};
/** @type {?} */
const daysMatrix = createMatrix(matrixOptions, (/**
* @param {?} date
* @return {?}
*/
date => date));
return {
daysMatrix,
month: firstDay
};
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} daysCalendar
* @param {?} formatOptions
* @param {?} monthIndex
* @return {?}
*/
function formatDaysCalendar(daysCalendar, formatOptions, monthIndex) {
return {
month: daysCalendar.month,
monthTitle: formatDate(daysCalendar.month, formatOptions.monthTitle, formatOptions.locale),
yearTitle: formatDate(daysCalendar.month, formatOptions.yearTitle, formatOptions.locale),
weekNumbers: getWeekNumbers(daysCalendar.daysMatrix, formatOptions.weekNumbers, formatOptions.locale),
weekdays: getShiftedWeekdays(formatOptions.locale),
weeks: daysCalendar.daysMatrix.map((/**
* @param {?} week
* @param {?} weekIndex
* @return {?}
*/
(week, weekIndex) => ({
days: week.map((/**
* @param {?} date
* @param {?} dayIndex
* @return {?}
*/
(date, dayIndex) => ({
date,
label: formatDate(date, formatOptions.dayLabel, formatOptions.locale),
monthIndex,
weekIndex,
dayIndex
})))
})))
};
}
/**
* @param {?} daysMatrix
* @param {?} format
* @param {?} locale
* @return {?}
*/
function getWeekNumbers(daysMatrix, format, locale) {
return daysMatrix.map((/**
* @param {?} days
* @return {?}
*/
(days) => (days[0] ? formatDate(days[0], format, locale) : '')));
}
/**
* @param {?} locale
* @return {?}
*/
function getShiftedWeekdays(locale) {
/** @type {?} */
const _locale = getLocale(locale);
/** @type {?} */
const weekdays = (/** @type {?} */ (_locale.weekdaysShort()));
/** @type {?} */
const firstDayOfWeek = _locale.firstDayOfWeek();
return [...weekdays.slice(firstDayOfWeek), ...weekdays.slice(0, firstDayOfWeek)];
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} formattedMonth
* @param {?} options
* @return {?}
*/
function flagDaysCalendar(formattedMonth, options) {
formattedMonth.weeks.forEach((/**
* @param {?} week
* @return {?}
*/
(week) => {
/* tslint:disable-next-line: cyclomatic-complexity */
week.days.forEach((/**
* @param {?} day
* @param {?} dayIndex
* @return {?}
*/
(day, dayIndex) => {
// datepicker
/** @type {?} */
const isOtherMonth = !isSameMonth(day.date, formattedMonth.month);
/** @type {?} */
const isHovered = !isOtherMonth && isSameDay(day.date, options.hoveredDate);
// date range picker
/** @type {?} */
const isSelectionStart = !isOtherMonth &&
options.selectedRange &&
isSameDay(day.date, options.selectedRange[0]);
/** @type {?} */
const isSelectionEnd = !isOtherMonth &&
options.selectedRange &&
isSameDay(day.date, options.selectedRange[1]);
/** @type {?} */
const isSelected = (!isOtherMonth && isSameDay(day.date, options.selectedDate)) ||
isSelectionStart ||
isSelectionEnd;
/** @type {?} */
const isInRange = !isOtherMonth &&
options.selectedRange &&
isDateInRange(day.date, options.selectedRange, options.hoveredDate);
/** @type {?} */
const isDisabled = options.isDisabled ||
isBefore(day.date, options.minDate, 'day') ||
isAfter(day.date, options.maxDate, 'day') ||
isDisabledDay(day.date, options.daysDisabled) ||
isDisabledDate(day.date, options.datesDisabled);
/** @type {?} */
const currentDate = new Date();
/** @type {?} */
const isToday = !isOtherMonth && isSameDay(day.date, currentDate);
/** @type {?} */
const customClasses = options.dateCustomClasses && options.dateCustomClasses
.map((/**
* @param {?} dcc
* @return {?}
*/
dcc => isSameDay(day.date, dcc.date) ? dcc.classes : []))
.reduce((/**
* @param {?} previousValue
* @param {?} currentValue
* @return {?}
*/
(previousValue, currentValue) => previousValue.concat(currentValue)), [])
.join(' ')
|| '';
// decide update or not
/** @type {?} */
const newDay = Object.assign({}, day, {
isOtherMonth,
isHovered,
isSelected,
isSelectionStart,
isSelectionEnd,
isInRange,
isDisabled,
isToday,
customClasses
});
if (day.isOtherMonth !== newDay.isOtherMonth ||
day.isHovered !== newDay.isHovered ||
day.isSelected !== newDay.isSelected ||
day.isSelectionStart !== newDay.isSelectionStart ||
day.isSelectionEnd !== newDay.isSelectionEnd ||
day.isDisabled !== newDay.isDisabled ||
day.isInRange !== newDay.isInRange ||
day.customClasses !== newDay.customClasses) {
week.days[dayIndex] = newDay;
}
}));
}));
// todo: add check for linked calendars
formattedMonth.hideLeftArrow =
options.isDisabled ||
(options.monthIndex > 0 && options.monthIndex !== options.displayMonths);
formattedMonth.hideRightArrow =
options.isDisabled ||
(options.monthIndex < options.displayMonths &&
options.monthIndex + 1 !== options.displayMonths);
formattedMonth.disableLeftArrow = isMonthDisabled(shiftDate(formattedMonth.month, { month: -1 }), options.minDate, options.maxDate);
formattedMonth.disableRightArrow = isMonthDisabled(shiftDate(formattedMonth.month, { month: 1 }), options.minDate, options.maxDate);
return formattedMonth;
}
/**
* @param {?} date
* @param {?} selectedRange
* @param {?} hoveredDate
* @return {?}
*/
function isDateInRange(date, selectedRange, hoveredDate) {
if (!date || !selectedRange[0]) {
return false;
}
if (selectedRange[1]) {
return date > selectedRange[0] && date <= selectedRange[1];
}
if (hoveredDate) {
return date > selectedRange[0] && date <= hoveredDate;
}
return false;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} mode
* @param {?=} minMode
* @return {?}
*/
function canSwitchMode(mode, minMode) {
return minMode ? mode >= minMode : true;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const height = 4;
/** @type {?} */
const width = 3;
/** @type {?} */
const shift = { month: 1 };
/**
* @param {?} viewDate
* @param {?} formatOptions
* @return {?}
*/
function formatMonthsCalendar(viewDate, formatOptions) {
/** @type {?} */
const initialDate = startOf(viewDate, 'year');
/** @type {?} */
const matrixOptions = { width, height, initialDate, shift };
/** @type {?} */
const monthMatrix = createMatrix(matrixOptions, (/**
* @param {?} date
* @return {?}
*/
date => ({
date,
label: formatDate(date, formatOptions.monthLabel, formatOptions.locale)
})));
return {
months: monthMatrix,
monthTitle: '',
yearTitle: formatDate(viewDate, formatOptions.yearTitle, formatOptions.locale)
};
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} monthCalendar
* @param {?} options
* @return {?}
*/
function flagMonthsCalendar(monthCalendar, options) {
monthCalendar.months.forEach((/**
* @param {?} months
* @param {?} rowIndex
* @return {?}
*/
(months, rowIndex) => {
months.forEach((/**
* @param {?} month
* @param {?} monthIndex
* @return {?}
*/
(month, monthIndex) => {
/** @type {?} */
const isHovered = isSameMonth(month.date, options.hoveredMonth);
/** @type {?} */
const isDisabled = options.isDisabled ||
isMonthDisabled(month.date, options.minDate, options.maxDate);
/** @type {?} */
const newMonth = Object.assign(/*{},*/ month, {
isHovered,
isDisabled
});
if (month.isHovered !== newMonth.isHovered ||
month.isDisabled !== newMonth.isDisabled) {
monthCalendar.months[rowIndex][monthIndex] = newMonth;
}
}));
}));
// todo: add check for linked calendars
monthCalendar.hideLeftArrow =
options.monthIndex > 0 && options.monthIndex !== options.displayMonths;
monthCalendar.hideRightArrow =
options.monthIndex < options.displayMonths &&
options.monthIndex + 1 !== options.displayMonths;
monthCalendar.disableLeftArrow = isYearDisabled(shiftDate(monthCalendar.months[0][0].date, { year: -1 }), options.minDate, options.maxDate);
monthCalendar.disableRightArrow = isYearDisabled(shiftDate(monthCalendar.months[0][0].date, { year: 1 }), options.minDate, options.maxDate);
return monthCalendar;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const height$1 = 4;
/** @type {?} */
const width$1 = 4;
/** @type {?} */
const yearsPerCalendar = height$1 * width$1;
/** @type {?} */
const initialShift = (Math.floor(yearsPerCalendar / 2) - 1) * -1;
/** @type {?} */
const shift$1 = { year: 1 };
/**
* @param {?} viewDate
* @param {?} formatOptions
* @return {?}
*/
function formatYearsCalendar(viewDate, formatOptions) {
/** @type {?} */
const initialDate = shiftDate(viewDate, { year: initialShift });
/** @type {?} */
const matrixOptions = { width: width$1, height: height$1, initialDate, shift: shift$1 };
/** @type {?} */
const yearsMatrix = createMatrix(matrixOptions, (/**
* @param {?} date
* @return {?}
*/
date => ({
date,
label: formatDate(date, formatOptions.yearLabel, formatOptions.locale)
})));
/** @type {?} */
const yearTitle = formatYearRangeTitle(yearsMatrix, formatOptions);
return {
years: yearsMatrix,
monthTitle: '',
yearTitle
};
}
/**
* @param {?} yearsMatrix
* @param {?} formatOptions
* @return {?}
*/
function formatYearRangeTitle(yearsMatrix, formatOptions) {
/** @type {?} */
const from = formatDate(yearsMatrix[0][0].date, formatOptions.yearTitle, formatOptions.locale);
/** @type {?} */
const to = formatDate(yearsMatrix[height$1 - 1][width$1 - 1].date, formatOptions.yearTitle, formatOptions.locale);
return `${from} - ${to}`;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} yearsCalendar
* @param {?} options
* @return {?}
*/
function flagYearsCalendar(yearsCalendar, options) {
yearsCalendar.years.forEach((/**
* @param {?} years
* @param {?} rowIndex
* @return {?}
*/
(years, rowIndex) => {
years.forEach((/**
* @param {?} year
* @param {?} yearIndex
* @return {?}
*/
(year, yearIndex) => {
/** @type {?} */
const isHovered = isSameYear(year.date, options.hoveredYear);
/** @type {?} */
const isDisabled = options.isDisabled ||
isYearDisabled(year.date, options.minDate, options.maxDate);
/** @type {?} */
const newMonth = Object.assign(/*{},*/ year, { isHovered, isDisabled });
if (year.isHovered !== newMonth.isHovered ||
year.isDisabled !== newMonth.isDisabled) {
yearsCalendar.years[rowIndex][yearIndex] = newMonth;
}
}));
}));
// todo: add check for linked calendars
yearsCalendar.hideLeftArrow =
options.yearIndex > 0 && options.yearIndex !== options.displayMonths;
yearsCalendar.hideRightArrow =
options.yearIndex < options.displayMonths &&
options.yearIndex + 1 !== options.displayMonths;
yearsCalendar.disableLeftArrow = isYearDisabled(shiftDate(yearsCalendar.years[0][0].date, { year: -1 }), options.minDate, options.maxDate);
/** @type {?} */
const i = yearsCalendar.years.length - 1;
/** @type {?} */
const j = yearsCalendar.years[i].length - 1;
yearsCalendar.disableRightArrow = isYearDisabled(shiftDate(yearsCalendar.years[i][j].date, { year: 1 }), options.minDate, options.maxDate);
return yearsCalendar;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/* tslint:disable-next-line: cyclomatic-complexity */
/**
* @param {?=} state
* @param {?=} action
* @return {?}
*/
function bsDatepickerReducer(state = initialDatepickerState, action) {
switch (action.type) {
case BsDatepickerActions.CALCULATE: {
return calculateReducer(state);
}
case BsDatepickerActions.FORMAT: {
return formatReducer(state);
}
case BsDatepickerActions.FLAG: {
return flagReducer(state);
}
case BsDatepickerActions.NAVIGATE_OFFSET: {
/** @type {?} */
const date = shiftDate(startOf(state.view.date, 'month'), action.payload);
/** @type {?} */
const newState = {
view: {
mode: state.view.mode,
date
}
};
return Object.assign({}, state, newState);
}
case BsDatepickerActions.NAVIGATE_TO: {
/** @type {?} */
const payload = action.payload;
/** @type {?} */
const date = setFullDate(state.view.date, payload.unit);
/** @type {?} */
let newState;
/** @type {?} */
let mode;
if (canSwitchMode(payload.viewMode, state.minMode)) {
mode = payload.viewMode;
newState = { view: { date, mode } };
}
else {
mode = state.view.mode;
newState = { selectedDate: date, view: { date, mode } };
}
return Object.assign({}, state, newState);
}
case BsDatepickerActions.CHANGE_VIEWMODE: {
if (!canSwitchMode(action.payload, state.minMode)) {
return state;
}
/** @type {?} */
const date = state.view.date;
/** @type {?} */
const mode = action.payload;
/** @type {?} */
const newState = { view: { date, mode } };
return Object.assign({}, state, newState);
}
case BsDatepickerActions.HOVER: {
return Object.assign({}, state, { hoveredDate: action.payload });
}
case BsDatepickerActions.SELECT: {
/** @type {?} */
const newState = {
selectedDate: action.payload,
view: state.view
};
/** @type {?} */
const mode = state.view.mode;
/** @type {?} */
const _date = action.payload || state.view.date;
/** @type {?} */
const date = getViewDate(_date, state.minDate, state.maxDate);
newState.view = { mode, date };
return Object.assign({}, state, newState);
}
case BsDatepickerActions.SET_OPTIONS: {
/** @type {?} */
const newState = action.payload;
// preserve view mode
/** @type {?} */
const mode = newState.minMode ? newState.minMode : state.view.mode;
/** @type {?} */
const _viewDate = isDateValid(newState.value) && newState.value
|| isArray(newState.value) && isDateValid(newState.value[0]) && newState.value[0]
|| state.view.date;
/** @type {?} */
const date = getViewDate(_viewDate, newState.minDate, newState.maxDate);
newState.view = { mode, date };
// update selected value
if (newState.value) {
// if new value is array we work with date range
if (isArray(newState.value)) {
newState.selectedRange = newState.value;
}
// if new value is a date -> datepicker
if (newState.value instanceof Date) {
newState.selectedDate = newState.value;
}
// provided value is not supported :)
// need to report it somehow
}
return Object.assign({}, state, newState);
}
// date range picker
case BsDatepickerActions.SELECT_RANGE: {
/** @type {?} */
const newState = {
selectedRange: action.payload,
view: state.view
};
/** @type {?} */
const mode = state.view.mode;
/** @type {?} */
const _date = action.payload && action.payload[0] || state.view.date;
/** @type {?} */
const date = getViewDate(_date, state.minDate, state.maxDate);
newState.view = { mode, date };
return Object.assign({}, state, newState);
}
case BsDatepickerActions.SET_MIN_DATE: {
return Object.assign({}, state, {
minDate: action.payload
});
}
case BsDatepickerActions.SET_MAX_DATE: {
return Object.assign({}, state, {
maxDate: action.payload
});
}
case BsDatepickerActions.SET_IS_DISABLED: {
return Object.assign({}, state, {
isDisabled: action.payload
});
}
case BsDatepickerActions.SET_DATE_CUSTOM_CLASSES: {
return Object.assign({}, state, {
dateCustomClasses: action.payload
});
}
default:
return state;
}
}
/**
* @param {?} state
* @return {?}
*/
function calculateReducer(state) {
// how many calendars
/** @type {?} */
const displayMonths = state.displayMonths;
// use selected date on initial rendering if set
/** @type {?} */
let viewDate = state.view.date;
if (state.view.mode === 'day') {
state.monthViewOptions.firstDayOfWeek = getLocale(state.locale).firstDayOfWeek();
/** @type {?} */
const monthsModel = new Array(displayMonths);
for (let monthIndex = 0; monthIndex < displayMonths; monthIndex++) {
// todo: for unlinked calendars it will be harder
monthsModel[monthIndex] = calcDaysCalendar(viewDate, state.monthViewOptions);
viewDate = shiftDate(viewDate, { month: 1 });
}
return Object.assign({}, state, { monthsModel });
}
if (state.view.mode === 'month') {
/** @type {?} */
const monthsCalendar = new Array(displayMonths);
for (let calendarIndex = 0; calendarIndex < displayMonths; calendarIndex++) {
// todo: for unlinked calendars it will be harder
monthsCalendar[calendarIndex] = formatMonthsCalendar(viewDate, getFormatOptions(state));
viewDate = shiftDate(viewDate, { year: 1 });
}
return Object.assign({}, state, { monthsCalendar });
}
if (state.view.mode === 'year') {
/** @type {?} */
const yearsCalendarModel = new Array(displayMonths);
for (let calendarIndex = 0; calendarIndex < displayMonths; calendarIndex++) {
// todo: for unlinked calendars it will be harder
yearsCalendarModel[calendarIndex] = formatYearsCalendar(viewDate, getFormatOptions(state));
viewDate = shiftDate(viewDate, { year: yearsPerCalendar });
}
return Object.assign({}, state, { yearsCalendarModel });
}
return state;
}
/**
* @param {?} state
* @param {?} action
* @return {?}
*/
function formatReducer(state, action) {
if (state.view.mode === 'day') {
/** @type {?} */
const formattedMonths = state.monthsModel.map((/**
* @param {?} month
* @param {?} monthIndex
* @return {?}
*/
(month, monthIndex) => formatDaysCalendar(month, getFormatOptions(state), monthIndex)));
return Object.assign({}, state, { formattedMonths });
}
// how many calendars
/** @type {?} */
const displayMonths = state.displayMonths;
// check initial rendering
// use selected date on initial rendering if set
/** @type {?} */
let viewDate = state.view.date;
if (state.view.mode === 'month') {
/** @type {?} */
const monthsCalendar = new Array(displayMonths);
for (let calendarIndex = 0; calendarIndex < displayMonths; calendarIndex++) {
// todo: for unlinked calendars it will be harder
monthsCalendar[calendarIndex] = formatMonthsCalendar(viewDate, getFormatOptions(state));
viewDate = shiftDate(viewDate, { year: 1 });
}
return Object.assign({}, state, { monthsCalendar });
}
if (state.view.mode === 'year') {
/** @type {?} */
const yearsCalendarModel = new Array(displayMonths);
for (let calendarIndex = 0; calendarIndex < displayMonths; calendarIndex++) {
// todo: for unlinked calendars it will be harder
yearsCalendarModel[calendarIndex] = formatYearsCalendar(viewDate, getFormatOptions(state));
viewDate = shiftDate(viewDate, { year: 16 });
}
return Object.assign({}, state, { yearsCalendarModel });
}
return state;
}
/**
* @param {?} state
* @param {?} action
* @return {?}
*/
function flagReducer(state, action) {
if (state.view.mode === 'day') {
/** @type {?} */
const flaggedMonths = state.formattedMonths.map((/**
* @param {?} formattedMonth
* @param {?} monthIndex
* @return {?}
*/
(formattedMonth, monthIndex) => flagDaysCalendar(formattedMonth, {
isDisabled: state.isDisabled,
minDate: state.minDate,
maxDate: state.maxDate,
daysDisabled: state.daysDisabled,
datesDisabled: state.datesDisabled,
hoveredDate: state.hoveredDate,
selectedDate: state.selectedDate,
selectedRange: state.selectedRange,
displayMonths: state.displayMonths,
dateCustomClasses: state.dateCustomClasses,
monthIndex
})));
return Object.assign({}, state, { flaggedMonths });
}
if (state.view.mode === 'month') {
/** @type {?} */
const flaggedMonthsCalendar = state.monthsCalendar.map((/**
* @param {?} formattedMonth
* @param {?} monthIndex
* @return {?}
*/
(formattedMonth, monthIndex) => flagMonthsCalendar(formattedMonth, {
isDisabled: state.isDisabled,
minDate: state.minDate,
maxDate: state.maxDate,
hoveredMonth: state.hoveredMonth,
displayMonths: state.displayMonths,
monthIndex
})));
return Object.assign({}, state, { flaggedMonthsCalendar });
}
if (state.view.mode === 'year') {
/** @type {?} */
const yearsCalendarFlagged = state.yearsCalendarModel.map((/**
* @param {?} formattedMonth
* @param {?} yearIndex
* @return {?}
*/
(formattedMonth, yearIndex) => flagYearsCal