@syncfusion/ej2-schedule
Version:
Flexible scheduling library with more built-in features and enhanced customization options similar to outlook and google calendar, allowing the users to plan and manage their appointments with efficient data-binding support.
1,093 lines • 69.1 kB
JavaScript
/* eslint-disable max-len */
import { isNullOrUndefined, getDefaultDateObject, getValue, cldrData } from '@syncfusion/ej2-base';
import { MS_PER_DAY, addDays, resetTime, capitalizeFirstWord } from '../schedule/base/util';
import { Islamic, Gregorian } from '../common/calendar-util';
import { Timezone } from '../schedule/timezone/timezone';
/**
* Date Generator from Recurrence Rule
*/
/**
* Generate Summary from Recurrence Rule
*
* @param {string} rule Accepts the Recurrence rule
* @param {L10n} localeObject Accepts the locale object
* @param {string} locale Accepts the locale name
* @param {CalendarType} calendarType Accepts the calendar type
* @returns {string} Returns the summary string from given recurrence rule
*/
export function generateSummary(rule, localeObject, locale, calendarType) {
if (calendarType === void 0) { calendarType = 'Gregorian'; }
var ruleObject = extractObjectFromRule(rule);
var summary = localeObject.getConstant(EVERY) + ' ';
var cldrObj;
var cldrObj1;
var calendarMode = calendarType.toLowerCase();
if (locale === 'en' || locale === 'en-US') {
var nameSpace1 = 'months.stand-alone.abbreviated';
var nameSpace = 'days.stand-alone.abbreviated';
cldrObj1 = (getValue(nameSpace1, getDefaultDateObject(calendarMode)));
cldrObj = (getValue(nameSpace, getDefaultDateObject(calendarMode)));
}
else {
var nameSpace1 = 'main.' + locale + '.dates.calendars.' + calendarMode + '.months.stand-alone.abbreviated';
var nameSpace = 'main.' + locale + '.dates.calendars.' + calendarMode + '.days.stand-alone.abbreviated';
cldrObj1 =
(getValue(nameSpace1, cldrData));
cldrObj =
(getValue(nameSpace, cldrData));
}
if (ruleObject.interval > 1) {
summary += ruleObject.interval + ' ';
}
switch (ruleObject.freq) {
case 'DAILY':
summary += localeObject.getConstant(DAYS);
break;
case 'WEEKLY':
summary += localeObject.getConstant(WEEKS) + ' ' + localeObject.getConstant(ON) + ' ';
ruleObject.day.forEach(function (day, index) {
summary += capitalizeFirstWord(getValue(DAYINDEXOBJECT["" + day], cldrObj), 'single');
summary += (((ruleObject.day.length - 1) === index) ? '' : ', ');
});
break;
case 'MONTHLY':
summary += localeObject.getConstant(MONTHS) + ' ' + localeObject.getConstant(ON) + ' ';
summary += getMonthSummary(ruleObject, cldrObj, localeObject);
break;
case 'YEARLY':
summary += localeObject.getConstant(YEARS) + ' ' + localeObject.getConstant(ON) + ' ';
summary += capitalizeFirstWord(getValue((ruleObject.month[0]).toString(), cldrObj1), 'single') + ' ';
summary += getMonthSummary(ruleObject, cldrObj, localeObject);
break;
}
if (ruleObject.count) {
summary += ', ' + (ruleObject.count) + ' ' + localeObject.getConstant(TIMES);
}
else if (ruleObject.until) {
var tempDate = ruleObject.until;
summary += ', ' + localeObject.getConstant(UNTIL)
+ ' ' + tempDate.getDate()
+ ' ' + capitalizeFirstWord(getValue((tempDate.getMonth() + 1).toString(), cldrObj1), 'single')
+ ' ' + tempDate.getFullYear();
}
return summary;
}
/**
* Generates Month summary
*
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @param {string[]} cldrObj Accepts the collections of month name from calendar
* @param {L10n} localeObj Accepts the locale object
* @returns {string} Returns the month summary string from given recurrence rule object
* @private
*/
function getMonthSummary(ruleObject, cldrObj, localeObj) {
var summary = '';
if (ruleObject.monthDay.length) {
summary += ruleObject.monthDay[0];
}
else if (ruleObject.day) {
var pos = ruleObject.setPosition - 1;
summary += localeObj.getConstant(WEEKPOS[pos > -1 ? pos : (WEEKPOS.length - 1)])
+ ' ' + capitalizeFirstWord(getValue(DAYINDEXOBJECT[ruleObject.day[0]], cldrObj), 'single');
}
return summary;
}
/**
* Generates the date collections from the given recurrence rule
*
* @param {Date} startDate Accepts the rule start date
* @param {string} rule Accepts the recurrence rule
* @param {string} excludeDate Accepts the exception dates in string format
* @param {number} startDayOfWeek Accepts the start day index of week
* @param {number} maximumCount Accepts the maximum number count to generate date collections
* @param {Date} viewDate Accepts the current date instead of start date
* @param {CalendarType} calendarMode Accepts the calendar type
* @param {string} newTimezone Accepts the timezone name
* @returns {number[]} Returns the collection of dates
*/
export function generate(startDate, rule, excludeDate, startDayOfWeek, maximumCount, viewDate, calendarMode, newTimezone) {
if (maximumCount === void 0) { maximumCount = MAXOCCURRENCE; }
if (viewDate === void 0) { viewDate = null; }
if (calendarMode === void 0) { calendarMode = 'Gregorian'; }
if (newTimezone === void 0) { newTimezone = null; }
var ruleObject = extractObjectFromRule(rule);
var cacheDate;
calendarUtil = getCalendarUtil(calendarMode);
var data = [];
var modifiedDate = new Date(startDate.getTime());
tempExcludeDate = [];
var tempDate = isNullOrUndefined(excludeDate) ? [] : excludeDate.split(',');
var tz = new Timezone();
tempDate.forEach(function (content) {
var parsedDate = getDateFromRecurrenceDateString(content);
if (newTimezone) {
parsedDate = tz.add(new Date(parsedDate.getTime()), newTimezone);
}
tempExcludeDate.push(new Date(parsedDate.getTime()).setHours(0, 0, 0, 0));
});
ruleObject.recExceptionCount = !isNullOrUndefined(ruleObject.count) ? tempExcludeDate.length : 0;
if (viewDate && viewDate > startDate && !ruleObject.count) {
tempViewDate = new Date(new Date(viewDate.getTime()).setHours(0, 0, 0));
}
else {
tempViewDate = null;
}
if (!ruleObject.until && tempViewDate) {
cacheDate = new Date(tempViewDate.getTime());
cacheDate.setDate(tempViewDate.getDate() + maximumCount * (ruleObject.interval));
ruleObject.until = cacheDate;
}
if (ruleObject.until && startDate > ruleObject.until) {
return data;
}
maxOccurrence = maximumCount;
startDayOfWeek = startDayOfWeek || 0;
setFirstDayOfWeek(DAYINDEX[parseInt(startDayOfWeek.toString(), 10)]);
switch (ruleObject.freq) {
case 'DAILY':
dailyType(modifiedDate, ruleObject.until, data, ruleObject);
break;
case 'WEEKLY':
weeklyType(modifiedDate, ruleObject.until, data, ruleObject, startDayOfWeek);
break;
case 'MONTHLY':
monthlyType(modifiedDate, ruleObject.until, data, ruleObject);
break;
case 'YEARLY':
yearlyType(modifiedDate, ruleObject.until, data, ruleObject);
}
return data;
}
/**
* Generate date object from given date string
*
* @param {string} recDateString Accepts the exception date as string
* @returns {Date} Returns the date from exception date string
*/
export function getDateFromRecurrenceDateString(recDateString) {
return new Date(recDateString.substr(0, 4) +
'-' + recDateString.substr(4, 2) +
'-' + recDateString.substr(6, 5) +
':' + recDateString.substr(11, 2) +
':' + recDateString.substr(13));
}
/**
* Internal method to handle exclude date
*
* @param {number[]} data Accepts the exception date collections
* @param {number} date Accepts the new exclude date
* @returns {void}
* @private
*/
function excludeDateHandler(data, date) {
var zeroIndex = new Date(date).setHours(0, 0, 0, 0);
if (tempExcludeDate.indexOf(zeroIndex) === -1 && (!tempViewDate || zeroIndex >= tempViewDate.getTime())) {
data.push(date);
}
}
/**
* Internal method for get date count
*
* @param {Date} startDate Accepts the date
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {number} Returns the number of date count
* @private
*/
function getDateCount(startDate, ruleObject) {
var count = maxOccurrence;
if (ruleObject.count) {
count = ruleObject.count;
}
else if (ruleObject.until) {
if (ruleObject.freq === 'DAILY' || ruleObject.freq === 'WEEKLY') {
count = Math.floor((ruleObject.until.getTime() - startDate.getTime()) / MS_PER_DAY) + 1;
}
else if (ruleObject.freq === 'MONTHLY' || ruleObject.freq === 'YEARLY') {
count = Math.floor(((ruleObject.until.getMonth() + 12 * ruleObject.until.getFullYear()) -
(startDate.getMonth() + 12 * startDate.getFullYear())) / ruleObject.interval) +
(ruleObject.day.length > 1 ? (Math.floor((ruleObject.until.getTime() - startDate.getTime()) / MS_PER_DAY) + 1) : 1);
if (ruleObject.freq === 'YEARLY') {
count = ruleObject.month.length > 1 ? (count * ruleObject.month.length) : count;
}
}
}
return count;
}
/**
* Internal method for daily type recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function dailyType(startDate, endDate, data, ruleObject) {
var tempDate = new Date(startDate.getTime());
var interval = ruleObject.interval;
var expectedCount = getDateCount(startDate, ruleObject);
var state;
var expectedDays = ruleObject.day;
while (compareDates(tempDate, endDate)) {
state = true;
state = validateRules(tempDate, ruleObject);
if (state && (expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1 || expectedDays.length === 0)) {
excludeDateHandler(data, tempDate.getTime());
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
break;
}
}
tempDate.setDate(tempDate.getDate() + interval);
if (tempDate.getHours() !== startDate.getHours()) {
tempDate.setHours(startDate.getHours());
}
}
}
/**
* Internal method for weekly type recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @param {number} startDayOfWeek Accepts the start day index of week
* @returns {void}
* @private
*/
function weeklyType(startDate, endDate, data, ruleObject, startDayOfWeek) {
var tempDate = new Date(startDate.getTime());
if (!ruleObject.day.length) {
ruleObject.day.push(DAYINDEX[startDate.getDay()]);
}
var interval = ruleObject.interval;
var expectedDays = ruleObject.day;
var expectedCount = getDateCount(startDate, ruleObject);
var weekState = true;
var wkstIndex;
var weekCollection = [];
if (expectedDays.length > 1) {
if (isNullOrUndefined(ruleObject.wkst) || ruleObject.wkst === '') {
ruleObject.wkst = dayIndex[0];
}
wkstIndex = DAYINDEX.indexOf(ruleObject.wkst);
while (compareDates(tempDate, endDate)) {
var startDateDiff = DAYINDEX.indexOf(DAYINDEX[tempDate.getDay()]) - wkstIndex;
startDateDiff = startDateDiff === -1 ? 6 : startDateDiff;
var weekstartDate = addDays(tempDate, -startDateDiff);
var weekendDate = addDays(weekstartDate, 6);
var compareTempDate = new Date(tempDate.getTime());
weekendDate = resetTime(weekendDate);
compareTempDate = resetTime(compareTempDate);
while (weekendDate >= compareTempDate) {
if (expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1) {
weekCollection.push([tempDate.getTime()]);
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
break;
}
tempDate.setDate(tempDate.getDate() + 1);
if (tempDate.getHours() !== startDate.getHours()) {
tempDate.setHours(startDate.getHours());
}
compareTempDate = new Date(tempDate.getTime());
compareTempDate = resetTime(compareTempDate);
}
tempDate.setDate(tempDate.getDate() - 1);
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
break;
}
tempDate.setDate((tempDate.getDate()) + 1 + ((interval - 1) * 7));
insertDataCollection(weekCollection, weekState, startDate, endDate, data, ruleObject);
weekCollection = [];
}
}
else {
tempDate = getStartDateForWeek(startDate, ruleObject.day);
if (interval > 1 && dayIndex.indexOf(ruleObject.day[0]) < (startDate.getDay() - startDayOfWeek)) {
tempDate.setDate(tempDate.getDate() + ((interval - 1) * 7));
}
while (compareDates(tempDate, endDate)) {
weekState = validateRules(tempDate, ruleObject);
if (weekState && (expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1)) {
excludeDateHandler(data, tempDate.getTime());
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
break;
}
tempDate.setDate(tempDate.getDate() + (interval * 7));
}
insertDataCollection(weekCollection, weekState, startDate, endDate, data, ruleObject);
weekCollection = [];
}
}
/**
* Internal method for monthly type recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function monthlyType(startDate, endDate, data, ruleObject) {
// Set monthday value if BYDAY, BYMONTH and Month day property is not set based on start date
if (!ruleObject.month.length && !ruleObject.day.length && !ruleObject.monthDay.length) {
ruleObject.monthDay.push(startDate.getDate());
if (ruleObject.freq === 'YEARLY') {
ruleObject.month.push(startDate.getMonth() + 1);
}
}
else if (ruleObject.month.length > 0 && !ruleObject.day.length && !ruleObject.monthDay.length) {
ruleObject.monthDay.push(startDate.getDate());
}
var ruleType = validateMonthlyRuleType(ruleObject);
switch (ruleType) {
case 'day':
switch (ruleObject.freq) {
case 'MONTHLY':
monthlyDayTypeProcessforMonthFreq(startDate, endDate, data, ruleObject);
break;
case 'YEARLY':
monthlyDayTypeProcess(startDate, endDate, data, ruleObject);
break;
}
break;
case 'both':
case 'date':
switch (ruleObject.freq) {
case 'MONTHLY':
monthlyDateTypeProcessforMonthFreq(startDate, endDate, data, ruleObject);
break;
case 'YEARLY':
monthlyDateTypeProcess(startDate, endDate, data, ruleObject);
break;
}
break;
}
}
/**
* Internal method for yearly type recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function yearlyType(startDate, endDate, data, ruleObject) {
var typeValue = checkYearlyType(ruleObject);
switch (typeValue) {
case 'MONTH':
monthlyType(startDate, endDate, data, ruleObject);
break;
case 'WEEKNO':
processWeekNo(startDate, endDate, data, ruleObject);
break;
case 'YEARDAY':
processYearDay(startDate, endDate, data, ruleObject);
break;
}
}
/**
* Internal method for process week no
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function processWeekNo(startDate, endDate, data, ruleObject) {
var stDate = calendarUtil.getYearLastDate(startDate, 0);
var tempDate;
var expectedCount = getDateCount(startDate, ruleObject);
var state;
var startDay;
var firstWeekSpan;
var weekNos = ruleObject.weekNo;
var weekNo;
var maxDate;
var minDate;
var weekCollection = [];
var expectedDays = ruleObject.day;
while (compareDates(stDate, endDate)) {
startDay = dayIndex.indexOf(DAYINDEX[stDate.getDay()]);
firstWeekSpan = (6 - startDay) + 1;
for (var index = 0; index < weekNos.length; index++) {
weekNo = weekNos[parseInt(index.toString(), 10)];
weekNo = (weekNo > 0) ? weekNo : 53 + weekNo + 1;
maxDate = (weekNo === 1) ? firstWeekSpan : firstWeekSpan + ((weekNo - 1) * 7);
minDate = (weekNo === 1) ? firstWeekSpan - 7 : firstWeekSpan + ((weekNo - 2) * 7);
while (minDate < maxDate) {
tempDate = new Date(stDate.getTime() + (MS_PER_DAY * minDate));
if (expectedDays.length === 0 || expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1) {
if (isNullOrUndefined(ruleObject.setPosition)) {
insertDateCollection(state, startDate, endDate, data, ruleObject, tempDate.getTime());
}
else {
weekCollection.push([tempDate.getTime()]);
}
}
minDate++;
}
}
if (!isNullOrUndefined(ruleObject.setPosition)) {
insertDatasIntoExistingCollection(weekCollection, state, startDate, endDate, data, ruleObject);
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
stDate = calendarUtil.getYearLastDate(tempDate, ruleObject.interval);
weekCollection = [];
}
}
/**
* Internal method for process year day
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function processYearDay(startDate, endDate, data, ruleObject) {
var stDate = calendarUtil.getYearLastDate(startDate, 0);
var tempDate;
var expectedCount = getDateCount(startDate, ruleObject);
var state;
var dateCollection = [];
var date;
var expectedDays = ruleObject.day;
while (compareDates(stDate, endDate)) {
for (var index = 0; index < ruleObject.yearDay.length; index++) {
date = ruleObject.yearDay[parseInt(index.toString(), 10)];
tempDate = new Date(stDate.getTime());
if ((date === calendarUtil.getLeapYearDaysCount() || date === -calendarUtil.getLeapYearDaysCount()) &&
(!calendarUtil.isLeapYear(calendarUtil.getFullYear(tempDate), 1))) {
tempDate.setDate(tempDate.getDate() + 1);
continue;
}
tempDate.setDate(tempDate.getDate() + ((date < 0) ?
calendarUtil.getYearDaysCount(tempDate, 1) + 1 + date : date));
if (expectedDays.length === 0 || expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1) {
if (ruleObject.setPosition == null) {
insertDateCollection(state, startDate, endDate, data, ruleObject, tempDate.getTime());
}
else {
dateCollection.push([tempDate.getTime()]);
}
}
}
if (!isNullOrUndefined(ruleObject.setPosition)) {
insertDatasIntoExistingCollection(dateCollection, state, startDate, endDate, data, ruleObject);
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
stDate = calendarUtil.getYearLastDate(tempDate, ruleObject.interval);
dateCollection = [];
}
}
/**
* Internal method to check yearly type
*
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {YearRuleType} Returns the Yearly rule type object
* @private
*/
function checkYearlyType(ruleObject) {
if (ruleObject.yearDay.length) {
return 'YEARDAY';
}
else if (ruleObject.weekNo.length) {
return 'WEEKNO';
}
return 'MONTH';
}
/**
* Internal method to initialize recurrence rule variables
*
* @param {Date} startDate Accepts the start date
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {RuleData} Return the rule data object
* @private
*/
function initializeRecRuleVariables(startDate, ruleObject) {
var ruleData = {
monthCollection: [],
index: 0,
tempDate: new Date(startDate.getTime()),
mainDate: new Date(startDate.getTime()),
expectedCount: getDateCount(startDate, ruleObject),
monthInit: 0,
dateCollection: []
};
if (ruleObject.month.length) {
calendarUtil.setMonth(ruleData.tempDate, ruleObject.month[0], ruleData.tempDate.getDate());
}
return ruleData;
}
/**
* Internal method for process monthly date type recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function monthlyDateTypeProcess(startDate, endDate, data, ruleObject) {
if (ruleObject.month.length) {
monthlyDateTypeProcessforMonthFreq(startDate, endDate, data, ruleObject);
return;
}
var ruleData = initializeRecRuleVariables(startDate, ruleObject);
var currentMonthDate;
ruleData.tempDate = ruleData.mainDate = calendarUtil.getMonthStartDate(ruleData.tempDate);
while (compareDates(ruleData.tempDate, endDate)) {
currentMonthDate = new Date(ruleData.tempDate.getTime());
while (calendarUtil.isSameYear(currentMonthDate, ruleData.tempDate) &&
(ruleData.expectedCount && (data.length + ruleObject.recExceptionCount) <= ruleData.expectedCount)) {
if (ruleObject.month.length === 0 || (ruleObject.month.length > 0
&& !calendarUtil.checkMonth(ruleData.tempDate, ruleObject.month))) {
processDateCollectionForByMonthDay(ruleObject, ruleData, endDate, false);
ruleData.beginDate = new Date(ruleData.tempDate.getTime());
ruleData.monthInit = setNextValidDate(ruleData.tempDate, ruleObject, ruleData.monthInit, ruleData.beginDate);
}
else {
calendarUtil.setValidDate(ruleData.tempDate, 1, 1);
ruleData.tempDate = getStartDateForWeek(ruleData.tempDate, ruleObject.day);
break;
}
}
ruleData.tempDate.setFullYear(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), currentMonthDate.getDate());
insertDataCollection(ruleData.dateCollection, ruleData.state, startDate, endDate, data, ruleObject);
if (calendarUtil.isLastMonth(ruleData.tempDate)) {
calendarUtil.setValidDate(ruleData.tempDate, 1, 1);
ruleData.tempDate = getStartDateForWeek(ruleData.tempDate, ruleObject.day);
}
if (ruleData.expectedCount && (data.length + ruleObject.recExceptionCount) >= ruleData.expectedCount) {
return;
}
ruleData.tempDate.setFullYear(ruleData.tempDate.getFullYear() + ruleObject.interval - 1);
ruleData.tempDate = getStartDateForWeek(ruleData.tempDate, ruleObject.day);
ruleData.monthInit = setNextValidDate(ruleData.tempDate, ruleObject, ruleData.monthInit, ruleData.beginDate);
ruleData.dateCollection = [];
}
}
/**
* Internal method for process monthly date type with month frequency from recurrence rule
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function monthlyDateTypeProcessforMonthFreq(startDate, endDate, data, ruleObject) {
var ruleData = initializeRecRuleVariables(startDate, ruleObject);
ruleData.tempDate = ruleData.mainDate = calendarUtil.getMonthStartDate(ruleData.tempDate);
if (((ruleObject.freq === 'MONTHLY' && ruleObject.interval === 12) || (ruleObject.freq === 'YEARLY')) &&
calendarUtil.getMonthDaysCount(startDate) < ruleObject.monthDay[0]) {
return;
}
while (compareDates(ruleData.tempDate, endDate)) {
ruleData.beginDate = new Date(ruleData.tempDate.getTime());
processDateCollectionForByMonthDay(ruleObject, ruleData, endDate, true, startDate, data);
if (!isNullOrUndefined(ruleObject.setPosition)) {
insertDatasIntoExistingCollection(ruleData.dateCollection, ruleData.state, startDate, endDate, data, ruleObject);
}
if (ruleData.expectedCount && (data.length + ruleObject.recExceptionCount) >= ruleData.expectedCount) {
return;
}
ruleData.monthInit = setNextValidDate(ruleData.tempDate, ruleObject, ruleData.monthInit, ruleData.beginDate);
ruleData.dateCollection = [];
}
}
/**
* To process date collection for Monthly & Yearly based on BYMONTH Day property
*
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @param {RuleData} recRuleVariables Accepts the rule data
* @param {Date} endDate Accepts the end date
* @param {boolean} isByMonth Accepts the boolean to validate either month or not
* @param {Date} startDate Accepts the start date
* @param {number[]} data Accepts the collection of dates
* @returns {void}
* @private
*/
function processDateCollectionForByMonthDay(ruleObject, recRuleVariables, endDate, isByMonth, startDate, data) {
for (var index = 0; index < ruleObject.monthDay.length; index++) {
recRuleVariables.date = ruleObject.monthDay[parseInt(index.toString(), 10)];
recRuleVariables.tempDate = calendarUtil.getMonthStartDate(recRuleVariables.tempDate);
var maxDate = calendarUtil.getMonthDaysCount(recRuleVariables.tempDate);
recRuleVariables.date = recRuleVariables.date > 0 ? recRuleVariables.date : (maxDate + recRuleVariables.date + 1);
if (validateProperDate(recRuleVariables.tempDate, recRuleVariables.date, recRuleVariables.mainDate)
&& (recRuleVariables.date > 0)) {
calendarUtil.setDate(recRuleVariables.tempDate, recRuleVariables.date);
if (endDate && recRuleVariables.tempDate > endDate) {
return;
}
if (ruleObject.day.length === 0 || ruleObject.day.indexOf(DAYINDEX[recRuleVariables.tempDate.getDay()]) > -1) {
if (isByMonth && isNullOrUndefined(ruleObject.setPosition) && (recRuleVariables.expectedCount
&& (data.length + ruleObject.recExceptionCount) < recRuleVariables.expectedCount)) {
insertDateCollection(recRuleVariables.state, startDate, endDate, data, ruleObject, recRuleVariables.tempDate.getTime());
}
else {
recRuleVariables.dateCollection.push([recRuleVariables.tempDate.getTime()]);
}
}
}
}
}
/**
* Internal method to set next valid date
*
* @param {Date} tempDate Accepts the date
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @param {number} monthInit Accepts the initial month
* @param {Date} beginDate Accepts the initial date
* @param {number} interval Accepts the interval duration
* @returns {number} Returnx the next valid date
* @private
*/
function setNextValidDate(tempDate, ruleObject, monthInit, beginDate, interval) {
if (beginDate === void 0) { beginDate = null; }
var monthData = beginDate ? beginDate.getMonth() : 0;
var startDate = calendarUtil.getMonthStartDate(tempDate);
interval = isNullOrUndefined(interval) ? ruleObject.interval : interval;
tempDate.setFullYear(startDate.getFullYear());
tempDate.setMonth(startDate.getMonth());
tempDate.setDate(startDate.getDate());
if (ruleObject.month.length) {
monthInit++;
monthInit = monthInit % ruleObject.month.length;
calendarUtil.setMonth(tempDate, ruleObject.month[parseInt(monthInit.toString(), 10)], 1);
if (monthInit === 0) {
calendarUtil.addYears(tempDate, interval, ruleObject.month[0]);
}
}
else {
if (beginDate && (beginDate.getFullYear() < tempDate.getFullYear())) {
monthData = tempDate.getMonth() - 1;
}
calendarUtil.setValidDate(tempDate, interval, 1, monthData, beginDate);
}
return monthInit;
}
/**
* To get month collection when BYDAY property having more than one value in list.
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function getMonthCollection(startDate, endDate, data, ruleObject) {
var expectedDays = ruleObject.day;
var tempDate = new Date(startDate.getTime());
tempDate = calendarUtil.getMonthStartDate(tempDate);
var monthCollection = [];
var dateCollection = [];
var dates = [];
var index;
var state;
var expectedCount = getDateCount(startDate, ruleObject);
var monthInit = 0;
var beginDate;
if (ruleObject.month.length) {
calendarUtil.setMonth(tempDate, ruleObject.month[0], 1);
}
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
while (compareDates(tempDate, endDate)
&& (expectedCount && (data.length + ruleObject.recExceptionCount) < expectedCount)) {
var currentMonthDate = new Date(tempDate.getTime());
var isHavingNumber = expectedDays.map(function (item) { return HASNUMBER.test(item); });
if (isHavingNumber.indexOf(true) > -1) {
for (var j = 0; j <= expectedDays.length - 1; j++) {
var expectedDaysArray = expectedDays[parseInt(j.toString(), 10)].match(SPLITNUMBERANDSTRING);
var position = parseInt(expectedDaysArray[0], 10);
tempDate = new Date(tempDate.getTime());
tempDate = calendarUtil.getMonthStartDate(tempDate);
tempDate = getStartDateForWeek(tempDate, expectedDays);
currentMonthDate.setFullYear(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate());
while (calendarUtil.isSameYear(currentMonthDate, tempDate) && calendarUtil.isSameMonth(currentMonthDate, tempDate)) {
if (expectedDaysArray[expectedDaysArray.length - 1] === DAYINDEX[currentMonthDate.getDay()]) {
monthCollection.push([currentMonthDate.getTime()]);
}
currentMonthDate.setDate(currentMonthDate.getDate() + (1));
}
currentMonthDate.setDate(currentMonthDate.getDate() - (1));
if (expectedDaysArray[0].indexOf('-') > -1) {
index = monthCollection.length - (-1 * position);
}
else {
index = position - 1;
}
index = isNaN(index) ? 0 : index;
if (monthCollection.length > 0) {
if (isNullOrUndefined(ruleObject.setPosition)) {
insertDatasIntoExistingCollection(monthCollection, state, startDate, endDate, data, ruleObject, index);
}
else {
dateCollection = [(filterDateCollectionByIndex(monthCollection, index, dates))];
}
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
monthCollection = [];
}
if (!isNullOrUndefined(ruleObject.setPosition)) {
insertDateCollectionBasedonBySetPos(dateCollection, state, startDate, endDate, data, ruleObject);
dates = [];
}
monthInit = setNextValidDate(tempDate, ruleObject, monthInit, beginDate);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
monthCollection = [];
}
else {
var weekCollection = [];
var dayCycleData = processWeekDays(expectedDays);
currentMonthDate.setFullYear(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate());
var initialDate = new Date(tempDate.getTime());
beginDate = new Date(tempDate.getTime());
while (calendarUtil.isSameMonth(initialDate, tempDate)) {
weekCollection.push(tempDate.getTime());
if (expectedDays.indexOf(DAYINDEX[tempDate.getDay()]) > -1) {
monthCollection.push(weekCollection);
weekCollection = [];
}
tempDate.setDate(tempDate.getDate()
+ dayCycleData[DAYINDEX[tempDate.getDay()]]);
}
index = ((ruleObject.setPosition < 1) ? (monthCollection.length + ruleObject.setPosition) : ruleObject.setPosition - 1);
if (isNullOrUndefined(ruleObject.setPosition)) {
index = 0;
var datas = [];
for (var week = 0; week < monthCollection.length; week++) {
for (var row = 0; row < monthCollection[parseInt(week.toString(), 10)].length; row++) {
datas.push(monthCollection[parseInt(week.toString(), 10)][parseInt(row.toString(), 10)]);
}
}
monthCollection = [datas];
}
if (monthCollection.length > 0) {
insertDatasIntoExistingCollection(monthCollection, state, startDate, endDate, data, ruleObject, index);
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
monthInit = setNextValidDate(tempDate, ruleObject, monthInit, beginDate);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
monthCollection = [];
}
}
}
/**
* To process monday day type for FREQ=MONTHLY
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function monthlyDayTypeProcessforMonthFreq(startDate, endDate, data, ruleObject) {
var expectedDays = ruleObject.day;
// When BYDAY property having more than 1 value.
if (expectedDays.length > 1) {
getMonthCollection(startDate, endDate, data, ruleObject);
return;
}
var tempDate = new Date(startDate.getTime());
var expectedCount = getDateCount(startDate, ruleObject);
var monthCollection = [];
var beginDate;
var monthInit = 0;
tempDate = calendarUtil.getMonthStartDate(tempDate);
if (ruleObject.month.length) {
calendarUtil.setMonth(tempDate, ruleObject.month[0], 1);
}
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
while (compareDates(tempDate, endDate) && (expectedCount && (data.length + ruleObject.recExceptionCount) < expectedCount)) {
beginDate = new Date(tempDate.getTime());
var currentMonthDate = new Date(tempDate.getTime());
while (calendarUtil.isSameMonth(tempDate, currentMonthDate)) {
monthCollection.push([currentMonthDate.getTime()]);
currentMonthDate.setDate(currentMonthDate.getDate() + (7));
}
// To filter date collection based on BYDAY Index, then BYSETPOS and to insert datas into existing collection
insertDateCollectionBasedonIndex(monthCollection, startDate, endDate, data, ruleObject);
monthInit = setNextValidDate(tempDate, ruleObject, monthInit, beginDate);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
monthCollection = [];
}
}
/**
* To process monday day type for FREQ=YEARLY
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function monthlyDayTypeProcess(startDate, endDate, data, ruleObject) {
var expectedDays = ruleObject.day;
var isHavingNumber = expectedDays.map(function (item) { return HASNUMBER.test(item); });
// If BYDAY property having more than 1 value in list
if (expectedDays.length > 1 && isHavingNumber.indexOf(true) > -1) {
processDateCollectionforByDayWithInteger(startDate, endDate, data, ruleObject);
return;
}
else if (ruleObject.month.length && expectedDays.length === 1 && isHavingNumber.indexOf(true) > -1) {
monthlyDayTypeProcessforMonthFreq(startDate, endDate, data, ruleObject);
return;
}
var tempDate = new Date(startDate.getTime());
var currentMonthDate;
var expectedCount = getDateCount(startDate, ruleObject);
var interval = ruleObject.interval;
var monthCollection = [];
if (ruleObject.month.length) {
calendarUtil.setMonth(tempDate, ruleObject.month[0], tempDate.getDate());
}
// Set the date as start date of the yeear if yearly freq having ByDay property alone
if (isNullOrUndefined(ruleObject.setPosition) && ruleObject.month.length === 0 && ruleObject.weekNo.length === 0) {
tempDate.setFullYear(startDate.getFullYear(), 0, 1);
}
tempDate = calendarUtil.getMonthStartDate(tempDate);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
while (compareDates(tempDate, endDate)) {
currentMonthDate = new Date(tempDate.getTime());
while (calendarUtil.isSameYear(currentMonthDate, tempDate) &&
(expectedCount && (data.length + ruleObject.recExceptionCount) <= expectedCount)) {
currentMonthDate = new Date(tempDate.getTime());
while (calendarUtil.isSameYear(currentMonthDate, tempDate)) {
if (ruleObject.month.length === 0 || (ruleObject.month.length > 0
&& !calendarUtil.checkMonth(tempDate, ruleObject.month))) {
if (expectedDays.length > 1) {
if (calendarUtil.compareMonth(currentMonthDate, tempDate)) {
calendarUtil.setValidDate(tempDate, 1, 1);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
break;
}
if (expectedDays.indexOf(DAYINDEX[currentMonthDate.getDay()]) > -1) {
monthCollection.push([currentMonthDate.getTime()]);
}
currentMonthDate.setDate(currentMonthDate.getDate() + (1));
}
else {
// If BYDAY property having 1 value in list
if (currentMonthDate.getFullYear() > tempDate.getFullYear()) {
calendarUtil.setValidDate(tempDate, 1, 1);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
break;
}
var newstr = getDayString(expectedDays[0]);
if (DAYINDEX[currentMonthDate.getDay()] === newstr
&& new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 0)
> new Date(startDate.getFullYear())) {
monthCollection.push([currentMonthDate.getTime()]);
}
currentMonthDate.setDate(currentMonthDate.getDate() + (7));
}
}
else {
calendarUtil.setValidDate(tempDate, 1, 1);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
break;
}
}
}
tempDate.setFullYear(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), currentMonthDate.getDate());
// To filter date collection based on BYDAY Index, then BYSETPOS and to insert datas into existing collection
insertDateCollectionBasedonIndex(monthCollection, startDate, endDate, data, ruleObject);
if (calendarUtil.isLastMonth(tempDate)) {
calendarUtil.setValidDate(tempDate, 1, 1);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
}
tempDate.setFullYear(tempDate.getFullYear() + interval - 1);
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
monthCollection = [];
}
}
/**
* To process the recurrence rule when BYDAY property having values with integer
*
* @param {Date} startDate Accepts the strat date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of dates
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function processDateCollectionforByDayWithInteger(startDate, endDate, data, ruleObject) {
var expectedDays = ruleObject.day;
var expectedCount = getDateCount(startDate, ruleObject);
var tempDate = new Date(startDate.getTime());
var interval = ruleObject.interval;
var monthCollection = [];
var dateCollection = [];
var index;
var state;
var monthInit = 0;
var currentMonthDate;
var currentDate;
var beginDate;
tempDate = calendarUtil.getMonthStartDate(tempDate);
var datas = [];
if (ruleObject.month.length) {
calendarUtil.setMonth(tempDate, ruleObject.month[0], 1);
}
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
while (compareDates(tempDate, endDate)) {
currentMonthDate = new Date(tempDate.getTime());
for (var i = 0; i <= ruleObject.month.length; i++) {
for (var j = 0; j <= expectedDays.length - 1; j++) {
tempDate = calendarUtil.getMonthStartDate(tempDate);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
monthCollection = [];
while (calendarUtil.isSameYear(currentMonthDate, tempDate) &&
(expectedCount && (data.length + ruleObject.recExceptionCount) <= expectedCount)) {
while (calendarUtil.isSameYear(currentMonthDate, tempDate)) {
currentMonthDate = new Date(tempDate.getTime());
if (ruleObject.month.length === 0 ||
(ruleObject.month.length > 0 && ruleObject.month[parseInt(i.toString(), 10)] === calendarUtil.getMonth(currentMonthDate))) {
var expectedDaysArray = expectedDays[parseInt(j.toString(), 10)].match(SPLITNUMBERANDSTRING);
var position = parseInt(expectedDaysArray[0], 10);
currentDate = new Date(tempDate.getTime());
while (calendarUtil.isSameYear(currentDate, tempDate)
&& calendarUtil.isSameMonth(currentDate, tempDate)) {
if (expectedDaysArray[expectedDaysArray.length - 1] === DAYINDEX[currentDate.getDay()]) {
monthCollection.push([currentDate.getTime()]);
}
currentDate.setDate(currentDate.getDate() + (1));
}
currentDate.setDate(currentDate.getDate() - (1));
if (expectedDaysArray[0].indexOf('-') > -1) {
index = monthCollection.length - (-1 * position);
}
else {
index = position - 1;
}
index = isNaN(index) ? 0 : index;
}
monthInit = setNextValidDate(tempDate, ruleObject, monthInit, beginDate, 1);
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
}
}
tempDate = j === 0 && currentDate ? new Date(currentDate.getTime()) : new Date(currentMonthDate.getTime());
if (monthCollection.length > 0) {
if (isNullOrUndefined(ruleObject.setPosition)) {
insertDatasIntoExistingCollection(monthCollection, state, startDate, endDate, data, ruleObject, index);
}
else {
dateCollection = [(filterDateCollectionByIndex(monthCollection, index, datas))];
}
}
if (expectedCount && (data.length + ruleObject.recExceptionCount) >= expectedCount) {
return;
}
}
}
if (!isNullOrUndefined(ruleObject.setPosition)) {
insertDateCollectionBasedonBySetPos(dateCollection, state, startDate, endDate, data, ruleObject);
datas = [];
}
if (calendarUtil.isLastMonth(tempDate)) {
calendarUtil.setValidDate(tempDate, 1, 1);
tempDate.setFullYear(tempDate.getFullYear() + interval - 1);
}
else {
tempDate.setFullYear(tempDate.getFullYear() + interval);
}
tempDate = getStartDateForWeek(tempDate, ruleObject.day);
if (ruleObject.month.length) {
calendarUtil.setMonth(tempDate, ruleObject.month[0], tempDate.getDate());
}
}
}
/**
* To get recurrence collection if BYSETPOS is null
*
* @param {number[]} monthCollection Accepts the month collection dates
* @param {string[]} expectedDays Accepts the exception dates
* @returns {RuleData} Returns the rule data object
* @private
*/
function getRecurrenceCollection(monthCollection, expectedDays) {
var index;
var recurrenceCollectionObject = { monthCollection: [], index: 0 };
if (expectedDays.length === 1) {
// To split numeric value from BYDAY property value
var expectedDaysArrays = expectedDays[0].match(SPLITNUMBERANDSTRING);
var arrPosition = void 0;
if (expectedDaysArrays.length > 1) {
arrPosition = parseInt(expectedDaysArrays[0], 10);
index = ((arrPosition < 1) ? (monthCollection.length + arrPosition) : arrPosition - 1);
}
else {
index = 0;
monthCollection = getDateCollectionforBySetPosNull(monthCollection);
}
}
else {
index = 0;
monthCollection = getDateCollectionforBySetPosNull(monthCollection);
}
recurrenceCollectionObject.monthCollection = monthCollection;
recurrenceCollectionObject.index = index;
return recurrenceCollectionObject;
}
/**
* Internal method to process the data collections
*
* @param {number[]} dateCollection Accepts the date collections
* @param {boolean} state Accepts the state
* @param {Date} startDate Accepts the start date
* @param {Date} endDate Accepts the end date
* @param {number[]} data Accepts the collection of numbers
* @param {RecRule} ruleObject Accepts the recurrence rule object
* @returns {void}
* @private
*/
function insertDataCollection(dateCollection, state, startDate, endDate, data, ruleObject) {
var index = ((ruleObject.setPosition < 1) ?
(dateCollection.length + ruleObject.setPosition) : ruleObject.setPosition - 1);
if (isNullOrUndefined(ruleObject.setPosition)) {
index = 0;
dateCollection = getDateCollectionforBySetPosNull(dateCollection);
}
if (dateCollection.length > 0) {
insertDatasIntoExistingCollection(dateCollection, state, startDate, endDate, data, ruleObject, index);
}
}
/**
* To process month collection if BYSETPOS is null
*
* @param {number[]} monthCollection Accepts the month date collections
* @returns {number[]} Returns the month date collections
* @private
*/
function getDateCollectionforBySetPosNull(monthCollection) {
var datas = [];
for (var week = 0; week < monthCollection.length; week++) {
for (var row = 0; row < monthCollection[parseInt(week.toString(), 10)].length; row++) {
datas.push(new Date(monthCollection[parseInt(week.toString(), 10)][parseInt(row.toString(), 10)]).getT