UNPKG

kendo-multi-calendar

Version:
194 lines (148 loc) 5.12 kB
declare namespace kendo { namespace ui { interface Calendar { _todayClick(e: CalendarEvent): void; } } } namespace kendoExt { export type CalendarDepth = 'month' | 'year' | 'decade' | 'century'; export interface MultiCalendarOptions extends kendo.ui.CalendarOptions { values?: Date[]; maxSelectedItems?: number | null; cleanSelectedItemsOnTodayClick?: boolean; } export class MultiCalendar extends kendo.ui.Calendar { public static fn: MultiCalendar; private static _views: { [key: string]: number } = { month: 0, year: 1, decade: 2, century: 3 }; public options: MultiCalendarOptions; private _values: Date[]; constructor(element: Element | JQuery | string, options?: MultiCalendarOptions) { super(element as Element, options); this._values = (options && options.values) || []; (this as any).navigate(); } private static isSameDate(first: Date, second: Date) { return ( first && second && first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth() && first.getDate() === second.getDate() ); } public values(newValues?: Date[]): Date[] { if (newValues !== undefined && this.canSelectItems(newValues.length)) { const valuesToClear = this._values.filter(value => { return newValues.every(newValue => !MultiCalendar.isSameDate(value, newValue)); }); let i = null; this._values = newValues.filter((item, index) => { for (i = index - 1; i >= 0; i -= 1) { if (MultiCalendar.isSameDate(item, newValues[i])) { return false; } } return true; }); this.updateSelection(this._values, valuesToClear); } return this._values; } public value(newValue?: Date | string): Date { const valueIndex: number = (this._values || []) .reduce( (acc, val, index) => (MultiCalendar.isSameDate(val, newValue as Date) ? index : acc), -1 ); const shouldAddNewValue = valueIndex === -1; const canAddNewValue = shouldAddNewValue && this._values && this.canSelectItems(this._values.length + 1); if (!shouldAddNewValue || canAddNewValue) { super.value(newValue as Date); } if (newValue) { let valuesToClear: Date[] = []; if (canAddNewValue) { this._values.push(newValue as Date); } else if (!shouldAddNewValue) { valuesToClear = this._values.splice(valueIndex, 1); } this.updateSelection(this._values, valuesToClear); } return super.value(); } public navigate(value: Date, view: string) { super.navigate(value, view); this.updateSelection(this._values); } public navigateDown(value: Date) { if (!value) { return; } const index: number = (this as any)._index; if (index === MultiCalendar._views[this.options.depth as string]) { this.value(value); this.trigger('change'); return; } this.navigate(value, (index - 1) as any); } public _todayClick(e: kendo.ui.CalendarEvent) { this.selectToday(); super._todayClick(e); } private canSelectItems(amount: number): boolean { const max = this.options.maxSelectedItems; return !max || amount <= max; } private cellByDate(value: string): JQuery { return (this as any)._table.find('td').filter(function () { return $(this.firstChild).attr((kendo as any).attr('value')) === value; }); } private updateSelection(valuesToSelect: Date[], valuesToClear: Date[] = []) { if ((this as any)._index === MultiCalendar._views[this.options.depth as string]) { const selected = 'k-state-selected'; const _value = (this as any)._value; if (_value) { this.cellByDate(this.view().toDateString(_value)).removeClass(selected); } valuesToSelect.forEach(value => { this.cellByDate(this.view().toDateString(value)).addClass(selected); }); valuesToClear.forEach(value => { this.cellByDate(this.view().toDateString(value)).removeClass(selected); }); } } private selectToday = () => { const today = new Date(); const value = new Date(today.getFullYear(), today.getMonth(), today.getDate()); const values = this.options.cleanSelectedItemsOnTodayClick ? [value] : [...this._values, value]; this.values(values); } } MultiCalendar.fn = MultiCalendar.prototype; MultiCalendar.fn.options = { ...kendo.ui.Calendar.fn.options, ...{ name: 'MultiCalendar', values: [], maxSelectedItems: null, cleanSelectedItemsOnTodayClick: true } }; kendo.ui.plugin(MultiCalendar); } interface JQuery { kendoMultiCalendar(options?: kendoExt.MultiCalendarOptions): JQuery; data(key: 'kendoMultiCalendar'): kendoExt.MultiCalendar; }