mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
2060 lines
96 KiB
JavaScript
2060 lines
96 KiB
JavaScript
/*jslint regexp: false, continue: true, indent: 4 */
|
||
/*global $, alert, jQuery */
|
||
"use strict";
|
||
|
||
(function ($) {
|
||
$.tools = $.tools || {version: '@VERSION'};
|
||
$.views.settings.debugMode(true);
|
||
|
||
var tool;
|
||
var LABELS = {};
|
||
|
||
tool = $.tools.recurrenceinput = {
|
||
conf: {
|
||
lang: 'de',
|
||
readOnly: false,
|
||
firstDay: 1,
|
||
prefix: '',
|
||
|
||
// "REMOTE" FIELD
|
||
startField: null,
|
||
startFieldYear: null,
|
||
startFieldMonth: null,
|
||
startFieldDay: null,
|
||
ajaxURL: null,
|
||
ajaxContentType: 'application/json; charset=utf8',
|
||
ributtonExtraClass: '',
|
||
|
||
// INPUT CONFIGURATION
|
||
hasRepeatForeverButton: true,
|
||
|
||
// 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'
|
||
]
|
||
},
|
||
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',
|
||
add_rules: 'Add',
|
||
edit_rules: 'Edit',
|
||
delete_rules: 'Delete',
|
||
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: [
|
||
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
|
||
'Friday', 'Saturday'],
|
||
shortWeekdays: [
|
||
'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||
|
||
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'
|
||
},
|
||
|
||
reccStart: 'Start date',
|
||
reccStartTime: 'Begin',
|
||
reccFoEndTime: 'End',
|
||
reccAllDay: 'All day',
|
||
removeEventDate: 'Remove event date',
|
||
});
|
||
|
||
|
||
var OCCURRENCETMPL = ['<div class="rioccurrences list-group list-group-flush">',
|
||
'{{for occurrences}}',
|
||
'<div class="occurrence {{:type}} list-group-item d-flex justify-content-between align-items-center p-1">',
|
||
'<span>',
|
||
'{{:formattedDate}}',
|
||
'{{if type === "start"}}',
|
||
'<span class="rlabel">{{:~root.i18n.recurrenceStart}}</span>',
|
||
'{{/if}}',
|
||
'{{if type === "rdate"}}',
|
||
'<span class="rlabel">{{:~root.i18n.additionalDate}}</span>',
|
||
'{{/if}}',
|
||
'</span>',
|
||
'{{if !~root.readOnly}}',
|
||
'<span class="action">',
|
||
'{{if type === "rrule"}}',
|
||
'<a date="{{:date}}" href="#"',
|
||
'class="{{:type}} btn btn-outline-secondary btn-sm" title="{{:~root.i18n.exclude}}">',
|
||
'<i class="fa fa-trash"></i>',
|
||
'</a>',
|
||
'{{/if}}',
|
||
'{{if type === "rdate"}}',
|
||
'<a date="{{:date}}" href="#"',
|
||
'class="{{:type}} btn btn-outline-secondary btn-sm" title="{{:~root.i18n.remove}}" >',
|
||
'<i class="fa fa-trash"></i>',
|
||
'</a>',
|
||
'{{/if}}',
|
||
'{{if type === "exdate"}}',
|
||
'<a date="{{:date}}" href="#"',
|
||
'class="{{:type}} btn btn-outline-secondary btn-sm" title="{{:~root.i18n.include}}">',
|
||
'<i class="fa fa-trash-restore"></i>',
|
||
'</a>',
|
||
'{{/if}}',
|
||
'</span>',
|
||
'{{/if}}',
|
||
'</div>',
|
||
'{{/for}}',
|
||
'<div class="batching">',
|
||
'{{for batch.batches}}',
|
||
'{{if #getIndex() === ~root.batch.currentBatch}}<span class="current">{{/if}}',
|
||
'<a href="#" start="{{:~root.batch.batches[#getIndex()][0]}}">[{{:~root.batch.batches[#getIndex()][0]}} - {{:~root.batch.batches[#getIndex()][1]}}]</a>',
|
||
'{{if #getIndex() === ~root.batch.currentBatch}}</span>{{/if}}',
|
||
'{{/for}}',
|
||
'</div></div>'].join('\n');
|
||
|
||
$.templates('occurrenceTmpl', OCCURRENCETMPL);
|
||
|
||
var DISPLAYTMPL = ['<div class="ridisplay">',
|
||
'<div class="rimain">',
|
||
'<div class="mb-2">',
|
||
'<div class="ridisplay-start"></div>',
|
||
'<div class="ridisplay-times"></div>',
|
||
'<div class="ridisplay">{{:i18n.displayUnactivate}}</div>',
|
||
'</div>',
|
||
'{{if !readOnly}}',
|
||
'<button type="button" name="riedit" class="btn btn-outline-secondary"><i class="fa fa-plus"></i> {{:i18n.add_rules}}</button>',
|
||
'<button type="button" name="ridelete" class="btn btn-outline-secondary" style="display:none"><i class="fa fa-times-circle"></i> {{:i18n.delete_rules}}</button>',
|
||
'<button type="button" class="btn btn-outline-secondary remove-date-defintion-btn d-none"><i class="fa fa-calendar-minus"></i> {{:i18n.removeEventDate}}</button>',
|
||
'{{/if}}',
|
||
'</div>',
|
||
'<div class="rioccurrences" style="display:none" /></div>'].join('\n');
|
||
|
||
$.templates('displayTmpl', DISPLAYTMPL);
|
||
|
||
var FORMTMPL = ['<div class="modal fade" tabindex="-1" role="dialog">',
|
||
'<div class="modal-dialog" role="document">',
|
||
'<div class="modal-content modal-recurrence">',
|
||
'<div class="modal-header">',
|
||
'<h5 class="modal-title">{{:i18n.title}}</h5>',
|
||
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">',
|
||
'<span aria-hidden="true">×</span>',
|
||
'</button>',
|
||
'</div>',
|
||
'<div class="modal-body">',
|
||
'<div class="riform">',
|
||
'<form>',
|
||
'<div id="{{:prefix}}messagearea" style="display: none;">',
|
||
'</div>',
|
||
|
||
'<div class="form-row">',
|
||
'<div class="form-group col-md-4">',
|
||
'<label class="mb-0" for="{{:prefix}}recc-start">{{:i18n.reccStart}}</label>',
|
||
'<input type="text" class="form-control datepicker" data-range-to="#{{:prefix}}recc-end" data-allday="#{{:prefix}}recc-allday" id="{{:prefix}}recc-start" name="recc-start" required="" />',
|
||
'</div>',
|
||
|
||
'<div class="form-group col-md-4" id="{{:prefix}}recc-start-time-group">',
|
||
'<label class="mb-0" for="{{:prefix}}recc-start-time">{{:i18n.reccStartTime}}</label>',
|
||
'<input type="text" class="form-control timepicker" id="{{:prefix}}recc-start-time" name="recc-start-time" required="" />',
|
||
'</div>',
|
||
|
||
'<div class="form-group col-md-4" id="{{:prefix}}recc-fo-end-time-group">',
|
||
'<label class="mb-0" for="{{:prefix}}recc-fo-end-time">{{:i18n.reccFoEndTime}}</label>',
|
||
'<input type="text" class="form-control timepicker" id="{{:prefix}}recc-fo-end-time" name="recc-fo-end-time" />',
|
||
'</div>',
|
||
'</div>',
|
||
|
||
'<div class="form-row">',
|
||
'<div class="form-group col-md">',
|
||
'<div class="form-check">',
|
||
'<input class="form-check-input" id="{{:prefix}}recc-allday" name="recc-allday" type="checkbox" value="y">',
|
||
'<label class="form-check-label" for="{{:prefix}}recc-allday">{{:i18n.reccAllDay}}</label>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
|
||
'<div class="form-row">',
|
||
'<div id="{{:prefix}}rirangeoptions" class="form-group col-md">',
|
||
'<label class="mb-0">{{:i18n.range}}</label>',
|
||
'<div class="input-group mb-1">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'checked="checked"',
|
||
'value="BYENDDATE"',
|
||
'name="rirangetype"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}rangetype:BYENDDATE"/>',
|
||
'{{:i18n.rangeByEndDate}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<input',
|
||
'type="text"',
|
||
'class="form-control"',
|
||
'name="rirangebyenddatecalendar" id="{{:prefix}}recc-end" />',
|
||
'</div>',
|
||
'<div class="input-group mb-1">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="BYOCCURRENCES"',
|
||
'name="rirangetype"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}rangetype:BYOCCURRENCES"/>',
|
||
'{{:i18n.rangeByOccurrences1}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<input',
|
||
'type="text" size="3"',
|
||
'value="7"',
|
||
'class="form-control"',
|
||
'name="rirangebyoccurrencesvalue" />',
|
||
'<div class="input-group-append">',
|
||
'<span class="input-group-text">',
|
||
'{{:i18n.rangeByOccurrences2}}',
|
||
'</span>',
|
||
'</div>',
|
||
'</div>',
|
||
'{{if hasRepeatForeverButton}}',
|
||
'<div class="input-group mb-1">',
|
||
'<div class="input-group-text w-100">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="NOENDDATE"',
|
||
'name="rirangetype"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}rangetype:NOENDDATE"/>',
|
||
'{{:i18n.rangeNoEnd}}',
|
||
'</div>',
|
||
'</div>',
|
||
'{{/if}}',
|
||
'</div>',
|
||
'</div>',
|
||
|
||
'<div class="form-row">',
|
||
'<div class="form-group col-md">',
|
||
'<label for="{{:name}}rtemplate" class="mb-0">',
|
||
'{{:i18n.recurrenceType}}',
|
||
'</label>',
|
||
'<select id="{{:prefix}}rirtemplate" name="rirtemplate" class="form-control">',
|
||
'{{props rtemplate}}',
|
||
'<option value="{{>key}}">{{:~root.i18n.rtemplate[key]}}</value>',
|
||
'{{/props}}',
|
||
'</select>',
|
||
'</div>',
|
||
|
||
'<div class="col-md">',
|
||
'<div id="{{:prefix}}ridailyinterval" class="form-group rifield">',
|
||
'<label for="{{:name}}dailyinterval" class="mb-0">',
|
||
'{{:i18n.dailyInterval1}}',
|
||
'</label>',
|
||
'<div class="input-group">',
|
||
'<input type="text" size="2"',
|
||
'value="1"',
|
||
'name="ridailyinterval"',
|
||
'class="form-control"',
|
||
'id="{{:prefix}}{{:name}}dailyinterval" />',
|
||
'<div class="input-group-append">',
|
||
'<span class="input-group-text">',
|
||
'{{:i18n.dailyInterval2}}',
|
||
'</span>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}riweeklyinterval" class="form-group rifield">',
|
||
'<label for="{{:name}}weeklyinterval" class="mb-0">',
|
||
'{{:i18n.weeklyInterval1}}',
|
||
'</label>',
|
||
'<div class="input-group">',
|
||
'<input type="text" size="2"',
|
||
'value="1"',
|
||
'name="riweeklyinterval"',
|
||
'class="form-control"',
|
||
'id="{{:prefix}}{{:name}}riweeklyinterval" />',
|
||
'<div class="input-group-append">',
|
||
'<span class="input-group-text">',
|
||
'{{:i18n.weeklyInterval2}}',
|
||
'</span>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}rimonthlyinterval" class="form-group rifield">',
|
||
'<label for="rimonthlyinterval" class="mb-0">{{:i18n.monthlyInterval1}}</label>',
|
||
'<div class="input-group">',
|
||
'<input type="text" size="2"',
|
||
'value="1"',
|
||
'name="rimonthlyinterval"',
|
||
'class="form-control" />',
|
||
'<div class="input-group-append">',
|
||
'<span class="input-group-text">',
|
||
'{{:i18n.monthlyInterval2}}',
|
||
'</span>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}riyearlyinterval" class="form-group rifield">',
|
||
'<label for="riyearlyinterval" class="mb-0">{{:i18n.yearlyInterval1}}</label>',
|
||
'<div class="input-group">',
|
||
'<input type="text" size="2"',
|
||
'value="1" ',
|
||
'class="form-control"',
|
||
'name="riyearlyinterval"/>',
|
||
'<div class="input-group-append">',
|
||
'<span class="input-group-text">',
|
||
'{{:i18n.yearlyInterval2}}',
|
||
'</span>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
|
||
'<div id="{{:prefix}}riweeklyweekdays" class="form-group rifield">',
|
||
'<label for="{{:name}}weeklyinterval" class="mb-0">{{:i18n.weeklyWeekdays}}</label>',
|
||
'<div>',
|
||
'{{for orderedWeekdays itemVar=\'~value\'}}',
|
||
'<div class="form-check form-check-inline">',
|
||
'<input type="checkbox"',
|
||
'name="riweeklyweekdays{{:~root.weekdays[~value]}}"',
|
||
'id="{{:prefix}}{{:name}}weeklyWeekdays{{:~root.weekdays[~value]}}"',
|
||
'class="form-check-input"',
|
||
'value="{{:~root.weekdays[~value]}}" />',
|
||
'<label for="{{:name}}weeklyWeekdays{{:~root.weekdays[~value]}}" class="form-check-label">{{:~root.i18n.shortWeekdays[~value]}}</label>',
|
||
'</div>',
|
||
'{{/for}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}rimonthlyoptions" class="form-group rifield">',
|
||
'<label for="rimonthlytype" class="mb-0">{{:i18n.monthlyRepeatOn}}</label>',
|
||
'<div>',
|
||
'<div class="input-group mb-1">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="DAYOFMONTH"',
|
||
'name="rimonthlytype"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}monthlytype:DAYOFMONTH" />',
|
||
'{{:i18n.monthlyDayOfMonth1}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<select name="rimonthlydayofmonthday" class="form-control"',
|
||
'id="{{:prefix}}{{:name}}monthlydayofmonthday">',
|
||
'{{for start=1 end=32}}',
|
||
'<option value="{{:}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<div class="input-group-append">',
|
||
'<div class="input-group-text">',
|
||
'{{:i18n.monthlyDayOfMonth2}}',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div class="input-group">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="WEEKDAYOFMONTH"',
|
||
'name="rimonthlytype"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}monthlytype:WEEKDAYOFMONTH" />',
|
||
'{{:i18n.monthlyWeekdayOfMonth1}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<select name="rimonthlyweekdayofmonthindex" class="form-control">',
|
||
'{{for i18n.orderIndexes}}',
|
||
'<option value="{{:~root.orderIndexes[$index]}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<select name="rimonthlyweekdayofmonth" class="form-control">',
|
||
'{{for orderedWeekdays itemVar=\'~value\'}}',
|
||
'<option value="{{:~root.weekdays[~value]}}">{{:~root.i18n.weekdays[~value]}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<div class="input-group-append">',
|
||
'<div class="input-group-text">',
|
||
'{{:i18n.monthlyWeekdayOfMonth3}}',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}riyearlyoptions" class="form-group rifield">',
|
||
'<label for="riyearlyType" class="mb-0">{{:i18n.yearlyRepeatOn}}</label>',
|
||
'<div>',
|
||
'<div class="input-group mb-1">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="DAYOFMONTH"',
|
||
'name="riyearlyType"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}yearlytype:DAYOFMONTH" />',
|
||
'{{:i18n.yearlyDayOfMonth1}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<select name="riyearlydayofmonthday" class="form-control">',
|
||
'{{for start=1 end=32}}',
|
||
'<option value="{{:}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<select name="riyearlydayofmonthmonth" class="form-control">',
|
||
'{{for i18n.months}}',
|
||
'<option value="{{:#getIndex()+1}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'</div>',
|
||
'<div class="input-group">',
|
||
'<div class="input-group-prepend">',
|
||
'<div class="input-group-text">',
|
||
'<input',
|
||
'type="radio"',
|
||
'value="WEEKDAYOFMONTH"',
|
||
'name="riyearlyType"',
|
||
'class="form-check-inline"',
|
||
'id="{{:prefix}}{{:name}}yearlytype:WEEKDAYOFMONTH"/>',
|
||
'{{:i18n.yearlyWeekdayOfMonth1}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<select name="riyearlyweekdayofmonthindex" class="form-control">',
|
||
'{{for i18n.orderIndexes}}',
|
||
'<option value="{{:~root.orderIndexes[#getIndex()]}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<select name="riyearlyweekdayofmonthday" class="form-control">',
|
||
'{{for orderedWeekdays itemVar=\'~value\'}}',
|
||
'<option value="{{:~root.weekdays[~value]}}">{{:~root.i18n.weekdays[~value]}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'<div class="input-group-append">',
|
||
'<div class="input-group-text">',
|
||
'{{:i18n.yearlyWeekdayOfMonth3}}',
|
||
'</div>',
|
||
'</div>',
|
||
'<select name="riyearlyweekdayofmonthmonth" class="form-control">',
|
||
'{{for i18n.months}}',
|
||
'<option value="{{:#getIndex()+1}}">{{:}}</option>',
|
||
'{{/for}}',
|
||
'</select>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
|
||
'<div id="{{:prefix}}occurences-show-container">',
|
||
'<a href="#" class="show-link" data-container="{{:prefix}}occurences-container" data-show-container="{{:prefix}}occurences-show-container"><i class="fa fa-chevron-down"></i> {{:i18n.preview}}</a>',
|
||
'</div>',
|
||
'<div id="{{:prefix}}occurences-container" style="display: none;">',
|
||
'<div class="rioccurrencesactions">',
|
||
'<div class="rioccurancesheader">',
|
||
'<h2 class="my-2">{{:i18n.preview}}',
|
||
'<span class="refreshbutton action">',
|
||
'<a class="btn btn-sm btn-outline-secondary rirefreshbutton" href="#" title="{{:i18n.refresh}}">',
|
||
'<i class="fa fa-sync-alt"></i>',
|
||
'</a>',
|
||
'</span>',
|
||
'</h2>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div class="rioccurrences">',
|
||
'</div>',
|
||
'<div class="rioccurrencesactions">',
|
||
'<div class="riaddoccurrence mt-3">',
|
||
'<div class="errorarea"></div>',
|
||
'<div class="input-group">',
|
||
'<div class="input-group-prepend">',
|
||
'<span class="input-group-text">{{:i18n.addDate}}</span>',
|
||
'</div>',
|
||
'<input type="text" class="form-control" name="adddate" id="{{:prefix}}adddate" />',
|
||
'<div class="input-group-append">',
|
||
'<input type="button" class="btn btn-outline-secondary" name="addoccurencebtn" id="{{:prefix}}addoccurencebtn" value="{{:i18n.add}}" />',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div class="mt-3" id="{{:prefix}}occurences-hide-container">',
|
||
'<a href="#" class="hide-link" data-container="{{:prefix}}occurences-container" data-show-container="{{:prefix}}occurences-show-container"><i class="fa fa-chevron-up"></i> {{:i18n.preview}}</a>',
|
||
'</div>',
|
||
'</div>',
|
||
'</form>',
|
||
'</div>',
|
||
'</div>',
|
||
'<div class="modal-footer">',
|
||
'<button type="button" class="btn btn-secondary" data-dismiss="modal">{{:i18n.cancel}}</button>',
|
||
'<button type="button" class="btn btn-primary risavebutton">{{:i18n.save}}</button>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>',
|
||
'</div>'].join('\n');
|
||
|
||
$.templates('formTmpl', FORMTMPL);
|
||
|
||
function format(date, fmt, conf) {
|
||
return $.datepicker.formatDate(fmt, date);
|
||
}
|
||
|
||
/**
|
||
* 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('#' + conf.prefix + rtemplate.fields[i]);
|
||
|
||
switch (rtemplate.fields[i]) {
|
||
|
||
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 ($.inArray(day, ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']) > -1) {
|
||
result += ';BYDAY=' + index + day;
|
||
human += ', ' + conf.i18n.monthlyWeekdayOfMonth1Human + ' ';
|
||
human += ' ' + conf.i18n.orderIndexes[$.inArray(index, conf.orderIndexes)];
|
||
human += ' ' + conf.i18n.monthlyWeekdayOfMonth2;
|
||
human += ' ' + conf.i18n.weekdays[$.inArray(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 ($.inArray(day, ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']) > -1) {
|
||
result += ';BYDAY=' + index + day;
|
||
human += ', ' + conf.i18n.yearlyWeekdayOfMonth1Human;
|
||
human += ' ' + conf.i18n.orderIndexes[$.inArray(index, conf.orderIndexes)];
|
||
human += ' ' + conf.i18n.yearlyWeekdayOfMonth2;
|
||
human += ' ' + conf.i18n.weekdays[$.inArray(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 = $.datepicker.formatDate("yymmdd", field.data('picker').datepicker("getDate"));
|
||
result += ';UNTIL=' + date + 'T000000';
|
||
if (tz === true) {
|
||
// Make it UTC:
|
||
result += 'Z';
|
||
}
|
||
human += ', ' + conf.i18n.rangeByEndDateHuman;
|
||
human += ' ' + $.datepicker.formatDate("D, dd.mm.yy", field.data('picker').datepicker("getDate"));
|
||
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);
|
||
|
||
if (property.indexOf(';') !== -1) {
|
||
pos = property.indexOf(';');
|
||
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 (splitDates[date].indexOf('Z') !== -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('#' + conf.prefix + rtemplate.fields[i]);
|
||
switch (rtemplate.fields[i]) {
|
||
|
||
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.prop('checked', $.inArray(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 (byday.indexOf(',') !== -1) {
|
||
// No support for multiple days in one month
|
||
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
|
||
byday = byday.split(",")[0];
|
||
}
|
||
index = byday.slice(0, -2);
|
||
if (index.charAt(0) !== '+' && index.charAt(0) !== '-') {
|
||
index = '+' + index;
|
||
}
|
||
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).prop('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 (byday.indexOf(',') !== -1) {
|
||
// No support for multiple days in one month
|
||
unsupportedFeatures.push(conf.i18n.multipleDayOfMonth);
|
||
byday = byday.split(",")[0];
|
||
}
|
||
index = byday.slice(0, -2);
|
||
if (index.charAt(0) !== '+' && index.charAt(0) !== '-') {
|
||
index = '+' + index;
|
||
}
|
||
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).prop('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('picker').datepicker("setDate", new Date(year, month, day));
|
||
}
|
||
|
||
selectors = field.find('input[name=rirangetype]');
|
||
for (index = 0; index < selectors.length; index++) {
|
||
radiobutton = selectors[index];
|
||
$(radiobutton).prop('checked', radiobutton.value === rangeType);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
var messagearea = form.find('#' + conf.prefix + '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, dialog;
|
||
var prefix = conf.prefix;
|
||
|
||
// Extend conf with non-configurable data used by templates.
|
||
var orderedWeekdays = [];
|
||
var index, i;
|
||
for (i = 0; i < 7; i++) {
|
||
index = i + conf.firstDay;
|
||
if (index > 6) {
|
||
index = index - 7;
|
||
}
|
||
orderedWeekdays.push(index);
|
||
}
|
||
|
||
$.extend(conf, {
|
||
orderIndexes: ['+1', '+2', '+3', '+4', '-1'],
|
||
weekdays: ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'],
|
||
orderedWeekdays: orderedWeekdays
|
||
});
|
||
|
||
// 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('#' + conf.prefix + 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.removeClass('rrule').addClass('exdate');
|
||
$this.parent().parent().addClass('exdate');
|
||
$(this).find('i').removeClass('fa-trash').addClass('fa-trash-restore');
|
||
$this.unbind(event);
|
||
$this.click(occurrenceInclude); // Jslint warns here, but that's OK.
|
||
}
|
||
|
||
function occurrenceInclude(event) {
|
||
event.preventDefault();
|
||
form.ical.EXDATE.splice($.inArray(this.attributes.date.value, form.ical.EXDATE), 1);
|
||
var $this = $(this);
|
||
$this.removeClass('exdate').addClass('rrule');
|
||
$this.parent().parent().removeClass('exdate');
|
||
$(this).find('i').removeClass('fa-trash-restore').addClass('fa-trash');
|
||
$this.unbind(event);
|
||
$this.click(occurrenceExclude);
|
||
}
|
||
|
||
function occurrenceDelete(event) {
|
||
event.preventDefault();
|
||
form.ical.RDATE.splice($.inArray(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#' + conf.prefix + 'adddate');
|
||
var datevalue = $.datepicker.formatDate("yymmdd", dateinput.data('picker').datepicker("getDate")) + 'T000000';
|
||
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 ($.inArray(datevalue, form.ical.RDATE) === -1) {
|
||
form.ical.RDATE.push(datevalue);
|
||
var html = ['<div class="occurrence rdate list-group-item d-flex justify-content-between align-items-center p-1" style="display: none;">',
|
||
'<span class="rdate">',
|
||
$.datepicker.formatDate("D, dd.mm.yy", dateinput.data('picker').datepicker("getDate")),
|
||
'<span class="rlabel">' + conf.i18n.additionalDate + '</span>',
|
||
'</span>',
|
||
'<span class="action">',
|
||
'<a date="' + datevalue + '" href="#" class="rdate btn btn-outline-secondary btn-sm" >',
|
||
'<i class="fa fa-trash"></i>',
|
||
'</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();
|
||
|
||
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('<i class="fa fa-edit"></i> ' + 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('<i class="fa fa-plus"></i>' + 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',
|
||
}); |