@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,263 lines • 64.8 kB
JavaScript
//#region ../src/kendo.calendar.js
const __meta__ = {
id: "calendar",
name: "Calendar",
category: "web",
description: "The Calendar widget renders a graphical calendar that supports navigation and selection.",
depends: ["core", "selectable"]
};
(function($, undefined) {
let kendo = window.kendo, support = kendo.support, ui = kendo.ui, Widget = ui.Widget, keys = kendo.keys, parse = kendo.parseDate, encode = kendo.htmlEncode, adjustDST = kendo.date.adjustDST, weekInYear = kendo.date.weekInYear, Selectable = kendo.ui.Selectable, RangeSelectable = kendo.ui.RangeSelectable, extractFormat = kendo._extractFormat, template = kendo.template, getCulture = kendo.getCulture, transitionOrigin = "transform-origin", cellTemplate = template((data) => `<td class="${data.cssClass}" role="gridcell"><span tabindex="-1" class="k-link" data-href="#" data-${data.ns}value="${data.dateString}">${data.value}</span></td>`), emptyCellTemplate = template(() => "<td role=\"gridcell\" class=\"k-calendar-td k-empty\"></td>"), otherMonthCellTemplate = template(() => "<td role=\"gridcell\" class=\"k-calendar-td k-empty\"> </td>"), weekNumberTemplate = template((data) => `<td class="k-calendar-td k-alt">${data.weekNumber}</td>`), outerWidth = kendo._outerWidth, ns = ".kendoCalendar", CLICK = "click" + ns, KEYDOWN_NS = "keydown" + ns, DOT = ".", EMPTY = " ", TABLE = "table", CALENDAR_VIEW = "k-calendar-view", ID = "id", MIN = "min", LEFT = "left", SLIDE = "slideIn", MONTH = "month", CENTURY = "century", CHANGE = "change", NAVIGATE = "navigate", VALUE = "value", HOVER = "k-hover", DISABLED = "k-disabled", FOCUSED = "k-focus", OTHERMONTH = "k-other-month", EMPTYCELL = "k-empty", TODAY = "k-calendar-nav-today", CELLSELECTOR = "td:has(.k-link)", START = "start", END = "end", CELLSELECTORVALID = "td:has(.k-link):not(." + DISABLED + "):not(." + EMPTYCELL + ")", WEEKCOLUMNSELECTOR = "td:not(:has(.k-link))", SELECTED = "k-selected", BLUR = "blur" + ns, FOCUS = "focus", FOCUS_WITH_NS = FOCUS + ns, MOUSEENTER = support.touch ? "touchstart" : "mouseenter", MOUSEENTER_WITH_NS = support.touch ? "touchstart" + ns : "mouseenter" + ns, MOUSELEAVE = support.touch ? "touchend" + ns + " touchmove" + ns : "mouseleave" + ns, MS_PER_MINUTE = 6e4, MS_PER_DAY = 864e5, PREVARROW = "_prevArrow", NEXTARROW = "_nextArrow", ARIA_DISABLED = "aria-disabled", ARIA_SELECTED = "aria-selected", ARIA_LABEL = "aria-label", extend = $.extend, DATE = Date, views = {
month: 0,
year: 1,
decade: 2,
century: 3
}, HEADERSELECTOR = ".k-header, .k-calendar-header", CLASSIC_HEADER_TEMPLATE = ({ actionAttr, size, isRtl }) => `<div class="k-header k-hstack">
<span tabindex="-1" data-href="#" ${actionAttr}="prev" role="button" class="k-calendar-nav-prev k-button ${size} k-button-flat k-icon-button" ${ARIA_LABEL}="Previous">${kendo.ui.icon({
icon: `caret-alt-${isRtl ? "right" : "left"}`,
iconClass: "k-button-icon"
})}</span></span>
<span tabindex="-1" data-href="#" ${actionAttr}="nav-up" id="` + kendo.guid() + `" role="button" class="k-calendar-nav-fast k-button ${size} k-button-flat k-flex"></span>
<span tabindex="-1" data-href="#" ${actionAttr}="next" role="button" class="k-calendar-nav-next k-button ${size} k-button-flat k-icon-button" ${ARIA_LABEL}="Next">${kendo.ui.icon({
icon: `caret-alt-${isRtl ? "left" : "right"}`,
iconClass: "k-button-icon"
})}</span>
</div>`, MODERN_HEADER_TEMPLATE = ({ actionAttr, size, messages, isRtl }) => `<div class="k-calendar-header">
<button ${actionAttr}="nav-up" id="` + kendo.guid() + `" class="k-calendar-title k-button ${size} k-button-flat k-button-primary">
<span class="k-button-text"></span>
</button>
<span class="k-spacer"></span>
<span class="k-calendar-nav">
<button tabindex="-1" ${actionAttr}=${isRtl ? "next" : "prev"} class="k-calendar-nav-prev k-button ${size} k-button-flat k-icon-button">
${kendo.ui.icon({
icon: `chevron-${isRtl ? "right" : "left"}`,
iconClass: "k-button-icon"
})}
</button>
<button tabindex="-1" ${actionAttr}="today" class="k-calendar-nav-today k-button ${size} k-button-flat" role="link">
<span class="k-button-text">${kendo.htmlEncode(messages.today)}</span>
</button>
<button tabindex="-1" ${actionAttr}=${isRtl ? "prev" : "next"} class="k-calendar-nav-next k-button ${size} k-button-flat k-icon-button">
${kendo.ui.icon({
icon: `chevron-${isRtl ? "left" : "right"}`,
iconClass: "k-button-icon"
})}
</button>
</span>
</div>`;
var Calendar = Widget.extend({
init: function(element, options) {
var that = this, value, id;
options = options || {};
options.componentType = options.componentType || "classic";
Widget.fn.init.call(that, element, options);
element = that.wrapper = that.element;
options = that.options;
options.url = kendo.unescape(options.url);
that.options.disableDates = getDisabledExpr(that.options.disableDates);
that._templates();
that._selectable();
that._header();
that._viewWrapper();
if (that.options.hasFooter) {
that._footer(that.footer);
} else {
that._today = that.element.find(".k-calendar-nav-today");
that._toggle();
}
id = element.addClass("k-calendar " + (options.weekNumber ? " k-week-number" : "")).on(MOUSEENTER_WITH_NS + " " + MOUSELEAVE, CELLSELECTOR, mousetoggle).on(KEYDOWN_NS, "table.k-calendar-table", that._move.bind(that)).on(CLICK + " touchend", CELLSELECTORVALID, function(e) {
var link = e.currentTarget.firstChild, value = toDateObject(link);
if ($(link).data("href").indexOf("#") != -1) {
e.preventDefault();
}
if (that._view.name == "month" && that.options.disableDates(value)) {
return;
}
if (that._view.name != "month" || that._isSingleSelection()) {
that._click($(link));
}
}).on("mouseup" + ns, "table.k-calendar-table, .k-calendar-footer", function() {
that._focusView(that.options.focusOnNav !== false);
}).attr(ID);
if (that.options.weekNumber) {
element.on(CLICK, WEEKCOLUMNSELECTOR, function(e) {
var first = $(e.currentTarget).closest("tr").find(CELLSELECTORVALID).first(), last = $(e.currentTarget).closest("tr").find(CELLSELECTORVALID).last();
if (that._isMultipleSelection()) {
that.selectable._lastActive = last;
that.selectable.selectRange(first, last);
that.selectable.trigger(CHANGE, { event: e });
}
if (that._isRangeSelection()) {
that.rangeSelectable._lastActive = last;
that.rangeSelectable.range(first, last);
that.rangeSelectable.change();
}
that._current = that._value = toDateObject(last.find("span"));
that._setCurrent(that._current);
});
}
normalize(options);
value = parse(options.value, options.format, options.culture);
that._selectDates = [];
that._index = views[options.start];
that._current = new DATE(+restrictValue(value, options.min, options.max));
that._addClassProxy = function() {
that._active = true;
if (that._cell.hasClass(DISABLED)) {
var todayString = that._view.toDateString(getToday());
that._cell = that._cellByDate(todayString);
}
that._cell.addClass(FOCUSED);
};
that._removeClassProxy = function() {
that._active = false;
if (that._cell) {
that._cell.removeClass(FOCUSED);
}
};
that.value(value);
if (that._isMultipleSelection() && options.selectDates.length > 0) {
that.selectDates(options.selectDates);
}
that._range = options.range;
if (that._isRangeSelection()) {
that.selectRange(that._range);
}
kendo.notify(that);
},
options: {
name: "Calendar",
value: null,
min: new DATE(1900, 0, 1),
max: new DATE(2099, 11, 31),
dates: [],
disableDates: null,
allowReverse: false,
centuryCellsFormat: "long",
url: "",
culture: "",
footer: "",
format: "",
month: {},
weekNumber: false,
range: {
start: null,
end: null,
target: START
},
selectable: "single",
selectDates: [],
start: MONTH,
depth: MONTH,
size: undefined,
showOtherMonthDays: true,
animation: {
horizontal: {
effects: SLIDE,
reverse: true,
duration: 500,
divisor: 2
},
vertical: {
effects: "zoomIn",
duration: 400
}
},
messages: {
weekColumnHeader: "",
today: "Today",
navigateTo: "Navigate to ",
parentViews: {
month: "year view",
year: "decade view",
decade: "century view"
}
},
componentType: "classic"
},
events: [CHANGE, NAVIGATE],
componentTypes: {
"classic": {
header: { template: CLASSIC_HEADER_TEMPLATE },
hasFooter: true,
linksSelector: ".k-button",
contentClasses: "k-calendar-table"
},
"modern": {
header: { template: MODERN_HEADER_TEMPLATE },
hasFooter: false,
linksSelector: ".k-button",
contentClasses: "k-calendar-table"
}
},
setOptions: function(options) {
let that = this, isComponentTypeChanged = false;
if (options.componentType) {
isComponentTypeChanged = options.componentType !== that.options.componentType;
}
normalize(options);
options.disableDates = getDisabledExpr(options.disableDates);
that._destroySelectable();
if (options.messages) {
options.messages = $.extend({}, true, that.options.messages, options.messages);
}
Widget.fn.setOptions.call(that, options);
that._templates();
that._selectable();
if (isComponentTypeChanged) {
let componentTypes = Calendar.prototype.componentTypes;
that.options.header = componentTypes[options.componentType].header;
that.options.hasFooter = componentTypes[options.componentType].hasFooter;
let header = that.element.find(HEADERSELECTOR)[0];
if (header) {
header.remove();
}
that._header();
}
that._viewWrapper();
if (that.options.hasFooter) {
that._footer(that.footer);
} else {
that.element.find(".k-calendar-footer").hide();
that._toggle();
}
that._index = views[that.options.start];
that.navigate();
let value = parse(options.value || that.options.value || that._value, options.format, options.culture);
if (isComponentTypeChanged) {
that._current = new DATE(+restrictValue(value, options.min, options.max));
that._cell = null;
that._table = null;
}
that.value(value);
if (options.weekNumber) {
that.element.addClass("k-week-number");
}
},
destroy: function() {
var that = this, today = that._today;
that.element.off(ns);
that._title.off(ns);
that[PREVARROW].off(ns);
that[NEXTARROW].off(ns);
that._destroySelectable();
kendo.destroy(that._table);
if (today) {
kendo.destroy(today.off(ns));
}
Widget.fn.destroy.call(that);
},
current: function() {
return this._current;
},
view: function() {
return this._view;
},
focus: function(table) {
table = table || this._table;
this._bindTable(table);
table.trigger("focus");
},
min: function(value) {
return this._option(MIN, value);
},
max: function(value) {
return this._option("max", value);
},
navigateToPast: function() {
this._navigate(PREVARROW, -1);
},
navigateToFuture: function() {
this._navigate(NEXTARROW, 1);
},
navigateUp: function() {
var that = this, index = that._index;
if (that._title.hasClass(DISABLED)) {
return;
}
that.navigate(that._current, ++index);
},
navigateDown: function(value) {
var that = this, index = that._index, depth = that.options.depth;
if (!value) {
return;
}
if (index === views[depth]) {
if (!isEqualDate(that._value, that._current) || !isEqualDate(that._value, value)) {
that.value(value);
that.trigger(CHANGE);
}
return;
}
that.navigate(value, --index);
},
navigate: function(value, view) {
view = isNaN(view) ? views[view] : view;
var that = this, options = that.options, culture = options.culture, min = options.min, max = options.max, title = that._title, from = that._table, old = that._oldTable, currentValue = that._current, future = value && +value > +currentValue, vertical = view !== undefined && view !== that._index, to, currentView, compare, disabled, viewWrapper = that.element.children(".k-calendar-view");
if (!value) {
value = currentValue;
}
that._current = value = new DATE(+restrictValue(value, min, max));
if (view === undefined) {
view = that._index;
} else {
that._index = view;
}
that._view = currentView = calendar.views[view];
compare = currentView.compare;
disabled = view === views[CENTURY];
title.toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
disabled = compare(value, min) < 1;
that[PREVARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
disabled = compare(value, max) > -1;
that[NEXTARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
if (from && old && old.data("animating")) {
old.kendoStop(true, true);
from.kendoStop(true, true);
}
that._oldTable = from;
if (!from || that._changeView) {
title.html("<span class=\"k-button-text\">" + currentView.title(value, min, max, culture) + "</span>");
if (that.options.messages.parentViews && that._view.name !== CENTURY) {
title.attr("title", encode(that.options.messages.navigateTo + that.options.messages.parentViews[that._view.name]));
} else {
title.removeAttr("title");
}
that._table = to = $(currentView.content(extend({
min,
max,
date: value,
url: options.url,
dates: options.dates,
format: options.format,
showOtherMonthDays: options.showOtherMonthDays,
centuryCellsFormat: options.centuryCellsFormat,
culture,
disableDates: options.disableDates,
isWeekColumnVisible: options.weekNumber,
messages: options.messages,
contentClasses: that.options.contentClasses
}, that[currentView.name])));
that._aria();
var replace = from && from.data("start") === to.data("start");
that._animate({
from,
to,
vertical,
future,
replace
});
viewWrapper.removeClass("k-calendar-monthview k-calendar-yearview k-calendar-decadeview k-calendar-centuryview");
viewWrapper.addClass("k-calendar-" + currentView.name + "view");
that.trigger(NAVIGATE);
that._focus(value);
}
if (view === views[options.depth] && that._selectDates.length > 0) {
that._visualizeSelectedDatesInView();
}
if (that._isSingleSelection()) {
if (view === views[options.depth] && that._value && !that.options.disableDates(that._value)) {
that._selectCell(that._value);
}
}
that._setCurrent(value);
if (!from && that._cell) {
that._cell.removeClass(FOCUSED);
}
that._changeView = true;
},
selectDates: function(dates) {
var that = this, validSelectedDates, datesUnique;
if (dates === undefined) {
return that._selectDates;
}
datesUnique = dates.map(function(date) {
return date.getTime();
}).filter(function(date, position, array) {
return array.indexOf(date) === position;
}).map(function(time) {
return new Date(time);
});
validSelectedDates = $.grep(datesUnique, function(value) {
if (value) {
return +that._validateValue(new Date(value.setHours(0, 0, 0, 0))) === +value;
}
});
that._selectDates = validSelectedDates.length > 0 ? validSelectedDates : datesUnique.length === 0 ? datesUnique : that._selectDates;
that._visualizeSelectedDatesInView();
},
value: function(value) {
var that = this, old = that._view, view = that._view;
if (value === undefined) {
return that._value;
}
value = that._validateValue(value);
if (value && that._isMultipleSelection()) {
var date = new Date(+value);
date.setHours(0, 0, 0, 0);
that._selectDates = [date];
that.selectable._lastActive = null;
}
if (old && value === null && that._cell) {
that._cell.removeClass(SELECTED);
} else {
that._changeView = !value || view && view.compare(value, that._current) !== 0;
that.navigate(value);
}
},
isRtl: function() {
return kendo.support.isRtl(this.wrapper);
},
_aria: function() {
var table = this._table;
table.attr("aria-labelledby", this._title.attr("id"));
if (this._view.name === "month" && this._isMultipleSelection()) {
table.attr("aria-multiselectable", "true");
}
},
_validateValue: function(value) {
var that = this, options = that.options, min = options.min, max = options.max;
if (value === null) {
that._current = createDate(that._current.getFullYear(), that._current.getMonth(), that._current.getDate());
}
value = parse(value, options.format, options.culture);
if (value !== null) {
value = new DATE(+value);
if (!isInRange(value, min, max)) {
value = null;
}
}
if (value === null || !that.options.disableDates(new Date(+value))) {
that._value = value;
} else if (that._value === undefined) {
that._value = null;
}
return that._value;
},
_visualizeSelectedDatesInView: function() {
var that = this;
var selectedDates = {};
$.each(that._selectDates, function(index, value) {
selectedDates[kendo.calendar.views[0].toDateString(value)] = value;
});
that.selectable.clear();
var cells = that._table.find(CELLSELECTOR).filter(function(index, element) {
return selectedDates[$(element.firstChild).attr(kendo.attr(VALUE))];
});
if (cells.length > 0) {
that.selectable._selectElement(cells, true);
}
},
_isSingleSelection: function() {
let selectable = this.options.selectable, selectableOptions = Selectable.parseOptions(selectable);
return selectableOptions.single;
},
_isMultipleSelection: function() {
let selectable = this.options.selectable, selectableOptions = Selectable.parseOptions(selectable);
return selectableOptions.multiple;
},
_isRangeSelection: function() {
let selectable = this.options.selectable, selectableOptions = Selectable.parseOptions(selectable);
return selectableOptions.range;
},
_selectable: function() {
let that = this, selectable = that.options.selectable, selectableOptions = Selectable.parseOptions(selectable);
if (!that._isMultipleSelection() && !that._isRangeSelection()) {
return;
}
if (that.rangeSelectable) {
that.rangeSelectable.destroy();
that.rangeSelectable = null;
}
if (selectableOptions.range) {
that.rangeSelectable = new RangeSelectable(that.wrapper, {
widget: that,
filter: ".k-calendar-monthview table " + CELLSELECTORVALID,
cellSelector: CELLSELECTOR,
cellSelectorValid: CELLSELECTORVALID,
change: that._onSelect.bind(that),
reverse: that.options.allowReverse,
resetOnStart: true,
ns
});
that.element.addClass("k-calendar-range");
} else {
that.selectable = new Selectable(that.wrapper, {
aria: true,
inputSelectors: "input,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-caret-alt-down,span.k-icon.k-i-caret-alt-up,span.k-svg-icon.k-svg-i-caret-alt-down,span.k-svg-icon.k-svg-i-caret-alt-up",
multiple: selectableOptions.multiple,
filter: "table.k-calendar-table:eq(0) " + CELLSELECTORVALID,
change: that._onSelect.bind(that),
relatedTarget: that._onRelatedTarget.bind(that)
});
}
},
_restoreSelection: function() {
const that = this;
let range;
that._preventChange = true;
if (that._isRangeSelection()) {
range = that.selectRange();
if (!range || !range.start) {
that._preventChange = false;
return;
}
that.selectRange(range);
}
that._preventChange = false;
},
selectRange: function(range) {
const that = this, view = that._view;
let startInRange, endInRange, visibleRange;
if (range === undefined) {
return that._range;
}
that._range = range;
if (!range.start) {
return;
}
visibleRange = that._visibleRange();
startInRange = that._dateInViews(range.start);
endInRange = range.end && that._dateInViews(range.end);
if (!startInRange && endInRange) {
that.rangeSelectable.selectTo(that._cellByDate(view.toDateString(range.end)));
}
if (startInRange && endInRange) {
that.rangeSelectable.range(that._cellByDate(view.toDateString(range.start)), that._cellByDate(view.toDateString(range.end)), false, that.options.allowReverse);
}
if (range.end && startInRange && !endInRange) {
that.rangeSelectable.selectFrom(that._cellByDate(view.toDateString(range.start)));
}
if (!range.end && startInRange) {
that.rangeSelectable.start(that._cellByDate(view.toDateString(range.start)));
}
if (+visibleRange.start > +range.start && +visibleRange.end < +range.end) {
that.rangeSelectable.mid(that.element.find(CELLSELECTORVALID));
}
},
_onRelatedTarget: function(target) {
var that = this;
if (that.selectable.options.multiple && target.is(CELLSELECTORVALID)) {
that._current = toDateObject(target.find("span"));
that._setCurrent(that._current);
}
},
_onSelect: function(e) {
let that = this, eventArgs = e, range, useEnd = e.sender._useEnd, useStart = e.sender._useStart, initialRange, start, end, value, target, selectableOptions = Selectable.parseOptions(that.options.selectable);
if (that._isRangeSelection()) {
range = e.sender.range();
initialRange = that.selectRange() || {};
target = initialRange.target;
if (range.start && range.start.length) {
start = toDateObject(range.start.find("span"));
}
if (range.end && range.end.length) {
end = toDateObject(range.end.find("span"));
}
if (target === END) {
target = START;
} else {
target = END;
}
that._range = {
start: useStart ? initialRange.start : start,
end: useEnd ? initialRange.end : end,
target
};
if (!that._preventChange) {
that.trigger(CHANGE);
}
value = end || start;
if (end && !that._dateInViews(end)) {
value = start;
}
that.selectRange(that._range);
that.value(value);
return;
}
if (!selectableOptions.multiple) {
if ($(eventArgs.event.currentTarget).is("td") && !$(eventArgs.event.currentTarget).hasClass("k-selected")) {
$(eventArgs.event.currentTarget).addClass("k-selected");
} else {
that._click($(eventArgs.event.currentTarget).find("span"));
}
return;
}
if (eventArgs.event.ctrlKey || eventArgs.event.metaKey) {
if ($(eventArgs.event.currentTarget).is(CELLSELECTORVALID)) {
that._toggleSelection($(eventArgs.event.currentTarget));
} else {
that._cellsBySelector(CELLSELECTORVALID).each(function(index, element) {
var value = toDateObject($(element).find("span"));
that._deselect(value);
});
that._addSelectedCellsToArray();
}
} else if (eventArgs.event.shiftKey) {
that._rangeSelection(that._cell);
} else if ($(eventArgs.event.currentTarget).is(CELLSELECTOR)) {
that.value(toDateObject($(eventArgs.event.currentTarget).find("span")));
} else {
that._selectDates = [];
that._addSelectedCellsToArray();
}
that.trigger(CHANGE);
},
_destroySelectable: function() {
var that = this;
if (that.selectable) {
that.selectable.destroy();
that.selectable = null;
}
if (that.rangeSelectable) {
that.rangeSelectable.destroy();
that.rangeSelectable = null;
}
},
_toggleSelection: function(currentCell) {
var that = this, date = toDateObject(currentCell.find("span"));
if (currentCell.hasClass("k-selected")) {
that._selectDates.push(date);
} else {
that._deselect(date);
}
},
_rangeSelection: function(toDateCell, startDate) {
var that = this, fromDate = startDate || toDateObject(that.selectable.value().first().find("span")), toDate = toDateObject(toDateCell.find("span")), daysDifference;
if (that.selectable._lastActive || that._value) {
fromDate = that.selectable._lastActive ? toDateObject(that.selectable._lastActive.find("span")) : new Date(+that._value);
} else {
that.selectable._lastActive = startDate ? that._cellByDate(that._view.toDateString(startDate), CELLSELECTORVALID) : that.selectable.value().first();
}
that._selectDates = [];
daysDifference = daysBetweenTwoDates(fromDate, toDate);
addDaysToArray(that._selectDates, daysDifference, fromDate, that.options.disableDates);
that._visualizeSelectedDatesInView();
},
_visibleRange: function() {
let table = this.element.find(DOT + CALENDAR_VIEW + EMPTY + TABLE), firstDateInView = toDateObject(table.first().find(CELLSELECTOR).first().find("span")), lastDateInView = toDateObject(table.last().find(CELLSELECTOR).last().find("span"));
return {
start: firstDateInView,
end: lastDateInView
};
},
_cellsBySelector: function(selector) {
var that = this;
return that._table.find(selector);
},
_addSelectedCellsToArray: function() {
var that = this;
that.selectable.value().each(function(index, item) {
var date = toDateObject($(item.firstChild));
if (!that.options.disableDates(date)) {
that._selectDates.push(date);
}
});
},
_deselect: function(date) {
var that = this;
var currentDateIndex = that._selectDates.map(Number).indexOf(+date);
if (currentDateIndex != -1) {
that._selectDates.splice(currentDateIndex, 1);
}
},
_dateInView: function(date) {
var that = this, firstDateInView = toDateObject(that._cellsBySelector(CELLSELECTORVALID).first().find("span")), lastDateInView = toDateObject(that._cellsBySelector(CELLSELECTORVALID).last().find("span"));
return +date <= +lastDateInView && +date >= +firstDateInView;
},
_isNavigatable: function(currentValue, cellIndex) {
var that = this;
var isDisabled = that.options.disableDates;
var cell;
var index;
if (that._view.name == "month") {
return !isDisabled(currentValue);
} else {
index = that.wrapper.find("." + FOCUSED).index();
cell = that.wrapper.find(".k-calendar-table td").eq(index + cellIndex);
return cell.is(CELLSELECTORVALID) || !isDisabled(currentValue);
}
},
_dateInViews: function(date) {
let that = this, tables = that.element.find(".k-calendar-view table"), firstDateInView = toDateObject(tables.first().find(CELLSELECTOR).first().find("span")), lastDateInView = toDateObject(tables.last().find(CELLSELECTOR).last().find("span"));
date = new Date(date.toDateString());
return +date <= +lastDateInView && +date >= +firstDateInView;
},
_move: function(e) {
var that = this, options = that.options, key = e.keyCode, view = that._view, index = that._index, min = that.options.min, max = that.options.max, currentValue = new DATE(+that._current), isRtl = that.isRtl(), isDisabled = that.options.disableDates, value, prevent, method, temp, cell, focusedCell, lastActive;
if (e.target === that._table[0]) {
that._active = true;
}
if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
value = 1;
prevent = true;
} else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
value = -1;
prevent = true;
} else if (key == keys.UP) {
value = index === 0 ? -7 : -4;
prevent = true;
} else if (key == keys.DOWN) {
value = index === 0 ? 7 : 4;
prevent = true;
} else if (key == keys.SPACEBAR) {
value = 0;
prevent = true;
} else if (key == keys.HOME || key == keys.END) {
method = key == keys.HOME ? "first" : "last";
temp = view[method](currentValue);
currentValue = new DATE(temp.getFullYear(), temp.getMonth(), temp.getDate(), currentValue.getHours(), currentValue.getMinutes(), currentValue.getSeconds(), currentValue.getMilliseconds());
currentValue.setFullYear(temp.getFullYear());
prevent = true;
} else if (key === 84) {
that._todayClick(e);
prevent = true;
}
if (e.ctrlKey || e.metaKey) {
if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
that.navigateToFuture();
prevent = true;
} else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
that.navigateToPast();
prevent = true;
} else if (key == keys.UP) {
that.navigateUp();
prevent = true;
} else if (key == keys.DOWN) {
that._click($(that._cell[0].firstChild));
prevent = true;
} else if ((key == keys.ENTER || key == keys.SPACEBAR) && that._isMultipleSelection()) {
that._keyboardToggleSelection(e);
var focusedDate = toDateObject($(that._cell[0]).find("span"));
that._setCurrent(focusedDate);
}
} else if (e.shiftKey) {
if (value !== undefined || method) {
if (!method) {
view.setDate(currentValue, value);
}
if (!isInRange(currentValue, min, max)) {
currentValue = restrictValue(currentValue, options.min, options.max);
}
if (isDisabled(currentValue)) {
currentValue = that._nextNavigatable(currentValue, value);
}
min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
if (that._isMultipleSelection()) {
that._keyboardRangeSelection(e, currentValue);
} else if (that._isRangeSelection()) {
if (!that._dateInViews(currentValue)) {
if (value > 0) {
that.navigateToFuture();
} else {
that.navigateToPast();
}
}
} else {
that._focus(currentValue);
}
}
if (that.rangeSelectable) {
cell = that._cellByDate(view.toDateString(currentValue));
lastActive = toDateObject((that.rangeSelectable._lastActive || focusedCell).find("span"));
if (!that._dateInViews(lastActive)) {
if (+lastActive > +currentValue) {
that.rangeSelectable._end = that.rangeSelectable._lastActive;
that.rangeSelectable.selectFrom(cell);
} else {
that.rangeSelectable.selectTo(cell);
}
} else {
if (that.rangeSelectable._end && that.rangeSelectable._end.is("." + FOCUSED)) {
that.rangeSelectable._lastActive = that.rangeSelectable._start;
} else {
that.rangeSelectable._lastActive = that._cellByDate(view.toDateString(lastActive));
}
that.rangeSelectable.range(that.rangeSelectable._lastActive, cell);
}
that.rangeSelectable.change();
that._setCurrent(currentValue);
}
} else {
if (key == keys.ENTER || key == keys.SPACEBAR) {
if (view.name == "month" && that._isMultipleSelection()) {
that.value(toDateObject($(that._cell.find("span"))));
that.selectable._lastActive = $(that._cell[0]);
that.trigger(CHANGE);
} else if (that.rangeSelectable) {
that.rangeSelectable.change();
} else {
that._click($(that._cell[0].firstChild));
}
prevent = true;
} else if (key == keys.PAGEUP) {
prevent = true;
that.navigateToPast();
} else if (key == keys.PAGEDOWN) {
prevent = true;
that.navigateToFuture();
}
if (value || method) {
if (!method) {
view.setDate(currentValue, value);
}
min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
if (!isInRange(currentValue, min, max)) {
currentValue = restrictValue(currentValue, options.min, options.max);
}
if (!that._isNavigatable(currentValue, value)) {
currentValue = that._nextNavigatable(currentValue, value);
}
if (that._isMultipleSelection()) {
if (!that._dateInView(currentValue)) {
that.navigate(currentValue);
} else {
that._current = currentValue;
that._setCurrent(currentValue);
}
} else {
that._focus(currentValue);
}
}
}
if (prevent) {
e.preventDefault();
}
return that._current;
},
_keyboardRangeSelection: function(event, currentValue) {
var that = this, fromDate, daysDifference;
if (!that._dateInView(currentValue)) {
that._selectDates = [];
fromDate = that.selectable._lastActive ? toDateObject(that.selectable._lastActive.find("span")) : currentValue;
daysDifference = daysBetweenTwoDates(fromDate, new Date(+currentValue));
addDaysToArray(that._selectDates, daysDifference, fromDate, that.options.disableDates);
that.navigate(currentValue);
that._current = currentValue;
that.selectable._lastActive = that.selectable._lastActive || that._cellByDate(that._view.toDateString(currentValue), CELLSELECTORVALID);
that.trigger(CHANGE);
return;
}
that.selectable.options.filter = that.wrapper.find("table").length > 1 && +currentValue > +that._current ? "table.k-calendar-table:eq(1) " + CELLSELECTORVALID : "table.k-calendar-table:eq(0) " + CELLSELECTORVALID;
that._setCurrent(currentValue);
that._current = currentValue;
that._rangeSelection(that._cellByDate(that._view.toDateString(currentValue), CELLSELECTORVALID), currentValue);
that.trigger(CHANGE);
that.selectable.options.filter = "table.k-calendar-table:eq(0) " + CELLSELECTORVALID;
},
_keyboardToggleSelection: function(event) {
var that = this;
event.currentTarget = that._cell[0];
that.selectable._lastActive = $(that._cell[0]);
if ($(that._cell[0]).hasClass(SELECTED)) {
that.selectable._unselect($(that._cell[0]));
} else {
that.selectable.value($(that._cell[0]));
}
that.selectable.trigger(CHANGE, { event });
},
_nextNavigatable: function(currentValue, value) {
var that = this, disabled = true, view = that._view, min = that.options.min, max = that.options.max, isDisabled = that.options.disableDates, navigatableDate = new Date(currentValue.getTime());
view.setDate(navigatableDate, -value);
while (disabled) {
view.setDate(currentValue, value);
if (!isInRange(currentValue, min, max)) {
currentValue = navigatableDate;
break;
}
disabled = isDisabled(currentValue);
}
return currentValue;
},
_animate: function(options) {
var that = this;
var from = options.from;
var to = options.to;
var active = that._active;
var viewWrapper = that.element.children(".k-calendar-view");
if (!from) {
viewWrapper.append(to);
that._bindTable(to);
} else if (from.parent().data("animating")) {
from.off(ns);
from.parent().kendoStop(true, true).remove();
from.remove();
viewWrapper.append(to);
that._focusView(active);
} else if (!from.is(":visible") || that.options.animation === false || options.replace) {
to.insertAfter(from);
from.off(ns).remove();
that._focusView(active);
} else {
that[options.vertical ? "_vertical" : "_horizontal"](from, to, options.future);
}
},
_horizontal: function(from, to, future) {
var that = this, active = that._active, horizontal = that.options.animation.horizontal, effects = horizontal.effects, viewWidth = outerWidth(from), margin = outerWidth(from, true) - viewWidth;
if (effects && effects.indexOf(SLIDE) != -1) {
from.add(to).css({ width: viewWidth });
from.wrap("<div/>");
that._focusView(active, from);
from.parent().css({
position: "relative",
width: viewWidth * 2 + 2 * margin,
display: "flex",
[future ? "margin-right" : "margin-left"]: -viewWidth - margin
});
to[future ? "insertAfter" : "insertBefore"](from);
extend(horizontal, {
effects: SLIDE + ":" + (future ? "right" : LEFT),
complete: function() {
from.off(ns).remove();
that._oldTable = null;
to.unwrap();
that._focusView(active);
}
});
from.parent().kendoStop(true, true).kendoAnimate(horizontal);
}
},
_vertical: function(from, to) {
var that = this, vertical = that.options.animation.vertical, effects = vertical.effects, active = that._active, cell, position;
if (effects && effects.indexOf("zoom") != -1) {
to.insertBefore(from);
from.css({
position: "absolute",
width: to.width()
});
if (transitionOrigin) {
cell = that._cellByDate(that._view.toDateString(that._current));
position = cell.position();
position = position.left + parseInt(cell.width() / 2, 10) + "px" + " " + (position.top + parseInt(cell.height() / 2, 10) + "px");
to.css(transitionOrigin, position);
}
from.kendoStop(true, true).kendoAnimate({
effects: "fadeOut",
duration: 600,
complete: function() {
from.off(ns).remove();
that._oldTable = null;
that._focusView(active);
}
});
to.kendoStop(true, true).kendoAnimate(vertical);
}
},
_cellByDate: function(value, selector) {
return this._table.find(selector ? selector : "td:not(." + OTHERMONTH + ")").filter(function() {
return $(this.firstChild).attr(kendo.attr(VALUE)) === value;
});
},
_selectCell: function(date) {
var that = this, cell = that._selectedCell, value = that._view.toDateString(date);
if (cell && cell[0]) {
cell[0].removeAttribute(ARIA_SELECTED);
cell.removeClass(SELECTED);
}
cell = that._cellByDate(value, CELLSELECTOR);
that._selectedCell = cell;
cell.addClass(SELECTED).attr(ARIA_SELECTED, true);
},
_setCurrent: function(date) {
var that = this, id = kendo.guid(), cell = that._cell, value = that._view.toDateString(date);
if (cell && cell[0]) {
cell.removeClass(FOCUSED);
cell[0].removeAttribute(ARIA_LABEL);
cell[0].removeAttribute(ID);
}
cell = that._cellByDate(value, that._isMultipleSelection() ? CELLSELECTOR : "td:not(." + OTHERMONTH + ")");
that._cell = cell;
cell.attr(ID, id).addClass(FOCUSED);
if (that._table[0]) {
that._table[0].removeAttribute("aria-activedescendant");
that._table.attr("aria-activedescendant", id);
}
},
_bindTable: function(table) {
table.on(FOCUS_WITH_NS, this._addClassProxy).on(BLUR, this._removeClassProxy);
},
_click: function(link) {
var that = this, options = that.options, currentValue = new Date(+that._current), value = toDateObject(link);
adjustDST(value, 0);
if (that._view.name == "month" && that.options.disableDates(value)) {
value = that._value;
}
that._view.setDate(currentValue, value);
that.navigateDown(restrictValue(currentValue, options.min, options.max));
},
_focus: function(value) {
var that = this, view = that._view;
if (view.compare(value, that._current) !== 0) {
that.navigate(value);
} else {
that._current = value;
that._setCurrent(value);
}
},
_focusView: function(active, table) {
if (active) {
this.focus(table);
}
},
_viewWrapper: function() {
var that = this;
var element = that.element;
var viewWrapper = element.children(".k-calendar-view");
if (!viewWrapper[0]) {
viewWrapper = $("<div class='k-calendar-view k-align-items-start k-justify-content-center k-hstack' />").insertAfter(element.find(HEADERSELECTOR));
}
},
_footer: function(template) {
var that = this, today = getToday(), element = that.element, footer = element.find(".k-calendar-footer");
if (!template) {
that._toggle(false);
footer.hide();
return;
}
if (!footer[0]) {
footer = $(`<div class="k-calendar-footer">
<button tabindex="-1" class="k-calendar-nav-today k-flex k-button k-button-flat k-button-primary" role="link">
<span class="k-button-text"></span>
</button>
</div>`).appendTo(element);
}
that._today = footer.show().find(".k-button-flat.k-button-primary").attr("title", kendo.toString(today, "D", that.options.culture));
footer.find(".k-button-text").html(template(today));
that._toggle();
},
_header: function() {
var that = this, element = that.element, linksSelector = that.options.linksSelector;
if (!element.find(HEADERSELECTOR)[0]) {
element.html(kendo.template(that.options.header.template)($.extend(true, {}, that.options, {
actionAttr: kendo.attr("action"),
size: kendo.getValidCssClass("k-button-", "size", that.options.size),
isRtl: that.isRtl()
})));
}
element.find(linksSelector).on(CLICK + " touchend" + ns, function() {
return false;
});
that._title = element.find("[" + kendo.attr("action") + "=\"nav-up\"]").on(CLICK + " touchend" + ns, function() {
that._active = that.options.focusOnNav !== false;
that.navigateUp();
});
that[PREVARROW] = element.find("[" + kendo.attr("action") + "=\"prev\"]").on(CLICK + " touchend" + ns, function() {
that._active = that.options.focusOnNav !== false;
that.navigateToPast();
});
that[NEXTARROW] = element.find("[" + kendo.attr("action") + "=\"next\"]").on(CLICK + " touchend" + ns, function() {
that._active = that.options.focusOnNav !== false;
that.navigateToFuture();
});
element.find("[" + kendo.attr("action") + "=\"today\"]").on(CLICK + " touchend" + ns, that._todayClick.bind(that));
},
_navigate: function(arrow, modifier) {
var that = this, index = that._index + 1, currentValue = new DATE(+that._current);
if (that._isMultipleSelection()) {
var firstDayCurrentMonth = that._table.find("td:not(." + OTHERMONTH + "):not(." + EMPTYCELL + ")").has(".k-link").first();
currentValue = toDateObject(firstDayCurrentMonth.find("span"));
that._current = new Date(+currentValue);
}
arrow = that[arrow];
if (!arrow.hasClass(DISABLED)) {
if (index > 3) {
currentValue.setFullYear(currentValue.getFullYear() + 100 * modifier);
} else {
calendar.views[index].setDate(currentValue, modifier);
}
that.navigate(currentValue);
that._restoreSelection();
}
},
_option: function(option, value) {
var that = this, options = that.options, currentValue = that._value || that._current, isBigger;
if (value === undefined) {
return options[option];
}
value = parse(value, options.format, options.culture);
if (!value) {
return;
}
options[option] = new DATE(+value);
if (option === MIN) {
isBigger = value > currentValue;
} else {
isBigger = currentValue > value;
}
if (isBigger || isEqualMonth(currentValue, value)) {
if (isBigger) {
that._value = null;
}
that._changeView = true;
}
if (!that._changeView) {
that._changeView = !!(options.month.content || options.month.empty);
}
that.navigate(that._value);
that._toggle();
},
_toggle: function(toggle) {
var that = this, options = that.options, isTodayDisabled = that.options.disableDates(getToday()), link = that._today, todayClass = that._todayClass();
if (toggle === undefined) {
toggle = isInRange(getToday(), options.min, options.max);
}
if (link) {
link.off(CLICK);
if (toggle && !isTodayDisabled) {
link.addClass(todayClass).removeClass(DISABLED).on(CLICK, that._todayClick.bind(that));
} else {
link.removeClass(todayClass).addClass(DISABLED).on(CLICK, prevent);
}
}
},
_todayClass: function() {
return TODAY;
},
_todayClick: function(e) {
var that = this, depth = views[that.options.depth], disabled = that.options.disableDates, today = getToday();
e.preventDefault();
if (disabled(today)) {
return;
}
if (that._view.compare(that._current, today) === 0 && that._index == depth) {
that._changeView = false;
}
if (that._isMultipleSelection()) {
that._selectDates = [today];
that.selectable._lastActive = null;
}
that._value = today;
that.navigate(today, depth);
that.trigger(CHANGE);
},
_templates: function() {
var that = this, options = that.options, footer = options.footer, month = options.month, content = month.content, weekNumber = month.weekNumber, empty = month.empty, footerTemplate = (data) => `${kendo.toString(data, "D", options.culture)}`;
that.month = {
content: (data) => `<td class="${data.cssClass}" role="gridcell"><span tabindex="-1" class="k-link ${data.linkClass}" data-href="${data.url}" ${kendo.attr(VALUE)}="${data.dateString}" title="${data.title}">${executeTemplate(content, data) || data.value}</span></td>`,
empty: (data) => `<td role="gridcell">${executeTemplate(empty, data) || " "}</td>`,
weekNumber: (data) => `<td class="k-calendar-td k-alt">${executeTemplate(weekNumber, data) || data.weekNumber}</td>`
};
that.year = { content: template((data) => `<td class="${data.cssClass}" role="gridcell"><span tabindex="-1" class="k-link" data-href="#" data-${data.ns}value="${data.dateString}" aria-label="${data.label}">${data.value}</span></td>`) };
if (footer && footer !== true) {
footerTemplate = footer;
}
that.footer = footer !== false ? template(footerTemplate, { useWithBlock: false }) : null;
},
_updateAria: function(ariaTemplate, date) {
var that = this;
var cell = that._cell;
var valueType = that.view().valueType();
var current = date || that.current();
var text;
if (valueType === "month") {
text = kendo.toString(current, "MMMM");
} else if (valueType === "date") {
text = kendo.toString(current, "D");
} else {
text = cell.text();
}
cell.attr("aria-label", ariaTemplate({
current,
valueType,
text
}));
return cell.attr("id");
}
});
ui.plugin(Calendar);
var calendar = {
firstDayOfMonth: function(date) {
return createDate(date.getFullYear(), date.getMonth(), 1);
},
firstVisibleDay: function(date, calendarInfo) {
calendarInfo = calendarInfo || kendo.culture().calendar;
var firstDay = calendarInfo.firstDay, firstVisibleDay = new DATE(date.getFullYear(), date.getMonth(), 1, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
firstVisibleDay.setFullYear(date.getFullYear());
while (firstVisibleDay.getDay() != firstDay) {
calendar.setTime(firstVisibleDay, -1 * MS_PER_DAY);
}
return firstVisibleDay;
},
setTime: function(date, time) {
var tzOffsetBefore = date.getTimezoneOffset(), resultDATE = new DATE(date.getTime() + time), tzOffsetDiff = resultDATE.getTimezoneOffset() - tzOffsetBefore;
date.setTime(resultDATE.getTime() + tzOffsetDiff * MS_PER_MINUTE);
},
views: [
{
name: MONTH,
title: function(date, min, max, culture) {
return getCalendarInfo(culture).months.names[date.getMonth()] + " " + date.getFullYear();
},
content: function(options) {
var that = this, idx = 0, min = options.min, max = options.max, date = options.date, dates = options.dates, format = options.format, culture = options.culture, navigateUrl = options.url, showHeader = options.showHeader, showOtherMonthDays = options.showOtherMonthDays, isWeekColumnVisible = options.isWeekColumnVisible, hasUrl = navigateUrl && dates[0], currentCalendar = getCalendarInfo(culture), firstDayIdx = currentCalendar.firstDay, days = currentCalendar.days, names = shiftArray(days.names, firstDayIdx), shortNames = shiftArray(days.namesShort, firstDayIdx), start = calendar.firstVisibleDay(date, currentCalendar), firstDayOfMonth = that.first(date), lastDayOfMonth = that.last(date), toDateString = that.toDateString, today = getToday(), contentClasses = options.contentClasses, html = "<table tabindex=\"0\" role=\"grid\" class=\"" + contentClasses + "\" cellspacing=\"0\" data-start=\"" + toDateString(start) + "\">";
if (showHeader) {
html += "<caption class=\"k-calendar-caption k-month-header\">" + this.title(date, min, max, culture) + "</caption>";
}
html += "<thead class=\"k-calendar-thead\"><tr role=\"row\" class=\"k-calendar-tr\">";
if (isWeekColumnVisible) {
html += "<th scope=\"col\" class=\"k-calendar-th k-alt\">" + encode(options.messages.weekColumnHeader) + "</th>";
}
for (; idx < 7; idx++) {
html += "<th scope=\"col\" class=\"k-calendar-th\" aria-label=\"" + names[idx] + "\">" + shortNames[idx] + "</th>";
}
adjustDST(today, 0);
today = +today;
return view({
cells: 42,
perRow: 7,
html: html += "</tr></thead><tbody class=\"k-calendar-tbody\"><tr role=\"row\" class=\"k-calendar-tr\">",
start: createDate(start.getFullYear(), start.getMonth(), start.getDate()),
isWeekColumnVisible,
weekNumber: options.weekNumber,
min: createDate(min.getFullYear(), min.getMonth(), min.getDate()),
max: createDate(max.getFullYear(), max.getMonth(), max.getDate()),
showOtherMonthDays,
content: options.content,
lastDayOfMonth,
empty: options.empty,
setter: that.setDate,
disableDates: options.disableDates,
build: function(date, idx, disableDates) {
var cssClass = ["k-calendar-td"], day = date.getDay(), linkClass = "", url = "#";
if (date < firstDayOfMonth || date > lastDayOfMonth) {
cssClass.push(OTHERMONTH);
}
if (disableDates(date)) {
cssClass.push(DISABLED);
}
if (+date === today) {
cssClass.push("k-today");
}
if (day === 0 || day === 6) {
cssClass.push("k-weekend");
}
if (hasUrl && inArray(+date, dates)) {
url = navigateUrl.replace("{0}", kendo.toString(date, format, culture));
linkClass = " k-action-link";
}
return {
date,
dates,
ns: kendo.ns,
title: kendo.toString(date, "D", culture),
value: date.getDate(),
dateString: toDateString(date),
cssClass: cssClass.join(" "),
linkClass,
url
};
},
weekNumberBuild: function(date) {
return {
weekNumber: weekInYear(date, kendo.culture().calendar.firstDay),
currentDate: date
};
}
});
},
first: function(date) {
return calendar.firstDayOfMonth(date);
},
last: function(date) {
var last = createDate(date.getFullYear(), date.getMonth() + 1, 0), first = calendar.firstDayOfMonth(date), timeOffset = Math.abs(last.getTimezoneOffset() - first.getTimezoneOffset());
i