'].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();
var year, month, day;
year = startdate.getFullYear();
month = startdate.getMonth() + 1;
day = startdate.getDate();
var data = {year: year,
month: month, // Sending January as 0? I think not.
day: day,
rrule: rfc5545,
format: conf.i18n.longDateFormat,
start: start};
var dict = {
url: conf.ajaxURL,
async: true, // Can't be tested if it's asynchronous, annoyingly.
type: 'post',
dataType: 'json',
contentType: conf.ajaxContentType,
cache: false,
data: JSON.stringify(data, null, '\t'),
success: function (data, status, jqXHR) {
var result, element;
if (!readonly) {
element = form;
} else {
element = display;
}
data.readOnly = readonly;
data.i18n = conf.i18n;
// Format dates:
var occurrence, date, y, m, d, each;
for (each in data.occurrences) {
if (data.occurrences.hasOwnProperty(each)) {
occurrence = data.occurrences[each];
date = occurrence.date;
y = parseInt(date.substring(0, 4), 10);
m = parseInt(date.substring(4, 6), 10) - 1; // jan=0
d = parseInt(date.substring(6, 8), 10);
occurrence.formattedDate = format(new Date(y, m, d), conf.i18n.longDateFormat, conf);
}
}
result = $.templates.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 + " " + jqXHR.statusText + " " + jqXHR.responseText);
}
};
$.ajax(dict);
}
function getField(field) {
var realField = null;
if (field instanceof Element) {
// See if it is a field already
realField = $(field);
}
if (realField == null || !realField.length) {
// Otherwise, we assume it's an id:
realField = $('#' + field);
}
if (realField == null || !realField.length) {
// Still not? Then it's a name.
realField = $("input[name='" + field + "']");
}
return realField;
}
function findStartDate() {
var startdate = null;
var startField, startFieldYear, startFieldMonth, startFieldDay;
var startField = conf.prefix + 'recc-start'; // conf.startField;
// Find the default byday and bymonthday from the start date, if any:
if (startField) {
startField = getField(startField);
if (!startField.length) {
// Field not found
return null;
}
// 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();
}
if (typeof startdate === 'string') {
// convert human readable, non ISO8601 dates, like
// '2014-04-24 19:00', where the 'T' separator is missing.
startdate = startdate.replace(' ', 'T');
}
startdate = new Date(startdate);
} else if (conf.startFieldYear &&
conf.startFieldMonth &&
conf.startFieldDay) {
startFieldYear = getField(conf.startFieldYear);
startFieldMonth = getField(conf.startFieldMonth);
startFieldDay = getField(conf.startFieldDay);
if (!startFieldYear.length &&
!startFieldMonth.length &&
!startFieldDay.length) {
// Field not found
return null;
}
startdate = new Date(startFieldYear.val(),
startFieldMonth.val() - 1,
startFieldDay.val());
}
if (startdate === null) {
return null;
}
// We have some sort of 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);
}
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()];
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 displayOn() {
display.find('div[class=ridisplay-start]').text($('#' + conf.prefix + 'start-user').val());
if ($('#' + conf.prefix + 'allday').is(':checked')) {
display.find('div[class=ridisplay-times]').text(conf.i18n.reccAllDay);
} else {
var times = $('#' + conf.prefix + 'start-time').val();
var end_time = $('#' + conf.prefix + 'end-time').val();
if (end_time) {
times += ' - ' + end_time
}
display.find('div[class=ridisplay-times]').text(times);
}
$('#' + conf.prefix + 'single-event-container').hide();
$('#' + conf.prefix + 'recc-event-container').show();
}
function recurrenceOn() {
var RFC5545 = widgetSaveToRfc5545(form, conf, false);
var label = display.find('div[class=ridisplay]');
label.text(conf.i18n.displayActivate + ' ' + RFC5545.description);
textarea.val(RFC5545.result).change();
// var startdate = findStartDate();
// if (startdate !== null) {
// loadOccurrences(startdate, widgetSaveToRfc5545(form, conf, false).result, 0, true);
// }
display.find('button[name="riedit"]').html(' ' + conf.i18n.edit_rules);
display.find('button[name="ridelete"]').show();
displayOn();
}
function displayOff() {
$('#' + conf.prefix + 'single-event-container').show();
$('#' + conf.prefix + 'recc-event-container').hide();
}
function recurrenceOff() {
var label = display.find('div[class=ridisplay]');
label.text(conf.i18n.displayUnactivate);
textarea.val('').change(); // Clear the textarea.
display.find('.rioccurrences').hide();
display.find('button[name="riedit"]').html('' + conf.i18n.add_rules);
display.find('button[name="ridelete"]').hide();
set_picker_date($('#' + conf.prefix + 'end-user'), null);
hideLink(null, $("#" + conf.prefix + "end-hide-container a.hide-link"));
displayOff();
}
function checkFields(form) {
var startDate, endDate, num, messagearea;
startDate = findStartDate();
// Hide any error message from before
messagearea = form.find('#' + conf.prefix + 'messagearea');
messagearea.text('');
messagearea.hide();
// Hide add field errors
form.find('.riaddoccurrence div.errorarea').text('').hide();
// Repeats Daily
if (form.find('#' + conf.prefix + '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('#' + conf.prefix + '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('#' + conf.prefix + '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('#' + conf.prefix + '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)) {
var start_moment = get_moment_with_time_from_fields(form.find('input[name=recc-start]'), form.find('input[name=recc-start-time]'));
set_picker_date($('#' + conf.prefix + 'start-user'), start_moment.toDate());
var end_time = form.find('input[name=recc-fo-end-time]').timepicker("getTime");
var end_datetime = null;
if (end_time != null) {
var end_moment = moment(start_moment).set({hour: end_time.getHours(), minute: end_time.getMinutes()});
if (end_moment < start_moment) {
end_moment = end_moment.add(1, 'days');
}
end_datetime = end_moment.toDate()
}
set_picker_date($('#' + conf.prefix + 'end-user'), end_datetime);
$('#' + conf.prefix + 'allday').prop('checked', form.find('input[name=recc-allday]').is(':checked'));
recurrenceOn();
// close overlay
dialog.modal('hide');
//form.overlay().close();
}
}
function cancel(event) {
event.preventDefault();
// close overlay
dialog.modal('hide');
//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 = $($.templates.displayTmpl(conf));
form = $($.templates.formTmpl(conf));
// Make an overlay and hide it
dialog = form;
//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()
start_datepicker(form.find('input[name=recc-start]'));
var rirangebyenddatecalendar_input = form.find('input[name=rirangebyenddatecalendar]');
start_datepicker(rirangebyenddatecalendar_input).datepicker("setDate", moment().toDate());
start_timepicker(form.find('input[name=recc-start-time]'));
start_timepicker(form.find('input[name=recc-fo-end-time]'));
if (textarea.val()) {
var result = widgetLoadFromRfc5545(form, conf, textarea.val(), false);
if (result === -1) {
var label = display.find('div[class=ridisplay]');
label.text(conf.i18n.noRule);
displayOff();
} else {
recurrenceOn();
}
} else {
displayOff();
}
/*
Do all the GUI stuff:
*/
// When you click "Delete...", the recurrence rules should be cleared.
display.find('button[name=ridelete]').click(function (e) {
e.preventDefault();
recurrenceOff();
});
// Show form overlay when you click on the "Edit..." link
display.find('button[name=riedit]').click(
function (e) {
// Load the form to set up the right fields to show, etc.
loadData(textarea.val());
e.preventDefault();
dialog.modal();
//form.overlay().load();
}
);
dialog.on('shown.bs.modal', function (e) {
var recc_start_time = form.find('input[name=recc-start-time]');
var recc_fo_end_time = form.find('input[name=recc-fo-end-time]');
recc_start_time.change(function() {
recc_fo_end_time.timepicker('option', 'minTime', $(this).timepicker("getTime"));
});
var recc_start_picker = form.find('input[id=' + conf.prefix + 'recc-start-user]');
var start_date = $('#' + conf.prefix + 'start-user').datepicker("getDate");
recc_start_picker.datepicker("setDate", start_date);
set_date_bounds(recc_start_picker);
recc_start_time.timepicker('setTime', $('#' + conf.prefix + 'start-time').timepicker("getTime"));
recc_start_time.change();
recc_fo_end_time.timepicker('setTime', $('#' + conf.prefix + 'end-time').timepicker("getTime"));
var recc_allday = form.find('input[name=recc-allday]');
recc_allday.prop('checked', $('#' + conf.prefix + 'allday').is(':checked'));
var allday_checked = recc_allday.is(':checked');
var recc_start_time_group = form.find("#" + conf.prefix + "recc-start-time-group");
var recc_fo_end_time_group = form.find("#" + conf.prefix + "recc-fo-end-time-group");
recc_start_time_group.toggle(!allday_checked);
recc_fo_end_time_group.toggle(!allday_checked);
recc_allday.on('change', function() {
recc_start_time_group.toggle(!this.checked);
recc_fo_end_time_group.toggle(!this.checked);
onAlldayChecked(this, conf.prefix + "recc-start");
var end_moment = get_moment_with_time_from_fields(form.find('input[name=recc-start]'), form.find('input[name=recc-start-time]'));
if (this.checked) {
end_moment = end_moment.endOf('day');
} else {
end_moment = end_moment.add(3, 'hours');
}
recc_fo_end_time.timepicker('setTime', end_moment.toDate());
});
form.find('#' + conf.prefix + 'occurences-show-container .show-link').click(function(e){
showLink(e, this);
});
form.find('#' + conf.prefix + 'occurences-hide-container .hide-link').click(function(e){
hideLink(e, this);
});
// Load the form to set up the right fields to show, etc.
loadData(textarea.val());
});
// Pop up the little add form when clicking "Add"
var riaddoccurrence_input = form.find('div.riaddoccurrence input#' + conf.prefix + 'adddate');
start_datepicker(riaddoccurrence_input).datepicker("setDate", moment().toDate());
form.find('input#' + conf.prefix + 'addoccurencebtn').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], input[name=recc-start]').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);
$('#' + conf.prefix + 'recc-button').click(function() {
display.find('button[name="riedit"]').click();
});
/*
* 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);
// hide the textarea
this.hide();
// save the data for next call
this.data('recurrenceinput', recurrenceinput);
return recurrenceinput;
};
}(jQuery));
jQuery.tools.recurrenceinput.localize("de", {
displayUnactivate: "Keine Wiederholungen",
displayActivate: "Alle ",
edit_rules: "Serie bearbeiten...",
add_rules: "Hinzufügen...",
delete_rules: "Serie zurücksetzen",
add: "Hinzufügen",
refresh: "Aktualisieren",
title: "Serientermin",
preview: "Ausgewählte Termine",
addDate: "Termin hinzufügen",
recurrenceType: "Wiederholt sich",
dailyInterval1: "Wiederholt sich alle",
dailyInterval2: "Tage",
weeklyInterval1: "Wiederholt sich alle",
weeklyInterval2: "Woche(n)",
weeklyWeekdays: "Wiederholt sich alle",
weeklyWeekdaysHuman: "am: ",
monthlyInterval1: "Wiederholt sich alle",
monthlyInterval2: "Monat(e)",
monthlyDayOfMonth1: "Tag",
monthlyDayOfMonth1Human: "am Tag",
monthlyDayOfMonth2: "des Monats",
monthlyDayOfMonth3: "Monat(e)",
monthlyDayOfMonth4: "monthly_day_of_month_4",
monthlyWeekdayOfMonth1: "Den",
monthlyWeekdayOfMonth1Human: "am",
monthlyWeekdayOfMonth2: " ",
monthlyWeekdayOfMonth3: "im Monat",
monthlyRepeatOn: "Wiederholt sich",
yearlyInterval1: "Wiederholt sich alle",
yearlyInterval2: "Jahr(e)",
yearlyDayOfMonth1: "Jeden",
yearlyDayOfMonth1Human: "am",
yearlyDayOfMonth2: " ",
yearlyDayOfMonth3: " ",
yearlyWeekdayOfMonth1: "Jeden",
yearlyWeekdayOfMonth1Human: "am",
yearlyWeekdayOfMonth2: " ",
yearlyWeekdayOfMonth3: "im",
yearlyWeekdayOfMonth4: " ",
yearlyRepeatOn: "Wiederholt sich",
range: "Ende der Wiederholung",
rangeNoEnd: "Niemals",
rangeByOccurrences1: "Endet nach",
rangeByOccurrences1Human: "endet nach",
rangeByOccurrences2: "Ereigniss(en)",
rangeByEndDate: "Bis ",
rangeByEndDateHuman: "endet am ",
including: ", und auch ",
except: ", ausser für",
cancel: "Abbrechen",
save: "Speichern",
recurrenceStart: "Beginn der Wiederholung",
additionalDate: "Weitere Termine",
include: "Eingeschlossen",
exclude: "Ausgenommen",
remove: "Entfernen",
orderIndexes: ["ersten", "zweiten", "dritten", "vierten", "letzten"],
months: [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember",
],
shortMonths: [
"Jan",
"Feb",
"Mär",
"Apr",
"Mai",
"Jun",
"Jul",
"Aug",
"Sep",
"Okt",
"Nov",
"Dez",
],
weekdays: [
"Sonntag",
"Montag",
"Dienstag",
"Mittwoch",
"Donnerstag",
"Freitag",
"Samstag",
],
shortWeekdays: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"],
longDateFormat: "D, dd.mm.yy",
shortDateFormat: "dd.mm.yy",
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:
"Dieses Widget unterstützt keine mehrfach angelegten Tage in monatlicher oder jährlicher Wiederholung",
bysetpos: "BYSETPOS wird nicht unterstützt",
noRule: "Keine RRULE in RRULE Daten",
noRepeatEvery: 'Error: The "Repeat every"-field must be between 1 and 1000',
noEndDate:
"Fehler: Das Terminende ist nicht gesetzt. Bitte geben Sie einen korrekten Wert ein.",
noRepeatOn: 'Error: "Repeat on"-value must be selected',
pastEndDate: "Fehler: Das Terminende kann nicht vor dem Terminanfang sein.",
noEndAfterNOccurrences:
'Error: The "After N occurrences"-field must be between 1 and 1000',
alreadyAdded: "Das Datum wurde bereits hinzugefügt",
rtemplate: {
daily: "Täglich",
mondayfriday: "Montags und Freitags",
weekdays: "Wochentags",
weekly: "Wöchentlich",
monthly: "Monatlich",
yearly: "Jährlich",
},
reccStart: "Startdatum",
reccStartTime: "Beginn",
reccFoEndTime: "Ende",
reccAllDay: "Ganztägig",
removeEventDate: 'Termin entfernen',
});