EnVisageOnline/Main/Source/EnVisage/Scripts/Kendo/kendo.scheduler.js

3978 lines
185 KiB
JavaScript

/**
* Kendo UI v2016.1.226 (http://www.telerik.com/kendo-ui)
* Copyright 2016 Telerik AD. All rights reserved.
*
* Kendo UI commercial licenses may be obtained at
* http://www.telerik.com/purchase/license-agreement/kendo-ui-complete
* If you do not own a commercial license, this file shall be governed by the trial license terms.
*/
(function (f, define) {
define('util/main', ['kendo.core'], f);
}(function () {
(function () {
var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend;
var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined';
function defined(value) {
return typeof value !== UNDEFINED;
}
function round(value, precision) {
var power = pow(precision);
return math.round(value * power) / power;
}
function pow(p) {
if (p) {
return math.pow(10, p);
} else {
return 1;
}
}
function limitValue(value, min, max) {
return math.max(math.min(value, max), min);
}
function rad(degrees) {
return degrees * DEG_TO_RAD;
}
function deg(radians) {
return radians / DEG_TO_RAD;
}
function isNumber(val) {
return typeof val === 'number' && !isNaN(val);
}
function valueOrDefault(value, defaultValue) {
return defined(value) ? value : defaultValue;
}
function sqr(value) {
return value * value;
}
function objectKey(object) {
var parts = [];
for (var key in object) {
parts.push(key + object[key]);
}
return parts.sort().join('');
}
function hashKey(str) {
var hash = 2166136261;
for (var i = 0; i < str.length; ++i) {
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
hash ^= str.charCodeAt(i);
}
return hash >>> 0;
}
function hashObject(object) {
return hashKey(objectKey(object));
}
var now = Date.now;
if (!now) {
now = function () {
return new Date().getTime();
};
}
function arrayLimits(arr) {
var length = arr.length, i, min = MAX_NUM, max = MIN_NUM;
for (i = 0; i < length; i++) {
max = math.max(max, arr[i]);
min = math.min(min, arr[i]);
}
return {
min: min,
max: max
};
}
function arrayMin(arr) {
return arrayLimits(arr).min;
}
function arrayMax(arr) {
return arrayLimits(arr).max;
}
function sparseArrayMin(arr) {
return sparseArrayLimits(arr).min;
}
function sparseArrayMax(arr) {
return sparseArrayLimits(arr).max;
}
function sparseArrayLimits(arr) {
var min = MAX_NUM, max = MIN_NUM;
for (var i = 0, length = arr.length; i < length; i++) {
var n = arr[i];
if (n !== null && isFinite(n)) {
min = math.min(min, n);
max = math.max(max, n);
}
}
return {
min: min === MAX_NUM ? undefined : min,
max: max === MIN_NUM ? undefined : max
};
}
function last(array) {
if (array) {
return array[array.length - 1];
}
}
function append(first, second) {
first.push.apply(first, second);
return first;
}
function renderTemplate(text) {
return kendo.template(text, {
useWithBlock: false,
paramName: 'd'
});
}
function renderAttr(name, value) {
return defined(value) && value !== null ? ' ' + name + '=\'' + value + '\' ' : '';
}
function renderAllAttr(attrs) {
var output = '';
for (var i = 0; i < attrs.length; i++) {
output += renderAttr(attrs[i][0], attrs[i][1]);
}
return output;
}
function renderStyle(attrs) {
var output = '';
for (var i = 0; i < attrs.length; i++) {
var value = attrs[i][1];
if (defined(value)) {
output += attrs[i][0] + ':' + value + ';';
}
}
if (output !== '') {
return output;
}
}
function renderSize(size) {
if (typeof size !== 'string') {
size += 'px';
}
return size;
}
function renderPos(pos) {
var result = [];
if (pos) {
var parts = kendo.toHyphens(pos).split('-');
for (var i = 0; i < parts.length; i++) {
result.push('k-pos-' + parts[i]);
}
}
return result.join(' ');
}
function isTransparent(color) {
return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
}
function arabicToRoman(n) {
var literals = {
1: 'i',
10: 'x',
100: 'c',
2: 'ii',
20: 'xx',
200: 'cc',
3: 'iii',
30: 'xxx',
300: 'ccc',
4: 'iv',
40: 'xl',
400: 'cd',
5: 'v',
50: 'l',
500: 'd',
6: 'vi',
60: 'lx',
600: 'dc',
7: 'vii',
70: 'lxx',
700: 'dcc',
8: 'viii',
80: 'lxxx',
800: 'dccc',
9: 'ix',
90: 'xc',
900: 'cm',
1000: 'm'
};
var values = [
1000,
900,
800,
700,
600,
500,
400,
300,
200,
100,
90,
80,
70,
60,
50,
40,
30,
20,
10,
9,
8,
7,
6,
5,
4,
3,
2,
1
];
var roman = '';
while (n > 0) {
if (n < values[0]) {
values.shift();
} else {
roman += literals[values[0]];
n -= values[0];
}
}
return roman;
}
function romanToArabic(r) {
r = r.toLowerCase();
var digits = {
i: 1,
v: 5,
x: 10,
l: 50,
c: 100,
d: 500,
m: 1000
};
var value = 0, prev = 0;
for (var i = 0; i < r.length; ++i) {
var v = digits[r.charAt(i)];
if (!v) {
return null;
}
value += v;
if (v > prev) {
value -= 2 * prev;
}
prev = v;
}
return value;
}
function memoize(f) {
var cache = Object.create(null);
return function () {
var id = '';
for (var i = arguments.length; --i >= 0;) {
id += ':' + arguments[i];
}
if (id in cache) {
return cache[id];
}
return f.apply(this, arguments);
};
}
function ucs2decode(string) {
var output = [], counter = 0, length = string.length, value, extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 55296 && value <= 56319 && counter < length) {
extra = string.charCodeAt(counter++);
if ((extra & 64512) == 56320) {
output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
} else {
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
function ucs2encode(array) {
return array.map(function (value) {
var output = '';
if (value > 65535) {
value -= 65536;
output += String.fromCharCode(value >>> 10 & 1023 | 55296);
value = 56320 | value & 1023;
}
output += String.fromCharCode(value);
return output;
}).join('');
}
deepExtend(kendo, {
util: {
MAX_NUM: MAX_NUM,
MIN_NUM: MIN_NUM,
append: append,
arrayLimits: arrayLimits,
arrayMin: arrayMin,
arrayMax: arrayMax,
defined: defined,
deg: deg,
hashKey: hashKey,
hashObject: hashObject,
isNumber: isNumber,
isTransparent: isTransparent,
last: last,
limitValue: limitValue,
now: now,
objectKey: objectKey,
round: round,
rad: rad,
renderAttr: renderAttr,
renderAllAttr: renderAllAttr,
renderPos: renderPos,
renderSize: renderSize,
renderStyle: renderStyle,
renderTemplate: renderTemplate,
sparseArrayLimits: sparseArrayLimits,
sparseArrayMin: sparseArrayMin,
sparseArrayMax: sparseArrayMax,
sqr: sqr,
valueOrDefault: valueOrDefault,
romanToArabic: romanToArabic,
arabicToRoman: arabicToRoman,
memoize: memoize,
ucs2encode: ucs2encode,
ucs2decode: ucs2decode
}
});
kendo.drawing.util = kendo.util;
kendo.dataviz.util = kendo.util;
}());
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('util/text-metrics', [
'kendo.core',
'util/main'
], f);
}(function () {
(function ($) {
var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined;
var LRUCache = Class.extend({
init: function (size) {
this._size = size;
this._length = 0;
this._map = {};
},
put: function (key, value) {
var lru = this, map = lru._map, entry = {
key: key,
value: value
};
map[key] = entry;
if (!lru._head) {
lru._head = lru._tail = entry;
} else {
lru._tail.newer = entry;
entry.older = lru._tail;
lru._tail = entry;
}
if (lru._length >= lru._size) {
map[lru._head.key] = null;
lru._head = lru._head.newer;
lru._head.older = null;
} else {
lru._length++;
}
},
get: function (key) {
var lru = this, entry = lru._map[key];
if (entry) {
if (entry === lru._head && entry !== lru._tail) {
lru._head = entry.newer;
lru._head.older = null;
}
if (entry !== lru._tail) {
if (entry.older) {
entry.older.newer = entry.newer;
entry.newer.older = entry.older;
}
entry.older = lru._tail;
entry.newer = null;
lru._tail.newer = entry;
lru._tail = entry;
}
return entry.value;
}
}
});
var defaultMeasureBox = $('<div style=\'position: absolute !important; top: -4000px !important; width: auto !important; height: auto !important;' + 'padding: 0 !important; margin: 0 !important; border: 0 !important;' + 'line-height: normal !important; visibility: hidden !important; white-space: nowrap!important;\' />')[0];
function zeroSize() {
return {
width: 0,
height: 0,
baseline: 0
};
}
var TextMetrics = Class.extend({
init: function (options) {
this._cache = new LRUCache(1000);
this._initOptions(options);
},
options: { baselineMarkerSize: 1 },
measure: function (text, style, box) {
if (!text) {
return zeroSize();
}
var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey);
if (cachedResult) {
return cachedResult;
}
var size = zeroSize();
var measureBox = box ? box : defaultMeasureBox;
var baselineMarker = this._baselineMarker().cloneNode(false);
for (var key in style) {
var value = style[key];
if (defined(value)) {
measureBox.style[key] = value;
}
}
$(measureBox).text(text);
measureBox.appendChild(baselineMarker);
doc.body.appendChild(measureBox);
if ((text + '').length) {
size.width = measureBox.offsetWidth - this.options.baselineMarkerSize;
size.height = measureBox.offsetHeight;
size.baseline = baselineMarker.offsetTop + this.options.baselineMarkerSize;
}
if (size.width > 0 && size.height > 0) {
this._cache.put(cacheKey, size);
}
measureBox.parentNode.removeChild(measureBox);
return size;
},
_baselineMarker: function () {
return $('<div class=\'k-baseline-marker\' ' + 'style=\'display: inline-block; vertical-align: baseline;' + 'width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;' + 'overflow: hidden;\' />')[0];
}
});
TextMetrics.current = new TextMetrics();
function measureText(text, style, measureBox) {
return TextMetrics.current.measure(text, style, measureBox);
}
function loadFonts(fonts, callback) {
var promises = [];
if (fonts.length > 0 && document.fonts) {
try {
promises = fonts.map(function (font) {
return document.fonts.load(font);
});
} catch (e) {
kendo.logToConsole(e);
}
Promise.all(promises).then(callback, callback);
} else {
callback();
}
}
kendo.util.TextMetrics = TextMetrics;
kendo.util.LRUCache = LRUCache;
kendo.util.loadFonts = loadFonts;
kendo.util.measureText = measureText;
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('util/base64', ['util/main'], f);
}(function () {
(function () {
var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode;
var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function encodeBase64(input) {
var output = '';
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = encodeUTF8(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4);
}
return output;
}
function encodeUTF8(input) {
var output = '';
for (var i = 0; i < input.length; i++) {
var c = input.charCodeAt(i);
if (c < 128) {
output += fromCharCode(c);
} else if (c < 2048) {
output += fromCharCode(192 | c >>> 6);
output += fromCharCode(128 | c & 63);
} else if (c < 65536) {
output += fromCharCode(224 | c >>> 12);
output += fromCharCode(128 | c >>> 6 & 63);
output += fromCharCode(128 | c & 63);
}
}
return output;
}
deepExtend(kendo.util, {
encodeBase64: encodeBase64,
encodeUTF8: encodeUTF8
});
}());
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('mixins/observers', ['kendo.core'], f);
}(function () {
(function ($) {
var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray;
var ObserversMixin = {
observers: function () {
this._observers = this._observers || [];
return this._observers;
},
addObserver: function (element) {
if (!this._observers) {
this._observers = [element];
} else {
this._observers.push(element);
}
return this;
},
removeObserver: function (element) {
var observers = this.observers();
var index = inArray(element, observers);
if (index != -1) {
observers.splice(index, 1);
}
return this;
},
trigger: function (methodName, event) {
var observers = this._observers;
var observer;
var idx;
if (observers && !this._suspended) {
for (idx = 0; idx < observers.length; idx++) {
observer = observers[idx];
if (observer[methodName]) {
observer[methodName](event);
}
}
}
return this;
},
optionsChange: function (e) {
this.trigger('optionsChange', e);
},
geometryChange: function (e) {
this.trigger('geometryChange', e);
},
suspend: function () {
this._suspended = (this._suspended || 0) + 1;
return this;
},
resume: function () {
this._suspended = math.max((this._suspended || 0) - 1, 0);
return this;
},
_observerField: function (field, value) {
if (this[field]) {
this[field].removeObserver(this);
}
this[field] = value;
value.addObserver(this);
}
};
deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } });
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.scheduler', [
'kendo.dropdownlist',
'kendo.editable',
'kendo.multiselect',
'kendo.window',
'kendo.datetimepicker',
'kendo.scheduler.recurrence',
'kendo.scheduler.view',
'kendo.scheduler.dayview',
'kendo.scheduler.agendaview',
'kendo.scheduler.monthview',
'kendo.scheduler.timelineview',
'kendo.mobile.actionsheet',
'kendo.mobile.pane',
'kendo.pdf'
], f);
}(function () {
var __meta__ = {
id: 'scheduler',
name: 'Scheduler',
category: 'web',
description: 'The Scheduler is an event calendar.',
depends: [
'dropdownlist',
'editable',
'multiselect',
'window',
'datepicker',
'datetimepicker',
'scheduler.recurrence',
'scheduler.view'
],
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-mobile',
name: 'Scheduler adaptive rendering',
description: 'Support for adaptive rendering',
depends: [
'mobile.actionsheet',
'mobile.pane'
]
},
{
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, input_support = kendo.support.input, MS_PER_DAY = date.MS_PER_DAY, getDate = date.getDate, getMilliseconds = kendo.date.getMilliseconds, recurrence = kendo.recurrence, 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, proxy = $.proxy, toString = Object.prototype.toString, isArray = $.isArray, NS = '.kendoScheduler', CLICK = 'click', CHANGE = 'change', CANCEL = 'cancel', REMOVE = 'remove', SAVE = 'save', ADD = 'add', EDIT = 'edit', valueStartEndBoundRegex = /(?:value:start|value:end)(?:,|$)/, TODAY = getDate(new Date()), 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?', DELETESERIESCONFIRM = 'Are you sure you want to delete the whole series?', COMMANDBUTTONTMPL = '<a class="k-button #=className#" #=attr# href="\\#">#=text#</a>', VIEWBUTTONTEMPLATE = kendo.template('<li class="k-current-view" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>'), TOOLBARTEMPLATE = kendo.template('<div class="k-floatwrap k-header k-scheduler-toolbar">' + '# if (pdf) { #' + '<ul class="k-reset k-scheduler-tools">' + '<li><a role="button" href="\\#" class="k-button k-pdf"><span class="k-icon k-i-pdf"></span>${messages.pdf}</a></li>' + '</ul>' + '# } #' + '<ul class="k-reset k-scheduler-navigation">' + '<li class="k-state-default k-header k-nav-today"><a role="button" href="\\#" class="k-link">${messages.today}</a></li>' + '<li class="k-state-default k-header k-nav-prev"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-w"></span></a></li>' + '<li class="k-state-default k-header k-nav-next"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-e"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<a role="button" href="\\#" class="k-link">' + '<span class="k-icon k-i-calendar"></span>' + '<span class="k-sm-date-format" data-#=ns#bind="text: formattedShortDate"></span>' + '<span class="k-lg-date-format" data-#=ns#bind="text: formattedDate"></span>' + '</a>' + '</li>' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-refresh"></span>' + '</a>' + '#}else{#' + '<ul class="k-reset k-header k-scheduler-views">' + '#for(var view in views){#' + '<li class="k-state-default k-view-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>' + '#}#' + '</ul>' + '#}#' + '</div>'), MOBILETOOLBARTEMPLATE = kendo.template('<div class="k-floatwrap k-header k-scheduler-toolbar">' + '<ul class="k-reset k-header k-scheduler-navigation">' + '<li class="k-state-default k-nav-today"><a role="button" href="\\#" class="k-link">${messages.today}</a></li>' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-refresh"></span>' + '</a>' + '#}else{#' + '<ul class="k-reset k-header k-scheduler-views">' + '#for(var view in views){#' + '<li class="k-state-default k-view-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>' + '#}#' + '</ul>' + '#}#' + '</div>' + '<div class="k-floatwrap k-header k-scheduler-toolbar">' + '<ul class="k-reset k-header k-scheduler-navigation">' + '<li class="k-state-default k-nav-prev"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-w"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<span class="k-sm-date-format" data-#=ns#bind="text: formattedShortDate"></span>' + '<span class="k-lg-date-format" data-#=ns#bind="text: formattedDate"></span>' + '</li>' + '<li class="k-state-default k-nav-next"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-e"></span></a></li>' + '</ul>' + '</div>'), MOBILEDATERANGEEDITOR = function (container, options) {
var attr = { name: options.field };
var datepicker_role = !input_support.date ? kendo.attr('role') + '="datepicker" ' : '';
var datetimepicker_role = kendo.attr('role') + '="datetimepicker" ';
var isAllDay = options.model.isAllDay;
var dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\'';
var dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\'';
appendTimezoneAttr(attr, options);
appendDateCompareValidator(attr, options);
$('<input type="datetime-local" required ' + kendo.attr('type') + '="date" ' + datetimepicker_role + kendo.attr('bind') + '="value:' + options.field + ',invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
$('<input type="date" required ' + kendo.attr('type') + '="date" ' + datepicker_role + 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 }, isAllDay = options.model.isAllDay, dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\' ', dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\' ';
appendTimezoneAttr(attr, options);
appendDateCompareValidator(attr, options);
$('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datetimepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
$('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',visible:isAllDay" ' + dateValidate + '/>').attr(attr).appendTo(container);
$('<span ' + kendo.attr('bind') + '="text: ' + options.field + 'Timezone"></span>').appendTo(container);
if (options.field === 'end') {
$('<span ' + kendo.attr('bind') + '="text: startTimezone, invisible: endTimezone"></span>').appendTo(container);
}
$('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
}, RECURRENCEEDITOR = function (container, options) {
$('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoRecurrenceEditor({
start: options.model.start,
timezone: options.timezone,
messages: options.messages
});
}, 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]
});
}, MOBILETIMEZONEPOPUP = function (container, options) {
var text = timezoneButtonText(options.model, options.messages.noTimezone);
$('<a href="#" class="k-button k-timezone-button" data-bind="invisible:isAllDay">' + text + '</a>').click(options.click).appendTo(container);
}, TIMEZONEPOPUP = function (container, options) {
$('<a href="#" class="k-button" data-bind="invisible:isAllDay">' + options.messages.timezoneEditorButton + '</a>').click(options.click).appendTo(container);
}, MOBILETIMEZONEEDITOR = function (container, options) {
$('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).toggle(options.visible).appendTo(container).kendoMobileTimezoneEditor({ optionLabel: options.noTimezone });
}, TIMEZONEEDITOR = function (container, options) {
$('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).toggle(options.visible).appendTo(container).kendoTimezoneEditor({ optionLabel: options.noTimezone });
};
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 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;
data = data || [];
for (idx = 0, length = data.length; idx < length; idx++) {
event = data[idx];
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;
}
}
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($.proxy(this.data, this), timezone);
this.serialize = wrapDataSerialization($.proxy(this.serialize, 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 dateCompareValidator(input) {
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;
}
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.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);
}
},
id: 'id',
fields: {
id: { type: 'number' },
title: {
defaultValue: '',
type: 'string'
},
start: {
type: 'date',
validation: { required: true }
},
startTimezone: { type: 'string' },
end: {
type: 'date',
validation: {
required: true,
dateCompare: { value: dateCompareValidator }
}
},
endTimezone: { type: 'string' },
recurrenceRule: {
defaultValue: '',
type: 'string'
},
recurrenceException: {
defaultValue: '',
type: 'string'
},
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 = {};
if (start && end) {
end = new Date(end.getTime() + MS_PER_DAY - 1);
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: 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.start;
head.set(RECURRENCE_EXCEPTION, head.recurrenceException.replace(recurrence.toExceptionString(start, this.reader.timezone), ''));
}
}
},
_addExceptionDate: function (model) {
var start = model.start;
var zone = this.reader.timezone;
var head = this.get(model.recurrenceId);
var recurrenceException = head.recurrenceException || '';
if (!recurrence.isException(recurrenceException, start, zone)) {
head.set(RECURRENCE_EXCEPTION, recurrenceException + recurrence.toExceptionString(start, zone));
}
}
});
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 || {}, data = dataSource.data;
dataSource.data = 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: SchedulerDataSource,
SchedulerDataReader: SchedulerDataReader,
SchedulerEvent: SchedulerEvent
});
var defaultCommands = {
update: {
text: 'Save',
className: 'k-primary k-scheduler-update'
},
canceledit: {
text: 'Cancel',
className: 'k-scheduler-cancel'
},
destroy: {
text: 'Delete',
imageClass: 'k-delete',
className: 'k-primary k-scheduler-delete',
iconClass: 'k-icon'
}
};
function trimOptions(options) {
delete options.name;
delete options.prefix;
delete options.remove;
delete options.edit;
delete options.add;
delete options.navigate;
return options;
}
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 dropDownResourceEditor(resource, model) {
var attr = createValidationAttributes(model, resource.field);
return function (container) {
$(kendo.format('<select data-{0}bind="value:{1}">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoDropDownList({
dataTextField: resource.dataTextField,
dataValueField: resource.dataValueField,
dataSource: resource.dataSource,
valuePrimitive: resource.valuePrimitive,
optionLabel: 'None',
template: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
});
};
}
function descriptionEditor(options) {
var attr = createValidationAttributes(options.model, options.field);
return function (container) {
$('<textarea name="description" class="k-textbox"/>').attr(attr).appendTo(container);
};
}
function multiSelectResourceEditor(resource, model) {
var attr = createValidationAttributes(model, resource.field);
return function (container) {
$(kendo.format('<select data-{0}bind="value:{1}">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoMultiSelect({
dataTextField: resource.dataTextField,
dataValueField: resource.dataValueField,
dataSource: resource.dataSource,
valuePrimitive: resource.valuePrimitive,
itemTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField),
tagTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
});
};
}
function multiSelectResourceEditorMobile(resource, model) {
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]));
}
$(kendo.format('<select data-{0}bind="value:{1}" multiple="multiple" data-{0}value-primitive="{3}">{2}</select>', kendo.ns, resource.field, options, resource.valuePrimitive)).appendTo(container).attr(attr);
};
}
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: start,
end: end
};
}
var editors = {
mobile: {
dateRange: MOBILEDATERANGEEDITOR,
timezonePopUp: MOBILETIMEZONEPOPUP,
timezone: MOBILETIMEZONEEDITOR,
recurrence: MOBILERECURRENCEEDITOR,
description: descriptionEditor,
multipleResources: multiSelectResourceEditorMobile,
resources: dropDownResourceEditor
},
desktop: {
dateRange: DATERANGEEDITOR,
timezonePopUp: TIMEZONEPOPUP,
timezone: TIMEZONEEDITOR,
recurrence: RECURRENCEEDITOR,
description: descriptionEditor,
multipleResources: multiSelectResourceEditor,
resources: dropDownResourceEditor
}
};
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 = proxy(this._toggleDateValidation, this);
},
_toggleDateValidation: function (e) {
if (e.field == 'isAllDay') {
var container = this.container, isAllDay = this.editable.options.model.isAllDay, 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],[type*=datetime]');
shouldValidate = isAllDay !== isDateTimeInput;
element.attr(kendo.attr('validate'), shouldValidate);
}
});
}
},
fields: function (editors, model) {
var that = this;
var messages = that.options.messages;
var timezone = that.options.timezone;
var click = function (e) {
e.preventDefault();
that._initTimezoneEditor(model, this);
};
var fields = [
{
field: 'title',
title: messages.editor.title
},
{
field: 'start',
title: messages.editor.start,
editor: editors.dateRange,
timezone: timezone
},
{
field: 'end',
title: messages.editor.end,
editor: editors.dateRange,
timezone: timezone
},
{
field: 'isAllDay',
title: messages.editor.allDayEvent
}
];
if (kendo.timezone.windows_zones) {
fields.push({
field: 'timezone',
title: messages.editor.timezone,
editor: editors.timezonePopUp,
click: click,
messages: messages.editor,
model: model
});
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: timezone,
messages: messages.recurrenceEditor,
pane: this.pane
});
}
if ('description' in model) {
fields.push({
field: 'description',
title: messages.editor.description,
editor: editors.description({
model: model,
field: 'description'
})
});
}
for (var resourceIndex = 0; resourceIndex < this.options.resources.length; resourceIndex++) {
var resource = this.options.resources[resourceIndex];
fields.push({
field: resource.field,
title: resource.title,
editor: resource.multiple ? editors.multipleResources(resource, model) : editors.resources(resource, model)
});
}
return fields;
},
end: function () {
return this.editable.end();
},
_buildEditTemplate: function (model, fields, editableFields) {
var messages = this.options.messages;
var settings = extend({}, kendo.Template, this.options.templateSettings);
var paramName = settings.paramName;
var template = this.options.editable.template;
var html = '';
if (template) {
if (typeof template === STRING) {
template = window.unescape(template);
}
html += kendo.template(template, settings)(model);
} else {
for (var idx = 0, length = fields.length; idx < length; idx++) {
var field = fields[idx];
if (field.field === 'startTimezone') {
html += '<div class="k-popup-edit-form k-scheduler-edit-form k-scheduler-timezones" style="display:none">';
html += '<div class="k-edit-form-container">';
html += '<div class="k-edit-label"></div>';
html += '<div class="k-edit-field"><label class="k-check"><input class="k-timezone-toggle" type="checkbox" />' + messages.editor.separateTimezones + '</label></div>';
}
html += '<div class="k-edit-label"><label for="' + field.field + '">' + (field.title || field.field || '') + '</label></div>';
if (!model.editable || model.editable(field.field)) {
editableFields.push(field);
html += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="k-edit-field"></div>';
} else {
var tmpl = '#:';
if (field.field) {
field = kendo.expr(field.field, paramName);
tmpl += field + '==null?\'\':' + field;
} else {
tmpl += '\'\'';
}
tmpl += '#';
tmpl = kendo.template(tmpl, settings);
html += '<div class="k-edit-field">' + tmpl(model) + '</div>';
}
if (field.field === 'endTimezone') {
html += this._createEndTimezoneButton();
}
}
}
return html;
},
_createEndTimezoneButton: function () {
return '</div></div>';
},
_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.mobile.ui.Pane.wrap(this.element);
this.pane.element.parent().css('height', this.options.height);
this.view = this.pane.view();
this._actionSheetButtonTemplate = kendo.template('<li><a #=attr# class="k-button #=className#" href="\\#">#:text#</a></li>');
this._actionSheetPopupOptions = $(document.documentElement).hasClass('km-root') ? { modal: false } : {
align: 'bottom center',
position: 'bottom center',
effect: 'slideIn:up'
};
},
options: {
animations: {
left: 'slide',
right: 'slide:right'
}
},
destroy: function () {
this.close();
this.unbind();
this.pane.destroy();
},
_initTimezoneEditor: function (model) {
var that = this;
var pane = that.pane;
var messages = that.options.messages;
var timezoneView = that.timezoneView;
var container = that.container.find('.k-scheduler-timezones');
var checkbox = container.find('.k-timezone-toggle');
var endTimezoneRow = container.find('.k-edit-label:last').add(container.find('.k-edit-field:last'));
var startTimezoneChange = function (e) {
if (e.field === 'startTimezone') {
var value = model.startTimezone;
checkbox.prop('disabled', !value);
if (!value) {
endTimezoneRow.hide();
model.set('endTimezone', '');
checkbox.prop('checked', 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 k-mobile-list">' + '<div data-role="header" class="k-header"><a href="#" class="k-button k-scheduler-cancel">' + messages.cancel + '</a>' + messages.editor.timezoneTitle + '<a href="#" class="k-button k-scheduler-update">' + messages.save + '</a></div></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);
}
model.unbind('change', startTimezoneChange);
var editView = pane.element.find('#edit').data('kendoMobileView');
var text = timezoneButtonText(model, messages.editor.noTimezone);
editView.contentElement().find('.k-timezone-button').text(text);
pane.navigate(editView, that.options.animations.right);
});
checkbox.click(function () {
endTimezoneRow.toggle(checkbox.prop('checked'));
model.set('endTimezone', '');
});
model.bind('change', startTimezoneChange);
}
checkbox.prop('checked', model.endTimezone).prop('disabled', !model.startTimezone);
if (model.endTimezone) {
endTimezoneRow.show();
} else {
endTimezoneRow.hide();
}
pane.navigate(timezoneView, that.options.animations.left);
},
_createActionSheetButton: function (options) {
options.template = this._actionSheetButtonTemplate;
return this.createButton(options);
},
showDialog: function (options) {
var type = '';
var html = '<ul><li class="km-actionsheet-title">' + options.title + '</li>';
var target = this.element.find('.k-event[' + kendo.attr('uid') + '=\'' + options.model.uid + '\']');
if (this.container) {
target = this.container.find('.k-scheduler-delete');
if (target[0]) {
type = 'phone';
}
}
for (var buttonIndex = 0; buttonIndex < options.buttons.length; buttonIndex++) {
html += this._createActionSheetButton(options.buttons[buttonIndex]);
}
html += '</ul>';
var actionSheet = $(html).appendTo(this.pane.view().element).kendoMobileActionSheet({
type: type,
cancel: this.options.messages.cancel,
cancelTemplate: '<li class="km-actionsheet-cancel"><a class="k-button" href="\\#">#:cancel#</a></li>',
close: function () {
this.destroy();
},
command: function (e) {
var buttonIndex = actionSheet.element.find('li:not(.km-actionsheet-cancel) > .k-button').index($(e.currentTarget));
if (buttonIndex > -1) {
actionSheet.close();
options.buttons[buttonIndex].click();
}
},
popup: this._actionSheetPopupOptions
}).data('kendoMobileActionSheet');
actionSheet.open(target);
},
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;
html += '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list" id="edit" ' + kendo.attr('uid') + '="' + model.uid + '">' + '<div data-role="header" class="k-header"><a href="#" class="k-button k-scheduler-cancel">' + cancelText + '</a>' + titleText + '<a href="#" class="k-button k-scheduler-update">' + updateText + '</a></div>';
var fields = this.fields(editors.mobile, model);
var that = this;
var editableFields = [];
html += this._buildEditTemplate(model, fields, editableFields);
if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false) {
html += '<div class="k-edit-buttons"><a href="#" class="k-scheduler-delete k-button">' + removeText + '</a></div>';
}
html += '</div>';
var view = pane.append(html);
var container = this.container = view.element;
this.editable = container.kendoEditable({
fields: editableFields,
model: model,
clearContainer: false,
target: that.options.target,
validateOnBlur: true
}).data('kendoEditable');
container.find('input[type=checkbox],input[type=radio]').parent('.k-edit-field').addClass('k-check').prev('.k-edit-label').addClass('k-check').click(function () {
$(this).next().children('input').click();
});
if (!this.trigger('edit', {
container: container,
model: model
})) {
container.on(CLICK + NS, 'a.k-scheduler-edit, a.k-scheduler-cancel, a.k-scheduler-update, a.k-scheduler-delete', 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';
}
that.trigger(name, {
container: container,
model: model
});
} else {
pane.navigate('#edit', that.options.animations.right);
}
});
pane.navigate(view, that.options.animations.left);
model.bind('change', that.toggleDateValidationHandler);
} else {
this.trigger('cancel', {
container: container,
model: 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('kendoMobileView');
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 + '" class="k-popup-edit-form k-scheduler-edit-form"><div class="k-edit-form-container">';
var messages = that.options.messages;
var updateText = messages.save;
var cancelText = messages.cancel;
var deleteText = messages.destroy;
var fields = this.fields(editors.desktop, model);
var editableFields = [];
html += this._buildEditTemplate(model, fields, editableFields);
var attr;
var options = isPlainObject(editable) ? editable.window : {};
html += '<div class="k-edit-buttons k-state-default">';
html += this.createButton({
name: 'update',
text: updateText,
attr: attr
}) + this.createButton({
name: 'canceledit',
text: cancelText,
attr: attr
});
if (!model.isNew() && editable.destroy !== false) {
html += this.createButton({
name: 'delete',
text: deleteText,
attr: attr
});
}
html += '</div></div></div>';
var container = this.container = $(html).appendTo(that.element).eq(0).kendoWindow(extend({
modal: true,
resizable: false,
draggable: true,
title: messages.editor.editorTitle,
visible: false,
close: function (e) {
if (e.userTriggered) {
if (that.trigger(CANCEL, {
container: container,
model: model
})) {
e.preventDefault();
}
}
}
}, options));
that.editable = container.kendoEditable({
fields: editableFields,
model: model,
clearContainer: false,
validateOnBlur: true,
target: that.options.target
}).data('kendoEditable');
if (!that.trigger(EDIT, {
container: container,
model: model
})) {
container.data('kendoWindow').center().open();
container.on(CLICK + NS, 'a.k-scheduler-cancel', function (e) {
e.preventDefault();
e.stopPropagation();
that.trigger(CANCEL, {
container: container,
model: model
});
});
container.on(CLICK + NS, 'a.k-scheduler-update', function (e) {
e.preventDefault();
e.stopPropagation();
that.trigger('save', {
container: container,
model: model
});
});
container.on(CLICK + NS, 'a.k-scheduler-delete', function (e) {
e.preventDefault();
e.stopPropagation();
that.trigger(REMOVE, {
container: container,
model: model
});
});
kendo.cycleForm(container);
model.bind('change', that.toggleDateValidationHandler);
} else {
that.trigger(CANCEL, {
container: container,
model: model
});
}
return that.editable;
},
close: function () {
var that = this;
var destroy = function () {
if (that.editable) {
that.editable.options.model.unbind('change', that.toggleDateValidationHandler);
that.editable.destroy();
that.editable = null;
that.container = null;
}
if (that.popup) {
that.popup.destroy();
that.popup = null;
}
};
if (that.editable) {
if (that._timezonePopup && that._timezonePopup.data('kendoWindow')) {
that._timezonePopup.data('kendoWindow').destroy();
that._timezonePopup = null;
}
if (that.container.is(':visible')) {
that.container.data('kendoWindow').bind('deactivate', destroy).close();
} else {
destroy();
}
} else {
destroy();
}
},
_createEndTimezoneButton: function () {
var messages = this.options.messages;
var html = '';
html += '<div class="k-edit-buttons k-state-default">';
html += this.createButton({
name: 'savetimezone',
text: messages.save
}) + this.createButton({
name: 'canceltimezone',
text: messages.cancel
});
html += '</div></div></div>';
return html;
},
showDialog: function (options) {
var html = kendo.format('<div class=\'k-popup-edit-form\'><div class=\'k-edit-form-container\'><p class=\'k-popup-message\'>{0}</p>', options.text);
html += '<div class="k-edit-buttons k-state-default">';
for (var buttonIndex = 0; buttonIndex < options.buttons.length; buttonIndex++) {
html += this.createButton(options.buttons[buttonIndex]);
}
html += '</div></div></div>';
var wrapper = this.element;
if (this.popup) {
this.popup.destroy();
}
var popup = this.popup = $(html).appendTo(wrapper).eq(0).on('click', '.k-button', function (e) {
e.preventDefault();
popup.close();
var buttonIndex = $(e.currentTarget).index();
options.buttons[buttonIndex].click();
}).kendoWindow({
modal: true,
resizable: false,
draggable: false,
title: options.title,
visible: false,
close: function () {
this.destroy();
wrapper.focus();
}
}).getKendoWindow();
popup.center().open();
},
_initTimezoneEditor: function (model, activator) {
var that = this;
var container = that.container.find('.k-scheduler-timezones');
var checkbox = container.find('.k-timezone-toggle');
var endTimezoneRow = container.find('.k-edit-label:last').add(container.find('.k-edit-field:last'));
var saveButton = container.find('.k-scheduler-savetimezone');
var cancelButton = container.find('.k-scheduler-canceltimezone');
var timezonePopup = that._timezonePopup;
var startTimezoneChange = function (e) {
if (e.field === 'startTimezone') {
var value = model.startTimezone;
checkbox.prop('disabled', !value);
if (!value) {
endTimezoneRow.hide();
model.set('endTimezone', '');
checkbox.prop('checked', false);
}
}
};
var wnd;
that._startTimezone = model.startTimezone;
that._endTimezone = model.endTimezone;
if (!timezonePopup) {
that._timezonePopup = timezonePopup = container.kendoWindow({
modal: true,
resizable: false,
draggable: true,
title: that.options.messages.editor.timezoneEditorTitle,
visible: false,
close: function (e) {
model.unbind('change', startTimezoneChange);
if (e.userTriggered) {
that._revertTimezones(model);
}
if (activator) {
activator.focus();
}
}
});
checkbox.click(function () {
endTimezoneRow.toggle(checkbox.prop('checked'));
model.set('endTimezone', '');
});
saveButton.click(function (e) {
e.preventDefault();
wnd.close();
});
cancelButton.click(function (e) {
e.preventDefault();
that._revertTimezones(model);
wnd.close();
});
model.bind('change', startTimezoneChange);
}
checkbox.prop('checked', model.endTimezone).prop('disabled', !model.startTimezone);
if (model.endTimezone) {
endTimezoneRow.show();
} else {
endTimezoneRow.hide();
}
wnd = timezonePopup.data('kendoWindow');
wnd.center().open();
}
});
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();
that._views();
that._toolbar();
that._dataSource();
that._resources();
that._resizeHandler = function () {
that.resize();
};
that.wrapper.on('mousedown' + NS + ' selectstart' + NS, function (e) {
if (!$(e.target).is(':kendoFocusable')) {
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._selectable();
that._ariaId = kendo.guid();
that._createEditor();
},
_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';
},
_isMobilePhoneView: function () {
var options = this.options;
return options.mobile === true && kendo.support.mobileOS && !kendo.support.mobileOS.tablet || options.mobile === 'phone';
},
_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: slots,
resources: view._resourceBySlot(selection)
};
}
if (!options) {
that._selection = null;
view.clearSelection();
return;
}
if ($.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];
}
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;
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: '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]);
}
}
}
},
_selectable: function () {
var that = this, wrapper = that.wrapper, selectEvent = kendo.support.mobileOS ? 'touchend' : 'mousedown';
if (!that.options.selectable) {
return;
}
that._tabindex();
wrapper.on(selectEvent + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', function (e) {
var which = e.which;
var button = e.button;
var browser = kendo.support.browser;
var isRight = which && which === 3 || button && button == 2;
if (kendo.support.mobileOS && e.isDefaultPrevented()) {
return;
}
if (!isRight) {
that._createSelection(e.currentTarget);
}
wrapper.focus();
if (browser.msie && browser.version < 9) {
setTimeout(function () {
wrapper.focus();
});
}
});
var mouseMoveHandler = $.proxy(that._mouseMove, 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 (!isRight) {
wrapper.on('mousemove' + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
}
});
wrapper.on('mouseup' + NS + ' mouseleave' + NS, function () {
wrapper.off('mousemove' + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
});
wrapper.on('focus' + NS, function () {
if (!that._selection) {
that._createSelection(that.wrapper.find('.k-scheduler-content').find('td:first'));
}
that._select();
});
wrapper.on('focusout' + NS, function () {
that.view().clearSelection();
that._ctrlKey = that._shiftKey = false;
});
wrapper.on('keydown' + NS, proxy(that._keydown, that));
wrapper.on('keyup' + NS, function (e) {
that._ctrlKey = e.ctrlKey;
that._shiftKey = e.shiftKey;
});
},
_select: function () {
var that = this;
var view = that.view();
var wrapper = that.wrapper;
var current = view.current();
var selection = that._selection;
if (current) {
current.removeAttribute('id');
current.removeAttribute('aria-label');
wrapper.removeAttr('aria-activedescendant');
}
view.select(selection);
current = view.current();
if (current && that._old !== current) {
var currentUid = $(current).data('uid');
if (that._old && currentUid && currentUid === $(that._old).data('uid')) {
return;
}
var labelFormat;
var data = selection;
var events = that._selectedEvents();
var slots = view._selectedSlots;
if (events[0]) {
data = events[0] || selection;
labelFormat = kendo.format(that.options.messages.ariaEventLabel, data.title, data.start, data.start);
} else {
labelFormat = kendo.format(that.options.messages.ariaSlotLabel, data.start, data.end);
}
current.setAttribute('id', that._ariaId);
current.setAttribute('aria-label', labelFormat);
wrapper.attr('aria-activedescendant', that._ariaId);
that._old = current;
that.trigger('change', {
start: selection.start,
end: selection.end,
events: events,
slots: 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;
},
_mouseMove: function (e) {
var that = this;
clearTimeout(that._moveTimer);
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, views = this.views;
for (view in views) {
if (!index) {
return view;
}
index--;
}
},
_keydown: function (e) {
var that = this, key = e.keyCode, view = that.view(), editable = view.options.editable, selection = that._selection, shiftKey = e.shiftKey;
that._ctrlKey = e.ctrlKey;
that._shiftKey = e.shiftKey;
if (key === keys.TAB) {
if (view.moveToEvent(selection, shiftKey)) {
that._select();
e.preventDefault();
}
} else if (editable && key === keys.ENTER) {
if (selection.events.length) {
if (editable.update !== false) {
that.editEvent(selection.events[0]);
}
} else if (editable.create !== false) {
if (selection.isAllDay) {
selection = $.extend({}, selection, { end: kendo.date.addDays(selection.end, -1) });
}
that.addEvent(extend({}, selection, view._resourceBySlot(selection)));
}
} else if (key === keys.DELETE && editable !== false && editable.destroy !== false) {
that.removeEvent(selection.events[0]);
} else if (key >= 49 && key <= 57) {
that.view(that._viewByIndex(key - 49));
} else if (view.move(selection, key, shiftKey)) {
if (view.inRange(selection)) {
that._select();
} else {
that.date(selection.start);
}
e.preventDefault();
}
that._adjustSelectedDate();
},
_createSelection: function (item) {
var uid, slot, selection;
if (!this._selection || !this._ctrlKey && !this._shiftKey) {
this._selection = {
events: [],
groupIndex: 0
};
}
item = $(item);
selection = this._selection;
if (item.is('.k-event')) {
uid = item.attr(kendo.attr('uid'));
}
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) {
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;
}
selection.index = dataItem.index;
if (this._ctrlKey) {
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,
messages: {
today: 'Today',
pdf: 'Export to PDF',
save: 'Save',
cancel: 'Cancel',
destroy: 'Delete',
deleteWindowTitle: 'Delete event',
ariaSlotLabel: 'Selected from {0:t} to {1:t}',
ariaEventLabel: '{0} on {1:D} at {2:t}',
views: {
day: 'Day',
week: 'Week',
workWeek: 'Work Week',
agenda: 'Agenda',
month: 'Month',
timeline: 'Timeline',
timelineWeek: 'Timeline Week',
timelineWorkWeek: 'Timeline Work Week',
timelineMonth: 'Timeline Month'
},
recurrenceMessages: {
deleteWindowTitle: 'Delete Recurring Item',
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 event',
description: 'Description',
repeat: 'Repeat',
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'
}
},
height: null,
width: null,
resources: [],
group: {
resources: [],
direction: 'horizontal'
},
views: [],
selectable: false
},
events: [
REMOVE,
EDIT,
CANCEL,
SAVE,
'add',
'dataBinding',
'dataBound',
'moveStart',
'move',
'moveEnd',
'resizeStart',
'resize',
'resizeEnd',
'navigate',
'change'
],
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.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();
}
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();
}
},
items: function () {
return this.wrapper.find('.k-scheduler-content').children('.k-event, .k-task');
},
_movable: function () {
var startSlot;
var endSlot;
var startTime;
var endTime;
var event;
var clonedEvent;
var that = this;
var originSlot;
var distance = 0;
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) {
if (isMobile && kendo.support.mobileOS.android) {
distance = 5;
}
that._moveDraggable = new kendo.ui.Draggable(that.element, {
distance: distance,
filter: '.k-event',
ignore: '.k-resize-handle',
holdToDrag: isMobile
});
if (movable) {
that._moveDraggable.bind('dragstart', function (e) {
var view = that.view();
var eventElement = e.currentTarget;
if (!view.options.editable || view.options.editable.move === false) {
e.preventDefault();
return;
}
if (isMobile && !eventElement.hasClass('k-event-active')) {
that.element.find('.k-event-active').removeClass('k-event-active');
e.preventDefault();
return;
}
event = that.occurrenceByUid(eventElement.attr(kendo.attr('uid')));
clonedEvent = event.clone();
clonedEvent.update(view._eventOptionsForMove(clonedEvent));
startSlot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
startTime = startSlot.startOffset(e.x.startLocation, e.y.startLocation, that.options.snap);
endSlot = startSlot;
originSlot = startSlot;
if (!startSlot || that.trigger('moveStart', { event: 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;
if (!slot) {
return;
}
endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
if (slot.isDaySlot !== startSlot.isDaySlot) {
startSlot = view._slotByPosition(e.x.location, e.y.location);
startTime = startSlot.startOffset(e.x.location, e.y.location, that.options.snap);
distance = endTime - startTime;
clonedEvent.isAllDay = slot.isDaySlot;
clonedEvent.start = kendo.timezone.toLocalDate(startTime);
clonedEvent.end = kendo.timezone.toLocalDate(endTime);
view._updateMoveHint(clonedEvent, slot.groupIndex, distance);
range = {
start: clonedEvent.start,
end: clonedEvent.end
};
} else {
distance = endTime - startTime;
view._updateMoveHint(clonedEvent, slot.groupIndex, distance);
range = moveEventRange(clonedEvent, distance);
}
if (!that.trigger('move', {
event: 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 {
view._updateMoveHint(clonedEvent, 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;
var endResources = that.view()._resourceBySlot(endSlot);
var startResources = that.view()._resourceBySlot(startSlot);
var prevented = that.trigger('moveEnd', {
event: event,
slot: {
element: endSlot.element,
start: endSlot.startDate(),
end: endSlot.endDate()
},
start: start,
end: end,
resources: endResources
});
if (!prevented && (event.start.getTime() !== start.getTime() || event.end.getTime() !== end.getTime() || originSlot.isDaySlot !== endSlot.isDaySlot || kendo.stringify(endResources) !== kendo.stringify(startResources))) {
var updatedEventOptions = that.view()._eventOptionsForMove(event);
var eventOptions;
if (originSlot.isDaySlot !== endSlot.isDaySlot) {
if (endSlot.isDaySlot) {
eventOptions = $.extend({
start: endSlot.startDate(),
end: endSlot.startDate(),
isAllDay: endSlot.isDaySlot
}, updatedEventOptions, endResources);
} else {
eventOptions = $.extend({
isAllDay: endSlot.isDaySlot,
start: start,
end: end
}, updatedEventOptions, endResources);
}
} else {
eventOptions = $.extend({
isAllDay: event.isAllDay,
start: start,
end: end
}, updatedEventOptions, endResources);
}
that._updateEvent(null, event, eventOptions);
}
e.currentTarget.removeClass('k-event-active');
this.cancelHold();
}).bind('dragcancel', function () {
that.view()._removeMoveHint();
this.cancelHold();
});
}
if (isMobile) {
that._moveDraggable.bind('hold', function (e) {
if (that.element.find('.k-scheduler-monthview').length) {
e.preventDefault();
}
that.element.find('.k-event-active').removeClass('k-event-active');
e.currentTarget.addClass('k-event-active');
});
if (!kendo.support.mobileOS.android) {
that._moveDraggable.userEvents.bind('press', function (e) {
e.preventDefault();
});
}
}
}
},
_resizable: function () {
var startTime;
var endTime;
var event;
var clonedEvent;
var slot;
var that = this;
var distance = 0;
function direction(handle) {
var directions = {
'k-resize-e': 'east',
'k-resize-w': '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: distance,
filter: '.k-resize-handle',
dragstart: function (e) {
var dragHandle = $(e.currentTarget);
var eventElement = dragHandle.closest('.k-event');
var uid = eventElement.attr(kendo.attr('uid'));
var view = that.view();
event = that.occurrenceByUid(uid);
clonedEvent = event.clone();
view._updateEventForResize(clonedEvent);
slot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
if (that.trigger('resizeStart', { event: event })) {
e.preventDefault();
}
startTime = kendo.date.toUtcTime(clonedEvent.start);
endTime = kendo.date.toUtcTime(clonedEvent.end);
},
drag: function (e) {
if (!slot) {
return;
}
var dragHandle = $(e.currentTarget);
var dir = direction(dragHandle);
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: 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.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);
}
}
var prevented = that.trigger('resizeEnd', {
event: event,
slot: {
element: slot.element,
start: slot.startDate(),
end: slot.endDate()
},
start: start,
end: end,
resources: that.view()._resourceBySlot(slot)
});
if (!prevented && end.getTime() >= start.getTime()) {
if (clonedEvent.start.getTime() != start.getTime() || clonedEvent.end.getTime() != end.getTime()) {
that.view()._updateEventForResize(event);
that._updateEvent(dir, event, {
start: start,
end: end
});
}
}
slot = null;
event = null;
},
dragcancel: function () {
that.view()._removeResizeHint();
slot = null;
event = null;
}
});
},
_updateEvent: function (dir, event, eventInfo) {
var that = this;
var updateEvent = function (event, callback) {
try {
that._preventRefresh = true;
event.update(eventInfo);
that._convertDates(event);
} finally {
that._preventRefresh = false;
}
if (!that.trigger(SAVE, { event: event })) {
if (callback) {
callback();
}
that._updateSelection(event);
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 callback = function () {
that._convertDates(head);
};
var exception = head.toOccurrence({
start: event.start,
end: event.end
});
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._editor.showDialog(options);
},
focus: function () {
this.wrapper.focus();
},
_confirmation: function (callback, model) {
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()) {
text = recurrenceMessages.deleteRecurringConfirmation ? recurrenceMessages.deleteRecurringConfirmation : DELETERECURRINGCONFIRM;
} else {
text = recurrenceMessages.deleteSeriesConfirmation ? recurrenceMessages.deleteSeriesConfirmation : DELETESERIESCONFIRM;
}
}
var buttons = [{
name: 'destroy',
text: messages.destroy,
click: function () {
callback();
}
}];
if (!(this._isMobile() && kendo.mobile.ui.Pane)) {
buttons.push({
name: 'canceledit',
text: messages.cancel,
click: function () {
callback(true);
}
});
}
this._unbindResize();
this.showDialog({
model: model,
text: text,
title: title,
buttons: buttons
});
this._bindResize();
} else {
callback();
}
},
addEvent: function (eventInfo) {
var editable = this._editor.editable;
var dataSource = this.dataSource;
var event;
eventInfo = eventInfo || {};
var prevented = this.trigger('add', { event: eventInfo });
if (!prevented && (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 editor = this._editor;
if (!editor) {
return;
}
var editable = editor.editable;
var container = editor.container;
var model = this._modelForContainer(container);
if (container && editable && editable.end() && !this.trigger(SAVE, {
container: container,
event: model
})) {
if (model.isRecurrenceHead()) {
this.dataSource._removeExceptions(model);
}
if (!model.dirty && !model.isOccurrence()) {
this._convertDates(model, 'remove');
}
this.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) {
return;
}
this.cancelEvent();
if (model.isRecurring()) {
this._editRecurringDialog(model);
} else {
this._editEvent(model);
}
},
_editEvent: function (model) {
this._unbindResize();
this._createPopupEditor(model);
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 that = this;
var editable = that.options.editable;
var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : 'dialog';
if (editRecurringMode === 'series') {
editSeries();
} else if (editRecurringMode === 'occurrence') {
editOccurrence();
} else {
this._unbindResize();
that.showDialog({
model: 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.mobile.ui.Pane) {
editor = that._editor = new MobileEditor(this.wrapper, extend({}, this.options, {
target: this,
timezone: that.dataSource.reader.timezone,
resources: that.resources,
createButton: proxy(this._createButton, this)
}));
} else {
editor = that._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
target: this,
createButton: proxy(this._createButton, 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.cancelEvent();
that.focus();
});
editor.bind('edit', function (e) {
if (that.trigger(EDIT, {
container: e.container,
event: e.model
})) {
e.preventDefault();
}
});
editor.bind('save', function () {
that.saveEvent();
});
editor.bind('remove', function (e) {
that.removeEvent(e.model);
});
},
_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) {
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 deleteOccurrenceConfirmation;
var deleteSeriesConfirmation;
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);
};
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);
};
}
var seriesCallback = deleteSeriesConfirmation || deleteSeries;
var occurrenceCallback = deleteOccurrenceConfirmation || deleteOccurrence;
if (that._isEditorOpened()) {
if (model.isException()) {
occurrenceCallback();
} 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) {
var that = this;
that.angular('cleanup', function () {
return { elements: that.items() };
});
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.view) {
var switchWorkDay = 'isWorkDay' in e;
var action = switchWorkDay ? 'changeWorkDay' : 'changeView';
if (!that.trigger('navigate', {
view: e.view,
isWorkDay: e.isWorkDay,
action: 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);
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 (that._viewsCount > 1) {
var viewButton = VIEWBUTTONTEMPLATE({
views: that.views,
view: name,
ns: kendo.ns
});
var firstButton = that.toolbar.find('.k-scheduler-views li:first-child');
if (firstButton.is('.k-current-view')) {
firstButton.replaceWith(viewButton);
} else {
that.toolbar.find('.k-scheduler-views').prepend(viewButton);
}
var viewButtons = that.toolbar.find('.k-scheduler-views li').removeClass('k-state-selected');
viewButtons.end().find('.k-view-' + name.replace(/\./g, '\\.').toLowerCase()).addClass('k-state-selected');
}
}
},
view: function (name) {
var that = this;
if (name) {
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);
this._model.set('formattedDate', view.dateForTitle());
this._model.set('formattedShortDate', view.shortDateForTitle());
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), type = view.type;
if (typeof type === STRING) {
type = kendo.getter(view.type)(window);
}
if (type) {
view = new type(this.wrapper, trimOptions(extend(true, {}, this.options, isSettings ? view : {}, {
resources: this.resources,
date: this.date(),
showWorkHours: this._workDayMode
})));
} 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.title;
hasType = true;
}
} else {
type = name = 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 () {
this.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 = proxy(that.refresh, that);
that._progressHandler = proxy(that._requestStart, that);
that._errorHandler = proxy(that._error, 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;
for (var idx = 0; idx < resources.length; idx++) {
var resource = resources[idx];
var field = resource.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: field,
name: resource.name || field,
title: resource.title || field,
dataTextField: resource.dataTextField || 'text',
dataValueField: resource.dataValueField || 'value',
dataColorField: resource.dataColorField || 'color',
valuePrimitive: resource.valuePrimitive != null ? resource.valuePrimitive : true,
multiple: resource.multiple || false,
dataSource: kendo.data.DataSource.create(dataSource)
});
}
var promises = $.map(that.resources, function (resource) {
return resource.dataSource.fetch();
});
$.when.apply(null, promises).then(function () {
if (that.options.autoBind) {
that.view(that._selectedViewName);
} else {
that._selectView(that._selectedViewName);
}
});
},
_initModel: function () {
var that = this;
that._model = kendo.observable({
selectedDate: new Date(this.options.date),
formattedDate: '',
formattedShortDate: ''
});
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-widget k-scheduler k-floatwrap').attr('role', 'grid').attr('aria-multiselectable', true);
if (that._isMobile()) {
that.wrapper.addClass('k-scheduler-mobile');
}
if (that._isMobilePhoneView()) {
that.wrapper.addClass('k-scheduler-phone');
}
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'));
},
_toolbar: function () {
var that = this;
var options = that.options;
var commands = [];
if (options.toolbar) {
commands = $.isArray(options.toolbar) ? options.toolbar : [options.toolbar];
}
var template = this._isMobilePhoneView() ? MOBILETOOLBARTEMPLATE : TOOLBARTEMPLATE;
var toolbar = $(template({
messages: options.messages,
pdf: $.grep(commands, function (item) {
return item == 'pdf' || item.name == 'pdf';
}).length > 0,
ns: kendo.ns,
views: that.views,
viewsCount: that._viewsCount
}));
that.wrapper.append(toolbar);
that.toolbar = toolbar;
kendo.bind(that.toolbar, that._model);
toolbar.on(CLICK + NS, '.k-pdf', function (e) {
e.preventDefault();
that.saveAsPDF();
});
toolbar.on(CLICK + NS, '.k-scheduler-navigation li', function (e) {
var li = $(this);
var date = new Date(that.date());
var action = '';
e.preventDefault();
if (li.hasClass('k-nav-today')) {
action = 'today';
date = new Date();
} else if (li.hasClass('k-nav-next')) {
action = 'next';
date = that.view().nextDate();
} else if (li.hasClass('k-nav-prev')) {
action = 'previous';
date = that.view().previousDate();
} else if (li.hasClass('k-nav-current') && !that._isMobilePhoneView()) {
that._showCalendar();
return;
}
if (!that.trigger('navigate', {
view: that._selectedViewName,
action: action,
date: date
})) {
that.date(date);
}
});
toolbar.on(CLICK + NS, '.k-scheduler-views li, .k-scheduler-refresh', function (e) {
e.preventDefault();
var name = $(this).attr(kendo.attr('name'));
if (!that.trigger('navigate', {
view: name,
action: 'changeView',
date: that.date()
})) {
that.view(name);
that.element.find('.k-state-expanded').removeClass('k-state-expanded');
}
});
toolbar.on(CLICK + NS, '.k-scheduler-views li.k-current-view', function () {
that.element.find('.k-scheduler-views').toggleClass('k-state-expanded');
});
toolbar.find('li').hover(function () {
$(this).addClass('k-state-hover');
}, function () {
$(this).removeClass('k-state-hover');
});
},
_showCalendar: function () {
var that = this, target = that.toolbar.find('.k-nav-current'), html = $('<div class="k-calendar-container"><div class="k-scheduler-calendar"/></div>');
if (!that.popup) {
that.popup = new Popup(html, {
anchor: target,
activate: 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: date
})) {
that.date(date);
that.popup.close();
}
},
min: that.options.min,
max: that.options.max
});
}
that.calendar.value(that.date());
},
copyAnchorStyles: false
});
}
that.popup.open();
},
refresh: function (e) {
var that = this;
var view = this.view();
this._progress(false);
this.angular('cleanup', function () {
return { elements: that.items() };
});
e = e || {};
if (!view) {
return;
}
if (e && e.action === 'itemchange' && (this._editor.editable || this._preventRefresh)) {
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.endDate());
view.render(this._data);
this.trigger('dataBound');
},
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 offset = $(element).offset();
return this.slotByPosition(offset.left, offset.top);
},
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' }
};
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);
},
options: {
name: 'TimezoneEditor',
value: '',
optionLabel: 'No timezone'
},
events: ['change'],
_zoneTitlePicker: function () {
var that = this, zoneTitle = $('<input id="' + that._zoneTitleId + '"/>').appendTo(that.wrapper);
that._zoneTitle = new kendo.ui.DropDownList(zoneTitle, {
dataSource: kendo.timezone.zones_titles,
dataValueField: 'other_zone',
dataTextField: 'name',
optionLabel: that.options.optionLabel
});
},
_zonePicker: function () {
var that = this, zone = $('<input />').appendTo(this.wrapper);
that._zone = new kendo.ui.DropDownList(zone, {
dataValueField: 'zone',
dataTextField: 'territory',
dataSource: that._zonesQuery.data,
cascadeFrom: that._zoneTitleId,
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: 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('<option value="#=other_zone#">#=name#</option>');
var ZONEOPTIONTEMPLATE = kendo.template('<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);
},
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: 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;
var options = that._options(kendo.timezone.zones_titles, ZONETITLEOPTIONTEMPLATE, that.options.optionLabel);
that._zoneTitle = $('<select>' + options + '</select>').appendTo(that.wrapper).change(function () {
var value = this.value;
var zone = that._zone;
that._bindZones(value);
if (value && zone[0].children.length > 1) {
zone.show();
} else {
zone.hide();
}
that._value = zone[0].value;
that.trigger('change');
});
},
_zonePicker: function () {
var that = this;
that._zone = $('<select style="display:none"></select>').appendTo(this.wrapper).change(function () {
that._value = this.value;
that.trigger('change');
});
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: 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[0].children.length > 1) {
zonePicker.show();
} else {
zonePicker.hide();
}
that._value = zone_value;
}
});
ui.plugin(MobileTimezoneEditor);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));