3978 lines
185 KiB
JavaScript
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)();
|
|
})); |