@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,509 lines (1,204 loc) • 109 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ({
/***/ 0:
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1303);
/***/ }),
/***/ 3:
/***/ (function(module, exports) {
module.exports = function() { throw new Error("define cannot be used indirect"); };
/***/ }),
/***/ 1010:
/***/ (function(module, exports) {
module.exports = require("./kendo.dropdownlist");
/***/ }),
/***/ 1122:
/***/ (function(module, exports) {
module.exports = require("./kendo.datepicker");
/***/ }),
/***/ 1139:
/***/ (function(module, exports) {
module.exports = require("./kendo.numerictextbox");
/***/ }),
/***/ 1303:
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function(f, define){
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(1010), __webpack_require__(1122), __webpack_require__(1139) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(function(){
var __meta__ = { // jshint ignore:line
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, 31, 30, 31, 30, 31, 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 + 1;
}
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, true);
diff = Math.round(date / kendoDate.MS_PER_DAY);
excess = intervalExcess(diff, interval);
if (excess !== 0) {
this._date(current, rule, excess);
modified = true;
}
} else if (frequency === "weekly") {
excess = this._getNumberOfWeeksBetweenDates(start, current);
var normalizedCurrentIndex = normalizeDayIndex(current.getDay(), weekStart);
var normalizedStartIndex = normalizeDayIndex(start.getDay(), weekStart);
if (normalizedCurrentIndex < normalizedStartIndex) {
excess += 1;
}
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;
},
_getNumberOfWeeksBetweenDates: function(first, second){
var weeks = (second - first) / 604800000;
var exactWeeks = Math.floor(weeks);
//this is happening when weeks pass DST change
if (weeks - exactWeeks > 0.99) {
exactWeeks = Math.round(weeks);
}
return exactWeeks;
},
_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",
CHANGE = "change";
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(exceptions.indexOf(";") !== -1 ? ";" : ",");
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; //convert to zero based index
}
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 = [],
shiftedStart,
shiftedEnd,
shiftedStartTime,
shifterEndTime;
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 ||
((freqName === "daily" || freqName === "hourly") && !rule.seconds)) {
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)) {
if(!event.isAllDay){
var startZone = event.startTimezone || event.endTimezone;
var endZone = event.endTimezone || event.startTimezone;
if((zone && startZone) || (!zone && !startZone)){
var startOffsetDiff = getZoneOffset(start, zone) - getZoneOffset(event.start, zone);
var endOffsetDiff = getZoneOffset(endDate, zone) - getZoneOffset(event.end, zone);
var startTZOffsetDiff = getZoneOffset(start, startZone) - getZoneOffset(event.start, startZone);
var endTZOffsetDiff = getZoneOffset(endDate, endZone) - getZoneOffset(event.end, endZone);
if(startOffsetDiff !== startTZOffsetDiff){
var offsetTicksStart = (startOffsetDiff - startTZOffsetDiff) * 60000;
shiftedStart = new Date(start.getTime() - offsetTicksStart);
shiftedStartTime = startTime - offsetTicksStart;
}
if(endOffsetDiff !== endTZOffsetDiff){
var offsetTicksEnd = (endOffsetDiff - endTZOffsetDiff) * 60000;
shiftedEnd = new Date(endDate.getTime() - offsetTicksEnd);
shifterEndTime = endTime - offsetTicksEnd;
}
}
}
events.push(event.toOccurrence({
start: shiftedStart || new Date(start),
end: shiftedEnd || endDate,
_startTime: shiftedStartTime || startTime,
_endTime: shifterEndTime || endTime
}));
shiftedStart = shiftedEnd = shiftedStartTime = shifterEndTime = null;
} 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;
var isMissingDSTHour = isDSTMissingHour(start);
freq.next(start, rule);
if(isMissingDSTHour && rule.freq!=="hourly" && kendoDate.toInvariantTime(event.start).getTime() !== kendoDate.toInvariantTime(start).getTime()){
rule._startTime = startTime = new Date(start.getTime() - 3600000);
}
freq.limit(start, end, rule);
}
}
return events;
}
function isDSTMissingHour(date){
var dateOffset = date.getTimezoneOffset();
var dateMinusHour = new Date(date.getTime() - 3600000);
var dateMinusHourOffset = dateMinusHour.getTimezoneOffset();
return dateOffset < dateMinusHourOffset;
}
function getZoneOffset(date, zone) {
return zone ? kendo.timezone.offset(date, zone): date.getTimezoneOffset();
}
function parseUTCDate(value, zone) {
value = kendo.parseDate(value, DATE_FORMATS); //Parse UTC to local time
if (value && zone) {
value = timezone.apply(value, 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) {