@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
4,485 lines • 177 kB
JavaScript
import "./kendo.icons.js";
import "./kendo.html.button.js";
import "./kendo.dropdownlist.js";
import "./kendo.multiselect.js";
import "./kendo.editable.js";
import "./kendo.window.js";
import "./kendo.segmentedcontrol.js";
import "./kendo.toolbar.js";
import "./kendo.switch.js";
import "./kendo.pane.js";
import "./kendo.pdf.js";
import "./kendo.dialog.js";
import "./kendo.datetimepicker.js";
import "./kendo.scheduler.view.js";
import "./kendo.scheduler.dayview.js";
import "./kendo.scheduler.agendaview.js";
import "./kendo.scheduler.monthview.js";
import "./kendo.scheduler.yearview.js";
import "./kendo.scheduler.recurrence.js";
import "./kendo.scheduler.timelineview.js";
//#region ../src/kendo.scheduler.js
const __meta__ = {
id: "scheduler",
name: "Scheduler",
category: "web",
description: "The Scheduler is an event calendar.",
depends: [
"dropdownlist",
"editable",
"multiselect",
"window",
"dialog",
"datepicker",
"datetimepicker",
"toolbar",
"scheduler.recurrence",
"scheduler.view",
"html.button",
"icons",
"segmentedcontrol"
],
features: [
{
id: "scheduler-dayview",
name: "Scheduler Day View",
description: "Scheduler Day View",
depends: ["scheduler.dayview"]
},
{
id: "scheduler-agendaview",
name: "Scheduler Agenda View",
description: "Scheduler Agenda View",
depends: ["scheduler.agendaview"]
},
{
id: "scheduler-monthview",
name: "Scheduler Month View",
description: "Scheduler Month View",
depends: ["scheduler.monthview"]
},
{
id: "scheduler-timelineview",
name: "Scheduler Timeline View",
description: "Scheduler Timeline View",
depends: ["scheduler.timelineview"]
},
{
id: "scheduler-yearview",
name: "Scheduler Year View",
description: "Scheduler Year View",
depends: ["scheduler.yearview"]
},
{
id: "scheduler-mobile",
name: "Scheduler adaptive rendering",
description: "Support for adaptive rendering",
depends: [
"dialog",
"pane",
"switch"
]
},
{
id: "scheduler-pdf-export",
name: "PDF export",
description: "Export the scheduler events as PDF",
depends: ["pdf", "drawing"]
},
{
id: "scheduler-timezones",
name: "Timezones",
description: "Allow selecting timezones different than Etc/UTC",
depends: ["timezones"]
}
]
};
(function($, undefined) {
var kendo = window.kendo, date = kendo.date, MS_PER_DAY = date.MS_PER_DAY, getDate = date.getDate, getMilliseconds = kendo.date.getMilliseconds, recurrence = kendo.recurrence, encode = kendo.htmlEncode, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, DataBoundWidget = ui.DataBoundWidget, STRING = "string", Popup = ui.Popup, Calendar = ui.Calendar, DataSource = kendo.data.DataSource, isPlainObject = $.isPlainObject, extend = $.extend, toString = Object.prototype.toString, isArray = Array.isArray, NS = ".kendoScheduler", CLICK = "click", MOUSEDOWN = "mousedown", TOUCHSTART = kendo.support.pointers ? "pointerdown" : "touchstart", TOUCHMOVE = kendo.support.pointers ? "pointermove" : "touchmove", TOUCHEND = kendo.support.pointers ? "pointerup" : "touchend", MOUSEMOVE = kendo.support.mousemove, CHANGE = "change", PROGRESS = "progress", ERROR = "error", CANCEL = "cancel", REMOVE = "remove", RESET = "resetSeries", SAVE = "save", ADD = "add", EDIT = "edit", DISABLED = "disabled", OPTION = "option", FOCUSEDSTATE = "k-focus", INVERSECOLORCLASS = "k-event-inverse", valueStartEndBoundRegex = /(?:value:start|value:end)(?:,|$)/, MIN_SCREEN = "(min-width: 1024px)", TODAY = getDate(/* @__PURE__ */ new Date()), EXCEPTION_SEPARATOR = ",", OLD_EXCEPTION_SEPARATOR_REGEXP = /\;/g, RECURRENCE_EXCEPTION = "recurrenceException", DELETECONFIRM = "Are you sure you want to delete this event?", DELETERECURRING = "Do you want to delete only this event occurrence or the whole series?", EDITRECURRING = "Do you want to edit only this event occurrence or the whole series?", DELETERECURRINGCONFIRM = "Are you sure you want to delete this event occurrence?", RESETSERIESCONFIRM = "Are you sure you want to reset the whole series?", DELETESERIESCONFIRM = "Are you sure you want to delete the whole series?", RESETTIMEZONECONFIRM = "Are you sure you want to reset the timezone?", TOOLBAR_HYSTERESIS = 20, ONGOING_CLASS = "k-event-ongoing", COMMANDBUTTONTMPL = ({ className, attr, text, icon, fillMode, themeColor }) => kendo.html.renderButton(`<button type="button" class="${className}" ${attr}>${text}</button>`, {
icon,
fillMode,
themeColor
}), VIEWS_DROPDOWN_TEMPLATE = kendo.template(({ label, views, type }) => `<select aria-label="${label}" class="k-picker k-dropdown-list k-dropdown ${type}">` + Object.keys(views).map((view) => `<option value="${view}">${views[view].title}</option>`).join("") + "</select>"), DEFAULT_TOOLS = {
pdf: {
name: "pdf",
type: "button",
icon: "file-pdf",
attributes: { class: "k-pdf" }
},
pdfMobile: {
name: "pdf",
type: "button",
icon: "file-pdf",
showText: "overflow",
attributes: { class: "k-pdf" }
},
today: {
name: "today",
type: "button",
fillMode: "flat",
attributes: { "ref-nav-today": "" }
},
previous: {
name: "previous",
type: "button",
icon: "chevron-left",
fillMode: "flat",
showText: "overflow",
attributes: { "ref-nav-prev": "" },
groupClass: "k-button-group-flat"
},
next: {
name: "next",
type: "button",
icon: "chevron-right",
fillMode: "flat",
showText: "overflow",
attributes: { "ref-nav-next": "" },
groupClass: "k-button-group-flat"
},
current: {
name: "current",
type: "button",
icon: "calendar",
fillMode: "flat",
text: "placeholder",
attributes: {
"aria-live": "polite",
class: "k-nav-current"
}
},
search: { template: `<span class="k-scheduler-search k-textbox k-input"><input tabindex="-1" autocomplete="off" class="k-input-inner k-scheduler-search-input k-input-inner" /><span class="k-input-suffix">${kendo.ui.icon("search")}</span></span>` },
refresh: {
name: "refresh",
type: "button",
icon: "arrow-rotate-cw",
showText: "overflow",
attributes: { class: "k-scheduler-refresh" }
},
create: {
name: "create",
type: "button",
icon: "plus",
text: "New Event",
attributes: {
class: "k-toolbar-button k-button k-button-primary",
"ref-toolbar-create": ""
}
},
createMobile: {
name: "create",
type: "button",
icon: "plus",
text: "New Event",
showText: "overflow",
attributes: {
class: "k-toolbar-button k-button",
"ref-toolbar-create": ""
}
},
calendar: {
name: "calendar",
type: "button",
icon: "calendar",
attributes: { class: "k-nav-calendar" }
},
previousMobile: {
name: "previous",
type: "button",
icon: "chevron-left",
showText: "overflow",
attributes: { "ref-nav-prev": "" },
groupClass: "k-scheduler-navigation"
},
nextMobile: {
name: "next",
type: "button",
icon: "chevron-right",
showText: "overflow",
attributes: { "ref-nav-next": "" },
groupClass: "k-scheduler-navigation"
},
currentMobile: { template: "<span class=\"k-scheduler-navigation\"><span class=\"k-nav-current\"><span class=\"k-m-date-format\"></span><span class=\"k-y-date-format\"></span></span></span>" },
view: {
name: "view",
type: "button",
togglable: true,
group: "views"
}
}, defaultDesktopTools = [
"create",
"today",
["previous", "next"],
"current",
{ type: "spacer" }
], defaultMobileToolsFirst = [["calendar"], { type: "spacer" }], defaultMobileToolsSecond = [
"previousMobile",
{ type: "spacer" },
"currentMobile",
{ type: "spacer" },
"nextMobile"
], MOBILEDATERANGEEDITOR = function(container, options) {
var attr = {
name: options.field,
title: options.title
};
var isAllDay = options.model.isAllDay;
var dateTimeValidate = kendo.attr("validate") + "='" + !isAllDay + "'";
var dateValidate = kendo.attr("validate") + "='" + !!isAllDay + "'";
appendTimezoneAttr(attr, options);
appendValidDateValidator(attr, options);
appendDateCompareValidator(attr, options);
$("<input type=\"datetime-local\" required " + kendo.attr("type") + "=\"datetime-local\" " + kendo.attr("bind") + "=\"value:" + options.field + ", invisible:isAllDay\" " + dateTimeValidate + "/>").attr(attr).appendTo(container);
$("<input type=\"date\" required " + kendo.attr("type") + "=\"date\" " + kendo.attr("bind") + "=\"value:" + options.field + ",visible:isAllDay\" " + dateValidate + "/>").attr(attr).appendTo(container);
$("<span " + kendo.attr("for") + "=\"" + options.field + "\" class=\"k-invalid-msg\"/>").hide().appendTo(container);
}, DATERANGEEDITOR = function(container, options) {
var attr = {
name: options.field,
title: options.title
}, isStart = options.field === "start", isEnd = options.field === "end";
appendTimezoneAttr(attr, options);
appendValidDateValidator(attr, options);
appendDateCompareValidator(attr, options);
var row = $("<div class=\"k-scheduler-edit-form-row k-pos-relative\"></div>").appendTo(container);
$("<input type=\"hidden\" required " + kendo.attr("bind") + "=\"value:" + options.field + "\" " + kendo.attr("validate") + "=\"true\"/>").attr(attr).attr("data-scheduler-date-part", "owner").appendTo(row);
$("<span " + kendo.attr("for") + "=\"" + options.field + "\" class=\"k-invalid-msg\"/>").hide().appendTo(row);
$("<input type=\"text\" " + kendo.attr("type") + "=\"date\" " + kendo.attr("role") + "=\"datepicker\" " + kendo.attr("validate") + "=\"false\"/>").attr({
name: options.field,
title: options.title
}).attr(kendo.attr("skip"), "true").attr("data-scheduler-field", options.field).attr("data-scheduler-date-part", "date").appendTo(row);
$(`<span class="k-scheduler-datetime-separator k-scheduler-datetime-label"
${isEnd ? "data-bind=\"invisible:isAllDay\"" : ""}
${isStart ? "data-separator-for='start'" : "data-separator-for='end'"}>
</span>`).text(isStart ? "from" : "to").appendTo(row);
$("<input type=\"text\" " + kendo.attr("type") + "=\"time\" " + kendo.attr("role") + "=\"timepicker\" " + kendo.attr("bind") + "=\"invisible:isAllDay\" " + kendo.attr("validate") + "=\"false\"/>").attr({
name: options.field,
title: options.title
}).attr(kendo.attr("skip"), "true").attr("data-scheduler-field", options.field).attr("data-scheduler-date-part", "time").appendTo(row);
if (isStart && !kendo.timezone.windows_zones) $(`<span class="k-col-span-2" data-bind="invisible:isAllDay"></span>`).appendTo(container);
}, positionDateRangeValidationMessage = function(message) {
var callout = message.find(".k-callout");
var field = message.attr(kendo.attr("for"));
var datePicker = message.parent().find("[data-scheduler-field='" + field + "'][data-scheduler-date-part=date]").data("kendoDatePicker");
if (!callout.length || !datePicker) return;
callout.removeClass("k-callout-n").addClass("k-callout-s");
message[0].style.removeProperty("right");
message[0].style.removeProperty("inset-inline-end");
message[0].style.setProperty("left", datePicker.wrapper.position().left + "px");
message[0].style.setProperty("inset-block-start", "auto");
message[0].style.setProperty("inset-block-end", "calc(100% + " + callout.outerHeight() / 2 + "px)");
message[0].style.setProperty("margin-block-start", "0px");
}, RECURRENCEEDITOR = function(container, options) {
$("<div " + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr({
name: options.field,
"aria-label": options.title
}).appendTo(container).kendoRecurrenceEditor({
start: options.model.start,
timezone: options.timezone,
messages: options.messages,
recurrenceRuleLabelTemplate: options.recurrenceRuleLabelTemplate
});
}, MOBILERECURRENCEEDITOR = function(container, options) {
$("<div " + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr({ name: options.field }).appendTo(container).kendoMobileRecurrenceEditor({
start: options.model.start,
timezone: options.timezone,
messages: options.messages,
pane: options.pane,
value: options.model[options.field]
});
}, MOBILEISALLDAYEDITOR = function(container, options) {
$("<input type=\"checkbox\" data-role=\"switch\"" + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr(kendo.attr("messages"), "{\"checked\":\"\",\"unchecked\":\"\"}").appendTo(container);
}, ISALLDAYEDITOR = function(container, options) {
var wrapper = $("<div class=\"k-scheduler-edit-form-row\"></div>").appendTo(container);
$("<input type=\"checkbox\" data-role=\"switch\"" + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr({
id: options.field,
name: options.field,
title: options.title ? options.title : options.field,
"aria-label": options.title ? options.title : options.field
}).attr(kendo.attr("messages"), "{\"checked\":\"\",\"unchecked\":\"\"}").appendTo(wrapper);
$("<span></span>").text(options.title || options.field).appendTo(wrapper);
}, MOBILETIMEZONEPOPUP = function(container, options) {
var text = timezoneButtonText(options.model, options.messages.noTimezone);
$("<span class=\"k-timezone-label\"></span>").text(text).appendTo(container);
$(kendo.ui.icon("arrow-chevron-right")).appendTo(container);
container.closest("li.k-item label").on(CLICK, options.click);
}, TIMEZONEBUTTON = function(container, options) {
let startContainer = $(container).parent().parent().find(".k-scheduler-datetime-grid");
if (startContainer.length) startContainer = startContainer.find("div[data-container-for='start']").length ? startContainer.find("div[data-container-for='start']") : startContainer;
setTimezoneButtonState($("<a href=\"#\" class=\"k-col-span-2 k-button k-button-flat k-button-primary k-icon-button k-timezone-btn\" title=\"" + encode(options.messages.timezone) + "\" data-bind=\"invisible:isAllDay\"><span class=\"k-button-text\">" + encode(options.messages.timezoneEditorButton) + "</span></a>").append($(kendo.ui.icon("globe")).addClass("k-button-icon")).on(CLICK, options.click).appendTo(startContainer), !options.model.isTimezoneInvisible, options.messages);
$(container).parent(".k-form-field").remove();
}, MOBILETIMEZONEEDITOR = function(container, options) {
$("<div class=\"k-mobiletimezoneeditor\" " + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr({ name: options.field }).appendTo(container).kendoMobileTimezoneEditor({ optionLabel: options.noTimezone });
}, TIMEZONEEDITOR = function(container, options) {
container.attr(kendo.attr("bind"), "invisible: isTimezoneInvisible");
$("<div " + kendo.attr("bind") + "=\"value:" + options.field + "\" />").attr({ name: options.field }).appendTo(container).kendoTimezoneEditor({
optionLabel: options.noTimezone,
title: options.title
});
};
function setTimezoneButtonState(timezoneBtn, active, messages) {
timezoneBtn.find(".k-button-text").toggleClass("k-hidden", active);
timezoneBtn.toggleClass("k-col-span-2", !active);
timezoneBtn.attr("title", active ? messages.resetTimezoneWindowTitle : messages.timezone);
if (active) timezoneBtn.attr("aria-label", messages.resetTimezoneWindowTitle);
else timezoneBtn.removeAttr("aria-label");
}
function timezoneButtonText(model, message) {
message = message || "";
if (model.startTimezone) {
message = model.startTimezone;
if (model.endTimezone) message += " | " + model.endTimezone;
}
return message;
}
function appendTimezoneAttr(attrs, options) {
var timezone = options.timezone;
if (timezone) attrs[kendo.attr("timezone")] = timezone;
}
function appendValidDateValidator(attrs, options) {
var validationRules = options.model.fields[options.field].validation;
if (validationRules) {
var validDateRule = validationRules.validDateValidator;
if (validDateRule && isPlainObject(validDateRule) && validDateRule.message) attrs[kendo.attr("validDate-msg")] = validDateRule.message;
}
}
function appendDateCompareValidator(attrs, options) {
var validationRules = options.model.fields[options.field].validation;
if (validationRules) {
var dateCompareRule = validationRules.dateCompare;
if (dateCompareRule && isPlainObject(dateCompareRule) && dateCompareRule.message) attrs[kendo.attr("dateCompare-msg")] = dateCompareRule.message;
}
}
function wrapDataAccess(originalFunction, timezone) {
return function(data) {
data = originalFunction(data);
convertData(data, "apply", timezone);
return data || [];
};
}
function wrapDataSerialization(originalFunction, timezone) {
return function(data) {
if (data) {
if (toString.call(data) !== "[object Array]" && !(data instanceof kendo.data.ObservableArray)) data = [data];
}
convertData(data, "remove", timezone, true);
data = originalFunction(data);
return data || [];
};
}
function convertData(data, method, timezone, removeUid) {
var event, idx, length, startOffset, endOffset;
data = data || [];
for (idx = 0, length = data.length; idx < length; idx++) {
event = data[idx];
startOffset = event.start ? event.start.getTimezoneOffset() : null;
endOffset = event.start ? event.end.getTimezoneOffset() : null;
if (removeUid) {
if (event.startTimezone || event.endTimezone) if (timezone) {
event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
event.start = kendo.timezone[method](event.start, timezone);
event.end = kendo.timezone[method](event.end, timezone);
} else {
event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
}
else if (timezone) {
event.start = kendo.timezone[method](event.start, timezone);
event.end = kendo.timezone[method](event.end, timezone);
}
} else if (event.startTimezone || event.endTimezone) {
event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
if (timezone) {
event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
}
} else if (timezone) {
event.start = kendo.timezone[method](event.start, timezone);
event.end = kendo.timezone[method](event.end, timezone);
}
if (removeUid) delete event.uid;
if (method === "remove" && event.start && startOffset && startOffset !== event.start.getTimezoneOffset()) event.start = new Date(event.start.getTime() + (startOffset - event.start.getTimezoneOffset()) * 6e4);
if (method === "remove" && event.end && endOffset && endOffset !== event.end.getTimezoneOffset()) event.end = new Date(event.end.getTime() + (endOffset - event.end.getTimezoneOffset()) * 6e4);
}
return data;
}
function getOccurrenceByUid(data, uid) {
var length = data.length, idx = 0, event;
for (; idx < length; idx++) {
event = data[idx];
if (event.uid === uid) return event;
}
}
var SchedulerDataReader = kendo.Class.extend({
init: function(schema, reader) {
var timezone = schema.timezone;
this.reader = reader;
if (reader.model) this.model = reader.model;
this.timezone = timezone;
this.data = wrapDataAccess(this.data.bind(this), timezone);
this.serialize = wrapDataSerialization(this.serialize.bind(this), timezone);
},
errors: function(data) {
return this.reader.errors(data);
},
parse: function(data) {
return this.reader.parse(data);
},
data: function(data) {
return this.reader.data(data);
},
total: function(data) {
return this.reader.total(data);
},
groups: function(data) {
return this.reader.groups(data);
},
aggregates: function(data) {
return this.reader.aggregates(data);
},
serialize: function(data) {
return this.reader.serialize(data);
}
});
function applyZone(date, fromZone, toZone) {
if (toZone) date = kendo.timezone.convert(date, fromZone, toZone);
else date = kendo.timezone.remove(date, fromZone);
return date;
}
function schedulerEditable(input) {
var editable;
input.parents().each(function() {
editable = $(this).data("kendoEditable");
return !editable;
});
return editable;
}
function validDateValidator(input) {
if (input.filter("[data-scheduler-date-part=owner]").length) {
var editable = schedulerEditable(input);
var value = editable && editable._validationEventInProgress ? input.data("schedulerValue") : editable && editable.options.model.get(input.attr("name"));
return value instanceof Date && !isNaN(value.getTime());
}
if (input.filter("[name=start]").length && input.filter("[title=Start]").length || input.filter("[name=end]").length && input.filter("[title=End]").length || input.filter(".k-recur-until").length) {
var date;
var picker = kendo.widgetInstance(input, kendo.ui);
if (picker) {
date = kendo.parseDate(input.val(), picker.options.format);
return !!date && picker.value();
} else {
date = kendo.parseDate(input.val());
return !!date;
}
}
return true;
}
function dateCompareValidator(input) {
if (input.filter("[data-scheduler-date-part=owner][name=end]").length) {
var editable = schedulerEditable(input);
if (editable && editable._validationEventInProgress) return true;
var model = editable && editable.options.model;
var start = model && model.get("start");
var end = model && model.get("end");
if (start instanceof Date && end instanceof Date) {
var timezone = input.attr(kendo.attr("timezone"));
var startTimezone = model.startTimezone;
var endTimezone = model.endTimezone;
startTimezone = startTimezone || endTimezone;
endTimezone = endTimezone || startTimezone;
if (startTimezone) {
start = applyZone(start, startTimezone, timezone);
end = applyZone(end, endTimezone, timezone);
}
return start <= end;
}
return true;
}
if (input.filter("[name=end]").length) {
var container = input.closest(".k-scheduler-edit-form");
var startInput = container.find("[name=start]:visible");
var endInput = container.find("[name=end]:visible");
if (endInput[0] && startInput[0]) {
var start, end;
var startPicker = kendo.widgetInstance(startInput, kendo.ui);
var endPicker = kendo.widgetInstance(endInput, kendo.ui);
var editable = container.data("kendoEditable");
var model = editable ? editable.options.model : null;
if (startPicker && endPicker) {
start = startPicker.value();
end = endPicker.value();
} else {
start = kendo.parseDate(startInput.val());
end = kendo.parseDate(endInput.val());
}
if (start && end) {
if (model) {
var timezone = startInput.attr(kendo.attr("timezone"));
var startTimezone = model.startTimezone;
var endTimezone = model.endTimezone;
startTimezone = startTimezone || endTimezone;
endTimezone = endTimezone || startTimezone;
if (startTimezone) {
start = applyZone(start, startTimezone, timezone);
end = applyZone(end, endTimezone, timezone);
}
}
return start <= end;
}
}
}
return true;
}
function untilDateCompareValidator(input) {
var untilPicker, until, container, startInput, start, startPicker;
if (input.filter(".k-recur-until").length) {
untilPicker = kendo.widgetInstance(input, kendo.ui);
until = untilPicker.value();
container = input.closest(".k-scheduler-edit-form");
startInput = container.find("[name=start]:visible");
if (startInput[0]) {
startPicker = kendo.widgetInstance(startInput, kendo.ui);
if (startPicker) start = startPicker.value();
else start = kendo.parseDate(startInput.val());
if (start && until) return start <= until;
}
}
return true;
}
var SchedulerEvent = kendo.data.Model.define({
init: function(value) {
var that = this;
kendo.data.Model.fn.init.call(that, value);
that._defaultId = that.defaults[that.idField];
},
_time: function(field) {
var date = this[field];
var fieldTime = "_" + field + "Time";
if (this[fieldTime]) return this[fieldTime] - kendo.date.toUtcTime(kendo.date.getDate(date));
return getMilliseconds(date);
},
_date: function(field) {
var fieldTime = "_" + field + "Time";
if (this[fieldTime]) return this[fieldTime] - this._time(field);
return kendo.date.getDate(this[field]);
},
clone: function(options, updateUid) {
var uid = this.uid, event = new this.constructor($.extend({}, this.toJSON(), options));
if (!updateUid) event.uid = uid;
return event;
},
duration: function() {
var end = this.end;
var start = this.start;
var offset = (end.getTimezoneOffset() - start.getTimezoneOffset()) * kendo.date.MS_PER_MINUTE;
return end - start - offset;
},
expand: function(start, end, zone) {
return recurrence ? recurrence.expand(this, start, end, zone) : [this];
},
update: function(eventInfo) {
for (var field in eventInfo) this.set(field, eventInfo[field]);
if (this._startTime) this.set("_startTime", kendo.date.toUtcTime(this.start));
if (this._endTime) this.set("_endTime", kendo.date.toUtcTime(this.end));
},
isMultiDay: function() {
return this.isAllDay || this.duration() >= kendo.date.MS_PER_DAY;
},
isException: function() {
return !this.isNew() && this.recurrenceId;
},
isOccurrence: function() {
return this.isNew() && this.recurrenceId;
},
isRecurring: function() {
return !!(this.recurrenceRule || this.recurrenceId);
},
isRecurrenceHead: function() {
return !!(this.id && this.recurrenceRule);
},
toOccurrence: function(options) {
options = $.extend(options, {
recurrenceException: null,
recurrenceRule: null,
recurrenceId: this.id || this.recurrenceId
});
options[this.idField] = this.defaults[this.idField];
return this.clone(options, true);
},
toJSON: function() {
var obj = kendo.data.Model.fn.toJSON.call(this);
obj.uid = this.uid;
delete obj._startTime;
delete obj._endTime;
return obj;
},
shouldSerialize: function(field) {
return kendo.data.Model.fn.shouldSerialize.call(this, field) && field !== "_defaultId";
},
set: function(key, value) {
var isAllDay = this.isAllDay || false;
kendo.data.Model.fn.set.call(this, key, value);
if (key == "isAllDay" && value != isAllDay) {
var start = kendo.date.getDate(this.start);
var end = new Date(this.end);
var milliseconds = kendo.date.getMilliseconds(end);
if (milliseconds === 0 && value) milliseconds = MS_PER_DAY;
this._normalizingAllDay = true;
try {
this.set("start", start);
if (value === true) {
kendo.date.setTime(end, -milliseconds);
if (end < start) end = start;
} else kendo.date.setTime(end, MS_PER_DAY - milliseconds);
this.set("end", end);
} finally {
delete this._normalizingAllDay;
}
}
},
id: "id",
fields: {
id: { type: "number" },
title: {
defaultValue: "",
type: "string"
},
start: {
type: "date",
validation: {
required: true,
validDate: { value: validDateValidator }
}
},
startTimezone: { type: "string" },
end: {
type: "date",
validation: {
required: true,
validDate: { value: validDateValidator },
dateCompare: { value: dateCompareValidator }
}
},
endTimezone: { type: "string" },
recurrenceRule: {
defaultValue: "",
type: "string",
validation: {
validDate: { value: validDateValidator },
untilDateCompare: { value: untilDateCompareValidator }
}
},
recurrenceException: {
defaultValue: "",
type: "string"
},
isReadonly: {
type: "boolean",
defaultValue: false
},
isAllDay: {
type: "boolean",
defaultValue: false
},
description: { type: "string" }
}
});
var SchedulerDataSource = DataSource.extend({
init: function(options) {
DataSource.fn.init.call(this, extend(true, {}, { schema: {
modelBase: SchedulerEvent,
model: SchedulerEvent
} }, options));
this.reader = new SchedulerDataReader(this.options.schema, this.reader);
},
expand: function(start, end) {
var data = this.view(), filter = {}, endOffset;
if (start && end) {
endOffset = end.getTimezoneOffset();
end = /* @__PURE__ */ new Date(end.getTime() + MS_PER_DAY - 1);
if (end.getTimezoneOffset() !== endOffset) end = kendo.timezone.apply(end, endOffset);
filter = {
logic: "or",
filters: [{
logic: "and",
filters: [
{
field: "start",
operator: "gte",
value: start
},
{
field: "end",
operator: "gte",
value: start
},
{
field: "start",
operator: "lte",
value: end
}
]
}, {
logic: "and",
filters: [{
field: "start",
operator: "lte",
value: /* @__PURE__ */ new Date(start.getTime() + MS_PER_DAY - 1)
}, {
field: "end",
operator: "gte",
value: start
}]
}]
};
data = new kendo.data.Query(expandAll(data, start, end, this.reader.timezone)).filter(filter).toArray();
}
return data;
},
cancelChanges: function(model) {
if (model && model.isOccurrence()) this._removeExceptionDate(model);
DataSource.fn.cancelChanges.call(this, model);
},
insert: function(index, model) {
if (!model) return;
if (!(model instanceof SchedulerEvent)) {
var eventInfo = model;
model = this._createNewModel();
model.accept(eventInfo);
}
if (!this._pushCreated && model.isRecurrenceHead() || model.recurrenceId) {
model = model.recurrenceId ? model : model.toOccurrence();
this._addExceptionDate(model);
}
return DataSource.fn.insert.call(this, index, model);
},
pushCreate: function(items) {
this._pushCreated = true;
DataSource.fn.pushCreate.call(this, items);
this._pushCreated = false;
},
remove: function(model) {
if (model.isRecurrenceHead()) this._removeExceptions(model);
else if (model.isRecurring()) this._addExceptionDate(model);
return DataSource.fn.remove.call(this, model);
},
_removeExceptions: function(model) {
var data = this.data().slice(0), item = data.shift(), id = model.id;
while (item) {
if (item.recurrenceId === id) DataSource.fn.remove.call(this, item);
item = data.shift();
}
model.set(RECURRENCE_EXCEPTION, "");
},
_removeExceptionDate: function(model) {
if (model.recurrenceId) {
var head = this.get(model.recurrenceId);
if (head) {
var start = model.defaults.start;
var replaceRegExp = new RegExp("(\\" + EXCEPTION_SEPARATOR + "?)" + recurrence.toExceptionString(start, this.reader.timezone));
var recurrenceException = (head.recurrenceException || "").replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, "");
if (replaceRegExp.test(recurrenceException)) head.set(RECURRENCE_EXCEPTION, recurrenceException.replace(replaceRegExp, ""));
else {
start = model.start;
replaceRegExp = new RegExp("(\\" + EXCEPTION_SEPARATOR + "?)" + recurrence.toExceptionString(start, this.reader.timezone));
head.set(RECURRENCE_EXCEPTION, recurrenceException.replace(replaceRegExp, ""));
}
}
}
},
_addExceptionDate: function(model) {
var start = model.start;
var zone = this.reader.timezone;
var head = this.get(model.recurrenceId);
var recurrenceException = (head.recurrenceException || "").replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, "");
if (!recurrence.isException(recurrenceException, start, zone)) {
var newException = recurrence.toExceptionString(start, zone);
model.defaults.start = start;
head.set(RECURRENCE_EXCEPTION, recurrenceException + (recurrenceException && newException ? EXCEPTION_SEPARATOR : "") + newException);
}
}
});
function expandAll(events, start, end, zone) {
var length = events.length, data = [], idx = 0;
for (; idx < length; idx++) data = data.concat(events[idx].expand(start, end, zone));
return data;
}
SchedulerDataSource.create = function(options) {
if (isArray(options) || options instanceof kendo.data.ObservableArray) options = { data: options };
var dataSource = options || {};
dataSource.data = dataSource.data;
if (!(dataSource instanceof SchedulerDataSource) && dataSource instanceof kendo.data.DataSource) throw new Error("Incorrect DataSource type. Only SchedulerDataSource instances are supported");
return dataSource instanceof SchedulerDataSource ? dataSource : new SchedulerDataSource(dataSource);
};
extend(true, kendo.data, {
SchedulerDataSource,
SchedulerDataReader,
SchedulerEvent
});
var defaultCommands = {
update: {
text: "Save",
className: "k-button-primary k-scheduler-update"
},
canceledit: {
text: "Cancel",
className: "k-scheduler-cancel"
},
destroy: {
text: "Delete",
icon: "trash",
imageClass: "k-i-trash",
className: "k-button-primary k-scheduler-delete",
iconClass: "k-icon"
}
};
function trimOptions(options, overrideOptions) {
delete options.name;
delete options.prefix;
delete options.remove;
delete options.edit;
delete options.add;
delete options.navigate;
for (var key in overrideOptions) options[key] = overrideOptions[key];
return options;
}
function descriptionEditor(options) {
var attr = createValidationAttributes(options.model, options.field);
return function(container, model) {
$("<textarea name=\"description\" placeholder=\"Add Description\" class=\"k-input-inner !k-resize-y\" title=\"" + model.title + "\"/>").attr(attr).appendTo(container).wrap("<span class=\"k-input k-textarea\"></span>");
};
}
function createValidationAttributes(model, field) {
var modelField = (model.fields || model)[field];
var specialRules = [
"url",
"email",
"number",
"date",
"boolean"
];
var validation = modelField ? modelField.validation : {};
var datatype = kendo.attr("type");
var inArray = $.inArray;
var ruleName;
var rule;
var attr = {};
for (ruleName in validation) {
rule = validation[ruleName];
if (inArray(ruleName, specialRules) >= 0) attr[datatype] = ruleName;
else if (!kendo.isFunction(rule)) attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule;
attr[kendo.attr(ruleName + "-msg")] = rule.message;
}
return attr;
}
function filterResourceEditorData(editor, parentValue, parentValueField, valueField) {
var editorValue = editor.value(), isMs = Array.isArray(editorValue), valueArray;
if (isMs) valueArray = JSON.parse(JSON.stringify(editorValue));
else valueArray = [editorValue.toString()];
editor.dataSource.data().forEach(function(item) {
if (item[parentValueField] === null || item[parentValueField] === undefined || item[parentValueField] == parentValue) item.set(DISABLED, false);
else {
var currentValue = item.get(valueField);
item.set(DISABLED, true);
if (valueArray.indexOf(currentValue) >= 0 || valueArray.indexOf(currentValue.toString()) >= 0) if (isMs) valueArray.splice(valueArray.indexOf(currentValue), 1);
else {
editor.value(null);
editor.trigger(CHANGE);
}
}
});
if (isMs && valueArray.length < editorValue.length) {
editor.value(valueArray);
editor.trigger(CHANGE);
}
}
function bindParentValueChangeHandler(container, currentEditor, resource, parent) {
var parentElement = container.closest(".k-scheduler-edit-form, .k-edit-form-container").find("[data-" + kendo.ns + "bind='value:" + parent + "']");
var parentWidget = parentElement.getKendoDropDownList();
if (parentWidget) parentWidget.bind(CHANGE, function(ev) {
filterResourceEditorData(currentEditor, ev.sender.value(), resource.dataParentValueField, resource.dataValueField);
});
else parentElement.on(CHANGE, function(ev) {
var parentValue = ev.target.value;
filterResourceEditorData(currentEditor, parentValue, resource.dataParentValueField, resource.dataValueField);
});
}
function filterMobileResourceEditorData(resource, currentEditor, parentSelectedValue) {
var options = currentEditor.find(OPTION), editorValue = currentEditor.val(), isMs = Array.isArray(editorValue), valueArray;
if (isMs) valueArray = JSON.parse(JSON.stringify(editorValue));
else valueArray = [editorValue];
resource.dataSource.view().forEach(function(item, index) {
var itemParentValue = kendo.getter(resource.dataParentValueField)(item);
if (itemParentValue === null || itemParentValue === undefined || itemParentValue == parentSelectedValue) options[index].removeAttribute(DISABLED);
else {
options[index].setAttribute(DISABLED, DISABLED);
var currentValue = "" + item.get(resource.dataValueField);
if (valueArray.indexOf(currentValue) >= 0) if (isMs) valueArray.splice(valueArray.indexOf(currentValue), 1);
else {
currentEditor.val(null);
currentEditor.trigger(CHANGE);
}
}
});
if (isMs && valueArray.length < editorValue.length) {
currentEditor.val(valueArray);
currentEditor.trigger(CHANGE);
}
}
function dropDownResourceEditor(resource, model, parent) {
var attr = createValidationAttributes(model, resource.field);
var ariaAttribute = resource.icon ? "aria-label=\"" + encode(resource.title || resource.field) + "\"" : "aria-labelledby=\"" + resource.field + "_label\"";
return function(container) {
var currentEditor;
if (parent) setTimeout(function() {
filterResourceEditorData(currentEditor, model[parent], resource.dataParentValueField, resource.dataValueField);
bindParentValueChangeHandler(container, currentEditor, resource, parent);
});
currentEditor = $(kendo.format("<select " + ariaAttribute + " data-{0}bind=\"value:{1}\" title=\"" + model.title + "\">", kendo.ns, resource.field)).appendTo(container).attr(attr).kendoDropDownList({
dataTextField: resource.dataTextField,
dataValueField: resource.dataValueField,
dataSource: resource.dataSource.data(),
valuePrimitive: resource.valuePrimitive,
optionLabel: "None",
template: (data) => `<span ${data.disabled ? "data-disabled" : ""}><span class="k-scheduler-mark" ${kendo.attr("style-background-color")}="${data[resource.dataColorField] || "none"}"></span>${data[resource.dataTextField]}</span>`,
select: function(e) {
if (e.dataItem && e.dataItem.disabled) e.preventDefault();
},
dataBound: function(e) {
let options = e.sender.list.find("li");
for (let i = 0; i < options.length; i++) {
var element = options.eq(i);
if (element.find("[data-disabled]").length > 0) element.addClass("k-disabled");
}
}
}).data("kendoDropDownList");
};
}
function dropDownResourceEditorMobile(resource, model, parent) {
var attr = createValidationAttributes(model, resource.field);
return function(container) {
var options = "";
var view = resource.dataSource.view();
for (var idx = 0, length = view.length; idx < length; idx++) options += kendo.format("<option value=\"{0}\">{1}</option>", kendo.getter(resource.dataValueField)(view[idx]), kendo.getter(resource.dataTextField)(view[idx]));
var currentEditor = $(kendo.format("<select aria-labelledby=\"" + resource.field + "_label\" data-{0}bind=\"value:{1}\">{2}</select>", kendo.ns, resource.field, options)).appendTo(container).attr(attr);
if (parent) setTimeout(function() {
var parentElement = container.closest(".k-stretched-view").find("[data-" + kendo.ns + "bind='value:" + parent + "']");
var parentSelectedValue = model[parent];
filterMobileResourceEditorData(resource, currentEditor, parentSelectedValue);
parentElement.on(CHANGE, function(ev) {
var parentValue = ev.target.value;
filterMobileResourceEditorData(resource, currentEditor, parentValue);
});
});
};
}
function multiSelectResourceEditor(resource, model, parent) {
var attr = createValidationAttributes(model, resource.field);
var ariaAttribute = resource.icon ? "aria-label=\"" + encode(resource.title || resource.field) + "\"" : "aria-labelledby=\"" + resource.field + "_label\"";
return function(container) {
var currentEditor;
if (parent) setTimeout(function() {
filterResourceEditorData(currentEditor, model[parent], resource.dataParentValueField, resource.dataValueField);
bindParentValueChangeHandler(container, currentEditor, resource, parent);
});
currentEditor = $(kendo.format("<select " + ariaAttribute + " data-{0}bind=\"value:{1}\">", kendo.ns, resource.field)).appendTo(container).attr(attr).kendoMultiSelect({
dataTextField: resource.dataTextField,
dataValueField: resource.dataValueField,
dataSource: resource.dataSource.data(),
valuePrimitive: resource.valuePrimitive,
itemTemplate: (data) => `<span ${data.disabled ? "data-disabled" : ""}><span class="k-scheduler-mark" ${kendo.attr("style-background-color")}="${data[resource.dataColorField] || "none"}"></span>${data[resource.dataTextField]}</span>`,
tagTemplate: (data) => `<span class="k-scheduler-mark" ${kendo.attr("style-background-color")}="${data[resource.dataColorField] || "none"}"></span>${data[resource.dataTextField]}`,
select: function(e) {
if (e.dataItem && e.dataItem.disabled) e.preventDefault();
},
dataBound: function(e) {
let options = e.sender.list.find("li");
for (let i = 0; i < options.length; i++) {
let element = options.eq(i);
if (element.find("[data-disabled]").length > 0) element.addClass("k-disabled");
}
}
}).data("kendoMultiSelect");
};
}
function multiSelectResourceEditorMobile(resource, model, parent) {
var attr = createValidationAttributes(model, resource.field);
return function(container) {
var options = "";
var view = resource.dataSource.view();
for (var idx = 0, length = view.length; idx < length; idx++) options += kendo.format("<option value=\"{0}\">{1}</option>", kendo.getter(resource.dataValueField)(view[idx]), kendo.getter(resource.dataTextField)(view[idx]));
var currentEditor = $(kendo.format("<select aria-labelledby=\"" + resource.field + "_label\" data-{0}bind=\"value:{1}\" multiple=\"multiple\">{2}</select>", kendo.ns, resource.field, options)).appendTo(container).attr(attr);
if (parent) setTimeout(function() {
var parentElement = container.closest(".k-stretched-view").find("[data-" + kendo.ns + "bind='value:" + parent + "']");
var parentSelectedValue = model[parent];
filterMobileResourceEditorData(resource, currentEditor, parentSelectedValue);
parentElement.on(CHANGE, function(ev) {
var parentValue = ev.target.value;
filterMobileResourceEditorData(resource, currentEditor, parentValue);
});
});
};
}
function moveEventRange(event, distance) {
var duration = event.end.getTime() - event.start.getTime();
var start = new Date(event.start.getTime());
kendo.date.setTime(start, distance);
var end = new Date(start.getTime());
kendo.date.setTime(end, duration, true);
return {
start,
end
};
}
var editors = {
mobile: {
dateRange: MOBILEDATERANGEEDITOR,
timezonePopUp: MOBILETIMEZONEPOPUP,
timezone: MOBILETIMEZONEEDITOR,
recurrence: MOBILERECURRENCEEDITOR,
description: descriptionEditor,
multipleResources: multiSelectResourceEditorMobile,
resources: dropDownResourceEditorMobile,
isAllDay: MOBILEISALLDAYEDITOR
},
desktop: {
dateRange: DATERANGEEDITOR,
timezonePopUp: TIMEZONEBUTTON,
timezone: TIMEZONEEDITOR,
recurrence: RECURRENCEEDITOR,
description: descriptionEditor,
multipleResources: multiSelectResourceEditor,
resources: dropDownResourceEditor,
isAllDay: ISALLDAYEDITOR
}
};
var Editor = kendo.Observable.extend({
init: function(element, options) {
kendo.Observable.fn.init.call(this);
this.element = element;
this.options = extend(true, {}, this.options, options);
this.createButton = this.options.createButton;
this.toggleDateValidationHandler = this._toggleDateValidation.bind(this);
},
_editorTitle: function(model) {
var editorMessages = this.options.messages.editor || {};
if (model && model.isNew && model.isNew()) return editorMessages.newEvent || editorMessages.editorTitle;
return editorMessages.editEvent || editorMessages.editorTitle;
},
_toggleDateValidation: function(e) {
if (e.field == "isAllDay") {
var container = this.container, isAllDay = this.editable.options.model.isAllDay, isMobile = this.options.mobile, bindAttribute = kendo.attr("bind"), element, isDateTimeInput, shouldValidate;
container.find("[" + bindAttribute + "*=end],[" + bindAttribute + "*=start]").each(function() {
element = $(this);
if (valueStartEndBoundRegex.test(element.attr(bindAttribute))) {
isDateTimeInput = element.is("[" + kendo.attr("role") + "=datetimepicker],[" + kendo.attr("role") + "=timepicker],[type*=datetime],[type=time]");
shouldValidate = isDateTimeInput ? !isAllDay : isMobile ? isAllDay : true;
element.attr(kendo.attr("validate"), shouldValidate.toString());
}
});
}
},
_initDateRangeEditors: function(model) {
var that = this;
var container = that.container;
var validator = container.data("kendoValidator");
var start = model.get("start");
var end = model.get("end");
that._dateRangeWidgets = [];
that._dateRangeDuration = start instanceof Date && end instanceof Date ? kendo.isFunction(model.duration) ? model.duration() : end.getTime() - start.getTime() : null;
if (validator && !kendo.isFunction(validator.options.rules.dateCompare)) validator.options.rules.dateCompare = dateCompareValidator;
["start", "end"].forEach(function(field) {
var dateInput = container.find("[data-scheduler-field='" + field + "'][data-scheduler-date-part=date]");
var timeInput = container.find("[data-scheduler-field='" + field + "'][data-scheduler-date-part=time]");
var datePicker = dateInput.data("kendoDatePicker");
var timePicker = timeInput.data("kendoTimePicker");
if (!datePicker || !timePicker) return;
if (validator) {
var owner = container.find("[data-scheduler-date-part=owner][name='" + field + "']");
var requiredMessage = validator.options.messages.required;
requiredMessage = kendo.isFunction(requiredMessage) ? requiredMessage(owner) : requiredMessage;
owner.attr(kendo.attr("required-msg"), kendo.format(requiredMessage, owner.attr("title")));
}
var dateChange = function() {
that._setDateRangePart(model, field, "date", datePicker.value());
};
var timeChange = function() {
that._setDateRangePart(model, field, "time", timePicker.value());
};
datePicker.value(model.get(field));
timePicker.value(model.get(field));
datePicker.bind(CHANGE, dateChange);
timePicker.bind(CHANGE, timeChange);
that._dateRangeWidgets.push({
field,
datePicker,
timePicker,
dateChange,
timeChange
});
});
if (!that._dateRangeWidgets.length) {
that._dateRangeWidgets = null;
return;
}
that._dateRangeModel = model;
that._dateRangeValidator = validator;
that._dateRangeValidateProxy = function(e) {
if (!model._normalizingAllDay || e.field !== "start" && e.field !== "end") that.editable._validateProxy(e);
};
if (validator) {
that._dateRangeValidateInput = validator.validateInput;
validator.validateInput = function(input) {
var valid = that._dateRangeValidateInput.call(this, input);
var owner = $(input);
if (!valid && owner.is("[data-scheduler-date-part=owner]")) {
var field = owner.attr("name");
positionDateRangeValidationMessage(container.find(".k-invalid-msg[" + kendo.attr("for") + "='" + field + "']"));
}
return valid;
};
}
that._dateRangeModelChangeHandler = function(e) {
if (e.field !== "start" && e.field !== "end") return;
var value = model.get(e.field);
var owner = container.find("[data-scheduler-date-part=owner][name='" + e.field + "']");
var datePicker = container.find("[data-scheduler-field='" + e.field + "'][data-scheduler-date-part=date]").data("kendoDatePicker");
var timePicker = container.find("[data-scheduler-field='" + e.field + "'][data-scheduler-date-part=time]").data("kendoTimePicker");
owner.val(value || "");
if (datePicker) datePicker.value(value);
if (timePicker) timePicker.value(value);
};
that._dateRangeValidationHandler = function(e) {
if (!e.input.is("[data-scheduler-date-part=owner]")) return;
var field = e.input.attr("name");
var isAllDay = model.get("isAllDay");
var dateInput = container.find("[data-scheduler-field='" + field + "'][data-scheduler-date-part=date]");
var timeInput = container.find("[data-scheduler-field='" + field + "'][data-scheduler-date-part=time]");
var dateWrapper = dateInput.data("kendoDatePicker").wrapper;
var timeWrapper = timeInput.data("kendoTimePicker").wrapper;
var message = container.find(".k-invalid-msg[" + kendo.attr("for") + "='" + field + "']");
var messageId = message.attr("id");
if (!e.valid) positionDateRangeValidationMessage(message);
dateWrapper.toggleClass("k-invalid", !e.valid);
timeWrapper.toggleClass("k-invalid", !e.valid && !isAllDay);
dateInput.attr("aria-invalid", (!e.valid).toString());
timeInput.attr("aria-invalid", (!e.valid && !isAllDay).toString());
dateWrapper.attr("aria-invalid", (!e.valid).toString());
timeWrapper.attr("aria-invalid", (!e.valid && !isAllDay).toString());
if (!e.valid && messageId) {
dateInput.attr("aria-describedby", messageId);
if (!isAllDay) timeInput.attr("aria-describedby", messageId);
} else {
dateInput.removeAttr("aria-describedby");
timeInput.removeAttr("aria-describedby");
}
};
that._dateRangeModelSetHandler = function(e) {
if (e.field === "start" || e.field === "end") container.find("[data-scheduler-date-part=owner][name='" + e.field + "']").val(e.value || "").data("schedulerValue", e.value);
};
model.unbind("set", that.editable._validateProxy);
model.unbind("equalSet", that.editable._validateProxy);
model.bind("set", that._dateRangeModelSetHandler);
model.bind("set", that._dateRangeValidateProxy);
model.bind("equalSet", that._dateRangeValidateProxy);
model.bind(CHANGE, that._dateRangeModelChangeHandler);
if (validator) validator.bind("validateInput", that._dateRangeValidationHandler);
},
_setDateRangePart: function(model, field, part, value) {
if (!(value instanceof Date) || isNaN(value.getTime())) {
model.set(field, null);
return;
}
var current = model.get(field);
var result = current instanceof Date && !isNaN(current.getTime()) ? new Date(current.getTime()) : new Date(value.getTime());
var duration = field === "start" ? this._dateRangeDuration : null;
if (part === "date") result.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
else result.setHours(value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds());
model.set(field, result);
if (duration !== null) {
var shiftedEnd = new Date(result.getTime());
kendo.date.setTime(shiftedEnd, duration);
model.set("end", shiftedEnd);
}
var endOwner = this.container && this.container.find("[data-scheduler-date-part=owner][name='end']");
if (this._dateRangeValidator && endOwner && endOwner.length) {
var endMessage = this.container.find(".k-invalid-msg[" + kendo.attr("for") + "='end']");
this._dateRangeValidator.validateInput(endOwner);
var renderedMessage = this.container.find(".k-invalid-msg[" + kendo.attr("for") + "='end']");
if (endMessage.length && renderedMessage.length && endMessage[0] !== renderedMessage[0]) {
endMessage.attr("class", renderedMessage.attr("class")).attr("id", renderedMessage.attr("id")).removeAttr("style").empty().append(renderedMessage.contents());
renderedMessage.replaceWith(endMessage);
positionDateRangeValidationMessage(endMessage);
}
}
},
_destroyDateRangeEditors: function() {
var that = this;
if (that._dateRangeWidgets) {
that._dateRangeWidgets.forEach(function(item) {
item.datePicker.unbind(CHANGE, item.dateChange);
item.timePicker.unbind(CHANGE, item.timeChange);
});
that._dateRangeWidgets = null;
}
var model = that._dateRangeModel;
var validator = that._dateRangeValidator;
if (model && that._dateRangeModelChangeHandler) model.unbind(CHANGE, that._dateRangeModelChangeHandler);
if (model && that._dateRangeModelSetHandler) model.unbind("set", that._dateRangeModelSetHandler);
if (model && that._dateRangeValidateProxy) {
model.unbind("set", that._dateRangeValidateProxy);
model.unbind("equalSet", that._dateRangeValidateProxy);
}
if (validator && that._dateRangeValidationHandler) validator.unbind("validateInput", that._dateRangeValidationHandler);
if (validator && that._dateRangeValidateInput) validator.validateInput = that._dateRangeValidateInput;
that._dateRangeModel = null;
that._dateRangeValidator = null;
that._dateRangeDuration = null;
that._dateRangeValidateInput = null;
that._dateRangeValidateProxy = null;
that._dateRangeModelChangeHandler = null;
that._dateRangeModelSetHandler = null;
that._dateRangeValidationHandler = null;
},
fields: function(editors, model) {
var that = this;
var messages = that.options.messages;
var timezone = that.options.timezone;
var click = function() {
that._toggleTimeZones(that.editable.element, model);
};
var change = function(e) {
var editorEl = $(that.editable.element);
var separator = editorEl.find("span[data-separator-for=\"start\"]");
var startRow = editorEl.find("div[data-container-for=\"start\"] > .k-scheduler-edit-form-row");
var endRow = editorEl.find("div[data-container-for=\"end\"] > .k-scheduler-edit-form-row");
if (e.checked) {
separator.text("to");
model.set("isTimezoneInvisible", true);
var timezoneBtn = editorEl.find(".k-timezone-btn");
if (timezoneBtn.length) setTimezoneButtonState(timezoneBtn, false, messages.editor);
var endDate = startRow.add(endRow).find("[data-scheduler-field=end][data-scheduler-date-part=date]").closest(".k-datepicker");
var endMessage = editorEl.find(".k-invalid-msg[" + kendo.attr("for") + "=end]");
endMessage.insertAfter(separator);
endDate.insertAfter(endMessage);
} else {
separator.text("from");
var endDate = startRow.find("[data-scheduler-field=end][data-scheduler-date-part=date]").closest(".k-datepicker");
var endMessage = editorEl.find(".k-invalid-msg[" + kendo.attr("for") + "=end]");
endDate.add(endMessage).prependTo(endRow);
}
};
var fields = [
{
field: "title",
title: messages.editor.title
},
{
field: "isAllDay",
title: messages.editor.allDayEvent,
editor: editors.isAllDay,
change
},
{
field: "start",
title: messages.editor.start,
editor: editors.dateRange,
timezone
},
{
field: "end",
title: messages.editor.end,
editor: editors.dateRange,
timezone
}
];
var checkHierarchical = function(item) {
return !!item[resource.dataParentValueField];
};
if (kendo.timezone.windows_zones) {
fields.push({
field: "timezone",
title: messages.editor.timezone,
editor: editors.timezonePopUp,
click,
messages: messages.editor,
model
});
model._set("isTimezoneInvisible", !(model.startTimezone || model.endTimezone));
fields.push({
field: "startTimezone",
title: messages.editor.startTimezone,
editor: editors.timezone,
noTimezone: messages.editor.noTimezone
});
fields.push({
field: "endTimezone",
title: messages.editor.endTimezone,
editor: editors.timezone,
noTimezone: messages.editor.noTimezone
});
}
if (!model.recurrenceId) fields.push({
field: "recurrenceRule",
title: messages.editor.repeat,
editor: editors.recurrence,
timezone,
messages: messages.recurrenceEditor,
pane: this.pane,
recurrenceRuleLabelTemplate: that.options.recurrenceRuleLabelTemplate
});
if ("description" in model) fields.push({
field: "description",
title: messages.editor.description,
editor: editors.description({
model,
field: "description"
})
});
for (var resourceIndex = 0; resourceIndex < this.options.resources.length; resourceIndex++) {
var resource = this.options.resources[resourceIndex];
var hasParent = resource.dataSource.view().some(checkHierarchical);
var parentResource, parent;
if (hasParent) {
parentResource = this.options.resources[resourceIndex - 1];
if (parentResource) parent = parentResource.field;
}
fields.push({
field: resource.field,
title: resource.title,
icon: resource.icon,
editor: resource.multiple ? editors.multipleResources(resource, model, parent) : editors.resources(resource, model, parent)
});
}
return fields;
},
end: function() {
var that = this;
if (that._dateRangeWidgets) that._dateRangeWidgets.map(function(item) {
return {
item,
dateValue: item.datePicker.value() || kendo.parseDate(item.datePicker.element.val(), item.datePicker.options.parseFormats, item.datePicker.options.culture),
timeValue: item.timePicker.value() || kendo.parseDate(item.timePicker.element.val(), item.timePicker.options.parseFormats, item.timePicker.options.culture)
};
}).forEach(function(values) {
var item = values.item;
var dateValue = values.dateValue;
var timeValue = values.timeValue;
if (dateValue && timeValue) {
that._setDateRangePart(that._dateRangeModel, item.field, "date", dateValue);
that._setDateRangePart(that._dateRangeModel, item.field, "time", timeValue);
} else that._dateRangeModel.set(item.field, null);
var value = that._dateRangeModel.get(item.field);
that.container.find("[data-scheduler-date-part=owner][name='" + item.field + "']").val(value || "").data("schedulerValue", value);
});
return this.editable.end();
},
_buildDesktopEditTemplate: function(model, fields, editableFields) {
this.options.messages;
const editableField = (fieldName) => {
if (!model.editable || model.editable(fieldName)) return `<div ${kendo.attr("container-for")}="${fieldName}" class="k-form-field-wrap"></div>`;
else return `<div class="k-form-field-wrap">${fieldName && kendo.getter(fieldName)(model) || ""}</div>`;
};
let datetimeGroupOpen = false;
const datetimeGroupFields = /* @__PURE__ */ new Set([
"isAllDay",
"start",
"end",
"timezone",
"startTimezone",
"endTimezone",
"recurrenceRule"
]);
const generateFields = (field) => {
const fieldName = field.field;
const fieldTitle = field.title;
const isEditable = !model.editable || model.editable(fieldName);
if (isEditable) editableFields.push(field);
let prefix = "";
if (datetimeGroupOpen && !datetimeGroupFields.has(fieldName)) {
prefix = "</div></div></div>";
datetimeGroupOpen = false;
}
if (fieldName === "isAllDay") {
datetimeGroupOpen = true;
return `<div class="k-form-field"><label class="k-label k-form-label" id="${fieldName}_label" aria-hidden="true">${kendo.ui.icon({
icon: "clock",
size: "xlarge"
})}</label><div class="k-form-field-wrap"><div class="k-scheduler-datetime-section">${editableField(fieldName)}`;
}
if ((fieldName === "start" || fieldName === "end") && datetimeGroupOpen) {
const containerHtml = isEditable ? `<div ${kendo.attr("container-for")}="${fieldName}" class="k-form-field-wrap" style="display:contents"></div>` : `<div class="k-form-field-wrap" style="display:contents">${kendo.getter(fieldName)(model) || ""}</div>`;
if (fieldName === "end") return containerHtml + "</div>";
return `<div class="k-scheduler-datetime-grid" ${kendo.attr("style-grid-template-columns")}="minmax(0, 2.5fr) minmax(0, 1fr) min-content">` + containerHtml;
}
if (fieldName === "startTimezone" || fieldName === "endTimezone") return `${editableField(fieldName)}`;
if (fieldName === "recurrenceRule") {
datetimeGroupOpen = false;
return `<div class='k-scheduler-edit-form-row'>${editableField(fieldName)}</div></div></div></div>`;
}
const label = `<label class="k-label k-form-label" for="${fieldName}" id="${fieldName}_label" ${field.icon ? "aria-hidden=\"true\"" : ""}>
${kendo.isPresent(field.icon) ? kendo.ui.icon({
icon: field.icon,
size: "xlarge"
}) : fieldTitle || fieldName || ""}
</label>`;
return prefix + `<div class="k-form-field">${label}${editableField(fieldName)}</div>`;
};
return `<div class="k-scheduler-edit-form k-form k-form-horizontal">${fields.map(generateFields).join("")}${datetimeGroupOpen ? "</div></div></div>" : ""}</div>`;
},
_buildMobileEditTemplate: function(model, fields, editableFields) {
var messages = this.options.messages;
const startTimezone = `<div class="k-popup-edit-form k-scheduler-edit-form k-scheduler-timezones" ${kendo.attr("style-display")}="none"><ul class="k-listgroup k-listgroup-flush"><li class="k-item k-listgroup-item"><label class="k-label k-listgroup-form-row"><span class="k-item-title k-listgroup-form-row">` + encode(messages.editor.separateTimezones) + "</span><span class=\"k-listgroup-form-field-wrapper\"><input class=\"k-timezone-toggle\" data-role=\"switch\" type=\"checkbox\" /></span></label></li>";
const editableField = (field) => {
const fieldName = field.field;
const fieldTitle = field.title;
const isEditable = !model.editable || model.editable(fieldName);
let midPart;
if (isEditable) midPart = `${fieldName === "timezone" ? `<label class="k-label k-listgroup-form-row" data-bind="css: { k-disabled: isAllDay }">` : `<label class="k-label k-listgroup-form-row">`}<span class="k-item-title k-listgroup-form-field-label">${fieldTitle || fieldName || ""}</span><div class="k-listgroup-form-field-wrapper" ${kendo.attr("container-for")}="${fieldName}"></div>`;
else midPart = `<li class="k-item k-listgroup-item"><label class="k-label k-no-click k-listgroup-form-row"><span class="k-item-title k-listgroup-form-field-label">${fieldTitle || fieldName || ""}</span><span class="k-no-editor k-listgroup-form-field-wrapper">${fieldName && kendo.getter(fieldName)(model) || ""}</span>`;
return `<li class="k-item k-listgroup-item">` + midPart + `</label></li>`;
};
const generateFields = (field) => {
const fieldName = field.field;
if (!model.editable || model.editable(fieldName)) editableFields.push(field);
return (fieldName === "timezone" || fieldName === "recurrenceRule" ? "</ul><ul class=\"k-listgroup k-listgroup-flush\">" : "") + (fieldName === "startTimezone" ? startTimezone : "") + editableField(field) + (fieldName === "recurrenceRule" ? "</ul><ul class=\"k-listgroup k-listgroup-flush\">" : "") + (fieldName === "endTimezone" ? "</ul></div>" : "");
};
return `<ul class="k-listgroup k-listgroup-flush">` + fields.map(generateFields).join("") + `</ul>`;
},
_buildEditTemplate: function(model, fields, editableFields, isMobile) {
var settings = extend({}, kendo.Template, this.options.templateSettings);
var template = this.options.editable.template;
var html = "";
if (template) {
if (typeof template === STRING) template = kendo.unescape(template);
html += kendo.template(template, settings)(model);
} else if (isMobile) html += "<div data-role=\"content\">" + this._buildMobileEditTemplate(model, fields, editableFields) + "</div>";
else html += this._buildDesktopEditTemplate(model, fields, editableFields);
return html;
},
_revertTimezones: function(model) {
model.set("startTimezone", this._startTimezone);
model.set("endTimezone", this._endTimezone);
delete this._startTimezone;
delete this._endTimezone;
}
});
var MobileEditor = Editor.extend({
init: function() {
Editor.fn.init.apply(this, arguments);
this.pane = kendo.Pane.wrap(this.element, { viewEngine: { viewOptions: {
renderOnInit: true,
wrap: false,
wrapInSections: true,
detachOnHide: false,
detachOnDestroy: false
} } });
this.pane.element.parent().css("height", this.options.height);
this.view = this.pane.view();
},
options: { animations: {
left: "slide",
right: "slide:right"
} },
destroy: function() {
this.close();
this.unbind();
this.pane.destroy();
},
_toggleTimeZones: function(container, model) {
this._initTimezoneEditor(model);
},
_initTimezoneEditor: function(model) {
var that = this;
var pane = that.pane;
var messages = that.options.messages;
var timezoneView = that.timezoneView;
var container = timezoneView ? timezoneView.content.find(".k-scheduler-timezones") : that.container.find(".k-scheduler-timezones");
var kSwitch = container.find("input.k-timezone-toggle").data("kendoSwitch");
var endTimezoneRow = container.find("li.k-item:not(.k-zonepicker)").last();
var startTimezoneChange = function(e) {
if (e.field === "startTimezone") {
var value = model.startTimezone;
kSwitch.enable(value);
if (!value) {
endTimezoneRow.hide();
model.set("endTimezone", "");
kSwitch.value(false);
}
}
};
that._startTimezone = model.startTimezone || "";
that._endTimezone = model.endTimezone || "";
if (!timezoneView) {
var html = "<div data-role=\"view\" class=\"k-popup-edit-form k-scheduler-edit-form\"><div data-role=\"header\" class=\"k-appbar k-appbar-primary\">" + kendo.html.renderButton(`<button class="k-header-cancel k-scheduler-cancel" title="${messages.cancel}" aria-label="${messages.cancel}"></button>`, {
fillMode: "flat",
icon: "chevron-left"
}) + `<span class="k-spacer"></span><span>${encode(messages.editor.timezoneTitle)}</span><span class="k-spacer"></span>` + encode(messages.editor.timezoneTitle) + kendo.html.renderButton(`<button class="k-header-done k-scheduler-update" title="${messages.save}" aria-label="${messages.save}"></button>`, {
fillMode: "flat",
icon: "check"
}) + "</div><div data-role=\"content\"></div>";
this.timezoneView = timezoneView = pane.append(html);
timezoneView.contentElement.append(container.show());
timezoneView.element.on(CLICK + NS, ".k-scheduler-cancel, .k-scheduler-update", function(e) {
e.preventDefault();
e.stopPropagation();
if ($(this).hasClass("k-scheduler-cancel")) that._revertTimezones(model);
var editView = that._editPane;
var text = timezoneButtonText(model, messages.editor.noTimezone);
editView.content.find(".k-timezone-label").text(text);
pane.navigate(editView, that.options.animations.right);
});
kSwitch.bind(CHANGE, function(ev) {
endTimezoneRow.toggle(ev.checked);
model.set("endTimezone", "");
});
model.bind(CHANGE, startTimezoneChange);
}
kSwitch.value(!!model.endTimezone);
kSwitch.enable(!!model.startTimezone);
if (model.endTimezone) endTimezoneRow.show();
else endTimezoneRow.hide();
pane.navigate(timezoneView, that.options.animations.left);
},
showDialog: function(options) {
var actions = options.buttons.map(function(button) {
return {
text: button.text,
action: button.click
};
});
actions.push({
text: this.options.messages.cancel,
primary: true
});
$("<div />").appendTo(document.body).kendoDialog({
close: function() {
this.destroy();
},
modal: { preventScroll: true },
closable: false,
title: false,
content: options.text,
actions
});
},
editEvent: function(model) {
var pane = this.pane;
var html = "";
var messages = this.options.messages;
var updateText = messages.save;
var removeText = messages.destroy;
var cancelText = messages.cancel;
var titleText = messages.editor.editorTitle;
var resetSeries = messages.resetSeries;
html += "<div data-role=\"view\" class=\"k-popup-edit-form k-scheduler-edit-form\"" + kendo.attr("uid") + "=\"" + model.uid + "\"><div data-role=\"header\" class=\"k-appbar k-appbar-primary\">" + kendo.html.renderButton(`<button class="k-header-cancel k-scheduler-cancel" title="${cancelText}" aria-label="${cancelText}"></button>`, {
fillMode: "flat",
icon: "chevron-left"
}) + `<span class="k-spacer"></span><span>${encode(titleText)}</span><span class="k-spacer"></span>` + kendo.html.renderButton(`<button class="k-header-done k-scheduler-update" title="${updateText}" aria-label="${updateText}"></button>`, {
fillMode: "flat",
icon: "check"
}) + "</div>";
var fields = this.fields(editors.mobile, model);
var that = this;
var editableFields = [];
html += this._buildEditTemplate(model, fields, editableFields, true);
html += "</div>";
var view = pane.append(html);
if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false && model.isRecurrenceHead() && model.recurrenceException) {
var resetSeriesBtn = "<ul class=\"k-edit-buttons k-listgroup k-listgroup-flush\"><li class=\"k-item k-listgroup-item\"><span class=\"k-scheduler-resetSeries k-link k-label\" aria-label=\"" + resetSeries + "\">" + resetSeries + "</span></li></ul>";
view.contentElement.append(resetSeriesBtn);
}
if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false) {
var deleteBtn = "<ul class=\"k-edit-buttons k-listgroup k-listgroup-flush\"><li class=\"k-item k-listgroup-item\"><span class=\"k-scheduler-delete k-link k-label\" aria-label=\"" + removeText + "\">" + removeText + "</span></li></ul>";
view.contentElement.append(deleteBtn);
}
this._editPane = view;
var container = this.container = view.element;
this.editable = container.kendoEditable({
fields: editableFields,
model,
clearContainer: false,
target: that.options.target,
validateOnBlur: true
}).data("kendoEditable");
if (!this.trigger("edit", {
container,
model
})) {
container.on(CLICK + NS, "a.k-scheduler-edit, .k-scheduler-cancel, .k-scheduler-update, span.k-scheduler-delete, span.k-scheduler-resetSeries", function(e) {
e.preventDefault();
e.stopPropagation();
var button = $(this);
if (!button.hasClass("k-scheduler-edit")) {
var name = "cancel";
if (button.hasClass("k-scheduler-update")) name = "save";
else if (button.hasClass("k-scheduler-delete")) name = "remove";
else if (button.hasClass("k-scheduler-resetSeries")) name = RESET;
that.trigger(name, {
container,
model
});
} else pane.navigate(this._editPane, that.options.animations.right);
});
pane.navigate(view, that.options.animations.left);
model.bind(CHANGE, that.toggleDateValidationHandler);
} else this.trigger("cancel", {
container,
model
});
return this.editable;
},
_views: function() {
return this.pane.element.find(kendo.roleSelector("view")).not(this.view.element);
},
close: function() {
if (this.container) {
this.pane.navigate("", this.options.animations.right);
var views = this._views();
var view;
for (var idx = 0, length = views.length; idx < length; idx++) {
view = views.eq(idx).data("kendoView");
if (view) view.purge();
}
views.remove();
this.container = null;
if (this.editable) {
this.editable.options.model.unbind(CHANGE, this.toggleDateValidationHandler);
this.editable.destroy();
this.editable = null;
}
this.timezoneView = null;
}
}
});
var PopupEditor = Editor.extend({
destroy: function() {
this.close();
this.unbind();
},
editEvent: function(model) {
var that = this;
var editable = that.options.editable;
var html = "<div " + kendo.attr("uid") + "=\"" + model.uid + "\">";
var $html;
var messages = that.options.messages;
var updateText = messages.save;
var cancelText = messages.cancel;
var deleteText = messages.destroy;
var deleteIcon = "trash";
var resetSeries = messages.resetSeries;
var fields = this.fields(editors.desktop, model);
var editableFields = [];
var fieldName;
html += this._buildEditTemplate(model, fields, editableFields, false);
var attr;
var options = isPlainObject(editable) ? editable.window : {};
html += "<div class=\"k-actions k-actions-end k-actions-horizontal k-window-actions k-dialog-actions\">";
if ((!model.isNew() || model.isRecurring()) && editable.destroy !== false) html += this.createButton({
name: "delete",
text: deleteText,
attr,
icon: deleteIcon,
fillMode: "flat",
themeColor: "primary"
});
html += this.createButton({
name: "canceledit",
text: cancelText,
attr
}) + this.createButton({
name: "update",
text: updateText,
attr
});
if (!model.isNew() && editable.destroy !== false && model.isRecurrenceHead() && model.recurrenceException) html += this.createButton({
name: "resetSeries",
text: resetSeries,
attr
});
html += "</div></div>";
$html = $(html);
kendo.applyStylesFromKendoAttributes($html, ["display", "grid-template-columns"]);
var container = this.container = $html.appendTo(that.element).eq(0).kendoDialog(extend({
title: that._editorTitle(model),
modal: true,
width: 800,
closable: true,
actions: [],
visible: false,
close: function(e) {
if (e.userTriggered) {
if (that.trigger(CANCEL, {
container,
model
})) e.preventDefault();
}
}
}, options));
that.editable = container.kendoEditable({
fields: editableFields,
model,
clearContainer: false,
validateOnBlur: true,
target: that.options.target
}).data("kendoEditable");
that._initDateRangeEditors(model);
for (var field in editableFields) {
if (editableFields[field].field !== "recurrenceRule") {
fieldName = editableFields[field].field;
var inputs = container.find("[name='" + fieldName + "']");
if ([
"title",
"isAllDay",
"start",
"end",
"startTimezone",
"endTimezone",
"description"
].includes(fieldName)) inputs.removeAttr("aria-labelledby").each(function() {
var input = $(this);
var inputLabel = input.attr("aria-label");
var fieldTitle = editableFields[field].title;
input.attr("aria-label", inputLabel && inputLabel !== fieldTitle ? fieldTitle + " " + inputLabel : fieldTitle);
});
else inputs.attr("aria-labelledby", fieldName + "_label");
}
if (editableFields[field].field === "title") container.find("label[for='" + fieldName + "']").text("").removeAttr("for").attr("aria-hidden", "true").prepend(kendo.ui.icon({
icon: "right-double-quotes",
size: "xlarge"
}));
if (editableFields[field].field === "description") container.find("label[for='" + fieldName + "']").text("").removeAttr("for").attr("aria-hidden", "true").prepend(kendo.ui.icon({
icon: "comment",
size: "xlarge"
}));
if (editableFields[field].field === "startTimezone" || editableFields[field].field === "endTimezone") {
let editableField = editableFields[field].field, startEndSelector = editableField === "startTimezone" ? "start" : "end", timeZoneContainer = container.find(`div[data-container-for='${fieldName}']`);
if (editableField === "startTimezone") {
let timezoneBtn = container.find(`div[data-container-for='${startEndSelector}']`).find(".k-timezone-btn");
timeZoneContainer.insertBefore(timezoneBtn);
that._startTimezoneChangeHandler = function(e) {
if (e.field === "startTimezone") model.set("endTimezone", model.startTimezone);
};
model.bind(CHANGE, that._startTimezoneChangeHandler);
} else {
let startEndContainer = container.find(`div[data-container-for='${startEndSelector}']`);
timeZoneContainer.appendTo(startEndContainer);
}
}
if (editableFields[field].field === "isAllDay") {
container.find("label[for='" + fieldName + "']").attr("id", fieldName + "_label");
let kSwitch = container.find(`div[data-container-for='${fieldName}']`).find("input").getKendoSwitch();
kSwitch.bind("change", editableFields[field].change);
if (kSwitch.value()) editableFields[field].change({ checked: true });
}
}
if (!that.trigger(EDIT, {
container,
model
})) {
container.data("kendoDialog").open();
container.on(CLICK + NS, "button.k-scheduler-cancel", function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger(CANCEL, {
container,
model
});
});
container.on(CLICK + NS, "button.k-scheduler-update", function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger("save", {
container,
model
});
});
container.on(CLICK + NS, "button.k-scheduler-delete", function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger(REMOVE, {
container,
model
});
});
container.on(CLICK + NS, "button.k-scheduler-resetSeries", function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger(RESET, {
container,
model
});
});
kendo.cycleForm(container);
model.bind(CHANGE, that.toggleDateValidationHandler);
} else that.trigger(CANCEL, {
container,
model
});
return that.editable;
},
close: function() {
var that = this;
var destroy = function() {
if (that.editable) {
var model = that.editable.options.model;
that._destroyDateRangeEditors();
model.unbind(CHANGE, that.toggleDateValidationHandler);
if (that._startTimezoneChangeHandler) {
model.unbind(CHANGE, that._startTimezoneChangeHandler);
that._startTimezoneChangeHandler = null;
}
that.editable.destroy();
that.editable = null;
that.container = null;
}
if (that.popup) {
that.popup.destroy();
that.popup = null;
}
};
if (that.editable) if (that.container.is(":visible")) that.container.data("kendoDialog").bind("hide", destroy).close();
else destroy();
else destroy();
},
showDialog: function(options) {
var actions = options.buttons.map(function(button) {
return {
text: button.text,
action: button.click,
primary: kendo.isPresent(button.primary) ? button.primary : false
};
});
$("<div />").appendTo(document.body).kendoDialog({
close: function() {
this.destroy();
},
modal: { preventScroll: true },
closable: kendo.isPresent(options.closable) ? options.closable : false,
title: options.title,
content: options.text,
actions
}).data("kendoDialog").open();
},
_toggleTimeZones: function(container, model) {
var that = this;
var messages = that.options.messages;
var editable = that.options.editable;
let timezoneBtn = container.find(".k-timezone-btn");
if (timezoneBtn.length) {
let textContainer = timezoneBtn.find(".k-button-text");
if (textContainer.length && !textContainer.hasClass("k-hidden")) {
setTimezoneButtonState(timezoneBtn, true, messages.editor);
model.set("isTimezoneInvisible", false);
} else if (textContainer.length && textContainer.hasClass("k-hidden")) if (editable === true || editable.confirmation !== false) that.showDialog({
title: messages.editor.resetTimezoneWindowTitle,
closable: true,
text: RESETTIMEZONECONFIRM,
buttons: [{
name: "canceledit",
text: messages.editor.cancelTimezoneReset,
primary: false,
click: function() {}
}, {
name: "resettimezone",
text: messages.editor.resetTimezone,
primary: true,
click: function() {
setTimezoneButtonState(timezoneBtn, false, messages.editor);
model.set("startTimezone", "");
model.set("endTimezone", "");
model.set("isTimezoneInvisible", true);
}
}]
});
else {
setTimezoneButtonState(timezoneBtn, false, messages.editor);
model.set("isTimezoneInvisible", true);
}
}
}
});
var Scheduler = DataBoundWidget.extend({
init: function(element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
if (!that.options.views || !that.options.views.length) that.options.views = ["day", "week"];
that.resources = [];
that._initModel();
that._wrapper();
if (that.options.selectable) that._tabindex();
that._views();
that._toolbar();
that._dataSource();
that._resources();
that._resizeHandler = function() {
that.resize();
};
that.wrapper.on(MOUSEDOWN + NS + " selectstart" + NS, function(e) {
var target = $(e.target);
if (!target.is(":kendoFocusable") && target.closest(".k-button").length === 0) e.preventDefault();
});
if (that.options.editable && that.options.editable.resize !== false) that._resizable();
that._movable();
that._bindResize();
if (that.options.messages && that.options.messages.recurrence) recurrence.options = that.options.messages.recurrence;
that._navigation();
that._selectable();
that._touchHandlers();
that._ariaId = kendo.guid();
that._createEditor();
that.mediaQueryList = kendo.mediaQuery(MIN_SCREEN);
that.mediaQueryList.onChange(that._onMediaChange.bind(that));
if (that._showWatermarkOverlay) that._showWatermarkOverlay(that.element[0]);
Widget.fn.endInit.call(that);
},
_onMediaChange: function(e) {
const that = this;
const view = that._selectedView;
const toolbarEl = that.toolbar;
const toolbar = toolbarEl.getKendoToolBar();
if (that._viewsDropDownButton) return;
const segmentedControlEl = toolbarEl.find(".k-scheduler-views");
if (e.matches) {
toolbar.hide(toolbarEl.find(".k-views-dropdown"));
segmentedControlEl.show();
} else {
toolbar.show(toolbarEl.find(".k-views-dropdown"));
segmentedControlEl.hide();
}
that._model.set("formattedDate", e.matches ? view.dateForTitle() : view.shortDateForTitle());
},
_bindResize: function() {
$(window).on("resize" + NS, this._resizeHandler);
},
_unbindResize: function() {
$(window).off("resize" + NS, this._resizeHandler);
},
dataItems: function() {
var that = this;
var items = that.items();
var events = that._data;
var eventsUids = $.map(items, function(item) {
return $(item).attr("data-uid");
});
var i;
var key;
var dict = {};
var eventsUidsLength = eventsUids.length;
for (i = 0; i < eventsUidsLength; i++) dict[eventsUids[i]] = null;
var eventsCount = events.length;
for (i = 0; i < eventsCount; i++) {
var event = events[i];
if (dict[event.uid] !== undefined) dict[event.uid] = event;
}
var sortedData = [];
for (key in dict) sortedData.push(dict[key]);
return sortedData;
},
_isMobile: function() {
var options = this.options;
return options.mobile === true && kendo.support.mobileOS || options.mobile === "phone" || options.mobile === "tablet";
},
_isTouch: function(event) {
return /touch/.test(event.type) || event.originalEvent && /touch/.test(event.originalEvent.pointerType);
},
_isInverseColor: function(eventElement) {
return eventElement.hasClass(INVERSECOLORCLASS);
},
_groupsByResource: function(resources, groupIndex, groupsArray, parentFieldValue, parentField) {
if (!groupsArray) groupsArray = [];
var resource = resources[0];
if (resource) {
var group;
var data = resource.dataSource.view();
var prevIndex = 0;
for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
var fieldValue = kendo.getter(resource.dataValueField)(data[dataIndex]);
var currentGroupIndex = groupIndex + prevIndex + dataIndex;
group = this._groupsByResource(resources.slice(1), currentGroupIndex, groupsArray, fieldValue, resource.field);
group[resource.field] = fieldValue;
prevIndex = group.groupIndex;
if (parentField && parentFieldValue) group[parentField] = parentFieldValue;
if (resources.length === 1) {
group.groupIndex = groupIndex + dataIndex;
groupsArray.push(group);
}
}
return group;
} else return {};
},
data: function() {
return this._data;
},
select: function(options) {
var that = this;
var view = that.view();
var selection = that._selection;
var groups = view.groups;
var selectedGroups;
if (options === undefined) {
var selectedEvents;
var slots = view._selectedSlots;
if (!selection) return [];
if (selection && selection.events) selectedEvents = that._selectedEvents();
return {
start: selection.start,
end: selection.end,
events: selectedEvents,
slots,
resources: view._resourceBySlot(selection)
};
}
if (!options) {
that._selection = null;
that._old = null;
view.clearSelection();
return;
}
if (Array.isArray(options)) options = { events: options.splice(0) };
if (options.resources) {
var fieldName;
var filters = [];
var groupsByResource = [];
if (view.groupedResources) that._groupsByResource(view.groupedResources, 0, groupsByResource);
for (fieldName in options.resources) filters.push({
field: fieldName,
operator: "eq",
value: options.resources[fieldName]
});
selectedGroups = new kendo.data.Query(groupsByResource).filter(filters).toArray();
}
if (options.events && options.events.length) {
that._selectEvents(options.events, selectedGroups);
that._select();
return;
}
if (groups && options.start && options.end) {
var rangeStart = getDate(view._startDate);
var rangeEnd = kendo.date.addDays(getDate(view._endDate), 1);
var group;
var ranges;
if (options.start < rangeEnd && rangeStart <= options.end) {
if (selectedGroups && selectedGroups.length) group = groups[selectedGroups[0].groupIndex];
else group = groups[0];
if (!group.timeSlotCollectionCount()) options.isAllDay = true;
ranges = group.ranges(options.start, options.end, options.isAllDay, false);
if (ranges.length) {
that._selection = {
start: kendo.timezone.toLocalDate(ranges[0].start.start),
end: kendo.timezone.toLocalDate(ranges[ranges.length - 1].end.end),
groupIndex: ranges[0].start.groupIndex,
index: ranges[0].start.index,
isAllDay: ranges[0].start.isDaySlot,
events: []
};
that._select();
}
}
}
},
_selectEvents: function(eventsUids, selectedGroups) {
var that = this;
var idx;
var view = that.view();
var groups = view.groups;
var eventsLength = eventsUids.length;
var isGrouped = selectedGroups && selectedGroups.length;
var ctrlKey = that._ctrlKey;
that._ctrlKey = true;
for (idx = 0; idx < eventsLength; idx++) if (groups && isGrouped) {
var currentGroup = groups[selectedGroups[0].groupIndex];
var events = [];
var timeSlotCollectionCount = currentGroup.timeSlotCollectionCount();
var daySlotCollectionCount = currentGroup.daySlotCollectionCount();
for (var collIdx = 0; collIdx < timeSlotCollectionCount; collIdx++) events = events.concat(currentGroup.getTimeSlotCollection(collIdx).events());
for (var dayCollIdx = 0; dayCollIdx < daySlotCollectionCount; dayCollIdx++) events = events.concat(currentGroup.getDaySlotCollection(dayCollIdx).events());
events = new kendo.data.Query(events).filter({
field: (event) => event.element[0].getAttribute("data-uid"),
operator: "eq",
value: eventsUids[idx]
}).toArray();
if (events[0]) that._createSelection(events[0].element);
} else {
var element = view.element.find(kendo.format(".k-event[data-uid={0}], .k-task[data-uid={0}]", eventsUids[idx]));
if (element.length) that._createSelection(element[0]);
}
that._ctrlKey = ctrlKey;
},
_touchHandlers: function() {
var that = this;
var startX;
var startY;
var endX;
var endY;
var timeStamp;
var wrapper = that.wrapper;
var touchMoveHandler = that._touchMove.bind(that);
wrapper.on(TOUCHSTART + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td, .k-event", function(e) {
var content = that.wrapper.find(".k-scheduler-content");
if (!that._isTouch(e)) return;
content.stop(true, false);
that._touchPosX = startX = that._tapPosition(e, "X");
that._touchPosY = startY = that._tapPosition(e, "Y");
that._userTouched = true;
that.view()._scrolling = false;
timeStamp = Date.now();
wrapper.on(TOUCHMOVE + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td, .k-event", touchMoveHandler);
});
wrapper.on("contextmenu" + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td, .k-event", function(e) {
that._preventFocus = true;
});
wrapper.on(TOUCHEND + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td, .k-event", function(e) {
if (!that._isTouch(e)) return;
var delta = Date.now() - timeStamp;
var content = that.wrapper.find(".k-scheduler-content");
var amplitude = -that._amplitude * (3e3 / delta);
endX = that._tapPosition(e, "X");
endY = that._tapPosition(e, "Y");
if (that._dragging) return;
if (that.options.selectable && (Math.abs(endX - startX) <= 10 || Math.abs(endY - startY) <= 10)) that._mouseDownSelection(e);
if (!kendo.support.kineticScrollNeeded && delta < 200 && Math.abs(endX - startX) > 10) content.animate({ scrollTop: content[0].scrollTop + amplitude });
wrapper.off(TOUCHMOVE + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td", touchMoveHandler);
});
},
_navigation: function() {
var that = this, wrapper = that.wrapper;
wrapper.on("focus" + NS, function() {
var selection = that._selection;
setTimeout(function() {
if (!that._preventFocus) {
if ((!selection || selection.events.length > 0 && wrapper.find("[data-uid='" + selection.events[0] + "']").length === 0) && !that._userTouched && !that._mouseDown) that._initialFocus();
else that._mouseDown = false;
that._select();
} else that._preventFocus = false;
}, 300);
});
wrapper.on("focusout" + NS, function() {
that._ctrlKey = that._shiftKey = false;
});
wrapper.on("keydown" + NS, that, that._keydown.bind(that));
wrapper.on("keyup" + NS, function(e) {
that._ctrlKey = e.ctrlKey;
that._shiftKey = e.shiftKey;
});
},
_selectable: function() {
var that = this;
var wrapper = that.wrapper;
if (!that.options.selectable) return;
wrapper.on(MOUSEDOWN + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td, .k-event, .k-scheduler-body td .k-link", function(e) {
if (that._isTouch(e)) return;
that._mouseDownSelection(e);
});
var mouseMoveHandler = that._mouseMove.bind(that);
wrapper.on(MOUSEDOWN + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td", function(e) {
var which = e.which;
var button = e.button;
var isRight = which && which === 3 || button && button == 2;
if (that._isTouch(e)) return;
if (!isRight) wrapper.on(MOUSEMOVE + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td", mouseMoveHandler);
});
wrapper.on("mouseup" + NS + " mousecancel" + NS, function() {
wrapper.off(MOUSEMOVE + NS, ".k-scheduler-header-all-day td, .k-scheduler-content td", mouseMoveHandler);
});
},
_mouseDownSelection: function(e) {
var which = e.which;
var button = e.button;
if (!(which && which === 3 || button && button == 2)) {
if (e.ctrlKey) this._ctrlKey = e.ctrlKey;
if (e.shiftKey) this._shiftKey = e.shiftKey;
this._mouseDown = true;
this._createSelection(e.currentTarget);
if ($(e.currentTarget).hasClass("k-event")) this._selection.eventElement = e.currentTarget;
}
if (this.view().name !== "year" && kendo._activeElement() !== this.wrapper.get(0)) kendo.focusElement(this.wrapper);
else this._select();
if (this.toolbar) this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
},
_selectFirstSlot: function() {
var firstAllDay = this.wrapper.find(".k-scheduler-header-all-day").find("td").first(), firstContent = this.wrapper.find(".k-scheduler-content").find("td").first(), firstSlot;
if (firstAllDay.length > 0) firstSlot = firstAllDay;
else if (firstContent.length > 0) firstSlot = firstContent;
else firstSlot = this.wrapper.find(".k-scheduler-body").find(".k-link").first();
this._createSelection(firstSlot);
},
_firstEvent: function() {
var firstEventInAllDay = this.wrapper.find(".k-scheduler-header-wrap .k-event, .k-task").first(), firstEventInContent = this.wrapper.find(".k-scheduler-content .k-event").first(), firstEvent, allDayEvent, contentEvent;
if (firstEventInAllDay.length > 0) if (firstEventInContent.length > 0) {
allDayEvent = this.occurrenceByUid(firstEventInAllDay.data("uid"));
contentEvent = this.occurrenceByUid(firstEventInContent.data("uid"));
firstEvent = allDayEvent.start <= contentEvent.start ? firstEventInAllDay : firstEventInContent;
} else firstEvent = firstEventInAllDay;
else if (firstEventInContent) firstEvent = firstEventInContent;
return firstEvent;
},
_initialFocus: function() {
var firstEvent = this._firstEvent();
if (this.options.selectable) if (firstEvent && firstEvent.length > 0) {
this._createSelection(firstEvent);
this._selection.eventElement = firstEvent[0];
} else this._selectFirstSlot();
else if (this.toolbar && this.toolbar.find("." + FOCUSEDSTATE).length === 0) this._focusToolbar();
else if (this.toolbar) this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
},
_select: function() {
const that = this, view = that.view(), wrapper = that.wrapper, selection = that._selection, oldSelection = that._old ? that._old.selection : null, oldEventsLength = that._old ? that._old.eventsLength : null;
let current = view.current();
if (!selection) return;
if (current) {
current.removeAttribute("id");
wrapper.removeAttr("aria-activedescendant");
}
view.select(selection);
that._selection.eventElement = null;
current = view.current();
if (current) {
current.setAttribute("id", that._ariaId);
wrapper.attr("aria-activedescendant", that._ariaId);
const oldSelectionStart = that._old ? that._old.selectionStart.getTime() : null;
const oldSelectionEnd = that._old ? that._old.selectionEnd.getTime() : null;
const selectionRangeChanged = selection.start.getTime() !== oldSelectionStart || selection.end.getTime() !== oldSelectionEnd;
if (oldSelection !== current || selection.events && oldEventsLength !== selection.events.length || selectionRangeChanged) {
var currentUid = $(current).data("uid");
if (that._old && currentUid && currentUid === $(that._old.selection).data("uid") && selection.events && that._old.eventsLength === selection.events.length) return;
var events = that._selectedEvents();
var slots = view._selectedSlots;
that._old = {
selection: current,
eventsLength: events.length,
selectionStart: selection.start,
selectionEnd: selection.end
};
that.trigger(CHANGE, {
start: selection.start,
end: selection.end,
events,
slots,
resources: view._resourceBySlot(selection)
});
}
}
},
_selectedEvents: function() {
var uids = this._selection.events;
var length = uids.length;
var idx = 0;
var event;
var events = [];
for (; idx < length; idx++) {
event = this.occurrenceByUid(uids[idx]);
if (event) events.push(event);
}
return events;
},
_tapPosition: function(event, coordinate) {
return /touch/.test(event.type) ? (event.originalEvent || event).changedTouches[0]["page" + coordinate] : event["page" + coordinate];
},
_touchMove: function(e) {
var that = this;
var content = that.wrapper.find(".k-scheduler-content");
var verticalScroll = content[0].scrollHeight > content[0].clientHeight;
var horizontalScroll = content[0].scrollWidth > content[0].clientWidth;
var endY = that._tapPosition(e, "Y");
var endX = that._tapPosition(e, "X");
var scrollTop = content[0].scrollTop - Math.round(endY - that._touchPosY);
var scrollLeft = content[0].scrollLeft - Math.round(endX - that._touchPosX);
var applyVerticalScroll = verticalScroll && Math.abs(endY - that._touchPosY) > 10;
var applyhorizontalScroll = horizontalScroll && Math.abs(endY - that._touchPosY) > 10;
if (that._dragging || kendo.support.kineticScrollNeeded || !that._isTouch(e)) return;
if (applyVerticalScroll || applyhorizontalScroll) {
that._amplitude = Math.round(endY - that._touchPosY);
that._touchPosY = endY;
that._touchPosX = endX;
content.animate({
scrollTop,
scrollLeft
}, 0);
that.view()._scrolling = true;
}
},
_mouseMove: function(e) {
var that = this;
clearTimeout(that._moveTimer);
if (that._isTouch(e)) return;
that._moveTimer = setTimeout(function() {
var view = that.view();
var selection = that._selection;
if (selection) {
var slot = view.selectionByElement($(e.currentTarget));
if (slot && selection.groupIndex === slot.groupIndex) {
var startDate = slot.startDate();
var endDate = slot.endDate();
if (startDate >= selection.end) selection.backward = false;
else if (endDate <= selection.start) selection.backward = true;
if (selection.backward) selection.start = startDate;
else selection.end = endDate;
that._select();
}
}
}, 5);
},
_viewByIndex: function(index) {
var view;
for (view in this.views) {
if (!index) return view;
index--;
}
},
_keydownToolbar: function(e) {
var key = e.keyCode;
if (e.altKey && key === keys.DOWN && this.toolbar.find(".k-nav-current").hasClass(FOCUSEDSTATE)) {
this._showCalendar();
e.preventDefault();
return;
} else if (key === keys.DOWN) {
if (this._selectedViewName === "year") this.view().calendar.focus();
else if (document.activeElement !== this.element[0]) this.element.focus();
e.preventDefault();
return;
}
},
_keydownView: function(e) {
var key = e.keyCode, isModifier = key === 16 || key === 18 || key === 17 || key === 91 || key === 92, selection = this._selection, view = this.view(), editable = view.options.editable, arrowKeys = [
keys.LEFT,
keys.RIGHT,
keys.UP,
keys.DOWN
], isRtl = kendo.support.isRtl(this.element), previous, content, cell;
if (isModifier) return;
if (!selection) return;
if (key === keys.ENTER || key === keys.SPACEBAR) {
if (view.activateMoreEvents && view.activateMoreEvents()) e.preventDefault();
else if (key === keys.ENTER && selection.events.length && editable) {
if (editable.update !== false) this.editEvent(selection.events[0]);
}
} else if ((key === keys.DELETE || key === keys.BACKSPACE) && editable !== false && editable.destroy !== false) this.removeEvent(selection.events[0]);
else if (arrowKeys.indexOf(key) > -1) {
previous = key === keys.UP || key === keys.LEFT && !isRtl || key === keys.RIGHT && isRtl;
view._navigationKey = key;
var movedToEvent = view.moveToEvent(selection, previous);
view._navigationKey = null;
if (movedToEvent) {
this._select();
if (document.activeElement !== this.element[0]) this.element.trigger("focus");
e.preventDefault();
}
} else if (key === keys.HOME || key === keys.END) {
e.preventDefault();
content = this.view().content.eq(0);
if (key === keys.HOME) cell = content.find(".k-scheduler-table td").first();
else cell = content.find(".k-scheduler-table td").last();
this.view()._scrollTo(cell[0], content[0]);
}
},
_keydownShortcut: function(key) {
var currentDate = /* @__PURE__ */ new Date(), timezone = this.options.timezone, editable = this.view().options.editable;
if (key === 66 && !!this.view().toggleFullDay) this.view().toggleFullDay();
else if (key === 67 && editable && editable.create !== false) this.addEvent(extend({}, {
start: this.date(),
end: this.date()
}));
else if (key === 84) {
if (timezone) {
var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
} else date = currentDate;
if (!this.trigger("navigate", {
view: this._selectedViewName,
action: "today",
date
})) this.date(date);
}
},
_keydownYearView: function(e) {
var view = this.view(), selection = this._selection, key = e.keyCode;
if (key === keys.TAB) return;
if (key === keys.F10) {
this._focusToolbar();
e.preventDefault();
} else {
this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
view.calendar.focus();
}
if (selection) this._adjustSelectedDate();
e.preventDefault();
},
_keydownAgendaView: function(e) {
var key = e.keyCode, view = this.view(), selection = this._selection, content, cell;
if (view.move(selection, key)) {
e.preventDefault();
this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
this._select();
} else if (key === keys.HOME || key === keys.END) {
e.preventDefault();
content = this.view().content.eq(0);
if (key === keys.HOME) cell = content.find(".k-scheduler-table td").first();
else cell = content.find(".k-scheduler-table td").last();
this.view()._scrollTo(cell[0], content[0]);
}
},
_keydownChangeView: function(key) {
var viewIndex = key - 49, viewByIndex;
if (viewIndex === -1) viewIndex = 9;
viewByIndex = this._viewByIndex(viewIndex);
if (viewByIndex && !this.trigger("navigate", {
view: viewByIndex,
action: "changeView",
date: this.date()
})) this.view(viewByIndex);
},
_keydownChangeDate: function(key) {
var isRtl = kendo.support.isRtl(this.element), direction = isRtl && key === keys.LEFT || !isRtl && key === keys.RIGHT ? "next" : "previous";
if (direction === "next") date = this.view().nextDate();
else date = this.view().previousDate();
if (!this.trigger("navigate", {
view: this._selectedViewName,
action: direction,
date
})) {
this.date(date);
this._initialFocus();
this._select();
}
},
_keydown: function(e) {
var key = e.keyCode, shortcutKeys = [
66,
67,
84
], toolbarIsFocused = $(e.target).closest(".k-toolbar").length > 0, altKey = e.altKey;
this._ctrlKey = e.ctrlKey;
this._shiftKey = e.shiftKey;
if (key === keys.ESC && this.popup && this.popup.visible()) {
this.popup.close();
e.preventDefault();
return;
}
if ((key === keys.LEFT || key === keys.RIGHT) && this._shiftKey) {
this._keydownChangeDate(key);
return;
}
if (altKey && key >= 48 && key <= 57) {
this._keydownChangeView(key);
return;
}
if (shortcutKeys.indexOf(key) > -1) {
if (!$(e.target).hasClass("k-scheduler-search-input")) this._keydownShortcut(key);
return;
}
if (toolbarIsFocused) this._keydownToolbar(e);
else {
if (this._selectedViewName === "year") {
this._keydownYearView(e);
return;
}
if (key === keys.F10) {
this._focusToolbar();
e.preventDefault();
return;
}
if (this._selectedViewName === "agenda") {
this._keydownAgendaView(e);
return;
}
this._keydownView(e);
}
},
_focusToolbar: function() {
this.toolbar.find("[tabindex=0]").first().trigger("focus").addClass(FOCUSEDSTATE);
},
_createSelection: function(item) {
var selection = this._selection, uid, slot;
item = $(item);
if (item.is(".k-event")) {
uid = item.attr(kendo.attr("uid"));
if (selection && selection.events.indexOf(uid) !== -1 && !this._ctrlKey) return;
}
if (!selection || !this._ctrlKey && !this._shiftKey) selection = this._selection = {
events: [],
groupIndex: 0
};
slot = this.view().selectionByElement(item);
if (slot) selection.groupIndex = slot.groupIndex || 0;
if (uid) slot = getOccurrenceByUid(this._data, uid);
if (slot && slot.uid) uid = [slot.uid];
this._updateSelection(slot, uid);
this._adjustSelectedDate();
},
_updateSelection: function(dataItem, events, groupIndex) {
var selection = this._selection;
if (dataItem && selection) {
var view = this.view();
if (dataItem.uid) dataItem = view._updateEventForSelection(dataItem);
if (this._shiftKey && selection.start && selection.end) {
var backward = dataItem.end < selection.end;
selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
if (backward && view._timeSlotInterval) kendo.date.setTime(selection.end, -view._timeSlotInterval());
} else {
selection.start = dataItem.startDate ? dataItem.startDate() : dataItem.start;
selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
}
if ("isDaySlot" in dataItem) selection.isAllDay = dataItem.isDaySlot;
else selection.isAllDay = dataItem.isAllDay;
if (groupIndex !== null && groupIndex !== undefined) selection.groupIndex = groupIndex;
selection.index = dataItem.index;
if (this._ctrlKey) {
var indexOfEvent = events && events.length ? selection.events.indexOf(events[0]) : -1;
if (indexOfEvent > -1) selection.events.splice(indexOfEvent, 1);
else selection.events = selection.events.concat(events || []);
} else selection.events = events || [];
}
},
options: {
name: "Scheduler",
date: TODAY,
editable: true,
autoBind: true,
snap: true,
mobile: false,
timezone: "",
allDaySlot: true,
min: new Date(1900, 0, 1),
max: new Date(2099, 11, 31),
toolbar: null,
workWeekStart: 1,
workWeekEnd: 5,
workDays: null,
showWorkHours: false,
startTime: TODAY,
endTime: TODAY,
currentTimeMarker: {
updateInterval: 1e4,
useLocalTimezone: true
},
ongoingEvents: {
cssClass: ONGOING_CLASS,
enabled: false,
updateInterval: 6e4,
useLocalTimezone: true
},
footer: {},
messages: {
today: "Today",
pdf: "Export to PDF",
save: "Save",
cancel: "Cancel",
destroy: "Delete",
resetSeries: "Reset Series",
deleteWindowTitle: "Delete event",
next: "Next",
previous: "Previous",
refresh: "Refresh",
selectView: "Select view",
ariaSlotLabel: "Selected from {0:t} to {1:t}",
ariaEventLabel: {
on: "on",
at: "at",
to: "to",
allDay: "(all day)",
prefix: ""
},
search: "Search...",
moreEventsPopover: {
eventsLabel: "Events",
noEvents: "No events on this date."
},
views: {
day: "Day",
week: "Week",
workWeek: "Work Week",
agenda: "Agenda",
month: "Month",
timeline: "Timeline",
timelineWeek: "Timeline Week",
timelineWorkWeek: "Timeline Work Week",
timelineMonth: "Timeline Month",
year: "Year"
},
recurrenceMessages: {
deleteWindowTitle: "Delete Recurring Item",
resetSeriesWindowTitle: "Reset Series",
deleteWindowOccurrence: "Delete current occurrence",
deleteWindowSeries: "Delete the series",
editWindowTitle: "Edit Recurring Item",
editWindowOccurrence: "Edit current occurrence",
editWindowSeries: "Edit the series"
},
editable: { confirmation: DELETECONFIRM },
editor: {
title: "Title",
start: "Start",
end: "End",
allDayEvent: "All day",
description: "Description",
repeat: "Repeat",
timezone: "Timezone",
startTimezone: "Start timezone",
endTimezone: "End timezone",
separateTimezones: "Use separate start and end time zones",
timezoneEditorTitle: "Timezones",
timezoneEditorButton: "Time zone",
timezoneTitle: "Time zones",
noTimezone: "No timezone",
editorTitle: "Event",
newEvent: "New Event",
editEvent: "Edit Event",
resetTimezoneWindowTitle: "Reset Timezone",
cancelTimezoneReset: "No",
resetTimezone: "Yes"
}
},
height: null,
width: null,
resources: [],
group: {
resources: [],
orientation: "horizontal"
},
views: [],
selectable: false,
recurrenceRuleLabelTemplate: null
},
events: [
REMOVE,
EDIT,
CANCEL,
SAVE,
"add",
"dataBinding",
"dataBound",
"moveStart",
"move",
"moveEnd",
"resizeStart",
"resize",
"resizeEnd",
"navigate",
CHANGE,
"kendoKeydown"
],
destroy: function() {
var that = this, element;
Widget.fn.destroy.call(that);
if (that.dataSource) {
that.dataSource.unbind(CHANGE, that._refreshHandler);
that.dataSource.unbind(PROGRESS, that._progressHandler);
that.dataSource.unbind(ERROR, that._errorHandler);
}
if (that._resourceRefreshHandler) for (var idx = 0; idx < that.resources.length; idx++) {
var resourceDS = that.resources[idx].dataSource;
resourceDS.unbind(CHANGE, that._resourceRefreshHandler);
resourceDS.unbind(PROGRESS, that._resourceProgressHandler);
resourceDS.unbind(ERROR, that._resourceErrorHandler);
}
if (that.calendar) {
that.calendar.destroy();
that.popup.destroy();
}
if (that.view()) that.view().destroy();
if (that._editor) that._editor.destroy();
if (this._moveDraggable) this._moveDraggable.destroy();
if (this._resizeDraggable) this._resizeDraggable.destroy();
if (that.mediaQueryList) that.mediaQueryList.destroy();
if (that._viewsSegmentedControl) {
that._viewsSegmentedControl.destroy();
that._viewsSegmentedControl = null;
}
if (that._viewsDropDownButton) {
that._viewsDropDownButton.destroy();
that._viewsDropDownButton = null;
}
if (that._toolbarResizeObserver) {
that._toolbarResizeObserver.disconnect();
that._toolbarResizeObserver = null;
}
element = that.element.add(that.wrapper).add(that.toolbar).add(that.popup);
element.off(NS);
clearTimeout(that._moveTimer);
that._model = null;
that.toolbar = null;
that.element = null;
$(window).off("resize" + NS, that._resizeHandler);
kendo.destroy(that.wrapper);
},
setDataSource: function(dataSource) {
this.options.dataSource = dataSource;
this._dataSource();
if (this.options.autoBind && dataSource.fetch) dataSource.fetch();
else if (isArray(dataSource)) this.view(this._selectedView);
},
items: function() {
var content = this.wrapper.find(".k-scheduler-content");
var view = this.view();
if (view && view.options.name === "agenda") return content.find(".k-task");
else return content.find(".k-event").add(this.wrapper.find(".k-scheduler-header-wrap").find(".k-scheduler-header-all-day").siblings());
},
_movable: function() {
var startSlot;
var endSlot;
var startResources;
var startTime;
var endTime;
var event;
var clonedEvent;
var that = this;
var originSlot;
var originStartTime;
var distance = 0;
var clonedEvents = [];
var cachedEvents = [];
var isMobile = that._isMobile();
var movable = that.options.editable && that.options.editable.move !== false;
var resizable = that.options.editable && that.options.editable.resize !== false;
if (movable || resizable && isMobile) {
that._dragging = false;
if (isMobile && kendo.support.mobileOS.android) distance = 5;
that._moveDraggable = new kendo.ui.Draggable(that.element, {
distance,
filter: ".k-event",
ignore: ".k-resize-handle, .k-readonly",
holdToDrag: isMobile,
autoScroll: true
});
if (movable) that._moveDraggable.bind("dragstart", function(e) {
var view = that.view();
var eventElement = e.currentTarget;
var isTouch = that._isTouch(e);
that._dragging = true;
if (!view.options.editable || view.options.editable.move === false) {
that._dragging = false;
e.preventDefault();
return;
}
if (isTouch && !eventElement.hasClass("k-event-active")) {
that._dragging = false;
that.element.find(".k-event-active").removeClass("k-event-active");
e.preventDefault();
return;
}
event = that.occurrenceByUid(eventElement.attr(kendo.attr("uid")));
if (event && event.isReadonly) {
that._dragging = false;
e.preventDefault();
return;
}
clonedEvent = event.clone();
event.clone();
clonedEvent.update(view._eventOptionsForMove(clonedEvent));
clonedEvent.inverseColor = that._isInverseColor(eventElement);
clonedEvents = [];
if (that._selection) {
var events = that._selection.events;
for (var i = 0; i < events.length; i++) {
var selectedEvent = that.occurrenceByUid(events[i]);
if (selectedEvent.isReadonly) continue;
var evtClone = selectedEvent.clone();
var evtCloneElement = this.element.find("div.k-event[data-uid=\"" + evtClone.uid + "\"]").eq(0);
evtClone.update(view._eventOptionsForMove(evtClone));
if (evtCloneElement.length) evtClone.inverseColor = that._isInverseColor(evtCloneElement);
clonedEvents.push(evtClone);
}
} else clonedEvents.push(clonedEvent);
startSlot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
startResources = view._resourceBySlot(startSlot);
const eventUtcStart = kendo.date.toUtcTime(event.start);
let snapOffset = 0;
if (that.options.snap && !startSlot.isDaySlot) {
const slotDuration = startSlot.end - startSlot.start;
if (slotDuration > 0) snapOffset = ((eventUtcStart - startSlot.start) % slotDuration + slotDuration) % slotDuration;
}
originStartTime = startTime = startSlot.startOffset(e.x.startLocation, e.y.startLocation, that.options.snap) + snapOffset;
endSlot = startSlot;
originSlot = startSlot;
if (!startSlot || that.trigger("moveStart", { event })) e.preventDefault();
}).bind("drag", function(e) {
var view = that.view();
var slot = view._slotByPosition(e.x.location, e.y.location);
var distance;
var range;
var i;
if (!slot) return;
endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
if (slot.isDaySlot !== startSlot.isDaySlot) if (slot.isDaySlot !== originSlot.isDaySlot) {
var slotIndex = $(startSlot.element).index();
var targetSlotElement = $(slot.element).parent().children().eq(slotIndex);
startSlot = view._slotByPosition(targetSlotElement.offset().left, targetSlotElement.offset().top);
startTime = startSlot.startOffset(e.x.location, e.y.location, true);
cachedEvents = clonedEvents.map(function(event) {
return event.clone();
});
for (i = 0; i < clonedEvents.length; i++) if (clonedEvents[i].isAllDay != slot.isDaySlot) {
clonedEvents[i].isAllDay = slot.isDaySlot;
clonedEvents[i].end = kendo.date.getDate(clonedEvents[i].start);
clonedEvents[i].start = kendo.date.getDate(clonedEvents[i].start);
if (!slot.isDaySlot) {
kendo.date.setTime(clonedEvents[i].start, kendo.date.getMilliseconds(view.startTime()));
kendo.date.setTime(clonedEvents[i].end, kendo.date.getMilliseconds(view.startTime()) + view._timeSlotInterval());
}
}
} else {
startSlot = $.extend(true, {}, originSlot);
startTime = originStartTime;
clonedEvents = cachedEvents;
}
distance = endTime - startTime;
for (i = 0; i < clonedEvents.length; i++) view._updateMoveHint(clonedEvents[i], slot.groupIndex, distance);
range = moveEventRange(clonedEvent, distance);
if (!that.trigger("move", {
event,
slot: {
element: slot.element,
start: slot.startDate(),
end: slot.endDate(),
isDaySlot: slot.isDaySlot
},
resources: view._resourceBySlot(slot),
start: range.start,
end: range.end
})) endSlot = slot;
else for (i = 0; i < clonedEvents.length; i++) view._updateMoveHint(clonedEvents[i], slot.groupIndex, distance);
}).bind("dragend", function(e) {
that.view()._removeMoveHint();
var distance = endTime - startTime;
var range = moveEventRange(clonedEvent, distance);
var start = range.start;
var end = range.end;
that._dragging = false;
var endResources = that.view()._resourceBySlot(endSlot);
if (!that.trigger("moveEnd", {
event,
slot: {
element: endSlot.element,
start: endSlot.startDate(),
end: endSlot.endDate()
},
start,
end,
resources: endResources
}) && (event.start.getTime() !== start.getTime() || event.end.getTime() !== end.getTime() || originSlot.isDaySlot !== endSlot.isDaySlot || kendo.stringify(endResources) !== kendo.stringify(startResources))) {
that._isMultiDrag = clonedEvents.length > 1;
for (var i = 0; i < clonedEvents.length; i++) {
var evt = clonedEvents[i];
range = moveEventRange(evt, distance);
var updatedEventOptions = that.view()._eventOptionsForMove(evt);
var eventOptions = $.extend({
isAllDay: evt.isAllDay,
start: range.start,
end: range.end
}, updatedEventOptions, endResources);
that._updateEvent(null, evt, eventOptions);
}
if (that._isMultiDrag) {
that.dataSource.sync();
that._isMultiDrag = false;
}
}
e.currentTarget.removeClass("k-event-active");
this.cancelHold();
clonedEvents = [];
cachedEvents = [];
}).bind("dragcancel", function() {
that.view()._removeMoveHint();
this.cancelHold();
clonedEvents = [];
cachedEvents = [];
});
that._moveDraggable.bind("hold", function(e) {
if (that._isTouch(e)) {
that.element.find(".k-event-active").removeClass("k-event-active");
if (that.options.selectable) that._createSelection(e.currentTarget);
e.currentTarget.addClass("k-event-active");
}
});
}
},
_resizable: function() {
var startTime;
var endTime;
var event;
var clonedEvent;
var slot;
var that = this;
var distance = 0;
const isRtl = kendo.support.isRtl(that.element);
function direction(handle) {
var directions = {
"k-resize-e": isRtl ? "west" : "east",
"k-resize-w": isRtl ? "east" : "west",
"k-resize-n": "north",
"k-resize-s": "south"
};
for (var key in directions) if (handle.hasClass(key)) return directions[key];
}
if (that._isMobile() && kendo.support.mobileOS.android) distance = 5;
that._resizeDraggable = new kendo.ui.Draggable(that.element, {
distance,
filter: ".k-resize-handle",
autoScroll: true,
dragstart: function(e) {
var uid = $(e.currentTarget).closest(".k-event").attr(kendo.attr("uid"));
var view = that.view();
that._dragging = true;
event = that.occurrenceByUid(uid);
if (event && event.isReadonly) {
that._dragging = false;
e.preventDefault();
return;
}
clonedEvent = event.clone();
view._updateEventForResize(clonedEvent);
slot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
if (that.trigger("resizeStart", { event })) e.preventDefault();
startTime = kendo.date.toUtcTime(clonedEvent.start);
endTime = kendo.date.toUtcTime(clonedEvent.end);
},
drag: function(e) {
if (!slot) return;
var dir = direction($(e.currentTarget));
var view = that.view();
var currentSlot = view._slotByPosition(e.x.location, e.y.location);
if (!currentSlot || slot.groupIndex != currentSlot.groupIndex) return;
slot = currentSlot;
var originalStart = startTime;
var originalEnd = endTime;
if (dir == "south") {
if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) if (clonedEvent.isAllDay) endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
else endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
} else if (dir == "north") {
if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
} else if (dir == "east") {
if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(slot.endDate())) >= kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.start))) if (clonedEvent.isAllDay) endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
else endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
else if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
} else if (dir == "west") {
if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.end)) >= kendo.date.toUtcTime(kendo.date.getDate(slot.startDate()))) startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
else if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
}
if (!that.trigger("resize", {
event,
slot: {
element: slot.element,
start: slot.startDate(),
end: slot.endDate()
},
start: kendo.timezone.toLocalDate(startTime),
end: kendo.timezone.toLocalDate(endTime),
resources: view._resourceBySlot(slot)
})) view._updateResizeHint(clonedEvent, slot.groupIndex, startTime, endTime);
else {
startTime = originalStart;
endTime = originalEnd;
}
},
dragend: function(e) {
var dragHandle = $(e.currentTarget);
var start = new Date(clonedEvent.start.getTime());
var end = new Date(clonedEvent.end.getTime());
var dir = direction(dragHandle);
that._dragging = false;
that.view()._removeResizeHint();
if (dir == "south") end = kendo.timezone.toLocalDate(endTime);
else if (dir == "north") start = kendo.timezone.toLocalDate(startTime);
else if (dir == "east") if (slot.isDaySlot) end = kendo.date.getDate(kendo.timezone.toLocalDate(endTime));
else end = kendo.timezone.toLocalDate(endTime);
else if (dir == "west") if (slot.isDaySlot) {
start = new Date(kendo.timezone.toLocalDate(startTime));
start.setHours(0);
start.setMinutes(0);
} else start = kendo.timezone.toLocalDate(startTime);
if (!that.trigger("resizeEnd", {
event,
slot: {
element: slot.element,
start: slot.startDate(),
end: slot.endDate()
},
start,
end,
resources: that.view()._resourceBySlot(slot)
}) && end.getTime() >= start.getTime()) {
if (clonedEvent.start.getTime() != start.getTime() || clonedEvent.end.getTime() != end.getTime()) {
that.view()._updateEventForResize(event);
that._updateEvent(dir, event, {
start,
end
});
}
}
slot = null;
event = null;
},
dragcancel: function() {
that._dragging = false;
that.view()._removeResizeHint();
slot = null;
event = null;
}
});
},
_updateEvent: function(dir, event, eventInfo) {
var that = this;
var updateEvent = function(event, callback) {
var start;
try {
that._preventRefresh = true;
event.update(eventInfo);
that._convertDates(event);
start = event.start;
if (dir && event.duration() % MS_PER_DAY === 0 && start.getHours() === 0 && start.getMinutes() === 0 && start.getSeconds() === 0 && start.getMilliseconds() === 0) event.set("isAllDay", true);
} finally {
that._preventRefresh = false;
}
if (!that.trigger(SAVE, { event })) {
if (callback) callback();
if (!that._isMultiDrag) that.dataSource.sync();
}
};
var recurrenceHead = function(event) {
if (event.recurrenceRule) return that.dataSource.getByUid(event.uid);
else return that.dataSource.get(event.recurrenceId);
};
var updateSeries = function() {
var head = recurrenceHead(event);
if (dir == "south" || dir == "north") {
if (eventInfo.start) {
var start = kendo.date.getDate(head.start);
kendo.date.setTime(start, getMilliseconds(eventInfo.start));
eventInfo.start = start;
}
if (eventInfo.end) {
var end = kendo.date.getDate(head.end);
kendo.date.setTime(end, getMilliseconds(eventInfo.end));
eventInfo.end = end;
}
}
that.dataSource._removeExceptions(head);
updateEvent(head);
};
var updateOccurrence = function() {
var head = recurrenceHead(event);
var eventUid;
var callback = function() {
that._convertDates(head);
if (that._selection) that._selection.events.push(eventUid);
};
var exception = head.toOccurrence({
start: event.start,
end: event.end
});
eventUid = exception.uid;
updateEvent(that.dataSource.add(exception), callback);
};
if (event.recurrenceRule || event.isOccurrence()) {
var recurrenceMessages = that.options.messages.recurrenceMessages;
that._showRecurringDialog(event, updateOccurrence, updateSeries, {
title: recurrenceMessages.editWindowTitle,
text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
occurrenceText: recurrenceMessages.editWindowOccurrence,
seriesText: recurrenceMessages.editWindowSeries
});
} else updateEvent(that.dataSource.getByUid(event.uid));
},
_modelForContainer: function(container) {
container = $(container).closest("[" + kendo.attr("uid") + "]");
return this.dataSource.getByUid(container.attr(kendo.attr("uid")));
},
showDialog: function(options) {
this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
this._editor.showDialog(options);
},
focus: function() {
this.wrapper.trigger("focus");
},
_confirmation: function(callback, model, isResetSeries) {
var editable = this.options.editable;
if (editable === true || editable.confirmation !== false) {
var messages = this.options.messages;
var title = messages.deleteWindowTitle;
var text = typeof editable.confirmation === STRING ? editable.confirmation : messages.editable.confirmation;
if (this._isEditorOpened() && model.isRecurring()) {
var recurrenceMessages = this.options.messages.recurrenceMessages;
title = recurrenceMessages.deleteWindowTitle;
if (model.isException() || model.isNew()) text = recurrenceMessages.deleteRecurringConfirmation ? recurrenceMessages.deleteRecurringConfirmation : DELETERECURRINGCONFIRM;
else text = recurrenceMessages.deleteSeriesConfirmation ? recurrenceMessages.deleteSeriesConfirmation : DELETESERIESCONFIRM;
if (isResetSeries) {
title = recurrenceMessages.resetSeriesWindowTitle;
text = recurrenceMessages.resetSeriesConfirmation ? recurrenceMessages.resetSeriesConfirmation : RESETSERIESCONFIRM;
}
}
var buttons = [{
name: "destroy",
text: isResetSeries ? messages.resetSeries : messages.destroy,
click: function() {
callback();
}
}];
if (!(this._isMobile() && kendo.Pane)) buttons.push({
name: "canceledit",
text: messages.cancel,
click: function() {
callback(true);
}
});
this._unbindResize();
this.showDialog({
model,
text,
title,
buttons
});
this._bindResize();
} else callback();
},
addEvent: function(eventInfo) {
var editable = this._editor.editable;
var dataSource = this.dataSource;
var event;
eventInfo = eventInfo || {};
if (!this.trigger("add", { event: eventInfo }) && (editable && editable.end() || !editable)) {
this.cancelEvent();
if (eventInfo && eventInfo.toJSON) eventInfo = eventInfo.toJSON();
event = dataSource.add(eventInfo);
if (event) {
this.cancelEvent();
this._editEvent(event);
}
}
},
saveEvent: function() {
var that = this;
var editor = that._editor;
var dataSource = that.dataSource;
if (!editor) return;
var editable = editor.editable;
var container = editor.container;
var model = that._modelForContainer(container);
var events, i, event;
if (container && editable && editor.end() && !that.trigger(SAVE, {
container,
event: model
})) {
if (!model.isOccurrence() && !!model.recurrenceException && !model.recurrenceRule) {
events = dataSource.data();
for (i = events.length - 1; i >= 0; i -= 1) {
event = events[i];
if (event && event.recurrenceId === model.id) dataSource.remove(event);
}
model.set("recurrenceException", "");
}
if (!model.dirty && !model.isOccurrence()) that._convertDates(model, "remove");
dataSource.sync();
}
},
cancelEvent: function() {
var editor = this._editor;
var container = editor.container;
var model;
if (container) {
model = this._modelForContainer(container);
if (model && model.isOccurrence()) {
this._convertDates(model, "remove");
this._convertDates(this.dataSource.get(model.recurrenceId), "remove");
}
this.dataSource.cancelChanges(model);
editor.close();
}
},
editEvent: function(uid) {
var model = typeof uid == "string" ? this.occurrenceByUid(uid) : uid;
if (!model || model.isReadonly) return;
this.cancelEvent();
if (model.isRecurring()) this._editRecurringDialog(model);
else this._editEvent(model);
},
_editEvent: function(model) {
this._preventRefresh = true;
this._unbindResize();
this._createPopupEditor(model);
this.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
this._bindResize();
},
_editRecurringDialog: function(model) {
var that = this;
var editOccurrence = function() {
if (model.isException()) that._editEvent(model);
else that.addEvent(model);
};
var editSeries = function() {
if (model.recurrenceId) model = that.dataSource.get(model.recurrenceId);
that._editEvent(model);
};
var recurrenceMessages = that.options.messages.recurrenceMessages;
that._showRecurringDialog(model, editOccurrence, editSeries, {
title: recurrenceMessages.editWindowTitle,
text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
occurrenceText: recurrenceMessages.editWindowOccurrence,
seriesText: recurrenceMessages.editWindowSeries
});
},
_showRecurringDialog: function(model, editOccurrence, editSeries, messages) {
var editable = this.options.editable;
var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : "dialog";
if (editRecurringMode === "occurrence" || this._isMultiDrag) editOccurrence();
else if (editRecurringMode === "series") editSeries();
else {
this._unbindResize();
this.showDialog({
model,
title: messages.title,
text: messages.text,
buttons: [{
text: messages.occurrenceText,
click: editOccurrence
}, {
text: messages.seriesText,
click: editSeries
}]
});
this._bindResize();
}
},
_createButton: function(command) {
var template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, options = {
className: "k-scheduler-" + (commandName || "").replace(/\s/g, ""),
text: commandName,
attr: ""
};
if (!commandName && !(isPlainObject(command) && command.template)) throw new Error("Custom commands should have name specified");
if (isPlainObject(command)) {
if (command.className) command.className += " " + options.className;
if (commandName === "edit" && isPlainObject(command.text)) {
command = extend(true, {}, command);
command.text = command.text.edit;
}
options = extend(true, options, defaultCommands[commandName], command);
} else options = extend(true, options, defaultCommands[commandName]);
return kendo.template(template)(options);
},
_convertDates: function(model, method) {
var timezone = this.dataSource.reader.timezone;
var startTimezone = model.startTimezone;
var endTimezone = model.endTimezone;
var start = model.start;
var end = model.start;
method = method || "apply";
startTimezone = startTimezone || endTimezone;
endTimezone = endTimezone || startTimezone;
if (startTimezone) {
if (timezone) if (method === "apply") {
start = kendo.timezone.convert(model.start, timezone, startTimezone);
end = kendo.timezone.convert(model.end, timezone, endTimezone);
} else {
start = kendo.timezone.convert(model.start, startTimezone, timezone);
end = kendo.timezone.convert(model.end, endTimezone, timezone);
}
else {
start = kendo.timezone[method](model.start, startTimezone);
end = kendo.timezone[method](model.end, endTimezone);
}
model._set("start", start);
model._set("end", end);
}
},
_createEditor: function() {
var that = this;
var editor;
if (this._isMobile() && kendo.Pane) editor = that._editor = new MobileEditor(this.wrapper, extend({}, this.options, {
target: this,
timezone: that.dataSource.reader.timezone,
resources: that.resources,
createButton: this._createButton.bind(this)
}));
else editor = that._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
target: this,
createButton: this._createButton.bind(this),
timezone: that.dataSource.reader.timezone,
resources: that.resources
}));
editor.bind("cancel", function(e) {
if (that.trigger("cancel", {
container: e.container,
event: e.model
})) {
e.preventDefault();
return;
}
that._preventRefresh = false;
that.cancelEvent();
if (that._attemptRefresh) that.refresh();
var todayButton = !that.options.selectable && that.toolbar.find("[ref-nav-today]").first();
if (todayButton && todayButton.length) {
that.toolbar.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
todayButton.trigger("focus").addClass(FOCUSEDSTATE);
} else that.focus();
});
editor.bind("edit", function(e) {
if (that.trigger(EDIT, {
container: e.container,
event: e.model
})) e.preventDefault();
});
editor.bind("save", function() {
that._preventRefresh = false;
that.saveEvent();
});
editor.bind("remove", function(e) {
that._preventRefresh = false;
that.removeEvent(e.model);
});
editor.bind("resetSeries", function(e) {
that._confirmation(function(cancel) {
that._preventRefresh = false;
if (!cancel) {
that.dataSource._removeExceptions(e.model);
that.saveEvent();
}
}, e.model, true);
});
},
_createPopupEditor: function(model) {
var editor = this._editor;
if (!model.isNew() || model.isOccurrence()) {
if (model.isOccurrence()) this._convertDates(model.recurrenceId ? this.dataSource.get(model.recurrenceId) : model);
this._convertDates(model);
}
this.editable = editor.editEvent(model);
},
removeEvent: function(uid) {
var that = this, model = typeof uid == "string" ? that.occurrenceByUid(uid) : uid;
if (!model || model.isReadonly) return;
if (model.isRecurring()) that._deleteRecurringDialog(model);
else that._confirmation(function(cancel) {
if (!cancel) that._removeEvent(model);
}, model);
},
occurrenceByUid: function(uid) {
var occurrence = this.dataSource.getByUid(uid);
if (!occurrence) occurrence = getOccurrenceByUid(this._data, uid);
return occurrence;
},
occurrencesInRange: function(start, end) {
return new kendo.data.Query(this._data).filter({
logic: "or",
filters: [{
logic: "and",
filters: [
{
field: "start",
operator: "gte",
value: start
},
{
field: "end",
operator: "gte",
value: start
},
{
field: "start",
operator: "lt",
value: end
}
]
}, {
logic: "and",
filters: [{
field: "start",
operator: "lte",
value: start
}, {
field: "end",
operator: "gt",
value: start
}]
}]
}).toArray();
},
_removeEvent: function(model) {
if (!this.trigger(REMOVE, { event: model })) {
if (this.dataSource.remove(model)) this.dataSource.sync();
}
},
_deleteRecurringDialog: function(model) {
var that = this;
var currentModel = model;
var editable = that.options.editable;
var deleteOccurrence;
var deleteSeries;
var createException;
var deleteOccurrenceConfirmation;
var deleteSeriesConfirmation;
var createExceptionConfirmation;
var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : "dialog";
deleteOccurrence = function() {
var occurrence = currentModel.recurrenceId ? currentModel : currentModel.toOccurrence();
var head = that.dataSource.get(occurrence.recurrenceId);
that._convertDates(head);
that._removeEvent(occurrence);
};
deleteSeries = function() {
if (currentModel.recurrenceId) currentModel = that.dataSource.get(currentModel.recurrenceId);
that._removeEvent(currentModel);
};
createException = function() {
that.dataSource.remove(currentModel);
that.dataSource.sync();
};
if (editRecurringMode != "dialog" || that._isEditorOpened()) {
deleteOccurrenceConfirmation = function() {
that._confirmation(function(cancel) {
if (!cancel) deleteOccurrence();
}, currentModel);
};
deleteSeriesConfirmation = function() {
that._confirmation(function(cancel) {
if (!cancel) deleteSeries();
}, currentModel);
};
createExceptionConfirmation = function() {
that._confirmation(function(cancel) {
if (!cancel) createException();
}, currentModel);
};
}
var seriesCallback = deleteSeriesConfirmation || deleteSeries;
var occurrenceCallback = deleteOccurrenceConfirmation || deleteOccurrence;
var exeptionCallback = createExceptionConfirmation || createException;
if (that._isEditorOpened()) if (model.isException()) occurrenceCallback();
else if (model.isNew()) exeptionCallback();
else seriesCallback();
else {
var recurrenceMessages = that.options.messages.recurrenceMessages;
that._showRecurringDialog(model, occurrenceCallback, seriesCallback, {
title: recurrenceMessages.deleteWindowTitle,
text: recurrenceMessages.deleteRecurring ? recurrenceMessages.deleteRecurring : DELETERECURRING,
occurrenceText: recurrenceMessages.deleteWindowOccurrence,
seriesText: recurrenceMessages.deleteWindowSeries
});
}
},
_isEditorOpened: function() {
return !!this._editor.container;
},
_unbindView: function(view) {
view.destroy();
},
_bindView: function(view) {
var that = this;
if (that.options.editable) {
if (that._viewRemoveHandler) view.unbind(REMOVE, that._viewRemoveHandler);
that._viewRemoveHandler = function(e) {
that.removeEvent(e.uid);
};
view.bind(REMOVE, that._viewRemoveHandler);
if (that._viewAddHandler) view.unbind(ADD, that._viewAddHandler);
that._viewAddHandler = function(e) {
that.addEvent(e.eventInfo);
};
view.bind(ADD, this._viewAddHandler);
if (that._viewEditHandler) view.unbind(EDIT, that._viewEditHandler);
that._viewEditHandler = function(e) {
that.editEvent(e.uid);
};
view.bind(EDIT, this._viewEditHandler);
}
if (that._viewNavigateHandler) view.unbind("navigate", that._viewNavigateHandler);
that._viewNavigateHandler = function(e) {
if (e.action) {
if (!that.trigger("navigate", {
view: e.view,
isWorkDay: e.isWorkDay,
action: e.action,
date: e.date
})) that.date(e.date);
} else if (e.view) {
var switchWorkDay = "isWorkDay" in e;
var action = switchWorkDay ? "changeWorkDay" : "changeView";
if (!that.trigger("navigate", {
view: e.view,
isWorkDay: e.isWorkDay,
action,
date: e.date
})) {
if (switchWorkDay) that._workDayMode = e.isWorkDay;
that._selectView(e.view);
that.date(e.date);
}
}
};
view.bind("navigate", that._viewNavigateHandler);
if (that._viewActivateHandler) view.unbind("activate", that._viewActivateHandler);
that._viewActivateHandler = function() {
var view = this;
if (that._selection) {
view.constrainSelection(that._selection);
if ($(document.activeElement).closest(".k-scheduler-toolbar").length === 0) if (document.activeElement !== that.wrapper[0]) that.element.trigger("focus");
else that._select();
that._adjustSelectedDate();
}
};
view.bind("activate", that._viewActivateHandler);
},
_selectView: function(name) {
var that = this;
if (name && that.views[name]) {
if (that._selectedView) that._unbindView(that._selectedView);
that._selectedView = that._renderView(name);
that._selectedViewName = name;
if (this._initialSize) {
this._initialSize = false;
this._onMediaChange(window.matchMedia(MIN_SCREEN));
}
if (that._viewsCount > 1 && !that._isMobile()) {
that.toolbar.find(".k-views-dropdown").val(name);
if (that._viewsSegmentedControl) that._viewsSegmentedControl.value(name);
} else if (that._viewsCount > 1) that.toolbar.find(".k-scheduler-mobile-views").find("[value=" + name.replace(/\./g, "\\.") + "]").prop("selected", "selected");
}
},
view: function(name) {
var that = this;
if (name) {
if (name === "year") that.wrapper.removeAttr("tabindex");
else that.wrapper.attr("tabindex", 0);
that._selectView(name);
that.rebind();
return;
}
return that._selectedView;
},
viewName: function() {
return this.view().name;
},
_renderView: function(name) {
var view = this._initializeView(name);
this._bindView(view);
if (kendo.support.mouseAndTouchPresent || kendo.support.pointers) {
view.content.css("-ms-touch-action", "pinch-zoom");
view.content.css("touch-action", "pinch-zoom");
}
this._model.set("formattedDate", view.dateForTitle());
this._model.set("formattedShortDate", view.shortDateForTitle());
this._model.set("formattedMobileDate", view.mobileDateForTitle ? view.mobileDateForTitle() : view.shortDateForTitle());
this._model.set("formattedYear", view.mobileYearForTitle ? view.mobileYearForTitle() : kendo.format("{0:yyyy}", view.startDate()));
this._updateToolbarDate();
if (this._viewsDropDownButton) {
var viewTitle = this.views[name] ? this.views[name].title : name;
this._viewsDropDownButton.element.find(".k-button-text").first().text(viewTitle);
}
return view;
},
resize: function(force) {
var size = this.getSize();
var currentSize = this._size;
var view = this.view();
if (!view || !view.groups) return;
if (force || !currentSize || size.width !== currentSize.width || size.height !== currentSize.height) {
this.refresh({ action: "resize" });
this._size = size;
}
},
_adjustSelectedDate: function() {
var date = this._model.selectedDate, selection = this._selection, start = selection.start;
if (start && !kendo.date.isInDateRange(date, getDate(start), getDate(selection.end))) date.setFullYear(start.getFullYear(), start.getMonth(), start.getDate());
},
_initializeView: function(name) {
var view = this.views[name];
if (view) {
var isSettings = isPlainObject(view), overrideOptions = {}, type = view.type;
if (typeof type === STRING) type = kendo.getter(view.type)(window);
if (isSettings && view.workDays && view.workDays.length) overrideOptions.workDays = view.workDays;
if (type) view = new type(this.wrapper, trimOptions(extend(true, {}, this.options, isSettings ? view : {}, {
resources: this.resources,
date: this.date(),
startTime: kendo.parseDate(view.startTime) || kendo.parseDate(this.options.startTime),
endTime: kendo.parseDate(view.endTime) || kendo.parseDate(this.options.endTime),
showWorkHours: this._workDayMode
}), overrideOptions));
else throw new Error("There is no such view");
}
return view;
},
_views: function() {
var views = this.options.views;
var view;
var defaultView;
var selected;
var isSettings;
var name;
var type;
var idx;
var length;
this.views = {};
this._viewsCount = 0;
for (idx = 0, length = views.length; idx < length; idx++) {
var hasType = false;
view = views[idx];
isSettings = isPlainObject(view);
if (isSettings) {
type = name = view.type ? view.type : view;
if (typeof type !== STRING) {
name = view.name || view.title;
hasType = true;
}
} else {
type = name = view;
view = {};
}
defaultView = defaultViews[name];
if (defaultView && !hasType) {
view.type = defaultView.type;
defaultView.title = this.options.messages.views[name];
if (defaultView.type === "day") defaultView.messages = { allDay: this.options.messages.allDay };
else if (defaultView.type === "agenda") defaultView.messages = {
event: this.options.messages.event,
date: this.options.messages.date,
time: this.options.messages.time
};
}
view = extend({ title: name }, defaultView, isSettings ? view : {});
if (name) {
this.views[name] = view;
this._viewsCount++;
if (!selected || view.selected) selected = name;
}
}
if (selected) this._selectedViewName = selected;
},
rebind: function() {
var that = this, resources = that.resources, resourceFetchArray = [];
if (that._preventRebind) {
that._preventRebind = false;
return;
}
if (that.options.autoBind === false && resources && resources.length > 0) {
resources.forEach(function(resource) {
if (resource.dataSource.data().length === 0) {
that._preventRebind = true;
resourceFetchArray.push(resource.dataSource.fetch());
}
});
$.when.apply(null, resourceFetchArray).then(function() {
that.dataSource.fetch();
that._preventRebind = false;
});
} else that.dataSource.fetch();
},
_dataSource: function() {
var that = this, options = that.options, dataSource = options.dataSource;
dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
if (options.timezone && !(dataSource instanceof SchedulerDataSource)) dataSource = extend(true, dataSource, { schema: { timezone: options.timezone } });
else if (dataSource instanceof SchedulerDataSource) options.timezone = dataSource.options.schema ? dataSource.options.schema.timezone : "";
if (that.dataSource && that._refreshHandler) that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
else {
that._refreshHandler = that.refresh.bind(that);
that._progressHandler = that._requestStart.bind(that);
that._errorHandler = that._error.bind(that);
}
that.dataSource = kendo.data.SchedulerDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
that.options.dataSource = that.dataSource;
},
_error: function() {
this._progress(false);
},
_requestStart: function() {
this._progress(true);
},
_progress: function(toggle) {
var element = this.element.find(".k-scheduler-content");
kendo.ui.progress(element, toggle);
},
_resources: function() {
var that = this;
var resources = that.options.resources;
var resourcePromises = [];
for (var idx = 0; idx < resources.length; idx++) {
var resource = resources[idx];
var field = resource.field;
var name = resource.name || field;
var dataSource = resource.dataSource;
if (!field || !dataSource) throw new Error("The \"field\" and \"dataSource\" options of the scheduler resource are mandatory.");
that.resources.push({
field,
name,
title: resource.title || field,
icon: resource.icon,
dataTextField: resource.dataTextField || "text",
dataValueField: resource.dataValueField || "value",
dataColorField: resource.dataColorField || "color",
dataParentValueField: resource.dataParentValueField || "parentValue",
valuePrimitive: resource.valuePrimitive != null ? resource.valuePrimitive : true,
multiple: resource.multiple || false,
dataSource: that._resourceDataSource(dataSource, name, resourcePromises)
});
}
if (!that.options.autoBind) that._selectView(that._selectedViewName);
else $.when.apply(null, resourcePromises).then(function() {
that.view(that._selectedViewName);
});
},
_resourceDataSource: function(resourceDS, groupName, promises) {
var that = this;
var dataSource = isArray(resourceDS) ? { data: resourceDS } : resourceDS;
var dataSourceInstance = kendo.data.DataSource.create(dataSource);
if (that.options.autoBind) promises.push(dataSourceInstance.fetch(function() {
that._bindResourceEvents(this, groupName);
}));
else that._bindResourceEvents(dataSourceInstance, groupName);
return dataSourceInstance;
},
_bindResourceEvents: function(resourceDS, groupName) {
var that = this;
var isResourceGrouped = that.options.group && that.options.group.resources.length && that.options.group.resources.indexOf(groupName) > -1;
if (!that._resourceRefreshHandler && isResourceGrouped) {
that._resourceRefreshHandler = that._refreshResource.bind(that);
that._resourceErrorHandler = that._error.bind(that);
}
if (isResourceGrouped) resourceDS.bind(CHANGE, that._resourceRefreshHandler).bind(ERROR, that._resourceErrorHandler);
},
_refreshResource: function() {
var that = this;
if (!(that._editor && that._editor.editable || that._preventRefresh)) that.view(that._selectedViewName);
},
_initModel: function() {
var that = this;
that._model = kendo.observable({
selectedDate: new Date(this.options.date),
formattedDate: "",
formattedShortDate: "",
formattedToolbarDate: ""
});
that._model.bind(CHANGE, function(e) {
if (e.field === "selectedDate") that.view(that._selectedViewName);
});
},
_wrapper: function() {
var that = this;
var options = that.options;
var height = options.height;
var width = options.width;
that.wrapper = that.element.addClass("k-scheduler");
if (that._isMobile()) that.wrapper.addClass("k-scheduler-mobile");
if (height) that.wrapper.height(height);
if (width) that.wrapper.width(width);
},
date: function(value) {
if (value != null && getDate(value) >= getDate(this.options.min) && getDate(value) <= getDate(this.options.max)) this._model.set("selectedDate", value);
return getDate(this._model.get("selectedDate"));
},
_toolbarEventInfo: function() {
var currentDate = /* @__PURE__ */ new Date();
var timezone = this.options.timezone;
var view = this.view();
var interval = view && view._timeSlotInterval ? view._timeSlotInterval() : 30 * kendo.date.MS_PER_MINUTE;
if (timezone) {
var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
currentDate = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
}
var start = new Date(this.date());
var startTime = Math.ceil(getMilliseconds(currentDate) / interval) * interval;
kendo.date.setTime(start, startTime);
var end = new Date(start);
kendo.date.setTime(end, interval);
return {
start,
end
};
},
_processHandlers: function(defaults) {
var that = this;
that._pdfClickHandler = (e) => {
e.preventDefault();
that.saveAsPDF();
};
that._createClickHandler = (e) => {
e.preventDefault();
that.addEvent(that._isMobile() ? undefined : that._toolbarEventInfo());
};
that._calendarClickHandler = that._currentClickHandler = (e) => {
e.preventDefault();
that._showCalendar(e.target);
};
that._todayClickHandler = (e) => {
e.preventDefault();
var timezone = that.options.timezone, currentDate = /* @__PURE__ */ new Date(), date;
if (timezone) {
var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
} else date = currentDate;
if (!that.trigger("navigate", {
view: that._selectedViewName,
action: "today",
date
})) that.date(date);
};
that._previousClickHandler = (e) => {
e.preventDefault();
var date = that.view().previousDate();
if (!that.trigger("navigate", {
view: that._selectedViewName,
action: "previous",
date
})) that.date(date);
};
that._nextClickHandler = (e) => {
e.preventDefault();
var date = that.view().nextDate();
if (!that.trigger("navigate", {
view: that._selectedViewName,
action: "next",
date
})) that.date(date);
};
that._refreshClickHandler = (e) => {
e.preventDefault();
var name = that.view().name;
if (!that.trigger("navigate", {
view: name,
action: "changeView",
date: that.date()
})) that.view(name);
};
that._viewClickHandler = (e) => {
var name = e.target.attr(kendo.attr("name"));
if (!that.trigger("navigate", {
view: name,
action: "changeView",
date: that.date()
})) that.view(name);
};
Object.values(defaults).map((t) => {
if (t.name) t.click = that["_" + t.name + "ClickHandler"];
});
},
_processDefaults: function() {
var views = this.views, defaults = $.extend(true, {}, DEFAULT_TOOLS), viewsButtons = [], isRtl = kendo.support.isRtl(this.wrapper), viewsDdl, viewsMobile;
Object.keys(views).map((name) => {
viewsButtons.push(name);
});
if (viewsButtons.length > 1) {
viewsDdl = VIEWS_DROPDOWN_TEMPLATE({
views: this.views,
label: this.options.messages.selectView,
type: "k-views-dropdown"
});
viewsMobile = VIEWS_DROPDOWN_TEMPLATE({
views: this.views,
label: this.options.messages.selectView,
type: "k-scheduler-mobile-views"
});
}
defaults.viewsDdl = { template: viewsDdl };
defaults.viewsMobile = { template: viewsMobile };
defaults.viewsSegmentedControl = { template: "<div class=\"k-scheduler-views\"></div>" };
this._viewsButtons = viewsButtons;
if (isRtl) {
defaults.previous.icon = "chevron-right";
defaults.next.icon = "chevron-left";
}
return defaults;
},
_processToolbarArray: function() {
var options = this.options, toolbarOptions = options.toolbar, commands = [], isMobile = this._isMobile(), tools, pdf, search;
if (toolbarOptions) commands = Array.isArray(toolbarOptions) ? toolbarOptions : [toolbarOptions];
pdf = $.grep(commands, function(item) {
return item == "pdf" || item.name == "pdf";
}).length > 0;
search = $.grep(commands, function(item) {
return item == "search" || item.name == "search";
}).length > 0;
if (isMobile) {
tools = [...defaultMobileToolsFirst];
if (options.editable) tools[0].push("createMobile");
} else tools = [...defaultDesktopTools];
if (search) tools.push("search");
if (pdf) if (isMobile) tools[0].unshift("pdfMobile");
else tools.unshift("pdf");
if (this._viewsCount === 1) tools.push("refresh");
else if (this._viewsCount > 1) if (isMobile) tools.push("viewsMobile");
else {
tools.push("viewsDdl");
tools.push("viewsSegmentedControl");
}
return tools;
},
_processViewTools: function(items) {
var result = items.map((item) => {
if (Array.isArray(item)) return this._processViewTools(item);
if ($.isPlainObject(item) && item.name && item.template) {
item = $.extend({}, item);
delete item.name;
}
return item;
}), viewsIndex = -1;
result.some((item, index) => {
if (item === "views" || item && item.name === "views") {
viewsIndex = index;
return true;
}
return false;
});
if (viewsIndex > -1) result.splice(viewsIndex, 1, "viewsDdl", "viewsSegmentedControl");
return result;
},
_processToolbarItems: function() {
var desktopItems = this.options.toolbar.items.desktop || this.options.toolbar.items, mobileItems = this.options.toolbar.items.mobile || this.options.toolbar.items;
if (!this._isMobile()) {
if (desktopItems.main) if (desktopItems.navigation) desktopItems = desktopItems.main.concat(desktopItems.navigation);
else desktopItems = desktopItems.main;
if (this._viewsCount > 1 && !desktopItems.some((item) => item === "views" || item && item.name === "views")) desktopItems = desktopItems.concat("views");
return { tools: this._processViewTools(desktopItems) };
} else if (Array.isArray(mobileItems)) return {
tools: this._processViewTools(mobileItems),
navigation: []
};
else return {
tools: this._processViewTools(mobileItems.main),
navigation: this._processViewTools(mobileItems.navigation)
};
},
_processTools: function() {
var toolbarOptions = this.options.toolbar;
if (toolbarOptions && toolbarOptions.items) return this._processToolbarItems();
else return { tools: this._processToolbarArray() };
},
_toolbar: function() {
var that = this;
var options = that.options;
var defaults = that._processDefaults();
var { tools, navigation } = that._processTools();
var toolbar = $("<div class='k-scheduler-toolbar'>");
var secondToolbar;
that._processHandlers(defaults);
that.wrapper.append(toolbar);
that.toolbar = toolbar;
toolbar.kendoToolBar({
resizable: false,
tools,
defaultTools: defaults,
parentMessages: options.messages
});
that._initViewsSegmentedControl();
if (that._isMobile() && (!navigation || navigation.length !== 0)) {
secondToolbar = $("<div class='k-scheduler-toolbar'>");
that.wrapper.append(secondToolbar);
that.toolbar = that.toolbar.add(secondToolbar);
secondToolbar.kendoToolBar({
resizable: false,
tools: navigation || [...defaultMobileToolsSecond],
defaultTools: defaults,
parentMessages: options.messages
});
}
that.toolbar.find(".k-nav-current .k-button-text").attr("data-" + kendo.ns + "bind", "text: formattedToolbarDate");
that.toolbar.find(".k-m-date-format").attr("data-" + kendo.ns + "bind", "text: formattedMobileDate");
that.toolbar.find(".k-y-date-format").attr("data-" + kendo.ns + "bind", "text: formattedYear");
kendo.bind(that.toolbar, that._model);
that.toolbar.find(".k-scheduler-search-input").attr({
placeholder: options.messages.search,
title: options.messages.search
});
toolbar.on("input" + NS, ".k-scheduler-search-input", kendo.throttle(function(e) {
that.dataSource.filter({
logic: "or",
filters: [{
field: "title",
operator: "contains",
value: e.target.value
}, {
field: "description",
operator: "contains",
value: e.target.value
}]
});
}, 250));
toolbar.on(CHANGE + NS, ".k-views-dropdown, .k-scheduler-mobile-views", function() {
var name = this.value;
if (!that.trigger("navigate", {
view: name,
action: "changeView",
date: that.date()
})) that.view(name);
});
that._initViewsDropDownButton();
if (!that._isMobile()) {
that._toolbarLevel = 0;
that._toolbarBreakpoints = [
Infinity,
Infinity,
Infinity
];
that.toolbar.first().css("flex-wrap", "nowrap");
if (typeof ResizeObserver !== "undefined") {
that._toolbarResizeObserver = new ResizeObserver(function() {
that._toolbarResize();
});
that._toolbarResizeObserver.observe(that.toolbar.first()[0]);
}
}
that._initialSize = true;
},
_initViewsSegmentedControl: function() {
const that = this;
const views = that.views;
const viewNames = Object.keys(views);
const container = that.toolbar.find(".k-scheduler-views");
if (!container.length || viewNames.length <= 1) return;
var segParent = container.parent();
segParent.attr("ref-toolbar-tool", "");
that._toolbarSegmentedContainer = segParent.is(that.toolbar.first()) ? container : segParent;
const items = viewNames.map(function(name) {
return {
value: name,
text: views[name].title
};
});
that._viewsSegmentedControl = container.kendoSegmentedControl({
items,
selectedValue: that._selectedViewName,
change: function(e) {
if (!that.trigger("navigate", {
view: e.value,
action: "changeView",
date: that.date()
})) {
that.view(e.value);
(that.element.find(".k-segmented-control-button")?.filter(`[data-value="${e.value}"]`))?.focus();
}
}
}).data("kendoSegmentedControl");
},
_initViewsDropDownButton: function() {
var that = this;
var views = that.views;
var viewNames = Object.keys(views);
var toolbar = that.toolbar.first();
if (!toolbar.find(".k-scheduler-views").length || viewNames.length <= 1) return;
var currentTitle = views[that._selectedViewName] ? views[that._selectedViewName].title : viewNames[0];
var items = viewNames.map(function(name) {
return {
text: views[name].title,
click: function() {
if (!that.trigger("navigate", {
view: name,
action: "changeView",
date: that.date()
})) that.view(name);
}
};
});
that._toolbarDropDownContainer = $("<div class=\"k-toolbar-views-dropdown\"></div>").hide().appendTo(toolbar);
that._viewsDropDownButton = $("<button type=\"button\"></button>").text(currentTitle).appendTo(that._toolbarDropDownContainer).kendoDropDownButton({
fillMode: "flat",
showArrowButton: true,
items
}).data("kendoDropDownButton");
that._viewsDropDownButton.element.addClass("k-toolbar-menu-button");
that._toolbarViewsDdlContainer = toolbar.find(".k-views-dropdown").parent();
if (that._toolbarViewsDdlContainer.length) that._toolbarViewsDdlContainer.hide();
that._toolbarCreateBtn = toolbar.find("[ref-toolbar-create]");
that._toolbarNavGroup = toolbar.find("[ref-nav-prev]").closest(".k-button-group");
that._toolbarTodayBtn = toolbar.find("[ref-nav-today]");
},
_updateToolbarDate: function() {
if (!this._model || this._isMobile()) return;
var date = (this._toolbarLevel || 0) >= 2 ? this._model.get("formattedShortDate") : this._model.get("formattedDate");
this._model.set("formattedToolbarDate", date);
},
_toolbarResize: function() {
var that = this;
if (that._toolbarResizing) return;
var toolbar = that.toolbar && that.toolbar.first();
if (!toolbar || !toolbar.is(":visible") || that._isMobile()) return;
that._toolbarResizing = true;
toolbar.css("overflow", "hidden");
var el = toolbar[0];
var containerWidth = el.clientWidth;
if (!containerWidth) {
that._toolbarResizing = false;
return;
}
var level = that._toolbarLevel || 0;
var breakpoints = that._toolbarBreakpoints;
var iterations = 0;
var changed = true;
while (changed && iterations < 4) {
changed = false;
iterations++;
if (that._measureToolbarContent(toolbar) > containerWidth && level < 3) {
breakpoints[level] = containerWidth;
level++;
changed = true;
that._applyToolbarLevel(level);
} else if (level > 0) {
that._applyToolbarLevel(level - 1);
if (that._measureToolbarContent(toolbar) <= containerWidth - TOOLBAR_HYSTERESIS) {
level--;
changed = true;
} else that._applyToolbarLevel(level);
}
}
if (level !== (that._toolbarLevel || 0)) {
that._toolbarLevel = level;
that._updateToolbarDate();
}
toolbar.css("overflow", "");
if (level >= 3 && that._measureToolbarContent(toolbar) > el.clientWidth) toolbar.css("flex-wrap", "wrap");
else toolbar.css("flex-wrap", "nowrap");
that._toolbarResizing = false;
},
_measureToolbarContent: function(toolbar) {
var gap = parseInt(toolbar.css("gap")) || 0;
var contentWidth = 0;
var visibleCount = 0;
toolbar.children().each(function() {
if (this.offsetWidth > 0 && !$(this).hasClass("k-spacer")) {
contentWidth += this.offsetWidth;
visibleCount++;
}
});
if (visibleCount > 1) contentWidth += gap * (visibleCount - 1);
return contentWidth;
},
_applyToolbarLevel: function(level) {
var that = this;
var segContainer = that._toolbarSegmentedContainer;
var sepEl = that._toolbarViewsSeparator;
var ddlEl = that._toolbarDropDownContainer;
var createBtn = that._toolbarCreateBtn;
var todayBtn = that._toolbarTodayBtn;
var navGroup = that._toolbarNavGroup;
if (segContainer) if (level === 0) segContainer.show();
else segContainer.hide();
if (sepEl) if (level === 1) sepEl.show();
else sepEl.hide();
if (ddlEl) if (level >= 1) ddlEl.show();
else ddlEl.hide();
if (createBtn) if (level >= 2) {
createBtn.addClass("k-icon-button");
createBtn.children(".k-button-text").hide();
} else {
createBtn.removeClass("k-icon-button");
createBtn.children(".k-button-text").show();
}
if (todayBtn && todayBtn.length) if (level >= 2) todayBtn.hide();
else todayBtn.show();
if (navGroup && navGroup.length) if (level >= 3) navGroup.hide();
else navGroup.show();
},
_showCalendar: function(targetElm) {
var that = this, target = targetElm || that.toolbar.find(".k-nav-current"), html = $("<div class=\"k-calendar-container\"><div class=\"k-scheduler-calendar\"></div></div>");
if (!that.popup) that.popup = new Popup(html, {
anchor: target,
isRtl: kendo.support.isRtl(that.element),
activate: function() {
if (that.popup && that.calendar) {
that.popup._toggleResize(false);
that.calendar.focus();
that.popup._toggleResize(true);
}
},
open: function() {
if (!that.calendar) that.calendar = new Calendar(this.element.find(".k-scheduler-calendar"), {
change: function() {
var date = this.value();
if (!that.trigger("navigate", {
view: that._selectedViewName,
action: "changeDate",
date
})) {
that.date(date);
that.popup.close();
}
if (!that._isMobile()) {
that._selectedView.element.trigger("focus");
that.toolbar.find(".k-nav-current").trigger("focus").addClass(FOCUSEDSTATE);
}
},
min: that.options.min,
max: that.options.max
});
that.calendar.element.on("keydown" + NS, function(e) {
if (e.keyCode === keys.ESC || e.keyCode === keys.TAB) {
that.popup.close();
that._selectedView.element.trigger("focus");
that.toolbar.find(".k-nav-current").trigger("focus").addClass(FOCUSEDSTATE);
}
});
that.calendar.setOptions({
start: that._selectedViewName === "year" ? "decade" : "month",
depth: that._selectedViewName === "year" ? "decade" : "month"
});
that.calendar.value(that.date());
},
copyAnchorStyles: false
});
that.popup.open();
},
refresh: function(e) {
var view = this.view();
var preventRefresh = e && e.action === "itemchange" && (this._editor.editable || this._preventRefresh) || this.dataSource.options.type === "signalr" && this._preventRefresh;
this._progress(false);
e = e || {};
if (!view) return;
if (preventRefresh) {
this._attemptRefresh = this.dataSource.options.type === "signalr";
return;
}
if (this.trigger("dataBinding", {
action: e.action || "rebind",
index: e.index,
items: e.items
})) return;
if (!(e && e.action === "resize") && this._editor) this._editor.close();
this._data = this.dataSource.expand(view.startDate(), view.visibleEndDate());
view.refreshLayout();
view.render(this._data);
view._readonlyEvents(this._data);
this.trigger("dataBound");
this._attemptRefresh = false;
},
slotByPosition: function(x, y) {
var view = this.view();
if (!view._slotByPosition) return null;
var slot = view._slotByPosition(x, y);
if (!slot) return null;
return {
startDate: slot.startDate(),
endDate: slot.endDate(),
groupIndex: slot.groupIndex,
element: slot.element,
isDaySlot: slot.isDaySlot
};
},
slotByElement: function(element) {
var el = $(element), offset = el.offset(), width = el.width(), height = el.height(), centerX = offset.left + width / 2, centerY = offset.top + height / 2, offset = $(element).offset();
return this.slotByPosition(centerX, centerY);
},
resourcesBySlot: function(slot) {
return this.view()._resourceBySlot(slot);
}
});
var defaultViews = {
day: { type: "kendo.ui.DayView" },
week: { type: "kendo.ui.WeekView" },
workWeek: { type: "kendo.ui.WorkWeekView" },
agenda: { type: "kendo.ui.AgendaView" },
month: { type: "kendo.ui.MonthView" },
timeline: { type: "kendo.ui.TimelineView" },
timelineWeek: { type: "kendo.ui.TimelineWeekView" },
timelineWorkWeek: { type: "kendo.ui.TimelineWorkWeekView" },
timelineMonth: { type: "kendo.ui.TimelineMonthView" },
year: { type: "kendo.ui.YearView" }
};
ui.plugin(Scheduler);
if (kendo.PDFMixin) {
kendo.PDFMixin.extend(Scheduler.prototype);
var SCHEDULER_EXPORT = "k-scheduler-pdf-export";
Scheduler.fn._drawPDF = function(progress) {
var wrapper = this.wrapper;
var styles = wrapper[0].style.cssText;
wrapper.css({
width: wrapper.width(),
height: wrapper.height()
});
wrapper.addClass(SCHEDULER_EXPORT);
var scheduler = this;
var promise = new $.Deferred();
var table = wrapper.find(".k-scheduler-content").find("table").css("table-layout", "auto");
setTimeout(function() {
table.css("table-layout", "fixed");
scheduler.resize(true);
scheduler._drawPDFShadow({}, { avoidLinks: scheduler.options.pdf.avoidLinks }).done(function(group) {
var args = {
page: group,
pageNumber: 1,
progress: 1,
totalPages: 1
};
progress.notify(args);
promise.resolve(args.page);
}).fail(function(err) {
promise.reject(err);
}).always(function() {
wrapper[0].style.cssText = styles;
wrapper.removeClass(SCHEDULER_EXPORT);
scheduler.resize(true);
scheduler.resize(true);
});
});
return promise;
};
}
var TimezoneEditor = Widget.extend({
init: function(element, options) {
var that = this, zones = kendo.timezone.windows_zones;
if (!zones || !kendo.timezone.zones_titles) throw new Error("kendo.timezones.min.js is not included.");
Widget.fn.init.call(that, element, options);
that.wrapper = that.element;
that._zonesQuery = new kendo.data.Query(zones);
that._zoneTitleId = kendo.guid();
that._zoneTitlePicker();
that._zonePicker();
that._zoneTitle.bind("cascade", function() {
if (!this.value()) that._zone.wrapper.hide();
});
that._zone.bind("cascade", function() {
that._value = this.value();
that.trigger(CHANGE);
});
that.value(that.options.value);
Widget.fn.endInit.call(this);
},
options: {
name: "TimezoneEditor",
value: "",
optionLabel: "No timezone"
},
events: [CHANGE],
_zoneTitlePicker: function() {
var that = this, zoneTitle = $("<input id=\"" + that._zoneTitleId + "\" aria-label=\"" + that.options.title + "\"/>").appendTo(that.wrapper), zones = [{
name: that.options.optionLabel,
other_zone: ""
}].concat(kendo.timezone.zones_titles);
that._zoneTitle = new kendo.ui.DropDownList(zoneTitle, {
dataSource: zones,
dataValueField: "other_zone",
dataTextField: "name",
filter: "contains"
});
},
_zonePicker: function() {
var that = this, zone = $("<input aria-label=\"" + that.options.title + "\"/>").appendTo(this.wrapper);
that._zone = new kendo.ui.DropDownList(zone, {
dataValueField: "zone",
dataTextField: "territory",
dataSource: that._zonesQuery.data,
cascadeFrom: that._zoneTitleId,
filter: "contains",
dataBound: function() {
that._value = this.value();
this.wrapper.toggle(this.dataSource.view().length > 1);
}
});
that._zone.wrapper.hide();
},
destroy: function() {
Widget.fn.destroy.call(this);
kendo.destroy(this.wrapper);
},
value: function(value) {
var that = this, zone;
if (value === undefined) return that._value;
zone = that._zonesQuery.filter({
field: "zone",
operator: "eq",
value
}).data[0];
if (zone) {
that._zoneTitle.value(zone.other_zone);
that._zone.value(zone.zone);
} else that._zoneTitle.select(0);
}
});
ui.plugin(TimezoneEditor);
var ZONETITLEOPTIONTEMPLATE = kendo.template(({ name, other_zone }) => `<option value="${other_zone}">${name}</option>`);
var ZONEOPTIONTEMPLATE = kendo.template(({ zone, territory }) => `<option value="${zone}">${territory}</option>`);
var MobileTimezoneEditor = Widget.extend({
init: function(element, options) {
var that = this, zones = kendo.timezone.windows_zones;
if (!zones || !kendo.timezone.zones_titles) throw new Error("kendo.timezones.min.js is not included.");
Widget.fn.init.call(that, element, options);
that.wrapper = that.element;
that._zonesQuery = new kendo.data.Query(zones);
that._zoneTitlePicker();
that._zonePicker();
that.value(that.options.value);
Widget.fn.endInit.call(this);
},
options: {
name: "MobileTimezoneEditor",
optionLabel: "No timezone",
value: ""
},
events: [CHANGE],
_bindZones: function(value) {
var data = value ? this._filter(value) : [];
this._zone.html(this._options(data, ZONEOPTIONTEMPLATE));
},
_filter: function(value) {
return this._zonesQuery.filter({
field: "other_zone",
operator: "eq",
value
}).data;
},
_options: function(data, template, optionLabel) {
var idx = 0;
var html = "";
var length = data.length;
if (optionLabel) html += template({
other_zone: "",
name: optionLabel
});
for (; idx < length; idx++) html += template(data[idx]);
return html;
},
_zoneTitlePicker: function() {
var that = this;
that._zoneTitle = $("<select>" + that._options(kendo.timezone.zones_titles, ZONETITLEOPTIONTEMPLATE, that.options.optionLabel) + "</select>").appendTo(that.wrapper).on("change", function() {
var value = this.value;
var zone = that._zonePickerLabel;
var zoneSelect = zone.find("select");
that._bindZones(value);
if (value && zoneSelect.children().length > 1) zone.show();
else zone.hide();
that._value = that._zone[0].value;
that.trigger(CHANGE);
});
},
_zonePicker: function() {
var that = this;
that._zonePickerLabel = $("<li class='k-item k-listgroup-item k-zonepicker'><label class='k-label k-listgroup-form-row'><span class='k-item-title k-listgroup-form-field-label'></span><div class='k-listgroup-form-field-wrapper'></div></label></li>").hide();
that._zone = $("<select></select>").appendTo(that._zonePickerLabel.find("div")).on("change", function() {
that._value = this.value;
that.trigger(CHANGE);
});
this.wrapper.closest(".k-item").after(that._zonePickerLabel);
that._bindZones(that._zoneTitle.val());
that._value = that._zone[0].value;
},
destroy: function() {
Widget.fn.destroy.call(this);
kendo.destroy(this.wrapper);
},
value: function(value) {
var that = this;
var zonePicker = that._zone;
var other_zone = "";
var zone_value = "";
var zone;
if (value === undefined) return that._value;
zone = that._zonesQuery.filter({
field: "zone",
operator: "eq",
value
}).data[0];
if (zone) {
zone_value = zone.zone;
other_zone = zone.other_zone;
}
that._zoneTitle.val(other_zone);
that._bindZones(other_zone);
zonePicker.val(zone_value);
zone_value = zonePicker[0].value;
if (zone_value && zonePicker.children.length > 1) that._zonePickerLabel.show();
else that._zonePickerLabel.hide();
that._value = zone_value;
}
});
ui.plugin(MobileTimezoneEditor);
})(window.kendo.jQuery);
var kendo_scheduler_default = kendo;
//#endregion
export { __meta__, kendo_scheduler_default as default };