kendo-multi-date-select
Version:
Kendo UI plugin for selecting multiple dates similar to MultiSelect.
336 lines (270 loc) • 8.58 kB
text/typescript
namespace kendoExt {
export interface MultiDateSelectOptions {
autoClose?: boolean;
enable?: boolean;
maxSelectedItems?: number;
cleanSelectedItemsOnTodayClick?: boolean;
placeholder?: string;
tagTemplate?: string;
values?: Date[];
footer?: string;
culture?: string;
format?: string;
min?: Date;
max?: Date;
start?: CalendarDepth;
depth?: CalendarDepth;
month?: Object;
dates?: Date[];
}
export class MultiDateSelect extends kendo.ui.Widget {
static navigateEvent = 'navigate';
static changeEvent = 'change';
static openEvent = 'open';
static closeEvent = 'close';
private _multiSelect: kendo.ui.MultiSelect;
private _multiCalendar: any;
private _popup: kendo.ui.Popup;
constructor(element: Element | JQuery | string, options?: MultiDateSelectOptions) {
super(element as Element, options);
this.initMultiSelect(element);
this.initPopup(element);
this.initCalendar(this._popup.element);
this.updateDateInterval();
}
private static removeTime(date: Date): Date {
const d = new Date(date.toString());
d.setMilliseconds(0);
d.setSeconds(0);
d.setMinutes(0);
d.setHours(0);
return d;
}
private static isDateGreater(first: Date, second: Date): boolean {
return (
MultiDateSelect.removeTime(first).getTime() > MultiDateSelect.removeTime(second).getTime()
);
}
private static isDateLesser(first: Date, second: Date): boolean {
return (
MultiDateSelect.removeTime(first).getTime() < MultiDateSelect.removeTime(second).getTime()
);
}
public open() {
this._popup.open();
}
public close() {
this._popup.close();
}
public toggle() {
if (this._popup.visible()) {
this.close();
} else {
this.open();
}
}
public destroy() {
this._multiSelect.wrapper.find('input').off('keydown');
this._popup.destroy();
this._multiSelect.destroy();
this._multiCalendar.destroy();
super.destroy();
}
public enable(enable: boolean) {
if (!enable) {
this.close();
}
this._multiSelect.enable(enable);
}
public readonly(readonly: boolean) {
if (readonly) {
this.close();
}
this._multiSelect.readonly(readonly);
}
public max(max?: Date): Date {
if (max !== undefined) {
this._multiCalendar.max(max);
this.updateDateInterval();
}
return this._multiCalendar.max();
}
public min(min?: Date): Date {
if (min !== undefined) {
this._multiCalendar.min(min);
this.updateDateInterval();
}
return this._multiCalendar.min();
}
public value(values?: Date[]): Date[] {
return this.values(values);
}
public values(values?: Date[]): Date[] {
if (values !== undefined) {
const min = this.min();
const max = this.max();
const vs = values
.filter(
(date: Date) =>
!(
(min && MultiDateSelect.isDateLesser(date, min)) ||
(max && MultiDateSelect.isDateGreater(date, max))
)
);
this._multiCalendar.values(vs);
this.updateMultiSelectValues(vs);
if (vs.length) {
this._multiCalendar.navigate(vs[vs.length - 1]);
}
}
return this._multiSelect.value();
}
public multiSelect(): kendo.ui.MultiSelect {
return this._multiSelect;
}
public multiCalendar(): MultiCalendar {
return this._multiCalendar;
}
private initMultiSelect(parent: Element | JQuery | string) {
const options = this.options;
const defaultTemplate = ((data: Date) => kendo.toString(data, options.format));
options.tagTemplate = options.tagTemplate || defaultTemplate;
const open = (e: kendo.ui.MultiSelectOpenEvent) => {
e.preventDefault();
this.open();
};
const change = () => {
this._multiCalendar.values(this._multiSelect.value());
this._popup.position();
this.trigger(MultiDateSelect.changeEvent);
};
this._multiSelect = $('<select multiple></select>')
.appendTo(parent)
.kendoMultiSelect({
dataSource: options.values,
value: options.values,
ignoreCase: false,
enable: options.enable,
maxSelectedItems: options.maxSelectedItems,
placeholder: options.placeholder,
tagTemplate: options.tagTemplate,
open: open,
change: change
})
.data('kendoMultiSelect');
(this._multiSelect as any)._filterSource = () => ({});
this._multiSelect.search = () => ({});
this._multiSelect.wrapper.find('input').on('keydown', (e: JQueryKeyEventObject) => {
const key = e.keyCode;
const inputValue = (e.target as any).value;
if (key === kendo.keys.ENTER) {
const parsedDate = kendo.parseDate(inputValue, options.format);
const values = this.values();
if (parsedDate && parsedDate <= this.max() && parsedDate >= this.min()) {
const dates = values.concat(parsedDate);
this._multiCalendar.values(dates);
this.updateMultiSelect();
this._multiCalendar.navigate(parsedDate);
this.trigger(MultiDateSelect.changeEvent);
}
}
});
}
private initPopup(parent: Element | JQuery | string) {
const open = () => this.trigger(MultiDateSelect.openEvent);
const close = () => this.trigger(MultiDateSelect.closeEvent);
this._popup = $('<div class="k-calendar-container"></div>')
.appendTo(document.body)
.kendoPopup({
...this.options.popup,
...{
name: 'Popup',
animation: this.options.animation,
anchor: parent,
open: open,
close: close
}
})
.data('kendoPopup');
}
private initCalendar(parent: Element | JQuery | string) {
const options = this.options;
const change = () => {
this.updateMultiSelect();
this.trigger(MultiDateSelect.changeEvent);
};
const navigate = () => this.trigger(MultiDateSelect.navigateEvent);
this._multiCalendar = $('<div></div>')
.appendTo(parent)
.kendoMultiCalendar({
values: options.values,
footer: options.footer,
culture: options.culture,
min: options.min,
max: options.max,
start: options.start,
depth: options.depth,
month: options.month,
dates: options.dates,
maxSelectedItems: options.maxSelectedItems,
cleanSelectedItemsOnTodayClick: options.cleanSelectedItemsOnTodayClick,
change: change,
navigate: navigate
})
.data('kendoMultiCalendar');
(kendo as any).calendar.makeUnselectable(this._multiCalendar.element);
}
private updateDateInterval() {
this.values(this.values());
}
private updateMultiSelectValues(values: Date[]) {
this._multiSelect.setDataSource(values as any);
this._multiSelect.value(values);
if (this._popup.visible()) {
this._popup.position();
}
}
private updateMultiSelect() {
this.updateMultiSelectValues(this._multiCalendar.values());
if (this.options.autoClose) {
this.close();
}
}
}
MultiDateSelect.fn = MultiDateSelect.prototype;
MultiDateSelect.fn.options = {
...kendo.ui.Widget.fn.options,
...{
name: 'MultiDateSelect',
autoClose: true,
popup: {},
animation: {},
enable: true,
maxSelectedItems: null,
cleanSelectedItemsOnTodayClick: true,
placeholder: '',
tagTemplate: '',
values: null,
footer: '',
culture: '',
format: 'M/d/yyyy',
min: new Date(1900, 0, 1),
max: new Date(2099, 11, 31),
start: 'month',
depth: 'month',
month: {},
dates: []
}
};
MultiDateSelect.fn.events = [
MultiDateSelect.navigateEvent,
MultiDateSelect.changeEvent,
MultiDateSelect.openEvent,
MultiDateSelect.closeEvent
];
kendo.ui.plugin(MultiDateSelect);
}
interface JQuery {
kendoMultiDateSelect(options?: kendoExt.MultiDateSelectOptions): JQuery;
data(key: 'kendoMultiDateSelect'): kendoExt.MultiDateSelect;
}