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

2297 lines
104 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('kendo.scheduler.recurrence', [
'kendo.dropdownlist',
'kendo.datepicker',
'kendo.numerictextbox'
], f);
}(function () {
var __meta__ = {
id: 'scheduler.recurrence',
name: 'Recurrence',
category: 'web',
depends: [
'dropdownlist',
'datepicker',
'numerictextbox'
],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, timezone = kendo.timezone, Class = kendo.Class, ui = kendo.ui, Widget = ui.Widget, DropDownList = ui.DropDownList, kendoDate = kendo.date, setTime = kendoDate.setTime, setDayOfWeek = kendoDate.setDayOfWeek, adjustDST = kendoDate.adjustDST, firstDayOfMonth = kendoDate.firstDayOfMonth, getMilliseconds = kendoDate.getMilliseconds, DAYS_IN_LEAPYEAR = [
0,
31,
60,
91,
121,
152,
182,
213,
244,
274,
305,
335,
366
], DAYS_IN_YEAR = [
0,
31,
59,
90,
120,
151,
181,
212,
243,
273,
304,
334,
365
], MONTHS = [
31,
28,
30,
31,
30,
31,
30,
31,
30,
31,
30,
31
], WEEK_DAYS = {
0: 'SU',
1: 'MO',
2: 'TU',
3: 'WE',
4: 'TH',
5: 'FR',
6: 'SA'
}, WEEK_DAYS_IDX = {
'SU': 0,
'MO': 1,
'TU': 2,
'WE': 3,
'TH': 4,
'FR': 5,
'SA': 6
}, DATE_FORMATS = [
'yyyy-MM-ddTHH:mm:ss.fffzzz',
'yyyy-MM-ddTHH:mm:sszzz',
'yyyy-MM-ddTHH:mm:ss',
'yyyy-MM-ddTHH:mm',
'yyyy-MM-ddTHH',
'yyyy-MM-dd',
'yyyyMMddTHHmmssfffzzz',
'yyyyMMddTHHmmsszzz',
'yyyyMMddTHHmmss',
'yyyyMMddTHHmm',
'yyyyMMddTHH',
'yyyyMMdd'
], RULE_NAMES = [
'months',
'weeks',
'yearDays',
'monthDays',
'weekDays',
'hours',
'minutes',
'seconds'
], RULE_NAMES_LENGTH = RULE_NAMES.length, RECURRENCE_DATE_FORMAT = 'yyyyMMddTHHmmssZ', limitation = {
months: function (date, end, rule) {
var monthRules = rule.months, months = ruleValues(monthRules, date.getMonth() + 1), changed = false;
if (months !== null) {
if (months.length) {
date.setMonth(months[0] - 1, 1);
} else {
date.setFullYear(date.getFullYear() + 1, monthRules[0] - 1, 1);
}
changed = true;
}
return changed;
},
monthDays: function (date, end, rule) {
var monthLength, month, days, changed = false, hours = date.getHours(), normalize = function (monthDay) {
if (monthDay < 0) {
monthDay = monthLength + monthDay;
}
return monthDay;
};
while (date <= end) {
month = date.getMonth();
monthLength = getMonthLength(date);
days = ruleValues(rule.monthDays, date.getDate(), normalize);
if (days === null) {
return changed;
}
changed = true;
if (days.length) {
date.setMonth(month, days.sort(numberSortPredicate)[0]);
adjustDST(date, hours);
if (month === date.getMonth()) {
break;
}
} else {
date.setMonth(month + 1, 1);
}
}
return changed;
},
yearDays: function (date, end, rule) {
var year, yearDays, changed = false, hours = date.getHours(), normalize = function (yearDay) {
if (yearDay < 0) {
yearDay = year + yearDay;
}
return yearDay;
};
while (date < end) {
year = leapYear(date) ? 366 : 365;
yearDays = ruleValues(rule.yearDays, dayInYear(date), normalize);
if (yearDays === null) {
return changed;
}
changed = true;
year = date.getFullYear();
if (yearDays.length) {
date.setFullYear(year, 0, yearDays.sort(numberSortPredicate)[0]);
adjustDST(date, hours);
break;
} else {
date.setFullYear(year + 1, 0, 1);
}
}
return changed;
},
weeks: function (date, end, rule) {
var weekStart = rule.weekStart, year, weeks, day, changed = false, hours = date.getHours(), normalize = function (week) {
if (week < 0) {
week = 53 + week;
}
return week;
};
while (date < end) {
weeks = ruleValues(rule.weeks, weekInYear(date, weekStart), normalize);
if (weeks === null) {
return changed;
}
changed = true;
year = date.getFullYear();
if (weeks.length) {
day = weeks.sort(numberSortPredicate)[0] * 7 - 1;
date.setFullYear(year, 0, day);
setDayOfWeek(date, weekStart, -1);
adjustDST(date, hours);
break;
} else {
date.setFullYear(year + 1, 0, 1);
}
}
return changed;
},
weekDays: function (date, end, rule) {
var weekDays = rule.weekDays;
var weekStart = rule.weekStart;
var weekDayRules = ruleWeekValues(weekDays, date, weekStart);
var hours = date.getHours();
var weekDayRule, day;
if (weekDayRules === null) {
return false;
}
weekDayRule = weekDayRules[0];
if (!weekDayRule) {
weekDayRule = weekDays[0];
setDayOfWeek(date, weekStart);
}
day = weekDayRule.day;
if (weekDayRule.offset) {
while (date <= end && !isInWeek(date, weekDayRule, weekStart)) {
if (weekInMonth(date, weekStart) === numberOfWeeks(date, weekStart)) {
date.setMonth(date.getMonth() + 1, 1);
adjustDST(date, hours);
} else {
date.setDate(date.getDate() + 7);
adjustDST(date, hours);
setDayOfWeek(date, weekStart, -1);
}
}
}
if (date.getDay() !== day) {
setDayOfWeek(date, day);
}
return true;
},
hours: function (date, end, rule) {
var hourRules = rule.hours, startTime = rule._startTime, startHours = startTime.getHours(), hours = ruleValues(hourRules, startHours), changed = false;
if (hours !== null) {
changed = true;
date.setHours(startHours);
adjustDST(date, startHours);
if (hours.length) {
hours = hours[0];
date.setHours(hours);
} else {
hours = date.getHours();
date.setDate(date.getDate() + 1);
adjustDST(date, hours);
hours = hourRules[0];
date.setHours(hours);
adjustDST(date, hours);
}
if (rule.minutes) {
date.setMinutes(0);
}
startTime.setHours(hours, date.getMinutes());
}
return changed;
},
minutes: function (date, end, rule) {
var minuteRules = rule.minutes, currentMinutes = date.getMinutes(), minutes = ruleValues(minuteRules, currentMinutes), hours = rule._startTime.getHours(), changed = false;
if (minutes !== null) {
changed = true;
if (minutes.length) {
minutes = minutes[0];
} else {
hours += 1;
minutes = minuteRules[0];
}
if (rule.seconds) {
date.setSeconds(0);
}
date.setHours(hours, minutes);
hours = hours % 24;
adjustDST(date, hours);
rule._startTime.setHours(hours, minutes, date.getSeconds());
}
return changed;
},
seconds: function (date, end, rule) {
var secondRules = rule.seconds, hours = rule._startTime.getHours(), seconds = ruleValues(secondRules, date.getSeconds()), minutes = date.getMinutes(), changed = false;
if (seconds !== null) {
changed = true;
if (seconds.length) {
date.setSeconds(seconds[0]);
} else {
minutes += 1;
date.setMinutes(minutes, secondRules[0]);
if (minutes > 59) {
minutes = minutes % 60;
hours = (hours + 1) % 24;
}
}
rule._startTime.setHours(hours, minutes, date.getSeconds());
}
return changed;
}
}, BaseFrequency = Class.extend({
next: function (date, rule) {
var startTime = rule._startTime, day = startTime.getDate(), minutes, seconds;
if (rule.seconds) {
seconds = date.getSeconds() + 1;
date.setSeconds(seconds);
startTime.setSeconds(seconds);
startTime.setDate(day);
} else if (rule.minutes) {
minutes = date.getMinutes() + 1;
date.setMinutes(minutes);
startTime.setMinutes(minutes);
startTime.setDate(day);
} else {
return false;
}
return true;
},
normalize: function (options) {
var rule = options.rule;
if (options.idx === 4 && rule.hours) {
rule._startTime.setHours(0);
this._hour(options.date, rule);
}
},
limit: function (date, end, rule) {
var interval = rule.interval, ruleName, firstRule, modified, idx, day;
while (date <= end) {
modified = firstRule = undefined;
day = date.getDate();
for (idx = 0; idx < RULE_NAMES_LENGTH; idx++) {
ruleName = RULE_NAMES[idx];
if (rule[ruleName]) {
modified = limitation[ruleName](date, end, rule);
if (firstRule !== undefined && modified) {
break;
} else {
firstRule = modified;
}
}
if (modified) {
this.normalize({
date: date,
rule: rule,
day: day,
idx: idx
});
}
}
if ((interval === 1 || !this.interval(rule, date)) && idx === RULE_NAMES_LENGTH) {
break;
}
}
},
interval: function (rule, current) {
var start = new Date(rule._startPeriod);
var date = new Date(current);
var hours = current.getHours();
var weekStart = rule.weekStart;
var interval = rule.interval;
var frequency = rule.freq;
var modified = false;
var excess = 0;
var month = 0;
var day = 1;
var diff;
var startTimeHours;
if (frequency === 'hourly') {
diff = date.getTimezoneOffset() - start.getTimezoneOffset();
startTimeHours = rule._startTime.getHours();
date = date.getTime();
if (hours !== startTimeHours) {
date += (startTimeHours - hours) * kendoDate.MS_PER_HOUR;
}
date -= start;
if (diff) {
date -= diff * kendoDate.MS_PER_MINUTE;
}
diff = Math.floor(date / kendoDate.MS_PER_HOUR);
excess = intervalExcess(diff, interval);
if (excess !== 0) {
this._hour(current, rule, excess);
modified = true;
}
} else if (frequency === 'daily') {
kendoDate.setTime(date, -start);
diff = Math.floor(date / kendoDate.MS_PER_DAY);
excess = intervalExcess(diff, interval);
if (excess !== 0) {
this._date(current, rule, excess);
modified = true;
}
} else if (frequency === 'weekly') {
diff = (current.getFullYear() - start.getFullYear()) * 52;
excess = weekInYear(current, weekStart) - weekInYear(start, weekStart) + diff;
excess = intervalExcess(excess, interval);
if (excess !== 0) {
kendoDate.setDayOfWeek(current, rule.weekStart, -1);
current.setDate(current.getDate() + excess * 7);
adjustDST(current, hours);
modified = true;
}
} else if (frequency === 'monthly') {
diff = current.getFullYear() - start.getFullYear();
diff = current.getMonth() - start.getMonth() + diff * 12;
excess = intervalExcess(diff, interval);
if (excess !== 0) {
day = rule._hasRuleValue ? 1 : current.getDate();
current.setFullYear(current.getFullYear(), current.getMonth() + excess, day);
adjustDST(current, hours);
modified = true;
}
} else if (frequency === 'yearly') {
diff = current.getFullYear() - start.getFullYear();
excess = intervalExcess(diff, interval);
if (!rule.months) {
month = current.getMonth();
}
if (!rule.yearDays && !rule.monthDays && !rule.weekDays) {
day = current.getDate();
}
if (excess !== 0) {
current.setFullYear(current.getFullYear() + excess, month, day);
adjustDST(current, hours);
modified = true;
}
}
return modified;
},
_hour: function (date, rule, interval) {
var startTime = rule._startTime, hours = startTime.getHours();
if (interval) {
hours += interval;
}
date.setHours(hours);
hours = hours % 24;
startTime.setHours(hours);
adjustDST(date, hours);
},
_date: function (date, rule, interval) {
var hours = date.getHours();
date.setDate(date.getDate() + interval);
if (!adjustDST(date, hours)) {
this._hour(date, rule);
}
}
}), HourlyFrequency = BaseFrequency.extend({
next: function (date, rule) {
if (!BaseFrequency.fn.next(date, rule)) {
this._hour(date, rule, 1);
}
},
normalize: function (options) {
var rule = options.rule;
if (options.idx === 4) {
rule._startTime.setHours(0);
this._hour(options.date, rule);
}
}
}), DailyFrequency = BaseFrequency.extend({
next: function (date, rule) {
if (!BaseFrequency.fn.next(date, rule)) {
this[rule.hours ? '_hour' : '_date'](date, rule, 1);
}
}
}), WeeklyFrequency = DailyFrequency.extend({
setup: function (rule, eventStartDate) {
if (!rule.weekDays) {
rule.weekDays = [{
day: eventStartDate.getDay(),
offset: 0
}];
}
}
}), MonthlyFrequency = BaseFrequency.extend({
next: function (date, rule) {
var day, hours;
if (!BaseFrequency.fn.next(date, rule)) {
if (rule.hours) {
this._hour(date, rule, 1);
} else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
this._date(date, rule, 1);
} else {
day = date.getDate();
hours = date.getHours();
date.setMonth(date.getMonth() + 1);
adjustDST(date, hours);
while (date.getDate() !== day) {
date.setDate(day);
adjustDST(date, hours);
}
this._hour(date, rule);
}
}
},
normalize: function (options) {
var rule = options.rule, date = options.date, hours = date.getHours();
if (options.idx === 0 && !rule.monthDays && !rule.weekDays) {
date.setDate(options.day);
adjustDST(date, hours);
} else {
BaseFrequency.fn.normalize(options);
}
},
setup: function (rule, eventStartDate, date) {
if (!rule.monthDays && !rule.weekDays) {
date.setDate(eventStartDate.getDate());
}
}
}), YearlyFrequency = MonthlyFrequency.extend({
next: function (date, rule) {
var day, hours = date.getHours();
if (!BaseFrequency.fn.next(date, rule)) {
if (rule.hours) {
this._hour(date, rule, 1);
} else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
this._date(date, rule, 1);
} else if (rule.months) {
day = date.getDate();
date.setMonth(date.getMonth() + 1);
adjustDST(date, hours);
while (date.getDate() !== day) {
date.setDate(day);
adjustDST(date, hours);
}
this._hour(date, rule);
} else {
date.setFullYear(date.getFullYear() + 1);
adjustDST(date, hours);
this._hour(date, rule);
}
}
},
setup: function () {
}
}), frequencies = {
'hourly': new HourlyFrequency(),
'daily': new DailyFrequency(),
'weekly': new WeeklyFrequency(),
'monthly': new MonthlyFrequency(),
'yearly': new YearlyFrequency()
}, CLICK = 'click';
function intervalExcess(diff, interval) {
var excess;
if (diff !== 0 && diff < interval) {
excess = interval - diff;
} else {
excess = diff % interval;
if (excess) {
excess = interval - excess;
}
}
return excess;
}
function dayInYear(date) {
var month = date.getMonth();
var days = leapYear(date) ? DAYS_IN_LEAPYEAR[month] : DAYS_IN_YEAR[month];
return days + date.getDate();
}
function weekInYear(date, weekStart) {
var year, days;
date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
adjustDST(date, 0);
year = date.getFullYear();
if (weekStart !== undefined) {
setDayOfWeek(date, weekStart, -1);
date.setDate(date.getDate() + 4);
} else {
date.setDate(date.getDate() + (4 - (date.getDay() || 7)));
}
adjustDST(date, 0);
days = Math.floor((date.getTime() - new Date(year, 0, 1, -6)) / 86400000);
return 1 + Math.floor(days / 7);
}
function weekInMonth(date, weekStart) {
var firstWeekDay = firstDayOfMonth(date).getDay();
var firstWeekLength = 7 - (firstWeekDay + 7 - (weekStart || 7)) || 7;
if (firstWeekLength < 0) {
firstWeekLength += 7;
}
return Math.ceil((date.getDate() - firstWeekLength) / 7) + 1;
}
function normalizeDayIndex(weekDay, weekStart) {
return weekDay + (weekDay < weekStart ? 7 : 0);
}
function normalizeOffset(date, rule, weekStart) {
var offset = rule.offset;
if (!offset) {
return weekInMonth(date, weekStart);
}
var lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
var weeksInMonth = weekInMonth(lastDate, weekStart);
var day = normalizeDayIndex(rule.day, weekStart);
var skipFirst = day < normalizeDayIndex(new Date(date.getFullYear(), date.getMonth(), 1).getDay(), weekStart);
var skipLast = day > normalizeDayIndex(lastDate.getDay(), weekStart);
if (offset < 0) {
offset = weeksInMonth + (offset + 1 - (skipLast ? 1 : 0));
} else if (skipFirst) {
offset += 1;
}
weeksInMonth -= skipLast ? 1 : 0;
if (offset < (skipFirst ? 1 : 0) || offset > weeksInMonth) {
return null;
}
return offset;
}
function numberOfWeeks(date, weekStart) {
return weekInMonth(new Date(date.getFullYear(), date.getMonth() + 1, 0), weekStart);
}
function isInWeek(date, rule, weekStart) {
return weekInMonth(date, weekStart) === normalizeOffset(date, rule, weekStart);
}
function ruleWeekValues(weekDays, date, weekStart) {
var currentDay = normalizeDayIndex(date.getDay(), weekStart);
var length = weekDays.length;
var ruleWeekOffset;
var weekDay, day;
var weekNumber;
var result = [];
var idx = 0;
for (; idx < length; idx++) {
weekDay = weekDays[idx];
weekNumber = weekInMonth(date, weekStart);
ruleWeekOffset = normalizeOffset(date, weekDay, weekStart);
if (ruleWeekOffset === null) {
continue;
}
if (weekNumber < ruleWeekOffset) {
result.push(weekDay);
} else if (weekNumber === ruleWeekOffset) {
day = normalizeDayIndex(weekDay.day, weekStart);
if (currentDay < day) {
result.push(weekDay);
} else if (currentDay === day) {
return null;
}
}
}
return result;
}
function ruleValues(rules, value, normalize) {
var idx = 0, length = rules.length, availableRules = [], ruleValue;
for (; idx < length; idx++) {
ruleValue = rules[idx];
if (normalize) {
ruleValue = normalize(ruleValue);
}
if (value === ruleValue) {
return null;
} else if (value < ruleValue) {
availableRules.push(ruleValue);
}
}
return availableRules;
}
function parseArray(list, range) {
var idx = 0, length = list.length, value;
for (; idx < length; idx++) {
value = parseInt(list[idx], 10);
if (isNaN(value) || value < range.start || value > range.end || value === 0 && range.start < 0) {
return null;
}
list[idx] = value;
}
return list.sort(numberSortPredicate);
}
function parseWeekDayList(list) {
var idx = 0, length = list.length, value, valueLength, day;
for (; idx < length; idx++) {
value = list[idx];
valueLength = value.length;
day = value.substring(valueLength - 2).toUpperCase();
day = WEEK_DAYS_IDX[day];
if (day === undefined) {
return null;
}
list[idx] = {
offset: parseInt(value.substring(0, valueLength - 2), 10) || 0,
day: day
};
}
return list;
}
function serializeWeekDayList(list) {
var idx = 0, length = list.length, value, valueString, result = [];
for (; idx < length; idx++) {
value = list[idx];
if (typeof value === 'string') {
valueString = value;
} else {
valueString = '' + WEEK_DAYS[value.day];
if (value.offset) {
valueString = value.offset + valueString;
}
}
result.push(valueString);
}
return result.toString();
}
function getMonthLength(date) {
var month = date.getMonth();
if (month === 1) {
if (new Date(date.getFullYear(), 1, 29).getMonth() === 1) {
return 29;
}
return 28;
}
return MONTHS[month];
}
function leapYear(year) {
year = year.getFullYear();
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
function numberSortPredicate(a, b) {
return a - b;
}
function parseExceptions(exceptions, zone) {
var idx = 0, length, date, dates = [];
if (exceptions) {
exceptions = exceptions.split(';');
length = exceptions.length;
for (; idx < length; idx++) {
date = parseUTCDate(exceptions[idx], zone);
if (date) {
dates.push(date);
}
}
}
return dates;
}
function isException(exceptions, date, zone) {
var dates = $.isArray(exceptions) ? exceptions : parseExceptions(exceptions, zone), dateTime = date.getTime() - date.getMilliseconds(), idx = 0, length = dates.length;
for (; idx < length; idx++) {
if (dates[idx].getTime() === dateTime) {
return true;
}
}
return false;
}
function toExceptionString(dates, zone) {
var idx = 0;
var length;
var date;
var result = [].concat(dates);
for (length = result.length; idx < length; idx++) {
date = result[idx];
date = kendo.timezone.convert(date, zone || date.getTimezoneOffset(), 'Etc/UTC');
result[idx] = kendo.toString(date, RECURRENCE_DATE_FORMAT);
}
return result.join(';') + ';';
}
function startPeriodByFreq(start, rule) {
var date = new Date(start);
switch (rule.freq) {
case 'yearly':
date.setFullYear(date.getFullYear(), 0, 1);
break;
case 'monthly':
date.setFullYear(date.getFullYear(), date.getMonth(), 1);
break;
case 'weekly':
setDayOfWeek(date, rule.weekStart, -1);
break;
default:
break;
}
if (rule.hours) {
date.setHours(0);
}
if (rule.minutes) {
date.setMinutes(0);
}
if (rule.seconds) {
date.setSeconds(0);
}
return date;
}
function endPeriodByFreq(start, rule) {
var date = new Date(start);
switch (rule.freq) {
case 'yearly':
date.setFullYear(date.getFullYear(), 11, 31);
break;
case 'monthly':
date.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
break;
case 'weekly':
setDayOfWeek(date, rule.weekStart, -1);
date.setDate(date.getDate() + 6);
break;
default:
break;
}
if (rule.hours) {
date.setHours(23);
}
if (rule.minutes) {
date.setMinutes(59);
}
if (rule.seconds) {
date.setSeconds(59);
}
return date;
}
function eventsByPosition(periodEvents, start, positions) {
var periodEventsLength = periodEvents.length;
var events = [];
var position;
var event;
for (var idx = 0, length = positions.length; idx < length; idx++) {
position = positions[idx];
if (position < 0) {
position = periodEventsLength + position;
} else {
position -= 1;
}
event = periodEvents[position];
if (event && event.start >= start) {
events.push(event);
}
}
return events;
}
function removeExceptionDates(periodEvents, exceptionDates, zone) {
var events = [];
var event;
for (var idx = 0; idx < periodEvents.length; idx++) {
event = periodEvents[idx];
if (!isException(exceptionDates, event.start, zone)) {
events.push(event);
}
}
return events;
}
function expand(event, start, end, zone) {
var rule = parseRule(event.recurrenceRule, zone), startTime, endTime, endDate, hours, minutes, seconds, durationMS, startPeriod, inPeriod, ruleStart, ruleEnd, useEventStart, freqName, exceptionDates, eventStartTime, eventStartMS, eventStart, count, freq, positions, currentIdx, periodEvents, events = [];
if (!rule) {
return [event];
}
positions = rule.positions;
currentIdx = positions ? 0 : 1;
ruleStart = rule.start;
ruleEnd = rule.end;
if (ruleStart || ruleEnd) {
event = event.clone({
start: ruleStart ? new Date(ruleStart.value[0]) : undefined,
end: ruleEnd ? new Date(ruleEnd.value[0]) : undefined
});
}
eventStart = event.start;
eventStartMS = eventStart.getTime();
eventStartTime = getMilliseconds(eventStart);
exceptionDates = parseExceptions(event.recurrenceException, zone);
if (!exceptionDates[0] && rule.exdates) {
exceptionDates = rule.exdates.value;
event.set('recurrenceException', toExceptionString(exceptionDates, zone));
}
startPeriod = start = new Date(start);
end = new Date(end);
freqName = rule.freq;
freq = frequencies[freqName];
count = rule.count;
if (rule.until && rule.until < end) {
end = new Date(rule.until);
}
useEventStart = freqName === 'yearly' || freqName === 'monthly' || freqName === 'weekly';
if (start < eventStartMS || count || rule.interval > 1 || useEventStart) {
start = new Date(eventStartMS);
} else {
hours = start.getHours();
minutes = start.getMinutes();
seconds = start.getSeconds();
if (!rule.hours) {
hours = eventStart.getHours();
}
if (!rule.minutes) {
minutes = eventStart.getMinutes();
}
if (!rule.seconds) {
seconds = eventStart.getSeconds();
}
start.setHours(hours, minutes, seconds, eventStart.getMilliseconds());
}
rule._startPeriod = new Date(start);
if (positions) {
start = startPeriodByFreq(start, rule);
end = endPeriodByFreq(end, rule);
var diff = getMilliseconds(end) - getMilliseconds(start);
if (diff < 0) {
hours = start.getHours();
end.setHours(hours, start.getMinutes(), start.getSeconds(), start.getMilliseconds());
kendoDate.adjustDST(end, hours);
}
rule._startPeriod = new Date(start);
rule._endPeriod = endPeriodByFreq(start, rule);
}
durationMS = event.duration();
rule._startTime = startTime = kendoDate.toInvariantTime(start);
if (freq.setup) {
freq.setup(rule, eventStart, start);
}
freq.limit(start, end, rule);
while (start <= end) {
endDate = new Date(start);
setTime(endDate, durationMS);
inPeriod = start >= startPeriod || endDate > startPeriod;
if (inPeriod && !isException(exceptionDates, start, zone) || positions) {
startTime = kendoDate.toUtcTime(kendoDate.getDate(start)) + getMilliseconds(rule._startTime);
endTime = startTime + durationMS;
if (eventStartMS !== start.getTime() || eventStartTime !== getMilliseconds(rule._startTime)) {
events.push(event.toOccurrence({
start: new Date(start),
end: endDate,
_startTime: startTime,
_endTime: endTime
}));
} else {
event._startTime = startTime;
event._endTime = endTime;
events.push(event);
}
}
if (positions) {
freq.next(start, rule);
freq.limit(start, end, rule);
if (start > rule._endPeriod) {
periodEvents = eventsByPosition(events.slice(currentIdx), eventStart, positions);
periodEvents = removeExceptionDates(periodEvents, exceptionDates, zone);
events = events.slice(0, currentIdx).concat(periodEvents);
rule._endPeriod = endPeriodByFreq(start, rule);
currentIdx = events.length;
}
if (count && count === currentIdx) {
break;
}
} else {
if (count && count === currentIdx) {
break;
}
currentIdx += 1;
freq.next(start, rule);
freq.limit(start, end, rule);
}
}
return events;
}
function parseUTCDate(value, zone) {
value = kendo.parseDate(value, DATE_FORMATS);
if (value && zone) {
value = timezone.convert(value, value.getTimezoneOffset(), zone);
}
return value;
}
function parseDateRule(dateRule, zone) {
var pairs = dateRule.split(';');
var pair;
var property;
var value;
var tzid;
var valueIdx, valueLength;
for (var idx = 0, length = pairs.length; idx < length; idx++) {
pair = pairs[idx].split(':');
property = pair[0];
value = pair[1];
if (property.indexOf('TZID') !== -1) {
tzid = property.substring(property.indexOf('TZID')).split('=')[1];
}
if (value) {
value = value.split(',');
for (valueIdx = 0, valueLength = value.length; valueIdx < valueLength; valueIdx++) {
value[valueIdx] = parseUTCDate(value[valueIdx], tzid || zone);
}
}
}
if (value) {
return {
value: value,
tzid: tzid
};
}
}
function parseRule(recur, zone) {
var instance = {};
var splits, value;
var idx = 0, length;
var ruleValue = false;
var rule, part, parts;
var property, weekStart, weekDays;
var predicate = function (a, b) {
var day1 = a.day, day2 = b.day;
if (day1 < weekStart) {
day1 += 7;
}
if (day2 < weekStart) {
day2 += 7;
}
return day1 - day2;
};
if (!recur) {
return null;
}
parts = recur.split('\n');
if (!parts[1] && (recur.indexOf('DTSTART') !== -1 || recur.indexOf('DTEND') !== -1 || recur.indexOf('EXDATE') !== -1)) {
parts = recur.split(' ');
}
for (idx = 0, length = parts.length; idx < length; idx++) {
part = $.trim(parts[idx]);
if (part.indexOf('DTSTART') !== -1) {
instance.start = parseDateRule(part, zone);
} else if (part.indexOf('DTEND') !== -1) {
instance.end = parseDateRule(part, zone);
} else if (part.indexOf('EXDATE') !== -1) {
instance.exdates = parseDateRule(part, zone);
} else if (part.indexOf('RRULE') !== -1) {
rule = part.substring(6);
} else if ($.trim(part)) {
rule = part;
}
}
rule = rule.split(';');
for (idx = 0, length = rule.length; idx < length; idx++) {
property = rule[idx];
splits = property.split('=');
value = $.trim(splits[1]).split(',');
switch ($.trim(splits[0]).toUpperCase()) {
case 'FREQ':
instance.freq = value[0].toLowerCase();
break;
case 'UNTIL':
instance.until = parseUTCDate(value[0], zone);
break;
case 'COUNT':
instance.count = parseInt(value[0], 10);
break;
case 'INTERVAL':
instance.interval = parseInt(value[0], 10);
break;
case 'BYSECOND':
instance.seconds = parseArray(value, {
start: 0,
end: 60
});
ruleValue = true;
break;
case 'BYMINUTE':
instance.minutes = parseArray(value, {
start: 0,
end: 59
});
ruleValue = true;
break;
case 'BYHOUR':
instance.hours = parseArray(value, {
start: 0,
end: 23
});
ruleValue = true;
break;
case 'BYMONTHDAY':
instance.monthDays = parseArray(value, {
start: -31,
end: 31
});
ruleValue = true;
break;
case 'BYYEARDAY':
instance.yearDays = parseArray(value, {
start: -366,
end: 366
});
ruleValue = true;
break;
case 'BYMONTH':
instance.months = parseArray(value, {
start: 1,
end: 12
});
ruleValue = true;
break;
case 'BYDAY':
instance.weekDays = weekDays = parseWeekDayList(value);
ruleValue = true;
break;
case 'BYWEEKNO':
instance.weeks = parseArray(value, {
start: -53,
end: 53
});
ruleValue = true;
break;
case 'BYSETPOS':
instance.positions = parseArray(value, {
start: -366,
end: 366
});
break;
case 'WKST':
instance.weekStart = weekStart = WEEK_DAYS_IDX[value[0]];
break;
}
}
if (instance.freq === undefined || instance.count !== undefined && instance.until) {
return null;
}
if (!instance.interval) {
instance.interval = 1;
}
if (weekStart === undefined) {
instance.weekStart = weekStart = kendo.culture().calendar.firstDay;
}
if (weekDays) {
instance.weekDays = weekDays.sort(predicate);
}
if (instance.positions && !ruleValue) {
instance.positions = null;
}
instance._hasRuleValue = ruleValue;
return instance;
}
function serializeDateRule(dateRule, zone) {
var value = dateRule.value;
var tzid = dateRule.tzid || '';
var length = value.length;
var idx = 0;
var val;
for (; idx < length; idx++) {
val = value[idx];
val = timezone.convert(val, tzid || zone || val.getTimezoneOffset(), 'Etc/UTC');
value[idx] = kendo.toString(val, 'yyyyMMddTHHmmssZ');
}
if (tzid) {
tzid = ';TZID=' + tzid;
}
return tzid + ':' + value.join(',') + ' ';
}
function serialize(rule, zone) {
var weekStart = rule.weekStart;
var ruleString = 'FREQ=' + rule.freq.toUpperCase();
var exdates = rule.exdates || '';
var start = rule.start || '';
var end = rule.end || '';
var until = rule.until;
if (rule.interval > 1) {
ruleString += ';INTERVAL=' + rule.interval;
}
if (rule.count) {
ruleString += ';COUNT=' + rule.count;
}
if (until) {
until = timezone.convert(until, zone || until.getTimezoneOffset(), 'Etc/UTC');
ruleString += ';UNTIL=' + kendo.toString(until, 'yyyyMMddTHHmmssZ');
}
if (rule.months) {
ruleString += ';BYMONTH=' + rule.months;
}
if (rule.weeks) {
ruleString += ';BYWEEKNO=' + rule.weeks;
}
if (rule.yearDays) {
ruleString += ';BYYEARDAY=' + rule.yearDays;
}
if (rule.monthDays) {
ruleString += ';BYMONTHDAY=' + rule.monthDays;
}
if (rule.weekDays) {
ruleString += ';BYDAY=' + serializeWeekDayList(rule.weekDays);
}
if (rule.hours) {
ruleString += ';BYHOUR=' + rule.hours;
}
if (rule.minutes) {
ruleString += ';BYMINUTE=' + rule.minutes;
}
if (rule.seconds) {
ruleString += ';BYSECOND=' + rule.seconds;
}
if (rule.positions) {
ruleString += ';BYSETPOS=' + rule.positions;
}
if (weekStart !== undefined) {
ruleString += ';WKST=' + WEEK_DAYS[weekStart];
}
if (start) {
start = 'DTSTART' + serializeDateRule(start, zone);
}
if (end) {
end = 'DTEND' + serializeDateRule(end, zone);
}
if (exdates) {
exdates = 'EXDATE' + serializeDateRule(exdates, zone);
}
if (start || end || exdates) {
ruleString = start + end + exdates + 'RRULE:' + ruleString;
}
return ruleString;
}
kendo.recurrence = {
rule: {
parse: parseRule,
serialize: serialize
},
expand: expand,
dayInYear: dayInYear,
weekInYear: weekInYear,
weekInMonth: weekInMonth,
numberOfWeeks: numberOfWeeks,
isException: isException,
toExceptionString: toExceptionString
};
var weekDayCheckBoxes = function (firstDay) {
var shortNames = kendo.culture().calendar.days.namesShort, length = shortNames.length, result = '', idx = 0, values = [];
for (; idx < length; idx++) {
values.push(idx);
}
shortNames = shortNames.slice(firstDay).concat(shortNames.slice(0, firstDay));
values = values.slice(firstDay).concat(values.slice(0, firstDay));
for (idx = 0; idx < length; idx++) {
result += '<label class="k-check"><input class="k-recur-weekday-checkbox" type="checkbox" value="' + values[idx] + '" /> ' + shortNames[idx] + '</label>';
}
return result;
};
var RECURRENCE_VIEW_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:messages.repeatEvery#</label></div>' + '<div class="k-edit-field"><input class="k-recur-interval"/>#:messages.interval#</div>' + '# } #' + '# if (frequency === "weekly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">#=weekDayCheckBoxes(firstWeekDay)#</div>' + '# } else if (frequency === "monthly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-month-radio" type="radio" name="month" value="monthday" />#:messages.day#</label>' + '<input class="k-recur-monthday" />' + '</li>' + '<li>' + '<input class="k-recur-month-radio" type="radio" name="month" value="weekday" />' + '<input class="k-recur-weekday-offset" /><input class="k-recur-weekday" />' + '</li>' + '</ul>' + '</div>' + '# } else if (frequency === "yearly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="monthday" />' + '<input class="k-recur-month" /><input class="k-recur-monthday" />' + '</li>' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="weekday" />' + '<input class="k-recur-weekday-offset" /><input class="k-recur-weekday" />#:messages.of#<input class="k-recur-month" />' + '</li>' + '</ul>' + '</div>' + '# } #' + '# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:end.label#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-end-never" type="radio" name="end" value="never" />#:end.never#</label>' + '</li>' + '<li>' + '<label><input class="k-recur-end-count" type="radio" name="end" value="count" />#:end.after#</label>' + '<input class="k-recur-count" />#:end.occurrence#' + '</li>' + '<li>' + '<label><input class="k-recur-end-until" type="radio" name="end" value="until" />#:end.on#</label>' + '<input class="k-recur-until" />' + '</li>' + '</ul>' + '</div>' + '# } #');
var DAY_RULE = [
{
day: 0,
offset: 0
},
{
day: 1,
offset: 0
},
{
day: 2,
offset: 0
},
{
day: 3,
offset: 0
},
{
day: 4,
offset: 0
},
{
day: 5,
offset: 0
},
{
day: 6,
offset: 0
}
];
var WEEKDAY_RULE = [
{
day: 1,
offset: 0
},
{
day: 2,
offset: 0
},
{
day: 3,
offset: 0
},
{
day: 4,
offset: 0
},
{
day: 5,
offset: 0
}
];
var WEEKEND_RULE = [
{
day: 0,
offset: 0
},
{
day: 6,
offset: 0
}
];
var BaseRecurrenceEditor = Widget.extend({
init: function (element, options) {
var start;
var that = this;
var frequencies = options && options.frequencies;
Widget.fn.init.call(that, element, options);
that.wrapper = that.element;
options = that.options;
options.start = start = options.start || kendoDate.today();
if (frequencies) {
options.frequencies = frequencies;
}
if (typeof start === 'string') {
options.start = kendo.parseDate(start, 'yyyyMMddTHHmmss');
}
if (options.firstWeekDay === null) {
options.firstWeekDay = kendo.culture().calendar.firstDay;
}
that._namespace = '.' + options.name;
},
options: {
value: '',
start: '',
timezone: '',
spinners: true,
firstWeekDay: null,
frequencies: [
'never',
'daily',
'weekly',
'monthly',
'yearly'
],
mobile: false,
messages: {
frequencies: {
never: 'Never',
hourly: 'Hourly',
daily: 'Daily',
weekly: 'Weekly',
monthly: 'Monthly',
yearly: 'Yearly'
},
hourly: {
repeatEvery: 'Repeat every: ',
interval: ' hour(s)'
},
daily: {
repeatEvery: 'Repeat every: ',
interval: ' day(s)'
},
weekly: {
interval: ' week(s)',
repeatEvery: 'Repeat every: ',
repeatOn: 'Repeat on: '
},
monthly: {
repeatEvery: 'Repeat every: ',
repeatOn: 'Repeat on: ',
interval: ' month(s)',
day: 'Day '
},
yearly: {
repeatEvery: 'Repeat every: ',
repeatOn: 'Repeat on: ',
interval: ' year(s)',
of: ' of '
},
end: {
label: 'End:',
mobileLabel: 'Ends',
never: 'Never',
after: 'After ',
occurrence: ' occurrence(s)',
on: 'On '
},
offsetPositions: {
first: 'first',
second: 'second',
third: 'third',
fourth: 'fourth',
last: 'last'
},
weekdays: {
day: 'day',
weekday: 'weekday',
weekend: 'weekend day'
}
}
},
events: ['change'],
_initInterval: function () {
var that = this;
var rule = that._value;
that._container.find('.k-recur-interval').kendoNumericTextBox({
spinners: that.options.spinners,
value: rule.interval || 1,
decimals: 0,
format: '#',
min: 1,
change: function () {
rule.interval = this.value();
that._trigger();
}
});
},
_weekDayRule: function (clear) {
var that = this;
var weekday = (that._weekDay.element || that._weekDay).val();
var offset = Number((that._weekDayOffset.element || that._weekDayOffset).val());
var weekDays = null;
var positions = null;
if (!clear) {
if (weekday === 'day') {
weekDays = DAY_RULE;
positions = offset;
} else if (weekday === 'weekday') {
weekDays = WEEKDAY_RULE;
positions = offset;
} else if (weekday === 'weekend') {
weekDays = WEEKEND_RULE;
positions = offset;
} else {
weekDays = [{
offset: offset,
day: Number(weekday)
}];
}
}
that._value.weekDays = weekDays;
that._value.positions = positions;
},
_weekDayView: function () {
var that = this;
var weekDays = that._value.weekDays;
var positions = that._value.positions;
var weekDayOffsetWidget = that._weekDayOffset;
var weekDayOffset;
var weekDayValue;
var length;
var method;
if (weekDays) {
length = weekDays.length;
if (positions) {
if (length === 7) {
weekDayValue = 'day';
weekDayOffset = positions;
} else if (length === 5) {
weekDayValue = 'weekday';
weekDayOffset = positions;
} else if (length === 2) {
weekDayValue = 'weekend';
weekDayOffset = positions;
}
}
if (!weekDayValue) {
weekDays = weekDays[0];
weekDayValue = weekDays.day;
weekDayOffset = weekDays.offset || '';
}
method = weekDayOffsetWidget.value ? 'value' : 'val';
weekDayOffsetWidget[method](weekDayOffset);
that._weekDay[method](weekDayValue);
}
},
_initWeekDay: function () {
var that = this, data;
var weekdayMessage = that.options.messages.weekdays;
var offsetMessage = that.options.messages.offsetPositions;
var weekDayInput = that._container.find('.k-recur-weekday');
var change = function () {
that._weekDayRule();
that._trigger();
};
if (weekDayInput[0]) {
that._weekDayOffset = new DropDownList(that._container.find('.k-recur-weekday-offset'), {
change: change,
dataTextField: 'text',
dataValueField: 'value',
dataSource: [
{
text: offsetMessage.first,
value: '1'
},
{
text: offsetMessage.second,
value: '2'
},
{
text: offsetMessage.third,
value: '3'
},
{
text: offsetMessage.fourth,
value: '4'
},
{
text: offsetMessage.last,
value: '-1'
}
]
});
data = [
{
text: weekdayMessage.day,
value: 'day'
},
{
text: weekdayMessage.weekday,
value: 'weekday'
},
{
text: weekdayMessage.weekend,
value: 'weekend'
}
];
that._weekDay = new DropDownList(weekDayInput, {
value: that.options.start.getDay(),
change: change,
dataTextField: 'text',
dataValueField: 'value',
dataSource: data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
return {
text: dayName,
value: idx
};
}))
});
that._weekDayView();
}
},
_initWeekDays: function () {
var that = this;
var rule = that._value;
var weekDays = that._container.find('.k-recur-weekday-checkbox');
if (weekDays[0]) {
weekDays.on(CLICK + that._namespace, function () {
rule.weekDays = $.map(weekDays.filter(':checked'), function (checkbox) {
return {
day: Number(checkbox.value),
offset: 0
};
});
if (!that.options.mobile) {
that._trigger();
}
});
if (rule.weekDays) {
var idx, weekDay;
var i = 0, l = weekDays.length;
var length = rule.weekDays.length;
for (; i < l; i++) {
weekDay = weekDays[i];
for (idx = 0; idx < length; idx++) {
if (weekDay.value == rule.weekDays[idx].day) {
weekDay.checked = true;
}
}
}
}
}
},
_initMonthDay: function () {
var that = this;
var rule = that._value;
var monthDayInput = that._container.find('.k-recur-monthday');
if (monthDayInput[0]) {
that._monthDay = new kendo.ui.NumericTextBox(monthDayInput, {
spinners: that.options.spinners,
min: 1,
max: 31,
decimals: 0,
format: '#',
value: rule.monthDays ? rule.monthDays[0] : that.options.start.getDate(),
change: function () {
var value = this.value();
rule.monthDays = value ? [value] : value;
that._trigger();
}
});
}
},
_initCount: function () {
var that = this, input = that._container.find('.k-recur-count'), rule = that._value;
that._count = input.kendoNumericTextBox({
spinners: that.options.spinners,
value: rule.count || 1,
decimals: 0,
format: '#',
min: 1,
change: function () {
rule.count = this.value();
that._trigger();
}
}).data('kendoNumericTextBox');
},
_initUntil: function () {
var that = this, input = that._container.find('.k-recur-until'), start = that.options.start, rule = that._value, until = rule.until;
that._until = input.kendoDatePicker({
min: until && until < start ? until : start,
value: until || new Date(start.getFullYear(), start.getMonth(), start.getDate(), 23, 59, 59),
change: function () {
var date = this.value();
rule.until = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
that._trigger();
}
}).data('kendoDatePicker');
},
_trigger: function () {
if (!this.options.mobile) {
this.trigger('change');
}
}
});
var RecurrenceEditor = BaseRecurrenceEditor.extend({
init: function (element, options) {
var that = this;
BaseRecurrenceEditor.fn.init.call(that, element, options);
that._initFrequency();
that._initContainer();
that.value(that.options.value);
},
options: { name: 'RecurrenceEditor' },
events: ['change'],
destroy: function () {
var that = this;
that._frequency.destroy();
that._container.find('input[type=radio],input[type=checkbox]').off(CLICK + that._namespace);
kendo.destroy(that._container);
BaseRecurrenceEditor.fn.destroy.call(that);
},
value: function (value) {
var that = this;
var timezone = that.options.timezone;
var freq;
if (value === undefined) {
if (!that._value.freq) {
return '';
}
return serialize(that._value, timezone);
}
that._value = parseRule(value, timezone) || {};
freq = that._value.freq;
if (freq) {
that._frequency.value(freq);
} else {
that._frequency.select(0);
}
that._initView(that._frequency.value());
},
_initContainer: function () {
var element = this.element, container = $('<div class="k-recur-view" />'), editContainer = element.parent('.k-edit-field');
if (editContainer[0]) {
container.insertAfter(editContainer);
} else {
element.append(container);
}
this._container = container;
},
_initFrequency: function () {
var that = this, options = that.options, frequencies = options.frequencies, messages = options.messages.frequencies, ddl = $('<input />'), frequency;
frequencies = $.map(frequencies, function (frequency) {
return {
text: messages[frequency],
value: frequency
};
});
frequency = frequencies[0];
if (frequency && frequency.value === 'never') {
frequency.value = '';
}
that.element.append(ddl);
that._frequency = new DropDownList(ddl, {
dataTextField: 'text',
dataValueField: 'value',
dataSource: frequencies,
change: function () {
that._value = {};
that._initView(that._frequency.value());
that.trigger('change');
}
});
},
_initView: function (frequency) {
var that = this;
var rule = that._value;
var options = that.options;
var data = {
frequency: frequency || 'never',
weekDayCheckBoxes: weekDayCheckBoxes,
firstWeekDay: options.firstWeekDay,
messages: options.messages[frequency],
end: options.messages.end
};
kendo.destroy(that._container);
that._container.html(RECURRENCE_VIEW_TEMPLATE(data));
if (!frequency) {
that._value = {};
return;
}
rule.freq = frequency;
if (frequency === 'weekly' && !rule.weekDays) {
rule.weekDays = [{
day: options.start.getDay(),
offset: 0
}];
}
that._initInterval();
that._initWeekDays();
that._initMonthDay();
that._initWeekDay();
that._initMonth();
that._initCount();
that._initUntil();
that._period();
that._end();
},
_initMonth: function () {
var that = this;
var rule = that._value;
var month = rule.months || [that.options.start.getMonth() + 1];
var monthInputs = that._container.find('.k-recur-month');
var options;
if (monthInputs[0]) {
options = {
change: function () {
rule.months = [Number(this.value())];
that.trigger('change');
},
dataTextField: 'text',
dataValueField: 'value',
dataSource: $.map(kendo.culture().calendar.months.names, function (monthName, idx) {
return {
text: monthName,
value: idx + 1
};
})
};
that._month1 = new DropDownList(monthInputs[0], options);
that._month2 = new DropDownList(monthInputs[1], options);
if (month) {
month = month[0];
that._month1.value(month);
that._month2.value(month);
}
}
},
_end: function () {
var that = this;
var rule = that._value;
var container = that._container;
var namespace = that._namespace;
var click = function (e) {
that._toggleEnd(e.currentTarget.value);
that.trigger('change');
};
var endRule;
that._buttonNever = container.find('.k-recur-end-never').on(CLICK + namespace, click);
that._buttonCount = container.find('.k-recur-end-count').on(CLICK + namespace, click);
that._buttonUntil = container.find('.k-recur-end-until').on(CLICK + namespace, click);
if (rule.count) {
endRule = 'count';
} else if (rule.until) {
endRule = 'until';
}
that._toggleEnd(endRule);
},
_period: function () {
var that = this;
var rule = that._value;
var monthly = rule.freq === 'monthly';
var toggleRule = monthly ? that._toggleMonthDay : that._toggleYear;
var selector = '.k-recur-' + (monthly ? 'month' : 'year') + '-radio';
var radioButtons = that._container.find(selector);
if (!monthly && rule.freq !== 'yearly') {
return;
}
radioButtons.on(CLICK + that._namespace, function (e) {
toggleRule.call(that, e.currentTarget.value);
that.trigger('change');
});
that._buttonMonthDay = radioButtons.eq(0);
that._buttonWeekDay = radioButtons.eq(1);
toggleRule.call(that, rule.weekDays ? 'weekday' : 'monthday');
},
_toggleEnd: function (endRule) {
var that = this;
var count, until;
var enableCount, enableUntil;
if (endRule === 'count') {
that._buttonCount.prop('checked', true);
enableCount = true;
enableUntil = false;
count = that._count.value();
until = null;
} else if (endRule === 'until') {
that._buttonUntil.prop('checked', true);
enableCount = false;
enableUntil = true;
count = null;
until = that._until.value();
} else {
that._buttonNever.prop('checked', true);
enableCount = enableUntil = false;
count = until = null;
}
that._count.enable(enableCount);
that._until.enable(enableUntil);
that._value.count = count;
that._value.until = until;
},
_toggleMonthDay: function (monthRule) {
var that = this;
var enableMonthDay = false;
var enableWeekDay = true;
var clear = false;
var monthDays;
if (monthRule === 'monthday') {
that._buttonMonthDay.prop('checked', true);
monthDays = [that._monthDay.value()];
enableMonthDay = true;
enableWeekDay = false;
clear = true;
} else {
that._buttonWeekDay.prop('checked', true);
monthDays = null;
}
that._weekDay.enable(enableWeekDay);
that._weekDayOffset.enable(enableWeekDay);
that._monthDay.enable(enableMonthDay);
that._value.monthDays = monthDays;
that._weekDayRule(clear);
},
_toggleYear: function (yearRule) {
var that = this;
var enableMonth1 = false;
var enableMonth2 = true;
var month;
if (yearRule === 'monthday') {
enableMonth1 = true;
enableMonth2 = false;
month = that._month1.value();
} else {
month = that._month2.value();
}
that._month1.enable(enableMonth1);
that._month2.enable(enableMonth2);
that._value.months = [month];
that._toggleMonthDay(yearRule);
}
});
ui.plugin(RecurrenceEditor);
var RECURRENCE_HEADER_TEMPLATE = kendo.template('<div class="k-edit-label"><label>#:headerTitle#</label></div>' + '<div class="k-edit-field k-recur-pattern k-scheduler-toolbar"></div>' + '<div class="k-recur-view"></div>');
var RECURRENCE_REPEAT_PATTERN_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:messages.repeatEvery#</label></div>' + '<div class="k-edit-field"><input class="k-recur-interval" pattern="\\\\d*"/>#:messages.interval#</div>' + '# } #' + '# if (frequency === "weekly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">#=weekDayCheckBoxes(firstWeekDay)#</div>' + '# } else if (frequency === "monthly") { #' + '<div class="k-edit-label"><label>#:messages.repeatBy#</label></div>' + '<div class="k-edit-field k-scheduler-toolbar k-repeat-rule"></div>' + '<div class="k-monthday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><input class="k-recur-monthday" pattern="\\\\d*"/></div>' + '</div>' + '<div class="k-weekday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.every#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday-offset"></select></div>' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday"></select></div>' + '</div>' + '# } else if (frequency === "yearly") { #' + '<div class="k-edit-label"><label>#:messages.repeatBy#</label></div>' + '<div class="k-edit-field k-scheduler-toolbar k-repeat-rule"></div>' + '<div class="k-monthday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><input class="k-recur-monthday" pattern="\\\\d*"/></div>' + '</div>' + '<div class="k-weekday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.every#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday-offset"></select></div>' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday"></select></div>' + '</div>' + '<div class="k-edit-label"><label>#:messages.month#</label></div>' + '<div class="k-edit-field"><select class="k-recur-month"></select></div>' + '# } #');
var RECURRENCE_END_PATTERN_TEMPLATE = kendo.template('# if (endPattern === "count") { #' + '<div class="k-edit-label"><label>#:messages.after#</label></div>' + '<div class="k-edit-field"><input class="k-recur-count" pattern="\\\\d*" /></div>' + '# } else if (endPattern === "until") { #' + '<div class="k-edit-label"><label>#:messages.on#</label></div>' + '<div class="k-edit-field"><input type="date" class="k-recur-until" /></div>' + '# } #');
var RECURRENCE_GROUP_BUTTON_TEMPLATE = kendo.template('<ul class="k-reset k-header k-scheduler-navigation">' + '#for (var i = 0, length = dataSource.length; i < length; i++) {#' + '<li class="k-state-default #= value === dataSource[i].value ? "k-state-selected" : "" #">' + '<a role="button" href="\\#" class="k-link" data-#=ns#value="#=dataSource[i].value#">#:dataSource[i].text#</a>' + '</li>' + '#}#' + '</ul>');
var MobileRecurrenceEditor = BaseRecurrenceEditor.extend({
init: function (element, options) {
var that = this;
BaseRecurrenceEditor.fn.init.call(that, element, options);
options = that.options;
that._optionTemplate = kendo.template('<option value="#:value#">#:text#</option>');
that.value(options.value);
that._pane = options.pane;
that._initRepeatButton();
that._initRepeatEnd();
that._defaultValue = that._value;
},
options: {
name: 'MobileRecurrenceEditor',
animations: {
left: 'slide',
right: 'slide:right'
},
mobile: true,
messages: {
cancel: 'Cancel',
update: 'Save',
endTitle: 'Repeat ends',
repeatTitle: 'Repeat pattern',
headerTitle: 'Repeat event',
end: {
patterns: {
never: 'Never',
after: 'After...',
on: 'On...'
},
never: 'Never',
after: 'End repeat after',
on: 'End repeat on'
},
daily: { interval: '' },
hourly: { interval: '' },
weekly: { interval: '' },
monthly: {
interval: '',
repeatBy: 'Repeat by: ',
dayOfMonth: 'Day of the month',
dayOfWeek: 'Day of the week',
repeatEvery: 'Repeat every',
every: 'Every',
day: 'Day '
},
yearly: {
interval: '',
repeatBy: 'Repeat by: ',
dayOfMonth: 'Day of the month',
dayOfWeek: 'Day of the week',
repeatEvery: 'Repeat every: ',
every: 'Every',
month: 'Month',
day: 'Day'
}
}
},
events: ['change'],
value: function (value) {
var that = this;
var timezone = that.options.timezone;
if (value === undefined) {
if (!that._value.freq) {
return '';
}
return serialize(that._value, timezone);
}
that._value = parseRule(value, timezone) || {};
},
destroy: function () {
this._destroyView();
kendo.destroy(this._endFields);
this._repeatButton.off(CLICK + this._namespace);
BaseRecurrenceEditor.fn.destroy.call(this);
},
_initRepeatButton: function () {
var that = this;
var freq = that.options.messages.frequencies[this._value.freq || 'never'];
that._repeatButton = $('<a href="#" class="k-button k-scheduler-recur">' + freq + '</a>').on(CLICK + that._namespace, function (e) {
e.preventDefault();
that._createView('repeat');
that._pane.navigate('recurrence', that.options.animations.left);
});
that.element.append(that._repeatButton);
},
_initRepeatEnd: function () {
var that = this;
var endLabelField = $('<div class="k-edit-label"><label>' + that.options.messages.end.mobileLabel + '</label></div>').insertAfter(that.element.parent('.k-edit-field'));
var endEditField = $('<div class="k-edit-field"><a href="#" class="k-button k-scheduler-recur-end"></a></div>').on(CLICK + that._namespace, function (e) {
e.preventDefault();
if (!that._value.freq) {
return;
}
that._createView('end');
that._pane.navigate('recurrence', that.options.animations.left);
}).insertAfter(endLabelField);
that._endFields = endLabelField.add(endEditField).toggleClass('k-state-disabled', !that._value.freq);
that._endButton = endEditField.find('.k-scheduler-recur-end').text(that._endText());
},
_endText: function () {
var rule = this._value;
var messages = this.options.messages.end;
var text = messages.never;
if (rule.count) {
text = kendo.format('{0} {1}', messages.after, rule.count);
} else if (rule.until) {
text = kendo.format('{0} {1:d}', messages.on, rule.until);
}
return text;
},
_initFrequency: function () {
var that = this;
var frequencyMessages = that.options.messages.frequencies;
var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
dataSource: $.map(this.options.frequencies, function (frequency) {
return {
text: frequencyMessages[frequency],
value: frequency !== 'never' ? frequency : ''
};
}),
value: that._value.freq || '',
ns: kendo.ns
});
that._view.element.find('.k-recur-pattern').append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
var li = $(this);
e.preventDefault();
li.addClass('k-state-selected').siblings().removeClass('k-state-selected');
that._value = { freq: li.children('a').attr(kendo.attr('value')) };
that._initRepeatView();
});
},
_initEndNavigation: function () {
var that = this;
var endMessages = that.options.messages.end.patterns;
var rule = that._value;
var value = '';
if (rule.count) {
value = 'count';
} else if (rule.until) {
value = 'until';
}
var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
dataSource: [
{
text: endMessages.never,
value: ''
},
{
text: endMessages.after,
value: 'count'
},
{
text: endMessages.on,
value: 'until'
}
],
value: value,
ns: kendo.ns
});
that._view.element.find('.k-recur-pattern').append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
var li = $(this);
var count = null;
var until = null;
e.preventDefault();
li.addClass('k-state-selected').siblings().removeClass('k-state-selected');
that._initEndView(li.children('a').attr(kendo.attr('value')));
if (that._count) {
count = that._count.value();
until = null;
} else if (that._until) {
count = null;
until = that._until.val ? kendo.parseDate(that._until.val(), 'yyyy-MM-dd') : that._until.value();
}
rule.count = count;
rule.until = until;
});
},
_createView: function (viewType) {
var that = this;
var options = that.options;
var messages = options.messages;
var headerTitle = messages[viewType === 'repeat' ? 'repeatTitle' : 'endTitle'];
var html = '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list" id="recurrence">' + '<div data-role="header" class="k-header">' + '<a href="#" class="k-button k-scheduler-cancel">' + messages.cancel + '</a>' + messages.headerTitle + '<a href="#" class="k-button k-scheduler-update">' + messages.update + '</a>' + '</div>';
var returnViewId = that._pane.view().id;
that._view = that._pane.append(html + RECURRENCE_HEADER_TEMPLATE({ headerTitle: headerTitle }));
that._view.element.on(CLICK + that._namespace, 'a.k-scheduler-cancel, a.k-scheduler-update', function (e) {
e.preventDefault();
e.stopPropagation();
if ($(this).hasClass('k-scheduler-update')) {
that.trigger('change');
that._defaultValue = $.extend({}, that._value);
} else {
that._value = that._defaultValue;
}
var frequency = that._value.freq;
that._endButton.text(that._endText());
that._endFields.toggleClass('k-state-disabled', !frequency);
that._repeatButton.text(messages.frequencies[frequency || 'never']);
that._pane.one('viewShow', function () {
that._destroyView();
});
that._pane.navigate(returnViewId, that.options.animations.right);
});
that._container = that._view.element.find('.k-recur-view');
if (viewType === 'repeat') {
that._initFrequency();
that._initRepeatView();
} else {
that._initEndNavigation();
that._initEndView();
}
},
_destroyView: function () {
if (this._view) {
this._view.destroy();
this._view.element.remove();
}
this._view = null;
},
_initRepeatView: function () {
var that = this;
var frequency = that._value.freq || 'never';
var data = {
frequency: frequency,
weekDayCheckBoxes: weekDayCheckBoxes,
firstWeekDay: that.options.firstWeekDay,
messages: that.options.messages[frequency]
};
var html = RECURRENCE_REPEAT_PATTERN_TEMPLATE(data);
var container = that._container;
var rule = that._value;
kendo.destroy(container);
container.html(html);
if (!html) {
that._value = {};
return;
}
if (frequency === 'weekly' && !rule.weekDays) {
rule.weekDays = [{
day: that.options.start.getDay(),
offset: 0
}];
}
that._initInterval();
that._initMonthDay();
that._initWeekDays();
that._initWeekDay();
that._initMonth();
that._period();
},
_initEndView: function (endPattern) {
var that = this;
var rule = that._value;
if (endPattern === undefined) {
if (rule.count) {
endPattern = 'count';
} else if (rule.until) {
endPattern = 'until';
}
}
var data = {
endPattern: endPattern,
messages: that.options.messages.end
};
kendo.destroy(that._container);
that._container.html(RECURRENCE_END_PATTERN_TEMPLATE(data));
that._initCount();
that._initUntil();
},
_initWeekDay: function () {
var that = this, data;
var weekdayMessage = that.options.messages.weekdays;
var offsetMessage = that.options.messages.offsetPositions;
var weekDaySelect = that._container.find('.k-recur-weekday');
var change = function () {
that._weekDayRule();
that.trigger('change');
};
if (weekDaySelect[0]) {
that._weekDayOffset = that._container.find('.k-recur-weekday-offset').html(that._options([
{
text: offsetMessage.first,
value: '1'
},
{
text: offsetMessage.second,
value: '2'
},
{
text: offsetMessage.third,
value: '3'
},
{
text: offsetMessage.fourth,
value: '4'
},
{
text: offsetMessage.last,
value: '-1'
}
])).change(change);
data = [
{
text: weekdayMessage.day,
value: 'day'
},
{
text: weekdayMessage.weekday,
value: 'weekday'
},
{
text: weekdayMessage.weekend,
value: 'weekend'
}
];
data = data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
return {
text: dayName,
value: idx
};
}));
that._weekDay = weekDaySelect.html(that._options(data)).change(change).val(that.options.start.getDay());
that._weekDayView();
}
},
_initMonth: function () {
var that = this;
var rule = that._value;
var start = that.options.start;
var month = rule.months || [start.getMonth() + 1];
var monthSelect = that._container.find('.k-recur-month');
var monthNames = kendo.culture().calendar.months.names;
if (monthSelect[0]) {
var data = $.map(monthNames, function (monthName, idx) {
return {
text: monthName,
value: idx + 1
};
});
monthSelect.html(that._options(data)).change(function () {
rule.months = [Number(this.value)];
});
that._monthSelect = monthSelect;
if (month) {
monthSelect.val(month[0]);
}
}
},
_period: function () {
var that = this;
var rule = that._value;
var container = that._container;
var messages = that.options.messages[rule.freq];
var repeatRuleGroupButton = container.find('.k-repeat-rule');
var weekDayView = container.find('.k-weekday-view');
var monthDayView = container.find('.k-monthday-view');
if (repeatRuleGroupButton[0]) {
var currentValue = rule.weekDays ? 'weekday' : 'monthday';
var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
value: currentValue,
dataSource: [
{
text: messages.dayOfMonth,
value: 'monthday'
},
{
text: messages.dayOfWeek,
value: 'weekday'
}
],
ns: kendo.ns
});
var init = function (val) {
var weekDayName = that._weekDay.val();
var weekDayOffset = that._weekDayOffset.val();
var monthDay = that._monthDay.value();
var month = that._monthSelect ? that._monthSelect.val() : null;
if (val === 'monthday') {
rule.weekDays = null;
rule.monthDays = monthDay ? [monthDay] : monthDay;
rule.months = month ? [Number(month)] : month;
weekDayView.hide();
monthDayView.show();
} else {
rule.monthDays = null;
rule.months = month ? [Number(month)] : month;
rule.weekDays = [{
offset: Number(weekDayOffset),
day: Number(weekDayName)
}];
weekDayView.show();
monthDayView.hide();
}
};
repeatRuleGroupButton.append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
var li = $(this).addClass('k-state-selected');
e.preventDefault();
li.siblings().removeClass('k-state-selected');
var value = li.children('a').attr(kendo.attr('value'));
init(value);
});
init(currentValue);
}
},
_initUntil: function () {
var that = this;
var input = that._container.find('.k-recur-until');
var start = that.options.start;
var rule = that._value;
var until = rule.until;
var min = until && until < start ? until : start;
if (kendo.support.input.date) {
that._until = input.attr('min', kendo.toString(min, 'yyyy-MM-dd')).val(kendo.toString(until || start, 'yyyy-MM-dd')).on('change', function () {
rule.until = kendo.parseDate(this.value, 'yyyy-MM-dd');
});
} else {
that._until = input.kendoDatePicker({
min: min,
value: until || start,
change: function () {
rule.until = this.value();
}
}).data('kendoDatePicker');
}
},
_options: function (data, optionLabel) {
var idx = 0;
var html = '';
var length = data.length;
var template = this._optionTemplate;
if (optionLabel) {
html += template({
value: '',
text: optionLabel
});
}
for (; idx < length; idx++) {
html += template(data[idx]);
}
return html;
}
});
ui.plugin(MobileRecurrenceEditor);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));