/** * Kendo UI v2016.1.112 (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 normalizeEventsByPosition(events, start, rule) { var periodEvents = events.slice(rule._startIdx); var periodEventsLength = periodEvents.length; var positions = rule.positions; var list = []; 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) { list.push(event); } } events = events.slice(0, rule._startIdx).concat(list); rule._startIdx = events.length; 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, current, events = []; if (!rule) { return [event]; } positions = rule.positions; current = 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); rule._startIdx = 0; } 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) { events = normalizeEventsByPosition(events, eventStart, rule); rule._endPeriod = endPeriodByFreq(start, rule); current = events.length; } if (count && count === current) { break; } } else { if (count && count === current) { break; } current++; 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 += ''; } return result; }; var RECURRENCE_VIEW_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '
' + '
#:messages.interval#
' + '# } #' + '# if (frequency === "weekly") { #' + '
' + '
#=weekDayCheckBoxes(firstWeekDay)#
' + '# } else if (frequency === "monthly") { #' + '
' + '
' + '' + '
' + '# } else if (frequency === "yearly") { #' + '
' + '
' + '' + '
' + '# } #' + '# if (frequency !== "never") { #' + '
' + '
' + '' + '
' + '# } #'); 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 = $('
'), 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 = $(''), 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('
' + '
' + '
'); var RECURRENCE_REPEAT_PATTERN_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '
' + '
#:messages.interval#
' + '# } #' + '# if (frequency === "weekly") { #' + '
' + '
#=weekDayCheckBoxes(firstWeekDay)#
' + '# } else if (frequency === "monthly") { #' + '
' + '
' + '' + '' + '# } else if (frequency === "yearly") { #' + '
' + '
' + '' + '' + '
' + '
' + '# } #'); var RECURRENCE_END_PATTERN_TEMPLATE = kendo.template('# if (endPattern === "count") { #' + '
' + '
' + '# } else if (endPattern === "until") { #' + '
' + '
' + '# } #'); var RECURRENCE_GROUP_BUTTON_TEMPLATE = kendo.template(''); 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(''); 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 = $('' + freq + '').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 = $('
').insertAfter(that.element.parent('.k-edit-field')); var endEditField = $('
').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 = '
' + '
' + '' + messages.cancel + '' + messages.headerTitle + '' + messages.update + '' + '
'; 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)(); }));