UNPKG

@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
//#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\">&nbsp;</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) || "&nbsp;"}</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