Skip to content

Instantly share code, notes, and snippets.

@bradparks
Created August 2, 2012 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradparks/3239452 to your computer and use it in GitHub Desktop.
Save bradparks/3239452 to your computer and use it in GitHub Desktop.
jquery recurrence with inArray wrapped (https://github.com/collective/jquery.recurrenceinput.js/issues/6)
/*jslint regexp: false, continue: true, indent: 4 */
/*global $, alert, jQuery */
(function ($) {
$.tools = $.tools || {version: '@VERSION'};
var tool;
var LABELS = {};
function safeInArray(value, aryData)
{
var result;
var isAnArray = Object.prototype.toString.call( someVar ) === '[object Array]';
if (isAnArray)
{
result = $.inArray(value, aryData);
}
else
{
var strValue = aryData + "";
result = strValue.indexOf(value);
}
return result;
};
tool = $.tools.recurrenceinput = {
conf: {
lang: 'en',
readOnly: false,
firstDay: 0,
// "REMOTE" FIELD
startField: null,
startFieldYear: null,
startFieldMonth: null,
startFieldDay: null,
ajaxURL: null,
// FORM OVERLAY
formOverlay: {
speed: 'fast',
fixed: false
},
// JQUERY TEMPLATE NAMES
template: {
form: '#jquery-recurrenceinput-form-tmpl',
display: '#jquery-recurrenceinput-display-tmpl'
},
// RECURRENCE TEMPLATES
rtemplate: {
daily: {
rrule: 'FREQ=DAILY',
fields: [
'ridailyinterval',
'rirangeoptions'
]
},
mondayfriday: {
rrule: 'FREQ=WEEKLY;BYDAY=MO,FR',
fields: [
'rirangeoptions'
]
},
weekdays: {
rrule: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR',
fields: [
'rirangeoptions'
]
},
weekly: {
rrule: 'FREQ=WEEKLY',
fields: [
'riweeklyinterval',
'riweeklyweekdays',
'rirangeoptions'
]
},
monthly: {
rrule: 'FREQ=MONTHLY',
fields: [
'rimonthlyinterval',
'rimonthlyoptions',
'rirangeoptions'
]
},
yearly: {
rrule: 'FREQ=YEARLY',
fields: [
'riyearlyinterval',
'riyearlyoptions',
'rirangeoptions'
]
}
}
},
localize: function (language, labels) {
LABELS[language] = labels;
},
setTemplates: function (templates, titles) {
var lang, template;
tool.conf.rtemplate = templates;
for (lang in titles) {
if (titles.hasOwnProperty(lang)) {
for (template in titles[lang]) {
if (titles[lang].hasOwnProperty(template)) {
LABELS[lang].rtemplate[template] = titles[lang][template];
}
}
}
}
}
};
tool.localize("en", {
displayUnactivate: 'Does not repeat',
displayActivate: 'Repeats every',
edit: 'Edit...',
add: 'Add',
refresh: 'Refresh',
title: 'Repeat',
preview: 'Selected dates',
addDate: 'Add date',
recurrenceType: 'Repeats:',
dailyInterval1: 'Repeat every:',
dailyInterval2: 'days',
weeklyInterval1: 'Repeat every:',
weeklyInterval2: 'week(s)',
weeklyWeekdays: 'Repeat on:',
weeklyWeekdaysHuman: 'on:',
monthlyInterval1: 'Repeat every:',
monthlyInterval2: 'month(s)',
monthlyDayOfMonth1: 'Day',
monthlyDayOfMonth1Human: 'on day',
monthlyDayOfMonth2: 'of the month',
monthlyDayOfMonth3: 'month(s)',
monthlyWeekdayOfMonth1: 'The',
monthlyWeekdayOfMonth1Human: 'on the',
monthlyWeekdayOfMonth2: '',
monthlyWeekdayOfMonth3: 'of the month',
monthlyRepeatOn: 'Repeat on:',
yearlyInterval1: 'Repeat every:',
yearlyInterval2: 'year(s)',
yearlyDayOfMonth1: 'Every',
yearlyDayOfMonth1Human: 'on',
yearlyDayOfMonth2: '',
yearlyDayOfMonth3: '',
yearlyWeekdayOfMonth1: 'The',
yearlyWeekdayOfMonth1Human: 'on the',
yearlyWeekdayOfMonth2: '',
yearlyWeekdayOfMonth3: 'of',
yearlyWeekdayOfMonth4: '',
yearlyRepeatOn: 'Repeat on:',
range: 'End recurrence:',
rangeNoEnd: 'Never',
rangeByOccurrences1: 'After',
rangeByOccurrences1Human: 'ends after',
rangeByOccurrences2: 'occurrence(s)',
rangeByEndDate: 'On',
rangeByEndDateHuman: 'ends on',
including: ', and also',
except: ', except for',
cancel: 'Cancel',
save: 'Save',
recurrenceStart: 'Start of the recurrence',
additionalDate: 'Additional date',
include: 'Include',
exclude: 'Exclude',
remove: 'Remove',
orderIndexes: ['first', 'second', 'third', 'fourth', 'last'],
months: [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'],
shortMonths: [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
weekdays: [
'Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday'],
shortWeekdays: [
'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
longDateFormat: 'mmmm dd, yyyy',
shortDateFormat: 'mm/dd/yyyy',
unsupportedFeatures: 'Warning: This event uses recurrence features not ' +
'supported by this widget. Saving the recurrence ' +
'may change the recurrence in unintended ways:',
noTemplateMatch: 'No matching recurrence template',
multipleDayOfMonth: 'This widget does not support multiple days in monthly or yearly recurrence',
bysetpos: 'BYSETPOS is not supported',
noRule: 'No RRULE in RRULE data',
noRepeatEvery: 'Error: The "Repeat every"-field must be between 1 and 1000',
noEndDate: 'Error: End date is not set. Please set a correct value',
noRepeatOn: 'Error: "Repeat on"-value must be selected',
pastEndDate: 'Error: End date cannot be before start date',
noEndAfterNOccurrences: 'Error: The "After N occurrences"-field must be between 1 and 1000',
alreadyAdded: 'This date was already added',
rtemplate: {
daily: 'Daily',
mondayfriday: 'Monday and Friday',
weekdays: 'Weekday',
weekly: 'Weekly',
monthly: 'Monthly',
yearly: 'Yearly'
}
});
var OCCURRENCETMPL = ['<div class="rioccurrences">',
'{{each occurrences}}',
'<div class="occurrence ${occurrences[$index].type}">',
'<span>',
'${occurrences[$index].formattedDate}',
'{{if occurrences[$index].type === "start"}}',
'<span class="rlabel">${i18n.recurrenceStart}</span>',
'{{/if}}',
'{{if occurrences[$index].type === "rdate"}}',
'<span class="rlabel">${i18n.additionalDate}</span>',
'{{/if}}',
'</span>',
'{{if !readOnly}}',
'<span class="action">',
'{{if occurrences[$index].type === "rrule"}}',
'<a date="${occurrences[$index].date}" href="#"',
'class="${occurrences[$index].type}" title="${i18n.exclude}">',
'${i18n.exclude}',
'</a>',
'{{/if}}',
'{{if occurrences[$index].type === "rdate"}}',
'<a date="${occurrences[$index].date}" href="#"',
'class="${occurrences[$index].type}" title="${i18n.remove}" >',
'${i18n.remove}',
'</a>',
'{{/if}}',
'{{if occurrences[$index].type === "exdate"}}',
'<a date="${occurrences[$index].date}" href="#"',
'class="${occurrences[$index].type}" title="${i18n.include}">',
'${i18n.include}',
'</a>',
'{{/if}}',
'</span>',
'{{/if}}',
'</div>',
'{{/each}}',
'<div class="batching">',
'{{each batch.batches}}',
'{{if $index === batch.currentBatch}}<span class="current">{{/if}}',
'<a href="#" start="${batch.batches[$index][0]}">[${batch.batches[$index][0]} - ${batch.batches[$index][1]}]</a>',
'{{if $index === batch.currentBatch}}</span>{{/if}}',
'{{/each}}',
'</div></div>'].join('\n');
$.template('occurrenceTmpl', OCCURRENCETMPL);
var DISPLAYTMPL = ['<div class="ridisplay">',
'<div class="rimain">',
'{{if !readOnly}}',
'<input type="checkbox" name="richeckbox" />',
'{{/if}}',
'<label class="ridisplay">${i18n.displayUnactivate}</label>',
'{{if !readOnly}}',
'<a href="#" name="riedit">${i18n.edit}</a>',
'{{/if}}',
'</div>',
'<div class="rioccurrences" style="display:none" /></div>'].join('\n');
$.template('displayTmpl', DISPLAYTMPL);
var FORMTMPL = ['<div class="riform">',
'<form>',
'<h1>${i18n.title}</h1>',
'<div id="messagearea" style="display: none;">',
'</div>',
'<div id="rirtemplate">',
'<label for="${name}rtemplate" class="label">',
'${i18n.recurrenceType}',
'</label>',
'<select id="rirtemplate" name="rirtemplate" class="field">',
'{{each rtemplate}}',
'<option value="${$index}">${i18n.rtemplate[$index]}</value>',
'{{/each}}',
'</select>',
'<div>',
'<div id="riformfields">',
'<div id="ridailyinterval" class="rifield">',
'<label for="${name}dailyinterval" class="label">',
'${i18n.dailyInterval1}',
'</label>',
'<div class="field">',
'<input type="text" size="2"',
'value="1"',
'name="ridailyinterval"',
'id="${name}dailyinterval" />',
'${i18n.dailyInterval2}',
'</div>',
'</div>',
'<div id="riweeklyinterval" class="rifield">',
'<label for="${name}weeklyinterval" class="label">',
'${i18n.weeklyInterval1}',
'</label>',
'<div class="field">',
'<input type="text" size="2"',
'value="1"',
'name="riweeklyinterval"',
'id="${name}weeklyinterval"/>',
'${i18n.weeklyInterval2}',
'</div>',
'</div>',
'<div id="riweeklyweekdays" class="rifield">',
'<label for="${name}weeklyinterval" class="label">${i18n.weeklyWeekdays}</label>',
'<div class="field">',
'{{each i18n.shortWeekdays}}',
'<div class="riweeklyweekday">',
'<input type="checkbox"',
'name="riweeklyweekdays${weekdays[$index]}"',
'id="${name}weeklyWeekdays${weekdays[$index]}"',
'value="${weekdays[$index]}" />',
'<label for="${name}weeklyWeekdays${weekdays[$index]}">${$value}</label>',
'</div>',
'{{/each}}',
'</div>',
'</div>',
'<div id="rimonthlyinterval" class="rifield">',
'<label for="rimonthlyinterval" class="label">${i18n.monthlyInterval1}</label>',
'<div class="field">',
'<input type="text" size="2"',
'value="1" ',
'name="rimonthlyinterval"/>',
'${i18n.monthlyInterval2}',
'</div>',
'</div>',
'<div id="rimonthlyoptions" class="rifield">',
'<label for="rimonthlytype" class="label">${i18n.monthlyRepeatOn}</label>',
'<div class="field">',
'<div>',
'<input',
'type="radio"',
'value="DAYOFMONTH"',
'name="rimonthlytype"',
'id="${name}monthlytype:DAYOFMONTH" />',
'<label for="${name}monthlytype:DAYOFMONTH">',
'${i18n.monthlyDayOfMonth1}',
'</label>',
'<select name="rimonthlydayofmonthday"',
'id="${name}monthlydayofmonthday">',
'{{each [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,',
'18,19,20,21,22,23,24,25,26,27,28,29,30,31]}}',
'<option value="${$value}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.monthlyDayOfMonth2}',
'</div>',
'<div>',
'<input',
'type="radio"',
'value="WEEKDAYOFMONTH"',
'name="rimonthlytype"',
'id="${name}monthlytype:WEEKDAYOFMONTH" />',
'<label for="${name}monthlytype:WEEKDAYOFMONTH">',
'${i18n.monthlyWeekdayOfMonth1}',
'</label>',
'<select name="rimonthlyweekdayofmonthindex">',
'{{each i18n.orderIndexes}}',
'<option value="${orderIndexes[$index]}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.monthlyWeekdayOfMonth2}',
'<select name="rimonthlyweekdayofmonth">',
'{{each i18n.weekdays}}',
'<option value="${weekdays[$index]}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.monthlyWeekdayOfMonth3}',
'</div>',
'</div>',
'</div>',
'<div id="riyearlyinterval" class="rifield">',
'<label for="riyearlyinterval" class="label">${i18n.yearlyInterval1}</label>',
'<div class="field">',
'<input type="text" size="2"',
'value="1" ',
'name="riyearlyinterval"/>',
'${i18n.yearlyInterval2}',
'</div>',
'</div>',
'<div id="riyearlyoptions" class="rifield">',
'<label for="riyearlyType" class="label">${i18n.yearlyRepeatOn}</label>',
'<div class="field">',
'<div>',
'<input',
'type="radio"',
'value="DAYOFMONTH"',
'name="riyearlyType"',
'id="${name}yearlytype:DAYOFMONTH" />',
'<label for="${name}yearlytype:DAYOFMONTH">',
'${i18n.yearlyDayOfMonth1}',
'</label>',
'<select name="riyearlydayofmonthmonth">',
'{{each i18n.months}}',
'<option value="${$index+1}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.yearlyDayOfMonth2}',
'<select name="riyearlydayofmonthday">',
'{{each [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,',
'18,19,20,21,22,23,24,25,26,27,28,29,30,31]}}',
'<option value="${$value}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.yearlyDayOfMonth3}',
'</div>',
'<div>',
'<input',
'type="radio"',
'value="WEEKDAYOFMONTH"',
'name="riyearlyType"',
'id="${name}yearlytype:WEEKDAYOFMONTH"/>',
'<label for="${name}yearlytype:WEEKDAYOFMONTH">',
'${i18n.yearlyWeekdayOfMonth1}',
'</label>',
'<select name="riyearlyweekdayofmonthindex">',
'{{each i18n.orderIndexes}}',
'<option value="${orderIndexes[$index]}">${$value}</option>',
'{{/each}}',
'</select>',
'<label for="${name}yearlytype:WEEKDAYOFMONTH">',
'${i18n.yearlyWeekdayOfMonth2}',
'</label>',
'<select name="riyearlyweekdayofmonthday">',
'{{each i18n.weekdays}}',
'<option value="${weekdays[$index]}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.yearlyWeekdayOfMonth3}',
'<select name="riyearlyweekdayofmonthmonth">',
'{{each i18n.months}}',
'<option value="${$index+1}">${$value}</option>',
'{{/each}}',
'</select>',
'${i18n.yearlyWeekdayOfMonth4}',
'</div>',
'</div>',
'</div>',
'<div id="rirangeoptions" class="rifield">',
'<label class="label">${i18n.range}</label>',
'<div class="field">',
'<div>',
'<input',
'type="radio"',
'value="NOENDDATE"',
'name="rirangetype"',
'id="${name}rangetype:NOENDDATE"/>',
'<label for="${name}rangetype:NOENDDATE">',
'${i18n.rangeNoEnd}',
'</label>',
'</div>',
'<div>',
'<input',
'type="radio"',
'checked="checked"',
'value="BYOCCURRENCES"',
'name="rirangetype"',
'id="${name}rangetype:BYOCCURRENCES"/>',
'<label for="${name}rangetype:BYOCCURRENCES">',
'${i18n.rangeByOccurrences1}',
'</label>',
'<input',
'type="text" size="3"',
'value="10"',
'name="rirangebyoccurrencesvalue" />',
'${i18n.rangeByOccurrences2}',
'</div>',
'<div>',
'<input',
'type="radio"',
'value="BYENDDATE"',
'name="rirangetype"',
'id="${name}rangetype:BYENDDATE"/>',
'<label for="${name}rangetype:BYENDDATE">',
'${i18n.rangeByEndDate}',
'</label>',
'<input',
'type="date"',
'name="rirangebyenddatecalendar" />',
'</div>',
'</div>',
'</div>',
'</div>',
'<div class="rioccurrencesactions">',
'<div class="rioccurancesheader">',
'<h2>${i18n.preview}</h2>',
'<span class="refreshbutton action">',
'<a class="rirefreshbutton" href="#" title="${i18n.refresh}">',
'${i18n.refresh}',
'</a>',
'</span>',
'</div>',
'</div>',
'<div class="rioccurrences">',
'</div>',
'<div class="rioccurrencesactions">',
'<div class="rioccurancesheader">',
'<h2>${i18n.addDate}</h2>',
'</div>',
'<div class="riaddoccurrence">',
'<div class="errorarea"></div>',
'<input type="date" name="adddate" id="adddate" />',
'<input type="button" name="addaction" id="addaction" value="${i18n.add}">',
'</div>',
'</div>',
'<div class="ributtons">',
'<input',
'type="submit"',
'class="ricancelbutton"',
'value="${i18n.cancel}" />',
'<input',
'type="submit"',
'class="risavebutton"',
'value="${i18n.save}" />',
'</div>',
'</form></div>'].join('\n');
$.template('formTmpl', FORMTMPL);
// Formatting function (mostly) from jQueryTools dateinput
var Re = /d{1,4}|m{1,4}|yy(?:yy)?|"[^"]*"|'[^']*'/g;
function zeropad(val, len) {
val = val.toString();
len = len || 2;
while (val.length < len) { val = "0" + val; }
return val;
}
function format(date, fmt, conf) {
var d = date.getDate(),
D = date.getDay(),
m = date.getMonth(),
y = date.getFullYear(),
flags = {
d: d,
dd: zeropad(d),
ddd: conf.i18n.shortWeekdays[D],
dddd: conf.i18n.weekdays[D],
m: m + 1,
mm: zeropad(m + 1),
mmm: conf.i18n.shortMonths[m],
mmmm: conf.i18n.months[m],
yy: String(y).slice(2),
yyyy: y
};
var result = fmt.replace(Re, function ($0) {
return flags.hasOwnProperty($0) ? flags[$0] : $0.slice(1, $0.length - 1);
});
return result;
}
/**
* Parsing RFC5545 from widget
*/
function widgetSaveToRfc5545(form, conf, tz) {
var value = form.find('select[name=rirtemplate]').val();
var rtemplate = conf.rtemplate[value];
var result = rtemplate.rrule;
var human = conf.i18n.rtemplate[value];
var field, input, weekdays, i18nweekdays, i, j, index, tmp;
var day, month, year, interval, yearlyType, occurrences, date;
for (i = 0; i < rtemplate.fields.length; i++) {
field = form.find('#' + rtemplate.fields[i]);
switch (field.attr('id')) {
case 'ridailyinterval':
interval = field.find('input[name=ridailyinterval]').val();
if (interval !== '1') {
result += ';INTERVAL=' + interval;
}
human = interval + ' ' + conf.i18n.dailyInterval2;
break;
case 'riweeklyinterval':
interval = field.find('input[name=riweeklyinterval]').val();
if (interval !== '1') {
result += ';INTERVAL=' + interval;
}
human = interval + ' ' + conf.i18n.weeklyInterval2;
break;
case 'riweeklyweekdays':
weekdays = '';
i18nweekdays = '';
for (j = 0; j < conf.weekdays.length; j++) {
input = field.find('input[name=riweeklyweekdays' + conf.weekdays[j] + ']');
if (input.is(':checked')) {
if (weekdays) {
weekdays += ',';
i18nweekdays += ', ';
}
weekdays += conf.weekdays[j];
i18nweekdays += conf.i18n.weekdays[j];
}
}
if (weekdays) {
result += ';BYDAY=' + weekdays;
human += ' ' + conf.i18n.weeklyWeekdaysHuman + ' ' + i18nweekdays;
}
break;
case 'rimonthlyinterval':
interval = field.find('input[name=rimonthlyinterval]').val();
if (interval !== '1') {
result += ';INTERVAL=' + interval;
}
human = interval + ' ' + conf.i18n.monthlyInterval2;
break;
case 'rimonthlyoptions':
var monthlyType = $('input[name=rimonthlytype]:checked', form).val();
switch (monthlyType) {
case 'DAYOFMONTH':
day = $('select[name=rimonthlydayofmonthday]', form).val();
result += ';BYMONTHDAY=' + day;
human += ', ' + conf.i18n.monthlyDayOfMonth1Human + ' ' + day + ' ' + conf.i18n.monthlyDayOfMonth2;
break;
case 'WEEKDAYOFMONTH':
index = $('select[name=rimonthlyweekdayofmonthindex]', form).val();
day = $('select[name=rimonthlyweekdayofmonth]', form).val();
if (safeInArray(day, ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']) > -1)
{
result += ';BYDAY=' + index + day;
human += ', ' + conf.i18n.monthlyWeekdayOfMonth1Human + ' ';
human += ' ' + conf.i18n.orderIndexes[safeInArray(index, conf.orderIndexes)];
human += ' ' + conf.i18n.monthlyWeekdayOfMonth2;
human += ' ' + conf.i18n.weekdays[safeInArray(day, conf.weekdays)];
human += ' ' + conf.i18n.monthlyDayOfMonth2;
}
break;
}
break;
case 'riyearlyinterval':
interval = field.find('input[name=riyearlyinterval]').val();
if (interval !== '1') {
result += ';INTERVAL=' + interval;
}
human = interval + ' ' + conf.i18n.yearlyInterval2;
break;
case 'riyearlyoptions':
yearlyType = $('input[name=riyearlyType]:checked', form).val();
switch (yearlyType) {
case 'DAYOFMONTH':
month = $('select[name=riyearlydayofmonthmonth]', form).val();
day = $('select[name=riyearlydayofmonthday]', form).val();
result += ';BYMONTH=' + month;
result += ';BYMONTHDAY=' + day;
human += ', ' + conf.i18n.yearlyDayOfMonth1Human + ' ' + conf.i18n.months[month - 1] + ' ' + day;
break;
case 'WEEKDAYOFMONTH':
index = $('select[name=riyearlyweekdayofmonthindex]', form).val();
day = $('select[name=riyearlyweekdayofmonthday]', form).val();
month = $('select[name=riyearlyweekdayofmonthmonth]', form).val();
result += ';BYMONTH=' + month;
if (safeInArray(day, ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']) > -1) {
result += ';BYDAY=' + index + day;
human += ', ' + conf.i18n.yearlyWeekdayOfMonth1Human;
human += ' ' + conf.i18n.orderIndexes[safeInArray(index, conf.orderIndexes)];
human += ' ' + conf.i18n.yearlyWeekdayOfMonth2;
human += ' ' + conf.i18n.weekdays[safeInArray(day, conf.weekdays)];
human += ' ' + conf.i18n.yearlyWeekdayOfMonth3;
human += ' ' + conf.i18n.months[month - 1];
human += ' ' + conf.i18n.yearlyWeekdayOfMonth4;
}
break;
}
break;
case 'rirangeoptions':
var rangeType = form.find('input[name=rirangetype]:checked').val();
switch (rangeType) {
case 'BYOCCURRENCES':
occurrences = form.find('input[name=rirangebyoccurrencesvalue]').val();
result += ';COUNT=' + occurrences;
human += ', ' + conf.i18n.rangeByOccurrences1Human;
human += ' ' + occurrences;
human += ' ' + conf.i18n.rangeByOccurrences2;
break;
case 'BYENDDATE':
field = form.find('input[name=rirangebyenddatecalendar]');
date = field.data('dateinput').getValue('yyyymmdd');
result += ';UNTIL=' + date + 'T000000';
if (tz === true) {
// Make it UTC:
result += 'Z';
}
human += ', ' + conf.i18n.rangeByEndDateHuman;
human += ' ' + field.data('dateinput').getValue(conf.i18n.longDateFormat);
break;
}
break;
}
}
if (form.ical.RDATE !== undefined && form.ical.RDATE.length > 0) {
form.ical.RDATE.sort();
tmp = [];
for (i = 0; i < form.ical.RDATE.length; i++) {
if (form.ical.RDATE[i] !== '') {
year = parseInt(form.ical.RDATE[i].substring(0, 4), 10);
month = parseInt(form.ical.RDATE[i].substring(4, 6), 10) - 1;
day = parseInt(form.ical.RDATE[i].substring(6, 8), 10);
tmp.push(format(new Date(year, month, day), conf.i18n.longDateFormat, conf));
}
}
if (tmp.length !== 0) {
human = human + conf.i18n.including + ' ' + tmp.join('; ');
}
}
if (form.ical.EXDATE !== undefined && form.ical.EXDATE.length > 0) {
form.ical.EXDATE.sort();
tmp = [];
for (i = 0; i < form.ical.EXDATE.length; i++) {
if (form.ical.EXDATE[i] !== '') {
year = parseInt(form.ical.EXDATE[i].substring(0, 4), 10);
month = parseInt(form.ical.EXDATE[i].substring(4, 6), 10) - 1;
day = parseInt(form.ical.EXDATE[i].substring(6, 8), 10);
tmp.push(format(new Date(year, month, day), conf.i18n.longDateFormat, conf));
}
}
if (tmp.length !== 0) {
human = human + conf.i18n.except + ' ' + tmp.join('; ');
}
}
result = 'RRULE:' + result;
if (form.ical.EXDATE !== undefined && form.ical.EXDATE.join() !== "") {
tmp = $.map(form.ical.EXDATE, function (x) {
if (x.length === 8) { // DATE format. Make it DATE-TIME
x += 'T000000';
}
if (tz === true) {
// Make it UTC:
x += 'Z';
}
return x;
});
result = result + '\nEXDATE:' + tmp;
}
if (form.ical.RDATE !== undefined && form.ical.RDATE.join() !== "") {
tmp = $.map(form.ical.RDATE, function (x) {
if (x.length === 8) { // DATE format. Make it DATE-TIME
x += 'T000000';
}
if (tz === true) {
// Make it UTC:
x += 'Z';
}
return x;
});
result = result + '\nRDATE:' + tmp;
}
return {result: result, description: human};
}
function parseLine(icalline) {
var result = {};
var pos = icalline.indexOf(':');
var property = icalline.substring(0, pos);
result.value = icalline.substring(pos + 1);
pos = property.indexOf(';');
if (pos !== -1) {
result.parameters = property.substring(pos + 1);
result.property = property.substring(0, pos);
} else {
result.parameters = null;
result.property = property;
}
return result;
}
function cleanDates(dates) {
// Get rid of timezones
// TODO: We could parse dates and range here, maybe?
var result = [];
var splitDates = dates.split(',');
var date;
for (date in splitDates) {
if (splitDates.hasOwnProperty(date)) {
if (safeInArray('Z', splitDates[date]) !== -1) {
result.push(splitDates[date].substring(0, 15));
} else {
result.push(splitDates[date]);
}
}
}
return result;
}
function parseIcal(icaldata) {
var lines = [];
var result = {};
var propAndValue = [];
var line = null;
var nextline;
lines = icaldata.split('\n');
lines.reverse();
while (true) {
if (lines.length > 0) {
nextline = lines.pop();
if (nextline.charAt(0) === ' ' || nextline.charAt(0) === '\t') {
// Line continuation:
line = line + nextline;
continue;
}
} else {
nextline = '';
}
// New line; the current one is finished, add it to the result.
if (line !== null) {
line = parseLine(line);
// We ignore properties for now
if (line.property === 'RDATE' || line.property === 'EXDATE') {
result[line.property] = cleanDates(line.value);
} else {
result[line.property] = line.value;
}
}
line = nextline;
if (line === '') {
break;
}
}
return result;
}
function widgetLoadFromRfc5545(form, conf, icaldata, force) {
var unsupportedFeatures = [];
var i, matches, match, matchIndex, rtemplate, d, input, index;
var selector, selectors, field, radiobutton, start, end;
var interval, byday, bymonth, bymonthday, count, until;
var day, month, year, weekday, ical;
form.ical = parseIcal(icaldata);
if (form.ical.RRULE === undefined) {
unsupportedFeatures.push(conf.i18n.noRule);
if (!force) {
return -1; // Fail!
}
} else {
matches = /INTERVAL=([0-9]+);?/.exec(form.ical.RRULE);
if (matches) {
interval = matches[1];
} else {
interval = '1';
}
matches = /BYDAY=([^;]+);?/.exec(form.ical.RRULE);
if (matches) {
byday = matches[1];
} else {
byday = '';
}
matches = /BYMONTHDAY=([^;]+);?/.exec(form.ical.RRULE);
if (matches) {
bymonthday = matches[1].split(",");
} else {
bymonthday = null;
}
matches = /BYMONTH=([^;]+);?/.exec(form.ical.RRULE);
if (matches) {
bymonth = matches[1].split(",");
} else {
bymonth = null;
}
matches = /COUNT=([0-9]+);?/.exec(form.ical.RRULE);
if (matches) {
count = matches[1];
} else {
count = null;
}
matches = /UNTIL=([0-9T]+);?/.exec(form.ical.RRULE);
if (matches) {
until = matches[1];
} else {
until = null;
}
matches = /BYSETPOS=([^;]+);?/.exec(form.ical.RRULE);
if (matches) {
unsupportedFeatures.push(conf.i18n.bysetpos);
}
// Find the best rule:
match = '';
matchIndex = null;
for (i in conf.rtemplate) {
if (conf.rtemplate.hasOwnProperty(i)) {
rtemplate = conf.rtemplate[i];
if (form.ical.RRULE.indexOf(rtemplate.rrule) === 0) {
if (form.ical.RRULE.length > match.length) {
// This is the best match so far
match = form.ical.RRULE;
matchIndex = i;
}
}
}
}
if (match) {
rtemplate = conf.rtemplate[matchIndex];
// Set the selector:
selector = form.find('select[name=rirtemplate]').val(matchIndex);
} else {
for (rtemplate in conf.rtemplate) {
if (conf.rtemplate.hasOwnProperty(rtemplate)) {
rtemplate = conf.rtemplate[rtemplate];
break;
}
}
unsupportedFeatures.push(conf.i18n.noTemplateMatch);
}
for (i = 0; i < rtemplate.fields.length; i++) {
field = form.find('#' + rtemplate.fields[i]);
switch (field.attr('id')) {
case 'ridailyinterval':
field.find('input[name=ridailyinterval]').val(interval);
break;
case 'riweeklyinterval':
field.find('input[name=riweeklyinterval]').val(interval);
break;
case 'riweeklyweekdays':
byday = byday.split(",");
for (d = 0; d < conf.weekdays.length; d++) {
day = conf.weekdays[d];
input = field.find('input[name=riweeklyweekdays' + day + ']');
input.attr('checked', safeInArray(day, byday) !== -1);
}
break;
case 'rimonthlyinterval':
field.find('input[name=rimonthlyinterval]').val(interval);
break;
case 'rimonthlyoptions':
var monthlyType = 'DAYOFMONTH'; // Default to using BYMONTHDAY
if (bymonthday) {
monthlyType = 'DAYOFMONTH';
if (bymonthday.length > 1) {
// No support for multiple days in one month
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
// Just keep the first
bymonthday = bymonthday[0];
}
field.find('select[name=rimonthlydayofmonthday]').val(bymonthday);
}
if (byday) {
monthlyType = 'WEEKDAYOFMONTH';
if (safeInArray(',', byday) !== -1) {
// No support for multiple days in one month
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
byday = byday.split(",")[0];
}
index = byday.slice(0, -2);
weekday = byday.slice(-2);
field.find('select[name=rimonthlyweekdayofmonthindex]').val(index);
field.find('select[name=rimonthlyweekdayofmonth]').val(weekday);
}
selectors = field.find('input[name=rimonthlytype]');
for (index = 0; index < selectors.length; index++) {
radiobutton = selectors[index];
$(radiobutton).attr('checked', radiobutton.value === monthlyType);
}
break;
case 'riyearlyinterval':
field.find('input[name=riyearlyinterval]').val(interval);
break;
case 'riyearlyoptions':
var yearlyType = 'DAYOFMONTH'; // Default to using BYMONTHDAY
if (bymonthday) {
yearlyType = 'DAYOFMONTH';
if (bymonthday.length > 1) {
// No support for multiple days in one month
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
bymonthday = bymonthday[0];
}
field.find('select[name=riyearlydayofmonthmonth]').val(bymonth);
field.find('select[name=riyearlydayofmonthday]').val(bymonthday);
}
if (byday) {
yearlyType = 'WEEKDAYOFMONTH';
if (safeInArray(',', byday) !== -1) {
// No support for multiple days in one month
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
byday = byday.split(",")[0];
}
index = byday.slice(0, -2);
weekday = byday.slice(-2);
field.find('select[name=riyearlyweekdayofmonthindex]').val(index);
field.find('select[name=riyearlyweekdayofmonthday]').val(weekday);
field.find('select[name=riyearlyweekdayofmonthmonth]').val(bymonth);
}
selectors = field.find('input[name=riyearlyType]');
for (index = 0; index < selectors.length; index++) {
radiobutton = selectors[index];
$(radiobutton).attr('checked', radiobutton.value === yearlyType);
}
break;
case 'rirangeoptions':
var rangeType = 'NOENDDATE';
if (count) {
rangeType = 'BYOCCURRENCES';
field.find('input[name=rirangebyoccurrencesvalue]').val(count);
}
if (until) {
rangeType = 'BYENDDATE';
input = field.find('input[name=rirangebyenddatecalendar]');
year = until.slice(0, 4);
month = until.slice(4, 6);
month = parseInt(month, 10) - 1;
day = until.slice(6, 8);
input.data('dateinput').setValue(year, month, day);
}
selectors = field.find('input[name=rirangetype]');
for (index = 0; index < selectors.length; index++) {
radiobutton = selectors[index];
$(radiobutton).attr('checked', radiobutton.value === rangeType);
}
break;
}
}
}
var messagearea = form.find('#messagearea');
if (unsupportedFeatures.length !== 0) {
messagearea.text(conf.i18n.unsupportedFeatures + ' ' + unsupportedFeatures.join('; '));
messagearea.show();
return 1;
} else {
messagearea.text('');
messagearea.hide();
return 0;
}
}
/**
* RecurrenceInput - form, display and tools for recurrenceinput widget
*/
function RecurrenceInput(conf, textarea) {
var self = this;
var form, display;
// Extend conf with non-configurable data used by templates.
$.extend(conf, {
orderIndexes: ['+1', '+2', '+3', '+4', '-1'],
weekdays: ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']
});
// The recurrence type dropdown should show certain fields depending
// on selection:
function displayFields(selector) {
var i;
// First hide all the fields
form.find('.rifield').hide();
// Then show the ones that should be shown.
var value = selector.val();
if (value) {
var rtemplate = conf.rtemplate[value];
for (i = 0; i < rtemplate.fields.length; i++) {
form.find('#' + rtemplate.fields[i]).show();
}
}
}
function occurrenceExclude(event) {
event.preventDefault();
if (form.ical.EXDATE === undefined) {
form.ical.EXDATE = [];
}
form.ical.EXDATE.push(this.attributes.date.value);
var $this = $(this);
$this.attr('class', 'exdate');
$this.parent().parent().addClass('exdate');
$this.unbind(event);
$this.click(occurrenceInclude); // Jslint warns here, but that's OK.
}
function occurrenceInclude(event) {
event.preventDefault();
form.ical.EXDATE.splice(safeInArray(this.attributes.date.value, form.ical.EXDATE), 1);
var $this = $(this);
$this.attr('class', 'rrule');
$this.parent().parent().removeClass('exdate');
$this.unbind(event);
$this.click(occurrenceExclude);
}
function occurrenceDelete(event) {
event.preventDefault();
form.ical.RDATE.splice(safeInArray(this.attributes.date.value, form.ical.RDATE), 1);
$(this).parent().parent().hide('slow', function () {
$(this).remove();
});
}
function occurrenceAdd(event) {
event.preventDefault();
var dateinput = form
.find('.riaddoccurrence input#adddate')
.data('dateinput');
var datevalue = dateinput.getValue('yyyymmddT000000');
if (form.ical.RDATE === undefined) {
form.ical.RDATE = [];
}
var errorarea = form.find('.riaddoccurrence div.errorarea');
errorarea.text('');
errorarea.hide();
// Add date only if it is not already in RDATE
if(safeInArray(datevalue, form.ical.RDATE) === -1) {
form.ical.RDATE.push(datevalue);
var html = ['<div class="occurrence rdate" style="display: none;">',
'<span class="rdate">',
dateinput.getValue(conf.i18n.longDateFormat),
'<span class="rlabel">' + conf.i18n.additionalDate + '</span>',
'</span>',
'<span class="action">',
'<a date="' + datevalue + '" href="#" class="rdate" >',
'Include',
'</a>',
'</span>',
'</div>'].join('\n');
form.find('div.rioccurrences').prepend(html);
$(form.find('div.rioccurrences div')[0]).slideDown();
$(form.find('div.rioccurrences .action a.rdate')[0]).click(occurrenceDelete);
} else {
errorarea.text(conf.i18n.alreadyAdded).show();
}
}
// element is where to find the tag in question. Can be the form
// or the display widget. Defaults to the form.
function loadOccurrences(startdate, rfc5545, start, readonly) {
var element, occurrenceDiv;
if (!readonly) {
element = form;
} else {
element = display;
}
occurrenceDiv = element.find('.rioccurrences');
occurrenceDiv.hide();
$.ajax({
url: conf.ajaxURL,
async: false, // Can't be tested if it's asynchronous, annoyingly.
type: 'post',
dataType: 'json',
data: {year: startdate.getFullYear(),
month: startdate.getMonth() + 1, // Sending January as 0? I think not.
day: startdate.getDate(),
rrule: rfc5545,
format: conf.i18n.longDateFormat,
start: start},
success: function (data, status, jqXHR) {
var result, element;
if (!readonly) {
element = form;
} else {
element = display;
}
data.readOnly = readonly;
data.i18n = conf.i18n;
result = $.tmpl('occurrenceTmpl', data);
occurrenceDiv = element.find('.rioccurrences');
occurrenceDiv.replaceWith(result);
// Add the batch actions:
element.find('.rioccurrences .batching a').click(
function (event) {
event.preventDefault();
loadOccurrences(startdate, rfc5545, this.attributes.start.value, readonly);
}
);
// Add the delete/undelete actions:
if (!readonly) {
element.find('.rioccurrences .action a.rrule').click(occurrenceExclude);
element.find('.rioccurrences .action a.exdate').click(occurrenceInclude);
element.find('.rioccurrences .action a.rdate').click(occurrenceDelete);
}
// Show the new div
element.find('.rioccurrences').show();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
}
function pad(number, length) {
// http://www.electrictoolbox.com/pad-number-zeroes-javascript/
var str = '' + number; // Confuses jslint.
while (str.length < length) {
str = '0' + str;
}
return str;
}
function getField(field) {
// See if it is a field already
var realField = $(field);
if (!realField.length) {
// Otherwise, we assume it's an id:
realField = $('#' + field);
}
return realField;
}
function findStartDate() {
var startdate = null;
var startField, startFieldYear, startFieldMonth, startFieldDay;
// Find the default byday and bymonthday from the start date, if any:
if (conf.startField) {
startField = getField(conf.startField);
// Now we have a field, see if it is a dateinput field:
startdate = startField.data('dateinput');
if (!startdate) {
//No, it wasn't, just try to interpret it with Date()
startdate = startField.val();
if (startdate === "") {
// Probably not an input at all. Try to see if it contains a date
startdate = startField.text();
}
} else {
// Yes it was, get the date:
startdate = startdate.getValue();
}
} else if (conf.startFieldYear &&
conf.startFieldMonth &&
conf.startFieldDay) {
startFieldYear = getField(conf.startFieldYear);
startFieldMonth = getField(conf.startFieldMonth);
startFieldDay = getField(conf.startFieldDay);
startdate = startFieldYear.val() + '-' +
pad(startFieldMonth.val(), 2) + '-' +
pad(startFieldDay.val(), 2);
}
if (startdate === null) {
return null;
}
// We have some sort of startdate:
startdate = new Date(startdate);
if (isNaN(startdate)) {
return null;
}
return startdate;
}
function findEndDate(form) {
var endField, enddate;
endField = form.find('input[name=rirangebyenddatecalendar]');
// Now we have a field, see if it is a dateinput field:
enddate = endField.data('dateinput');
if (!enddate) {
//No, it wasn't, just try to interpret it with Date()
enddate = endField.val();
} else {
// Yes it was, get the date:
enddate = enddate.getValue();
}
enddate = new Date(enddate);
// if the end date is incorrect or the field is left empty
if (isNaN(enddate) || endField.val() === "") {
return null;
}
return enddate;
}
function findIntField(fieldName, form) {
var field, num, isInt;
field = form.find('input[name=' + fieldName + ']');
num = field.val();
// if it's not a number or the field is left empty
if (isNaN(num) || (num.toString().indexOf('.') !== -1) || field.val() === "") {
return null;
}
return num;
}
// Loading (populating) display and form widget with
// passed RFC5545 string (data)
function loadData(rfc5545) {
var selector, format, startdate, dayindex, day;
if (rfc5545) {
widgetLoadFromRfc5545(form, conf, rfc5545, true);
// check checkbox
display.find('input[name=richeckbox]')
.attr('checked', true);
}
startdate = findStartDate();
if (startdate !== null) {
// If the date is a real date, set the defaults in the form
form.find('select[name=rimonthlydayofmonthday]').val(startdate.getDate());
dayindex = conf.orderIndexes[Math.floor((startdate.getDate() - 1) / 7)];
day = conf.weekdays[startdate.getDay() - 1];
form.find('select[name=rimonthlyweekdayofmonthindex]').val(dayindex);
form.find('select[name=rimonthlyweekdayofmonth]').val(day);
form.find('select[name=riyearlydayofmonthmonth]').val(startdate.getMonth() + 1);
form.find('select[name=riyearlydayofmonthday]').val(startdate.getDate());
form.find('select[name=riyearlyweekdayofmonthindex]').val(dayindex);
form.find('select[name=riyearlyweekdayofmonthday]').val(day);
form.find('select[name=riyearlyweekdayofmonthmonth]').val(startdate.getMonth() + 1);
// Now when we have a start date, we can also do an ajax call to calculate occurrences:
loadOccurrences(startdate, widgetSaveToRfc5545(form, conf, false).result, 0, false);
// Show the add and refresh buttons:
form.find('div.rioccurrencesactions').show();
} else {
// No EXDATE/RDATE support
form.find('div.rioccurrencesactions').hide();
}
selector = form.find('select[name=rirtemplate]');
displayFields(selector);
}
function recurrenceOn() {
var RFC5545 = widgetSaveToRfc5545(form, conf, false);
var label = display.find('label[class=ridisplay]');
label.text(conf.i18n.displayActivate + ' ' + RFC5545.description);
textarea.val(RFC5545.result);
var startdate = findStartDate();
if (startdate !== null) {
loadOccurrences(startdate, widgetSaveToRfc5545(form, conf, false).result, 0, true);
}
}
function recurrenceOff() {
var label = display.find('label[class=ridisplay]');
label.text(conf.i18n.displayUnactivate);
textarea.val('');
display.find('.rioccurrences').hide();
}
function toggleRecurrence(e) {
var checkbox = display.find('input[name=richeckbox]');
if (checkbox.is(':checked')) {
recurrenceOn();
} else {
recurrenceOff();
}
}
function checkFields(form) {
var startDate, endDate, num, messagearea;
startDate = findStartDate();
// Hide any error message from before
messagearea = form.find('#messagearea');
messagearea.text('');
messagearea.hide();
// Hide add field errors
form.find('.riaddoccurrence div.errorarea').text('').hide();
// Repeats Daily
if (form.find('#ridailyinterval').css('display') === 'block') {
// Check repeat every field
num = findIntField('ridailyinterval', form);
if(!num || num < 1 || num > 1000) {
messagearea.text(conf.i18n.noRepeatEvery).show();
return false;
}
}
// Repeats Weekly
if (form.find('#riweeklyinterval').css('display') === 'block') {
// Check repeat every field
num = findIntField('riweeklyinterval', form);
if(!num || num < 1 || num > 1000) {
messagearea.text(conf.i18n.noRepeatEvery).show();
return false;
}
}
// Repeats Monthly
if (form.find('#rimonthlyinterval').css('display') === 'block') {
// Check repeat every field
num = findIntField('rimonthlyinterval', form);
if(!num || num < 1 || num > 1000) {
messagearea.text(conf.i18n.noRepeatEvery).show();
return false;
}
// Check repeat on
if(form.find('#rimonthlyoptions input:checked').length == 0) {
messagearea.text(conf.i18n.noRepeatOn).show();
return false;
}
}
// Repeats Yearly
if (form.find('#riyearlyinterval').css('display') === 'block') {
// Check repeat every field
num = findIntField('riyearlyinterval', form);
if(!num || num < 1 || num > 1000) {
messagearea.text(conf.i18n.noRepeatEvery).show();
return false;
}
// Check repeat on
if(form.find('#riyearlyoptions input:checked').length == 0) {
messagearea.text(conf.i18n.noRepeatOn).show();
return false;
}
}
// End recurrence fields
// If after N occurences is selected, check its value
if (form.find('input[value="BYOCCURRENCES"]:visible:checked').length > 0) {
num = findIntField('rirangebyoccurrencesvalue', form);
if(!num || num < 1 || num > 1000) {
messagearea.text(conf.i18n.noEndAfterNOccurrences).show();
return false;
}
}
// If end date is selected, check its value
if (form.find('input[value="BYENDDATE"]:visible:checked').length > 0) {
endDate = findEndDate(form);
if (!endDate) {
// if endDate is null that means the field is empty
messagearea.text(conf.i18n.noEndDate).show();
return false;
} else if (endDate < startDate) {
// the end date cannot be before start date
messagearea.text(conf.i18n.pastEndDate).show();
return false;
}
}
return true;
}
function save(event) {
event.preventDefault();
// if no field errors, process the request
if (checkFields(form)) {
// close overlay
form.overlay().close();
// check checkbox
display.find('input[name=richeckbox]')
.attr('checked', true);
recurrenceOn();
}
}
function cancel(event) {
event.preventDefault();
// close overlay
form.overlay().close();
}
function updateOccurances() {
var startDate;
startDate = findStartDate();
// if no field errors, process the request
if (checkFields(form)) {
loadOccurrences(startDate,
widgetSaveToRfc5545(form, conf, false).result,
0,
false);
}
}
/*
Load the templates
*/
display = $.tmpl('displayTmpl', conf);
form = $.tmpl('formTmpl', conf);
// Make an overlay and hide it
form.overlay(conf.formOverlay).hide();
form.ical = {RDATE: [], EXDATE: []};
$.tools.dateinput.localize(conf.lang, {
months: LABELS[conf.lang].months.join(),
shortMonths: LABELS[conf.lang].shortMonths.join(),
days: LABELS[conf.lang].weekdays.join(),
shortDays: LABELS[conf.lang].shortWeekdays.join()
});
// Make the date input into a calendar dateinput()
form.find('input[name=rirangebyenddatecalendar]').dateinput({
selectors: true,
lang: conf.lang,
format: conf.i18n.shortDateFormat,
firstDay: conf.firstDay,
yearRange: [-5, 10]
}).data('dateinput').setValue(new Date());
if (textarea.val()) {
var result = widgetLoadFromRfc5545(form, conf, textarea.val(), false);
if (result === -1) {
var label = display.find('label[class=ridisplay]');
label.text(conf.i18n.noRule);
} else {
recurrenceOn();
}
}
/*
Do all the GUI stuff:
*/
// When you click on the checkbox, recurrence should toggle on/off.
display.find('input[name=richeckbox]').click(toggleRecurrence);
// Show form overlay when you click on the "Edit..." link
display.find('a[name=riedit]').click(
function (e) {
// Load the form to set up the right fields to show, etc.
loadData(textarea.val());
e.preventDefault();
form.overlay().load();
}
);
// Pop up the little add form when clicking "Add..."
form.find('div.riaddoccurrence input#adddate').dateinput({
selectors: true,
lang: conf.lang,
format: conf.i18n.shortDateFormat,
firstDay: conf.firstDay,
yearRange: [-5, 10]
}).data('dateinput').setValue(new Date());
form.find('input#addaction').click(occurrenceAdd);
// When the reload button is clicked, reload
form.find('a.rirefreshbutton').click(
function (event) {
event.preventDefault();
updateOccurances();
}
);
// When selecting template, update what fieldsets are visible.
form.find('select[name=rirtemplate]').change(
function (e) {
displayFields($(this));
}
);
// When focus goes to a drop-down, select the relevant radiobutton.
form.find('select').change(
function (e) {
$(this).parent().find('> input').click().change();
}
);
form.find('input[name=rirangebyoccurrencesvalue]').change(
function (e) {
$(this).parent().find('input[name=rirangetype]').click().change();
}
);
form.find('input[name=rirangebyenddatecalendar]').change(function() {
// Update only if the occurances are shown
$(this).parent().find('input[name=rirangetype]').click();
if (form.find('.rioccurrencesactions:visible').length !== 0) {
updateOccurances();
}
});
// Update the selected dates section
form.find('input:radio, .riweeklyweekday > input, input[name=ridailyinterval], input[name=riweeklyinterval], input[name=rimonthlyinterval], input[name=riyearlyinterval]').change(
function (e) {
// Update only if the occurances are shown
if (form.find('.rioccurrencesactions:visible').length !== 0) {
updateOccurances();
}
}
);
/*
Save and cancel methods:
*/
form.find('.ricancelbutton').click(cancel);
form.find('.risavebutton').click(save);
/*
* Public API of RecurrenceInput
*/
$.extend(self, {
display: display,
form: form,
loadData: loadData, //Used by tests.
save: save //Used by tests.
});
}
/*
* jQuery plugin implementation
*/
$.fn.recurrenceinput = function (conf) {
if (this.data('recurrenceinput')) {
// plugin already installed
return this.data('recurrenceinput');
}
// "compile" configuration for widget
var config = $.extend({}, tool.conf);
$.extend(config, conf);
$.extend(config, {i18n: LABELS[config.lang], name: this.attr('name')});
// our recurrenceinput widget instance
var recurrenceinput = new RecurrenceInput(config, this);
// hide textarea and place display widget after textarea
recurrenceinput.form.appendTo('body');
this.after(recurrenceinput.display);
if (this.val()) {
recurrenceinput.display.find(
'input[name=richeckbox]'
).attr('checked', true);
}
// hide the textarea
this.hide();
// save the data for next call
this.data('recurrenceinput', recurrenceinput);
return recurrenceinput;
};
}(jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment