Upgrade to fullcalendar 3.9.0 - Part I

Just started, still many issues, no printing, no elastic, no agenda view
This commit is contained in:
Aleksander Machniak 2019-01-04 16:12:33 +00:00
parent 618fbe9b35
commit eb85d762c7
9 changed files with 21074 additions and 7809 deletions

View file

@ -1323,12 +1323,21 @@ class calendar extends rcube_plugin
*/ */
function load_events() function load_events()
{ {
$events = $this->driver->load_events( $start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GET);
rcube_utils::get_input_value('start', rcube_utils::INPUT_GET), $end = rcube_utils::get_input_value('end', rcube_utils::INPUT_GET);
rcube_utils::get_input_value('end', rcube_utils::INPUT_GET), $query = rcube_utils::get_input_value('q', rcube_utils::INPUT_GET);
($query = rcube_utils::get_input_value('q', rcube_utils::INPUT_GET)), $sorce = rcube_utils::get_input_value('source', rcube_utils::INPUT_GET);
rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)
); if (!is_numeric($start) || strpos($start, 'T')) {
$start = new DateTime($start, $this->timezone);
$start = $start->getTimestamp();
}
if (!is_numeric($end) || strpos($end, 'T')) {
$end = new DateTime($end, $this->timezone);
$end = $end->getTimestamp();
}
$events = $this->driver->load_events($start, $end, $query, $source);
echo $this->encode($events, !empty($query)); echo $this->encode($events, !empty($query));
exit; exit;
} }
@ -1767,8 +1776,6 @@ class calendar extends rcube_plugin
// configuration // configuration
$settings['default_calendar'] = $this->rc->config->get('calendar_default_calendar'); $settings['default_calendar'] = $this->rc->config->get('calendar_default_calendar');
$settings['default_view'] = (string)$this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view']); $settings['default_view'] = (string)$this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view']);
$settings['date_agenda'] = (string)$this->rc->config->get('calendar_date_agenda', $this->defaults['calendar_date_agenda']);
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']); $settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']); $settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
$settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']); $settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
@ -1889,24 +1896,31 @@ class calendar extends rcube_plugin
$event['description'] = trim($h2t->get_text()); $event['description'] = trim($h2t->get_text());
} }
// mapping url => vurl because of the fullcalendar client script // mapping url => vurl, allday => allDay because of the fullcalendar client script
$event['vurl'] = $event['url']; $event['vurl'] = $event['url'];
$event['allDay'] = !empty($event['allday']);
unset($event['url']); unset($event['url']);
unset($event['allday']);
$event['className'] = $event['className'] ? explode(' ', $event['className']) : array();
if ($addcss) {
$event['className'][] = 'fc-event-cal-' . asciiwords($event['calendar'], true);
}
if ($event['allDay']) {
$event['end'] = $event['end']->add(new DateInterval('P1D'));
}
return array( return array(
'_id' => $event['calendar'] . ':' . $event['id'], // unique identifier for fullcalendar '_id' => $event['calendar'] . ':' . $event['id'], // unique identifier for fullcalendar
'start' => $this->lib->adjust_timezone($event['start'], $event['allday'])->format('c'), 'start' => $this->lib->adjust_timezone($event['start'], $event['allDay'])->format('c'),
'end' => $this->lib->adjust_timezone($event['end'], $event['allday'])->format('c'), 'end' => $this->lib->adjust_timezone($event['end'], $event['allDay'])->format('c'),
// 'changed' might be empty for event recurrences (Bug #2185) // 'changed' might be empty for event recurrences (Bug #2185)
'changed' => $event['changed'] ? $this->lib->adjust_timezone($event['changed'])->format('c') : null, 'changed' => $event['changed'] ? $this->lib->adjust_timezone($event['changed'])->format('c') : null,
'created' => $event['created'] ? $this->lib->adjust_timezone($event['created'])->format('c') : null, 'created' => $event['created'] ? $this->lib->adjust_timezone($event['created'])->format('c') : null,
'title' => strval($event['title']), 'title' => strval($event['title']),
'description' => strval($event['description']), 'description' => strval($event['description']),
'location' => strval($event['location']), 'location' => strval($event['location']),
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') .
'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true) .
rtrim(' ' . $event['className']),
'allDay' => ($event['allday'] == 1),
) + $event; ) + $event;
} }
@ -2056,7 +2070,11 @@ class calendar extends rcube_plugin
// convert dates into DateTime objects in user's current timezone // convert dates into DateTime objects in user's current timezone
$event['start'] = new DateTime($event['start'], $this->timezone); $event['start'] = new DateTime($event['start'], $this->timezone);
$event['end'] = new DateTime($event['end'], $this->timezone); $event['end'] = new DateTime($event['end'], $this->timezone);
$event['allday'] = (bool)$event['allday']; $event['allday'] = (bool) (isset($event['allDay']) ? $event['allDay'] : $event['allday']);
if ($event['allday']) {
}
// start/end is all we need for 'move' action (#1480) // start/end is all we need for 'move' action (#1480)
if ($action == 'move') { if ($action == 'move') {
@ -2433,14 +2451,15 @@ class calendar extends rcube_plugin
$skin_path = $this->local_skin_path(); $skin_path = $this->local_skin_path();
$this->include_stylesheet($skin_path . '/fullcalendar.css'); $this->include_stylesheet($skin_path . '/fullcalendar.css');
$this->include_stylesheet($skin_path . '/print.css'); $this->include_stylesheet($skin_path . '/print.css');
// Add JS files to the page header // Add JS files to the page header
$this->include_script('print.js'); $this->include_script('print.js');
$this->include_script('lib/js/moment.js');
$this->include_script('lib/js/fullcalendar.js'); $this->include_script('lib/js/fullcalendar.js');
$this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css')); $this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css'));
$this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list')); $this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list'));
$this->rc->output->set_pagetitle($title); $this->rc->output->set_pagetitle($title);
$this->rc->output->send("calendar.print"); $this->rc->output->send("calendar.print");
} }

View file

@ -71,20 +71,6 @@ function rcube_calendar_ui(settings)
var sensitivitylabels = { 'public':rcmail.gettext('public','calendar'), 'private':rcmail.gettext('private','calendar'), 'confidential':rcmail.gettext('confidential','calendar') }; var sensitivitylabels = { 'public':rcmail.gettext('public','calendar'), 'private':rcmail.gettext('private','calendar'), 'confidential':rcmail.gettext('confidential','calendar') };
var ui_loading = rcmail.set_busy(true, 'loading'); var ui_loading = rcmail.set_busy(true, 'loading');
// general datepicker settings
var datepicker_settings = {
// translate from fullcalendar format to datepicker format
dateFormat: settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'),
firstDay: settings.first_day,
// dayNamesMin: settings.days_short,
monthNames: settings.months,
monthNamesShort: settings.months,
changeMonth: false,
showWeek: settings.show_weekno >= 0,
showOtherMonths: true,
selectOtherMonths: true
};
// global fullcalendar settings // global fullcalendar settings
var fullcalendar_defaults = { var fullcalendar_defaults = {
aspectRatio: 1, aspectRatio: 1,
@ -96,42 +82,52 @@ function rcube_calendar_ui(settings)
firstDay : settings.first_day, firstDay : settings.first_day,
firstHour : settings.first_hour, firstHour : settings.first_hour,
slotMinutes : 60/settings.timeslots, slotMinutes : 60/settings.timeslots,
timeFormat: { views: {
'': settings.time_format, basic: {
agenda: settings.time_format + '{ - ' + settings.time_format + '}', timeFormat: settings.time_format,
list: settings.time_format + '{ - ' + settings.time_format + '}', },
table: settings.time_format + '{ - ' + settings.time_format + '}' year: {
columnFormat: settings.date_agenda,
titleFormat: settings.dates_long,
},
month: {
columnFormat: 'ddd', // Mon
titleFormat: 'MMMM YYYY',
},
week: {
columnFormat: 'ddd ' + settings.date_short, // Mon 9/7
titleFormat: settings.dates_long,
},
day: {
columnFormat: 'dddd ' + settings.date_short, // Monday 9/7
titleFormat: 'dddd ' + settings.date_long,
}
}, },
timeFormat: settings.time_format,
axisFormat : settings.time_format, axisFormat : settings.time_format,
columnFormat: { /*
month: 'ddd', // Mon
week: 'ddd ' + settings.date_short, // Mon 9/7
day: 'dddd ' + settings.date_short, // Monday 9/7
table: settings.date_agenda
},
titleFormat: {
month: 'MMMM yyyy',
week: settings.dates_long,
day: 'dddd ' + settings.date_long,
table: settings.dates_long
},
listPage: 7, // advance one week in agenda view listPage: 7, // advance one week in agenda view
listRange: settings.agenda_range, listRange: settings.agenda_range,
listSections: settings.agenda_sections, listSections: settings.agenda_sections,
tableCols: ['handle', 'date', 'time', 'title', 'location'], tableCols: ['handle', 'date', 'time', 'title', 'location'],
*/
defaultView: rcmail.env.view || settings.default_view, defaultView: rcmail.env.view || settings.default_view,
allDayText: rcmail.gettext('all-day', 'calendar'), allDayText: rcmail.gettext('all-day', 'calendar'),
weekNumbers: settings.show_weekno > 0, weekNumbers: settings.show_weekno > 0,
weekNumberTitle: rcmail.gettext('weekshort', 'calendar') + ' ', weekNumberTitle: rcmail.gettext('weekshort', 'calendar') + ' ',
buttonText: { buttonText: {
prev: ' ◄ ',
next: ' ► ',
today: settings['today'], today: settings['today'],
day: rcmail.gettext('day', 'calendar'), day: rcmail.gettext('day', 'calendar'),
week: rcmail.gettext('week', 'calendar'), week: rcmail.gettext('week', 'calendar'),
month: rcmail.gettext('month', 'calendar'), month: rcmail.gettext('month', 'calendar'),
table: rcmail.gettext('agenda', 'calendar') listYear: rcmail.gettext('agenda', 'calendar')
}, },
buttonIcons: {
prev: 'left-single-arrow',
next: 'right-single-arrow'
},
theme: false,
/*
listTexts: { listTexts: {
until: rcmail.gettext('until', 'calendar'), until: rcmail.gettext('until', 'calendar'),
past: rcmail.gettext('pastevents', 'calendar'), past: rcmail.gettext('pastevents', 'calendar'),
@ -144,6 +140,7 @@ function rcube_calendar_ui(settings)
future: rcmail.gettext('futureevents', 'calendar'), future: rcmail.gettext('futureevents', 'calendar'),
week: rcmail.gettext('weekofyear', 'calendar') week: rcmail.gettext('weekofyear', 'calendar')
}, },
*/
currentTimeIndicator: settings.time_indicator, currentTimeIndicator: settings.time_indicator,
// event rendering // event rendering
eventRender: function(event, element, view) { eventRender: function(event, element, view) {
@ -153,14 +150,15 @@ function rcube_calendar_ui(settings)
} }
if (view.name != 'month') { if (view.name != 'month') {
if (event.location) { if (event.location) {
element.find('div.fc-event-title').after('<div class="fc-event-location">@&nbsp;' + Q(event.location) + '</div>'); element.find('div.fc-title').after('<div class="fc-event-location">@&nbsp;' + Q(event.location) + '</div>');
} }
var time_element = element.find('div.fc-time');
if (event.sensitivity && event.sensitivity != 'public') if (event.sensitivity && event.sensitivity != 'public')
element.find('div.fc-event-time').append('<i class="fc-icon-sensitive"></i>'); time_element.append('<i class="fc-icon-sensitive"></i>');
if (event.recurrence) if (event.recurrence)
element.find('div.fc-event-time').append('<i class="fc-icon-recurring"></i>'); time_element.append('<i class="fc-icon-recurring"></i>');
if (event.alarms || (event.valarms && event.valarms.length)) if (event.alarms || (event.valarms && event.valarms.length))
element.find('div.fc-event-time').append('<i class="fc-icon-alarms"></i>'); time_element.append('<i class="fc-icon-alarms"></i>');
} }
if (event.status) { if (event.status) {
element.addClass('cal-event-status-' + String(event.status).toLowerCase()); element.addClass('cal-event-status-' + String(event.status).toLowerCase());
@ -175,7 +173,7 @@ function rcube_calendar_ui(settings)
}, },
// callback when a specific event is clicked // callback when a specific event is clicked
eventClick: function(event, ev, view) { eventClick: function(event, ev, view) {
if (!event.temp && String(event.className).indexOf('fc-type-freebusy') < 0) if (!event.temp && (!event.className || event.className.indexOf('fc-type-freebusy') < 0))
event_show_dialog(event, ev); event_show_dialog(event, ev);
} }
}; };
@ -184,7 +182,6 @@ function rcube_calendar_ui(settings)
var Q = this.quote_html; var Q = this.quote_html;
var text2html = this.text2html; var text2html = this.text2html;
var event_date_text = this.event_date_text; var event_date_text = this.event_date_text;
var parse_datetime = this.parse_datetime;
var date2unixtime = this.date2unixtime; var date2unixtime = this.date2unixtime;
var fromunixtime = this.fromunixtime; var fromunixtime = this.fromunixtime;
var parseISO8601 = this.parseISO8601; var parseISO8601 = this.parseISO8601;
@ -226,8 +223,8 @@ function rcube_calendar_ui(settings)
// clone the given date object and optionally adjust time // clone the given date object and optionally adjust time
var clone_date = function(date, adjust) var clone_date = function(date, adjust)
{ {
var d = new Date(date.getTime()); var d = 'toDate' in date ? date.toDate() : new Date(date.getTime());
// set time to 00:00 // set time to 00:00
if (adjust == 1) { if (adjust == 1) {
d.setHours(0); d.setHours(0);
@ -238,7 +235,7 @@ function rcube_calendar_ui(settings)
d.setHours(23); d.setHours(23);
d.setMinutes(59); d.setMinutes(59);
} }
return d; return d;
}; };
@ -256,6 +253,11 @@ function rcube_calendar_ui(settings)
return date2servertime(date).replace(/[^0-9]/g, '').substr(0, (dateonly ? 8 : 14)); return date2servertime(date).replace(/[^0-9]/g, '').substr(0, (dateonly ? 8 : 14));
} }
var format_date = function(date, format)
{
return $.fullCalendar.formatDate('toDate' in date ? date : moment(date), format);
};
var format_datetime = function(date, mode, voice) var format_datetime = function(date, mode, voice)
{ {
return me.format_datetime(date, mode, voice); return me.format_datetime(date, mode, voice);
@ -633,11 +635,19 @@ function rcube_calendar_ui(settings)
var priority = $('#edit-priority').val(event.priority); var priority = $('#edit-priority').val(event.priority);
var sensitivity = $('#edit-sensitivity').val(event.sensitivity); var sensitivity = $('#edit-sensitivity').val(event.sensitivity);
var syncstart = $('#edit-recurrence-syncstart input'); var syncstart = $('#edit-recurrence-syncstart input');
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000); var end = 'toDate' in event.end ? event.end : moment(event.end);
var startdate = $('#edit-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration); var start = 'toDate' in event.start ? event.start : moment(event.start);
var starttime = $('#edit-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show(); var duration = Math.round((end.format('x') - start.format('x')) / 1000);
var enddate = $('#edit-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
var endtime = $('#edit-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show(); // Correct the fullCalendar end date for all-day events
if (!end.hasTime()) {
end.subtract(1, 'days');
}
var startdate = $('#edit-startdate').val(format_date(start, settings.date_format)).data('duration', duration);
var starttime = $('#edit-starttime').val(format_date(start, settings.time_format)).show();
var enddate = $('#edit-enddate').val(format_date(end, settings.date_format));
var endtime = $('#edit-endtime').val(format_date(end, settings.time_format)).show();
var allday = $('#edit-allday').get(0); var allday = $('#edit-allday').get(0);
var notify = $('#edit-attendees-donotify').get(0); var notify = $('#edit-attendees-donotify').get(0);
var invite = $('#edit-attendees-invite').get(0); var invite = $('#edit-attendees-invite').get(0);
@ -769,8 +779,8 @@ function rcube_calendar_ui(settings)
// init dialog buttons // init dialog buttons
var buttons = [], var buttons = [],
save_func = function() { save_func = function() {
var start = parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val()); var start = me.parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val()); var end = me.parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
// basic input validatetion // basic input validatetion
if (start.getTime() > end.getTime()) { if (start.getTime() > end.getTime()) {
@ -1146,11 +1156,14 @@ function rcube_calendar_ui(settings)
// set form elements // set form elements
var allday = $('#edit-allday').get(0); var allday = $('#edit-allday').get(0);
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000); var end = 'toDate' in event.end ? event.end : moment(event.end);
freebusy_ui.startdate = $('#schedule-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration); var start = 'toDate' in event.start ? event.start : moment(event.start);
freebusy_ui.starttime = $('#schedule-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show(); var duration = Math.round((end.format('x') - start.format('x')) / 1000);
freebusy_ui.enddate = $('#schedule-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
freebusy_ui.endtime = $('#schedule-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show(); freebusy_ui.startdate = $('#schedule-startdate').val(format_date(start, settings.date_format)).data('duration', duration);
freebusy_ui.starttime = $('#schedule-starttime').val(format_date(start, settings.time_format)).show();
freebusy_ui.enddate = $('#schedule-enddate').val(format_date(end, settings.date_format));
freebusy_ui.endtime = $('#schedule-endtime').val(format_date(end, settings.time_format)).show();
if (allday.checked) { if (allday.checked) {
freebusy_ui.starttime.val("12:00").hide(); freebusy_ui.starttime.val("12:00").hide();
@ -1319,16 +1332,16 @@ function rcube_calendar_ui(settings)
for (var s = 0, t = freebusy_ui.start.getTime(); t < freebusy_ui.end.getTime(); s++) { for (var s = 0, t = freebusy_ui.start.getTime(); t < freebusy_ui.end.getTime(); s++) {
curdate.setTime(t); curdate.setTime(t);
datestr = fc.fullCalendar('formatDate', curdate, date_format); datestr = format_date(curdate, date_format);
if (datestr != lastdate) { if (datestr != lastdate) {
if (lastdate && !allday) break; if (lastdate && !allday) break;
dates_row += '<th colspan="' + dayslots + '" class="boxtitle date' + $.fullCalendar.formatDate(curdate, 'ddMMyyyy') + '">' + Q(datestr) + '</th>'; dates_row += '<th colspan="' + dayslots + '" class="boxtitle date' + format_date(curdate, 'DDMMYYYY') + '">' + Q(datestr) + '</th>';
lastdate = datestr; lastdate = datestr;
} }
// set css class according to working hours // set css class according to working hours
css = is_weekend(curdate) || (freebusy_ui.interval <= 60 && !is_workinghour(curdate)) ? 'offhours' : 'workinghours'; css = is_weekend(curdate) || (freebusy_ui.interval <= 60 && !is_workinghour(curdate)) ? 'offhours' : 'workinghours';
times_row += '<td class="' + times_css + css + '" id="t-' + Math.floor(t/1000) + '">' + Q(allday ? rcmail.gettext('all-day','calendar') : $.fullCalendar.formatDate(curdate, settings['time_format'])) + '</td>'; times_row += '<td class="' + times_css + css + '" id="t-' + Math.floor(t/1000) + '">' + Q(allday ? rcmail.gettext('all-day','calendar') : format_date(curdate, settings.time_format)) + '</td>';
slots_row += '<td class="' + css + '">&nbsp;</td>'; slots_row += '<td class="' + css + '">&nbsp;</td>';
t += interval * 60000; t += interval * 60000;
@ -1674,10 +1687,10 @@ function rcube_calendar_ui(settings)
} }
me.selected_event.start = start; me.selected_event.start = start;
me.selected_event.end = end; me.selected_event.end = end;
freebusy_ui.startdate.val($.fullCalendar.formatDate(start, settings['date_format'])); freebusy_ui.startdate.val(format_date(start, settings.date_format));
freebusy_ui.starttime.val($.fullCalendar.formatDate(start, settings['time_format'])); freebusy_ui.starttime.val(format_date(start, settings.time_format));
freebusy_ui.enddate.val($.fullCalendar.formatDate(end, settings['date_format'])); freebusy_ui.enddate.val(format_date(end, settings.date_format));
freebusy_ui.endtime.val($.fullCalendar.formatDate(end, settings['time_format'])); freebusy_ui.endtime.val(format_date(end, settings.time_format));
freebusy_ui.needsupdate = true; freebusy_ui.needsupdate = true;
}; };
@ -1793,8 +1806,8 @@ function rcube_calendar_ui(settings)
if (me.selected_event) { if (me.selected_event) {
var allday = $('#edit-allday').get(0); var allday = $('#edit-allday').get(0);
me.selected_event.allDay = allday.checked; me.selected_event.allDay = allday.checked;
me.selected_event.start = parse_datetime(allday.checked ? '12:00' : $('#edit-starttime').val(), $('#edit-startdate').val()); me.selected_event.start = me.parse_datetime(allday.checked ? '12:00' : $('#edit-starttime').val(), $('#edit-startdate').val());
me.selected_event.end = parse_datetime(allday.checked ? '13:00' : $('#edit-endtime').val(), $('#edit-enddate').val()); me.selected_event.end = me.parse_datetime(allday.checked ? '13:00' : $('#edit-endtime').val(), $('#edit-enddate').val());
if (event_attendees) if (event_attendees)
freebusy_ui.needsupdate = true; freebusy_ui.needsupdate = true;
$('#edit-startdate').data('duration', Math.round((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / 1000)); $('#edit-startdate').data('duration', Math.round((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / 1000));
@ -2103,8 +2116,7 @@ function rcube_calendar_ui(settings)
eventRender: function(event, element, view) { eventRender: function(event, element, view) {
var title = rcmail.get_label(event.status, 'calendar'); var title = rcmail.get_label(event.status, 'calendar');
element.addClass('status-' + event.status); element.addClass('status-' + event.status);
element.find('.fc-event-head').hide(); element.find('.fc-title').text(title);
element.find('.fc-event-title').text(title);
element.attr('aria-label', me.event_date_text(event, true) + ': ' + title); element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
} }
})); }));
@ -2414,13 +2426,13 @@ function rcube_calendar_ui(settings)
event_show_dialog(me.selected_event); event_show_dialog(me.selected_event);
} }
}; };
// add the given date to the RDATE list // add the given date to the RDATE list
var add_rdate = function(date) var add_rdate = function(date)
{ {
var li = $('<li>') var li = $('<li>')
.attr('data-value', date2servertime(date)) .attr('data-value', date2servertime(date))
.html('<span>' + Q($.fullCalendar.formatDate(date, settings['date_format'])) + '</span>') .append($('<span>').text(format_date(date, settings.date_format)))
.appendTo('#edit-recurrence-rdates'); .appendTo('#edit-recurrence-rdates');
$('<a>').attr('href', '#del') $('<a>').attr('href', '#del')
@ -2459,19 +2471,20 @@ function rcube_calendar_ui(settings)
{ {
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata'); me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar/event', $.extend({ action:action, e:data }, (add || {}))); rcmail.http_post('calendar/event', $.extend({ action:action, e:data }, (add || {})));
// render event temporarily into the calendar // render event temporarily into the calendar
if ((data.start && data.end) || data.id) { if ((data.start && data.end) || data.id) {
var event = data.id ? $.extend(fc.fullCalendar('clientEvents', function(e){ return e.id == data.id; })[0], data) : data; var event = data.id ? $.extend(fc.fullCalendar('clientEvents', data.id)[0], data) : data;
if (data.start) if (data.start)
event.start = data.start; event.start = data.start;
if (data.end) if (data.end)
event.end = data.end; event.end = data.end;
if (data.allday !== undefined) if (data.allDay !== undefined)
event.allDay = data.allday; event.allDay = data.allDay;
event.editable = false; event.editable = false;
event.temp = true; event.temp = true;
event.className = 'fc-event-cal-'+data.calendar+' fc-event-temp'; event.className = ['fc-event-cal-'+data.calendar, 'fc-event-temp'];
fc.fullCalendar(data.id ? 'updateEvent' : 'renderEvent', event); fc.fullCalendar(data.id ? 'updateEvent' : 'renderEvent', event);
// mark all recurring instances as temp // mark all recurring instances as temp
@ -2480,7 +2493,7 @@ function rcube_calendar_ui(settings)
$.each(fc.fullCalendar('clientEvents', function(e){ return e.id == base_id || e.recurrence_id == base_id; }), function(i,ev) { $.each(fc.fullCalendar('clientEvents', function(e){ return e.id == base_id || e.recurrence_id == base_id; }), function(i,ev) {
ev.temp = true; ev.temp = true;
ev.editable = false; ev.editable = false;
event.className += ' fc-event-temp'; event.className.push('fc-event-temp');
fc.fullCalendar('updateEvent', ev); fc.fullCalendar('updateEvent', ev);
}); });
} }
@ -2632,7 +2645,7 @@ function rcube_calendar_ui(settings)
fc.fullCalendar('refetchEvents'); fc.fullCalendar('refetchEvents');
} }
}).addClass('event-update-confirm').show(); }).addClass('event-update-confirm').show();
return false; return false;
} }
// show regular confirm box when deleting // show regular confirm box when deleting
@ -2643,7 +2656,7 @@ function rcube_calendar_ui(settings)
// do update // do update
update_event(action, data); update_event(action, data);
return true; return true;
}; };
@ -2700,7 +2713,7 @@ function rcube_calendar_ui(settings)
modal: true, modal: true,
width: 680, width: 680,
height: h, height: h,
title: $.fullCalendar.formatDate(date, 'dddd ' + settings['date_long']), title: format_date(date, 'dddd ' + settings.date_long),
buttons: [{ buttons: [{
text: rcmail.gettext('cancel', 'calendar'), text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel', 'class': 'cancel',
@ -2720,7 +2733,7 @@ function rcube_calendar_ui(settings)
year: date.getFullYear(), year: date.getFullYear(),
eventSources: sources eventSources: sources
})); }));
this.fisheye_date = date; this.fisheye_date = date;
}; };
@ -2839,7 +2852,7 @@ function rcube_calendar_ui(settings)
this.print_calendars = function(view) this.print_calendars = function(view)
{ {
if (!view) view = fc.fullCalendar('getView').name; if (!view) view = fc.fullCalendar('getView').name;
var date = fc.fullCalendar('getDate') || new Date(); var date = fc.fullCalendar('getDate').toDate();
var range = fc.fullCalendar('option', 'listRange'); var range = fc.fullCalendar('option', 'listRange');
var sections = fc.fullCalendar('option', 'listSections'); var sections = fc.fullCalendar('option', 'listSections');
rcmail.open_window(rcmail.url('print', { view: view, date: date2unixtime(date), range: range, sections: sections, search: this.search_query }), true, true); rcmail.open_window(rcmail.url('print', { view: view, date: date2unixtime(date), range: range, sections: sections, search: this.search_query }), true, true);
@ -2849,9 +2862,7 @@ function rcube_calendar_ui(settings)
this.add_event = function(templ) { this.add_event = function(templ) {
if (this.selected_calendar) { if (this.selected_calendar) {
var now = new Date(); var now = new Date();
var date = fc.fullCalendar('getDate'); var date = fc.fullCalendar('getDate').toDate();
if (typeof date != 'Date')
date = now;
date.setHours(now.getHours()+1); date.setHours(now.getHours()+1);
date.setMinutes(0); date.setMinutes(0);
var end = new Date(date.getTime()); var end = new Date(date.getTime());
@ -2941,9 +2952,10 @@ function rcube_calendar_ui(settings)
this.calendar_refresh_source = function(id) this.calendar_refresh_source = function(id)
{ {
// got race-conditions fc.currentFetchID when using refetchEvents, // got race-conditions fc.currentFetchID when using refetchEventSources,
// so we remove and add the source instead // so we remove and add the source instead
// fc.fullCalendar('refetchEvents', me.calendars[id]); // fc.fullCalendar('refetchEventSources', me.calendars[id]);
// TODO: Check it again with fullcalendar >= 3.9
fc.fullCalendar('removeEventSource', me.calendars[id]); fc.fullCalendar('removeEventSource', me.calendars[id]);
fc.fullCalendar('addEventSource', me.calendars[id]); fc.fullCalendar('addEventSource', me.calendars[id]);
}; };
@ -3093,7 +3105,7 @@ function rcube_calendar_ui(settings)
attachmt = $('#event-export-attachments').get(0).checked; attachmt = $('#event-export-attachments').get(0).checked;
if (range == 'custom') if (range == 'custom')
start = date2unixtime(parse_datetime('00:00', $('#event-export-startdate').val())); start = date2unixtime(me.parse_datetime('00:00', $('#event-export-startdate').val()));
else if (range > 0) else if (range > 0)
start = 'today -' + range + ' months'; start = 'today -' + range + ' months';
@ -3229,16 +3241,13 @@ function rcube_calendar_ui(settings)
return false; return false;
} }
}); });
fc.fullCalendar('refetchEvents', source, true);
} }
else if (!source.active) { else if (!source.active) {
source.active = true; source.active = true;
fc.fullCalendar('addEventSource', source);
$('#rcmlical' + source.id + ' input').prop('checked', true); $('#rcmlical' + source.id + ' input').prop('checked', true);
} }
else
fc.fullCalendar('refetchEvents', source, true);
fc.fullCalendar('refetchEventSources', source);
fetch_counts(); fetch_counts();
} }
// add/update single event object // add/update single event object
@ -3261,7 +3270,7 @@ function rcube_calendar_ui(settings)
} }
// refetch all calendars // refetch all calendars
else if (p.refetch) { else if (p.refetch) {
fc.fullCalendar('refetchEvents', undefined, true); fc.fullCalendar('refetchEvents');
fetch_counts(); fetch_counts();
} }
}; };
@ -3271,8 +3280,8 @@ function rcube_calendar_ui(settings)
{ {
var view = fc.fullCalendar('getView'); var view = fc.fullCalendar('getView');
query.start = date2unixtime(view.visStart); query.start = date2unixtime(view.start.toDate());
query.end = date2unixtime(view.visEnd); query.end = date2unixtime(view.end.toDate());
if (this.search_query) if (this.search_query)
query.q = this.search_query; query.q = this.search_query;
@ -3327,7 +3336,7 @@ function rcube_calendar_ui(settings)
var query = { view: fc.fullCalendar('getView').name }, var query = { view: fc.fullCalendar('getView').name },
date = fc.fullCalendar('getDate'); date = fc.fullCalendar('getDate');
if (date) if (date)
query.date = date2unixtime(date); query.date = date2unixtime(date.toDate());
rcmail.redirect(rcmail.url('', query)); rcmail.redirect(rcmail.url('', query));
} }
@ -3337,7 +3346,7 @@ function rcube_calendar_ui(settings)
var query = { view: current_view }, var query = { view: current_view },
date = fc.fullCalendar('getDate'); date = fc.fullCalendar('getDate');
if (date) if (date)
query.date = date2unixtime(date); query.date = date2unixtime(date.toDate());
if (window.history.replaceState) if (window.history.replaceState)
window.history.replaceState({}, document.title, rcmail.url('', query).replace('&_action=', '')); window.history.replaceState({}, document.title, rcmail.url('', query).replace('&_action=', ''));
@ -3388,9 +3397,10 @@ function rcube_calendar_ui(settings)
this.search_query = q; this.search_query = q;
// change to list view // change to list view
fc.fullCalendar('option', 'listSections', 'month') fc.fullCalendar('option', 'listSections', 'month');
.fullCalendar('option', 'listRange', Math.max(60, settings['agenda_range'])) fc.fullCalendar('option', 'listRange', Math.max(60, settings.agenda_range));
.fullCalendar('changeView', 'table'); // TODO: fullcalendar 3.9 has dateOrRange argument here, shall we use it?
fc.fullCalendar('changeView', 'listYear');
update_agenda_toolbar(); update_agenda_toolbar();
@ -3416,8 +3426,8 @@ function rcube_calendar_ui(settings)
fc.find('.fc-list-content > .fc-listappend').hide(); fc.find('.fc-list-content > .fc-listappend').hide();
// restore original event sources and view mode from fullcalendar // restore original event sources and view mode from fullcalendar
fc.fullCalendar('option', 'listSections', settings['agenda_sections']) fc.fullCalendar('option', 'listSections', settings.agenda_sections);
.fullCalendar('option', 'listRange', settings['agenda_range']); fc.fullCalendar('option', 'listRange', settings.agenda_range);
update_agenda_toolbar(); update_agenda_toolbar();
@ -3478,7 +3488,7 @@ function rcube_calendar_ui(settings)
.append($('<span class="inner">').text(rcmail.gettext(elastic ? 'earlierevents' : 'searchearlierdates', 'calendar'))) .append($('<span class="inner">').text(rcmail.gettext(elastic ? 'earlierevents' : 'searchearlierdates', 'calendar')))
.appendTo(lc) .appendTo(lc)
.click(function() { .click(function() {
fc.fullCalendar('incrementDate', 0, -1, 0); fc.fullCalendar('incrementDate', "-P1M");
}); });
lc.append(" "); lc.append(" ");
@ -3489,11 +3499,12 @@ function rcube_calendar_ui(settings)
.click(function() { .click(function() {
var range = fc.fullCalendar('option', 'listRange'); var range = fc.fullCalendar('option', 'listRange');
if (range < 90) { if (range < 90) {
fc.fullCalendar('option', 'listRange', fc.fullCalendar('option', 'listRange') + 30).fullCalendar('render'); fc.fullCalendar('option', 'listRange', fc.fullCalendar('option', 'listRange') + 30);
fc.fullCalendar('render');
update_agenda_toolbar(); update_agenda_toolbar();
} }
else else
fc.fullCalendar('incrementDate', 0, 1, 0); fc.fullCalendar('incrementDate', "P1M");
}); });
} }
} }
@ -3532,7 +3543,7 @@ function rcube_calendar_ui(settings)
me.calendars[id] = $.extend({ me.calendars[id] = $.extend({
url: rcmail.url('calendar/load_events', { source: id }), url: rcmail.url('calendar/load_events', { source: id }),
className: 'fc-event-cal-'+id, className: ['fc-event-cal-' + id],
id: id id: id
}, cal); }, cal);
@ -3767,7 +3778,7 @@ function rcube_calendar_ui(settings)
if (rcmail.env.itip_events && rcmail.env.itip_events.length) { if (rcmail.env.itip_events && rcmail.env.itip_events.length) {
me.calendars['--invitation--itip'] = { me.calendars['--invitation--itip'] = {
events: rcmail.env.itip_events, events: rcmail.env.itip_events,
className: 'fc-event-cal---invitation--itip', className: ['fc-event-cal---invitation--itip'],
color: '#fff', color: '#fff',
textColor: '#333', textColor: '#333',
editable: false, editable: false,
@ -3782,7 +3793,7 @@ function rcube_calendar_ui(settings)
header: { header: {
right: 'prev,next today', right: 'prev,next today',
center: 'title', center: 'title',
left: 'agendaDay,agendaWeek,month,table' left: 'agendaDay,agendaWeek,month,listYear'
}, },
date: viewdate.getDate(), date: viewdate.getDate(),
month: viewdate.getMonth(), month: viewdate.getMonth(),
@ -3799,64 +3810,68 @@ function rcube_calendar_ui(settings)
me.events_loaded($(this).fullCalendar('clientEvents').length); me.events_loaded($(this).fullCalendar('clientEvents').length);
}, },
// callback for date range selection // callback for date range selection
select: function(start, end, allDay, e, view) { select: function(start, end, e, view) {
var range_select = (!allDay || start.getDate() != end.getDate()) var range_select = (start.hasTime() || start != end)
if (dialog_check(e) && range_select) if (dialog_check(e) && range_select)
event_edit_dialog('new', { start:start, end:end, allDay:allDay, calendar:me.selected_calendar }); event_edit_dialog('new', { start:start, end:end, allDay:!start.hasTime(), calendar:me.selected_calendar });
if (range_select || ignore_click) if (range_select || ignore_click)
view.calendar.unselect(); view.calendar.unselect();
}, },
// callback for clicks in all-day box // callback for clicks in all-day box
dayClick: function(date, allDay, e, view) { dayClick: function(date, e, view) {
var now = new Date().getTime(); var now = new Date().getTime();
if (now - day_clicked_ts < 400 && day_clicked == date.getTime()) { // emulate double-click on day if (now - day_clicked_ts < 400 && day_clicked == date.toDate().getTime()) { // emulate double-click on day
var enddate = new Date(); enddate.setTime(date.getTime() + DAY_MS - 60000); var enddate = new Date();
return event_edit_dialog('new', { start:date, end:enddate, allDay:allDay, calendar:me.selected_calendar }); if (date.hasTime())
enddate.setTime(date.toDate().getTime() + DAY_MS - 60000);
return event_edit_dialog('new', { start:date, end:enddate, allDay:!date.hasTime(), calendar:me.selected_calendar });
} }
if (!ignore_click) { if (!ignore_click) {
view.calendar.gotoDate(date); view.calendar.gotoDate(date);
if (day_clicked && new Date(day_clicked).getMonth() != date.getMonth()) if (day_clicked && new Date(day_clicked).getMonth() != date.toDate().getMonth())
view.calendar.select(date, date, allDay); view.calendar.select(date, date);
} }
day_clicked = date.getTime(); day_clicked = date.toDate().getTime();
day_clicked_ts = now; day_clicked_ts = now;
}, },
// callback when an event was dragged and finally dropped // callback when an event was dragged and finally dropped
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) { eventDrop: function(event, delta, revertFunc) {
if (event.end == null || event.end.getTime() < event.start.getTime()) { var allday = !event.start.hasTime();
event.end = new Date(event.start.getTime() + (allDay ? DAY_MS : HOUR_MS));
if (!event.end || event.end.format('x') < event.start.format('x')) {
event.end = new Date(event.start.format('x') + (allday ? DAY_MS : HOUR_MS));
} }
// moved to all-day section: set times to 12:00 - 13:00 // moved to all-day section: set times to 12:00 - 13:00
if (allDay && !event.allDay) { if (allday && !event.allDay) {
event.start.setHours(12); event.start.hours(12);
event.start.setMinutes(0); event.start.minutes(0);
event.start.setSeconds(0); event.start.seconds(0);
event.end.setHours(13); event.end.hours(13);
event.end.setMinutes(0); event.end.minutes(0);
event.end.setSeconds(0); event.end.seconds(0);
} }
// moved from all-day section: set times to working hours // moved from all-day section: set times to working hours
else if (event.allDay && !allDay) { else if (event.allDay && !allday) {
var newstart = event.start.getTime(); var newstart = event.start.format('x');
revertFunc(); // revert to get original duration revertFunc(); // revert to get original duration
var numdays = Math.max(1, Math.round((event.end.getTime() - event.start.getTime()) / DAY_MS)) - 1; var numdays = Math.max(1, Math.round((event.end.format('x') - event.start.format('x')) / DAY_MS)) - 1;
event.start = new Date(newstart); event.start = moment(newstart);
event.end = new Date(newstart + numdays * DAY_MS); event.end = moment(newstart + numdays * DAY_MS);
event.end.setHours(settings['work_end'] || 18); event.end.hours(settings.work_end || 18);
event.end.setMinutes(0); event.end.minutes(0);
if (event.end.getTime() < event.start.getTime()) if (event.end.diff(event.start) < 0)
event.end = new Date(newstart + HOUR_MS); event.end = new Date(newstart + HOUR_MS);
} }
// send move request to server // send move request to server
var data = { var data = {
id: event.id, id: event.id,
calendar: event.calendar, calendar: event.calendar,
start: date2servertime(event.start), start: date2servertime(event.start),
end: date2servertime(event.end), end: date2servertime(event.end),
allday: allDay?1:0 allDay: allday?1:0
}; };
update_event_confirm('move', event, data); update_event_confirm('move', event, data);
}, },
@ -3864,9 +3879,9 @@ function rcube_calendar_ui(settings)
eventResize: function(event, delta) { eventResize: function(event, delta) {
// sanitize event dates // sanitize event dates
if (event.allDay) if (event.allDay)
event.start.setHours(12); event.start.hours(12);
if (!event.end || event.end.getTime() < event.start.getTime()) if (!event.end || event.end.diff(event.start) < 0)
event.end = new Date(event.start.getTime() + HOUR_MS); event.end = new Date(event.start.format('x') + HOUR_MS);
// send resize request to server // send resize request to server
var data = { var data = {
@ -3874,39 +3889,35 @@ function rcube_calendar_ui(settings)
calendar: event.calendar, calendar: event.calendar,
start: date2servertime(event.start), start: date2servertime(event.start),
end: date2servertime(event.end), end: date2servertime(event.end),
allday: event.allDay?1:0 allDay: event.allDay?1:0
}; };
update_event_confirm('resize', event, data); update_event_confirm('resize', event, data);
}, },
viewDisplay: function(view) { viewRender: function(view) {
$('#agendaoptions')[view.name == 'table' ? 'show' : 'hide'](); $('#agendaoptions')[view.name == 'listYear' ? 'show' : 'hide']();
if (minical) { if (minical) {
window.setTimeout(function(){ minical.datepicker('setDate', fc.fullCalendar('getDate')); }, exec_deferred); window.setTimeout(function(){ minical.datepicker('setDate', fc.fullCalendar('getDate').toDate()); }, exec_deferred);
if (view.name != current_view) if (view.name != current_view)
me.view_resize(); me.view_resize();
current_view = view.name; current_view = view.name;
me.update_state(); me.update_state();
} }
},
viewRender: function(view) {
if (fc && view.name == 'month')
fc.fullCalendar('option', 'maxHeight', Math.floor((view.element.parent().height()-18) / 6) - 35);
} }
})); }));
// if start date is changed, shift end date according to initial duration // if start date is changed, shift end date according to initial duration
var shift_enddate = function(dateText) { var shift_enddate = function(dateText) {
var newstart = parse_datetime('0', dateText); var newstart = me.parse_datetime('0', dateText);
var newend = new Date(newstart.getTime() + $('#edit-startdate').data('duration') * 1000); var newend = new Date(newstart.getTime() + $('#edit-startdate').data('duration') * 1000);
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format'])); $('#edit-enddate').val(format_date(newend, me.settings.date_format));
event_times_changed(); event_times_changed();
}; };
// Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. // Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
// Uses the default $.datepicker.iso8601Week() function but takes firstDay setting into account. // Uses the default $.datepicker.iso8601Week() function but takes firstDay setting into account.
// This is a temporary fix until http://bugs.jqueryui.com/ticket/8420 is resolved. // This is a temporary fix until http://bugs.jqueryui.com/ticket/8420 is resolved.
var iso8601Week = datepicker_settings.calculateWeek = function(date) { var iso8601Week = me.datepicker_settings.calculateWeek = function(date) {
var mondayOffset = Math.abs(1 - datepicker_settings.firstDay); var mondayOffset = Math.abs(1 - me.datepicker_settings.firstDay);
return $.datepicker.iso8601Week(new Date(date.getTime() + mondayOffset * 86400000)); return $.datepicker.iso8601Week(new Date(date.getTime() + mondayOffset * 86400000));
}; };
@ -3921,14 +3932,15 @@ function rcube_calendar_ui(settings)
}; };
// initialize small calendar widget using jQuery UI datepicker // initialize small calendar widget using jQuery UI datepicker
minical = $('#datepicker').datepicker($.extend(datepicker_settings, { minical = $('#datepicker').datepicker($.extend(me.datepicker_settings, {
inline: true, inline: true,
changeMonth: true, changeMonth: true,
changeYear: true, changeYear: true,
onSelect: function(dateText, inst) { onSelect: function(dateText, inst) {
ignore_click = true; ignore_click = true;
var d = minical.datepicker('getDate'); //parse_datetime('0:0', dateText); var d = minical.datepicker('getDate');
fc.fullCalendar('gotoDate', d).fullCalendar('select', d, d, true); fc.fullCalendar('gotoDate', d)
fc.fullCalendar('select', d, d);
setTimeout(function() { pretty_select($('select', minical)); }, 25); setTimeout(function() { pretty_select($('select', minical)); }, 25);
}, },
onChangeMonthYear: function(year, month, inst) { onChangeMonthYear: function(year, month, inst) {
@ -3936,9 +3948,13 @@ function rcube_calendar_ui(settings)
setTimeout(function() { pretty_select($('select', minical)); }, 25); setTimeout(function() { pretty_select($('select', minical)); }, 25);
}, },
beforeShowDay: function(date) { beforeShowDay: function(date) {
// TODO: this pretty_select() calls should be implemented in a different way
setTimeout(function() { pretty_select($('select', minical)); }, 25); setTimeout(function() { pretty_select($('select', minical)); }, 25);
var view = fc.fullCalendar('getView');
var active = view.visStart && date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime(); var view = fc.fullCalendar('getView'),
dt = moment(date).format('YYYYMMDD'),
active = view.start && view.start.format('YYYYMMDD') <= dt && view.end.format('YYYYMMDD') > dt;
return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), '']; return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), ''];
} }
})) // set event handler for clicks on calendar week cell of the datepicker widget })) // set event handler for clicks on calendar week cell of the datepicker widget
@ -3951,7 +3967,7 @@ function rcube_calendar_ui(settings)
if (minical.data('year')) if (minical.data('year'))
base_date.setYear(minical.data('year')); base_date.setYear(minical.data('year'));
base_date.setHours(12); base_date.setHours(12);
base_date.setDate(base_date.getDate() - ((base_date.getDay() + 6) % 7) + datepicker_settings.firstDay); base_date.setDate(base_date.getDate() - ((base_date.getDay() + 6) % 7) + me.datepicker_settings.firstDay);
var base_kw = iso8601Week(base_date), var base_kw = iso8601Week(base_date),
target_kw = parseInt(cell.html()), target_kw = parseInt(cell.html()),
wdiff = target_kw - base_kw; wdiff = target_kw - base_kw;
@ -3960,9 +3976,10 @@ function rcube_calendar_ui(settings)
else if (wdiff < -10) else if (wdiff < -10)
base_date.setYear(base_date.getFullYear() + 1); base_date.setYear(base_date.getFullYear() + 1);
// select monday of the chosen calendar week // select monday of the chosen calendar week
var day_off = base_date.getDay() - datepicker_settings.firstDay, var day_off = base_date.getDay() - me.datepicker_settings.firstDay,
date = new Date(base_date.getTime() - day_off * DAY_MS + wdiff * 7 * DAY_MS); date = new Date(base_date.getTime() - day_off * DAY_MS + wdiff * 7 * DAY_MS);
fc.fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek'); fc.fullCalendar('gotoDate', date)
fc.fullCalendar('changeView', 'agendaWeek');
minical.datepicker('setDate', date); minical.datepicker('setDate', date);
setTimeout(function() { pretty_select($('select', minical)); }, 25); setTimeout(function() { pretty_select($('select', minical)); }, 25);
} }
@ -4011,11 +4028,11 @@ function rcube_calendar_ui(settings)
$('#edit-recurrence-syncstart').hide(); $('#edit-recurrence-syncstart').hide();
}; };
$('#eventedit:not([data-notabs])').tabs({activate: tab_change}); // Larry $('#eventedit:not([data-notabs])').tabs({activate: tab_change}); // Larry
$('#eventedit a.nav-link').on('show.bs.tab', tab_change); // Elastic $('#eventedit a.nav-link').on('show.bs.tab', tab_change); // Elastic
$('#edit-enddate').datepicker(datepicker_settings); $('#edit-enddate').datepicker(me.datepicker_settings);
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); }); $('#edit-startdate').datepicker(me.datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
$('#edit-enddate').datepicker('option', 'onSelect', event_times_changed).change(event_times_changed); $('#edit-enddate').datepicker('option', 'onSelect', event_times_changed).change(event_times_changed);
$('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); event_times_changed(); }); $('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); event_times_changed(); });
@ -4030,10 +4047,10 @@ function rcube_calendar_ui(settings)
// adjust end time when changing start // adjust end time when changing start
$('#edit-starttime').change(function(e) { $('#edit-starttime').change(function(e) {
var dstart = $('#edit-startdate'), var dstart = $('#edit-startdate'),
newstart = parse_datetime(this.value, dstart.val()), newstart = me.parse_datetime(this.value, dstart.val()),
newend = new Date(newstart.getTime() + dstart.data('duration') * 1000); newend = new Date(newstart.getTime() + dstart.data('duration') * 1000);
$('#edit-endtime').val($.fullCalendar.formatDate(newend, me.settings['time_format'])); $('#edit-endtime').val(format_date(newend, me.settings.time_format));
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format'])); $('#edit-enddate').val(format_date(newend, me.settings.date_format));
event_times_changed(); event_times_changed();
}); });
@ -4052,7 +4069,7 @@ function rcube_calendar_ui(settings)
} }
}); });
$('#event-export-startdate').datepicker(datepicker_settings); $('#event-export-startdate').datepicker(me.datepicker_settings);
// init attendees autocompletion // init attendees autocompletion
var ac_props; var ac_props;
@ -4176,14 +4193,16 @@ function rcube_calendar_ui(settings)
}); });
$('#agenda-listrange').change(function(e){ $('#agenda-listrange').change(function(e){
settings['agenda_range'] = parseInt($(this).val()); settings.agenda_range = parseInt($(this).val());
fc.fullCalendar('option', 'listRange', settings['agenda_range']).fullCalendar('render'); fc.fullCalendar('option', 'listRange', settings.agenda_range)
fc.fullCalendar('render');
// TODO: save new settings in prefs // TODO: save new settings in prefs
}).val(settings['agenda_range']); }).val(settings.agenda_range);
$('#agenda-listsections').change(function(e){ $('#agenda-listsections').change(function(e){
settings['agenda_sections'] = $(this).val(); settings.agenda_sections = $(this).val();
fc.fullCalendar('option', 'listSections', settings['agenda_sections']).fullCalendar('render'); fc.fullCalendar('option', 'listSections', settings.agenda_sections);
fc.fullCalendar('render');
// TODO: save new settings in prefs // TODO: save new settings in prefs
}).val(fc.fullCalendar('option', 'listSections')); }).val(fc.fullCalendar('option', 'listSections'));
@ -4199,10 +4218,6 @@ function rcube_calendar_ui(settings)
// fetch counts for some calendars // fetch counts for some calendars
fetch_counts(); fetch_counts();
// add proprietary css styles if not IE
if (!bw.ie)
$('div.fc-content').addClass('rcube-fc-content');
// Save-as-event dialog content // Save-as-event dialog content
if (rcmail.env.action == 'dialog-ui') { if (rcmail.env.action == 'dialog-ui') {
var date = new Date(), event = {allDay: false, calendar: me.selected_calendar}; var date = new Date(), event = {allDay: false, calendar: me.selected_calendar};
@ -4324,10 +4339,10 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// Elastic mods // Elastic mods
if ($('#calendar').data('elastic-mode')) { if ($('#calendar').data('elastic-mode')) {
var selector = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-left'), var selector = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-toolbar > .fc-left'),
nav = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-right'); nav = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-toolbar > .fc-right');
$('.fc-header-left > span').each(function() { $('.fc-header-toolbar > .fc-left button').each(function() {
var new_btn, cl = 'btn btn-secondary', btn = $(this), var new_btn, cl = 'btn btn-secondary', btn = $(this),
activate = function(button) { activate = function(button) {
selector.children('.active').removeClass('active'); selector.children('.active').removeClass('active');
@ -4352,19 +4367,19 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
}); });
$.each(['prev', 'today', 'next'], function() { $.each(['prev', 'today', 'next'], function() {
var btn = $('.fc-header-right').find('.fc-button-' + this); var btn = $('.fc-header-toolbar > .fc-right').find('.fc-button-' + this);
$('<button>').attr({'class': 'btn btn-secondary', type: 'button'}) $('<button>').attr({'class': 'btn btn-secondary', type: 'button'})
.text(btn.text()).appendTo(nav).on('click', function() { btn.click(); }); .text(btn.text()).appendTo(nav).on('click', function() { btn.click(); });
}); });
$('#timezone-display').appendTo($('.fc-header-center')).removeClass('hidden'); $('#timezone-display').appendTo($('.fc-header-toolbar > .fc-center')).removeClass('hidden');
$('#agendaoptions').detach().insertAfter('table.fc-header'); $('#agendaoptions').detach().insertAfter('table.fc-header');
$('.content-frame-navigation a.button.date').appendTo('.content > .searchbar'); $('.content-frame-navigation a.button.date').appendTo('.content > .searchbar');
// Mobile header title // Mobile header title
if (window.MutationObserver) { if (window.MutationObserver) {
var title = $('.fc-header-title'), var title = $('.fc-header-toolbar > .fc-center h2'),
mobile_header = $('#layout > .content > .header > .header-title'), mobile_header = $('#layout > .content > .header > .header-title'),
callback = function() { callback = function() {
var text = title.text(); var text = title.text();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1585,7 +1585,7 @@ a.dropdown-link:after {
top: 0; top: 0;
} }
#resource-freebusy-calendar .fc-content .fc-event-bg { #resource-freebusy-calendar .fc-content .fc-bg {
background: 0; background: 0;
} }
@ -1636,32 +1636,16 @@ a.dropdown-link:after {
/* fullcalendar style overrides */ /* fullcalendar style overrides */
.rcube-fc-content { .calendarmain .fc-body {
overflow: hidden;
border: 0;
border-radius: 4px;
}
.calendarmain .fc-content {
position: absolute !important;
top: 40px;
left: 0;
right: 0;
bottom: 0;
background: #fff; background: #fff;
} }
.calendarmain.quickview-active .fc-content { .calendarmain.quickview-active .fc-body {
background-image: url('images/focusview.png'); background-image: url('images/focusview.png');
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
#fish-eye-view .fc-content {
top: 2px;
bottom: 2px;
}
#quickview-calendar { #quickview-calendar {
padding: 8px; padding: 8px;
overflow: hidden; overflow: hidden;
@ -1704,15 +1688,12 @@ a.dropdown-link:after {
margin-right: 0; margin-right: 0;
} }
.calendarmain #calendar .fc-header-left .fc-button { .calendarmain #calendar .fc-left .fc-button {
display: inline-block;
margin: 0;
text-align: center;
font-size: 10px; font-size: 10px;
color: #555; color: #555;
min-width: 50px; min-width: 50px;
max-width: 75px; max-width: 75px;
height: 13px; height: 43px;
line-height: 1em; line-height: 1em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -1727,63 +1708,87 @@ a.dropdown-link:after {
-webkit-box-shadow: none; -webkit-box-shadow: none;
-moz-box-shadow: none; -moz-box-shadow: none;
outline: none; outline: none;
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
} }
.calendarmain #calendar .fc-header-left .fc-button:focus { .calendarmain #calendar .fc-left .fc-button:focus {
color: #fff; color: #fff;
text-shadow: 0px 1px 1px #666; text-shadow: 0px 1px 1px #666;
background-color: rgba(30,150,192, 0.5); background-color: rgba(30,150,192, 0.5);
border-radius: 3px; border-radius: 3px;
} }
.calendarmain #calendar .fc-header-left .fc-button.fc-state-active { .calendarmain #calendar .fc-left .fc-button::-moz-focus-inner {
border: 0;
}
.calendarmain #calendar .fc-left .fc-button.fc-state-active {
font-weight: bold; font-weight: bold;
color: #222; color: #222;
text-shadow: none; text-shadow: none;
background-color: transparent; background-color: transparent;
} }
.calendarmain #calendar .fc-header-left .fc-button-agendaDay { .calendarmain #calendar .fc-left .fc-agendaDay-button {
background-position: center -120px; background-position: center -120px;
} }
.calendarmain #calendar .fc-header-left .fc-button-agendaDay.fc-state-active { .calendarmain #calendar .fc-left .fc-agendaDay-button.fc-state-active {
background-position: center -160px; background-position: center -160px;
} }
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek { .calendarmain #calendar .fc-left .fc-agendaWeek-button {
background-position: center -200px; background-position: center -200px;
} }
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek.fc-state-active { .calendarmain #calendar .fc-left .fc-agendaWeek-button.fc-state-active {
background-position: center -240px; background-position: center -240px;
} }
.calendarmain #calendar .fc-header-left .fc-button-month { .calendarmain #calendar .fc-left .fc-month-button {
background-position: center -280px; background-position: center -280px;
} }
.calendarmain #calendar .fc-header-left .fc-button-month.fc-state-active { .calendarmain #calendar .fc-left .fc-month-button.fc-state-active {
background-position: center -320px; background-position: center -320px;
} }
.calendarmain #calendar .fc-header-left .fc-button-table { .calendarmain #calendar .fc-left .fc-listYear-button {
background-position: center -360px; background-position: center -360px;
display: none; /* hide Agenda button for now */
} }
.calendarmain #calendar .fc-header-left .fc-button-table.fc-state-active { .calendarmain #calendar .fc-left .fc-listYear.fc-state-active {
background-position: center -400px; background-position: center -400px;
} }
.calendarmain #calendar .fc-header-right { .calendarmain #calendar .fc-header-toolbar .fc-right {
padding-right: 252px;
padding-top: 4px; padding-top: 4px;
} }
.calendarmain #calendar .fc-header-toolbar .fc-center {
line-height: 2.5em;
overflow: hidden;
text-align: center;
display: block;
}
.calendarmain #calendar .fc-header-toolbar .fc-center h2 {
float: none;
}
.calendarmain #calendar .fc-header-title { .calendarmain #calendar .fc-header-title {
padding-top: 5px; padding-top: 5px;
} }
#calendar .fc-toolbar.fc-header-toolbar {
margin-bottom: 4px;
margin-right: 250px;
}
.fc-event { .fc-event {
font-size: 1em !important; font-size: 1em !important;
} }
@ -1791,18 +1796,6 @@ a.dropdown-link:after {
.fc-event-hori.fc-type-freebusy, .fc-event-hori.fc-type-freebusy,
.fc-event-vert.fc-type-freebusy { .fc-event-vert.fc-type-freebusy {
opacity: 0.60; opacity: 0.60;
/*
color: #fff !important;
background: rgba(80,80,80,0.85) !important;
background: -moz-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.9) 100%) !important;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(80,80,80,0.85)), color-stop(100%,rgba(48,48,48,0.9))) !important;
background: -webkit-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: -o-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: -ms-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: linear-gradient(to bottom, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
border-color: #444 !important;
cursor: default !important;
*/
-moz-box-shadow: inset 0px 1px 0 0px #888; -moz-box-shadow: inset 0px 1px 0 0px #888;
-webkit-box-shadow: inset 0px 1px 0 0px #888; -webkit-box-shadow: inset 0px 1px 0 0px #888;
-o-box-shadow: inset 0px 1px 0 0px #888; -o-box-shadow: inset 0px 1px 0 0px #888;
@ -1813,20 +1806,8 @@ a.dropdown-link:after {
color: #999; color: #999;
} }
.fc-event-hori.fc-type-freebusy .fc-event-skin, .fc-event-hori.fc-type-freebusy .fc-title,
.fc-event-hori.fc-type-freebusy .fc-event-inner, .fc-event-vert.fc-type-freebusy .fc-title {
.fc-event-vert.fc-type-freebusy .fc-event-skin,
.fc-event-vert.fc-type-freebusy .fc-event-inner {
/*
background-color: transparent !important;
border-color: #444 !important;
color: #fff !important;
text-shadow: 0 1px 1px #000;
*/
}
.fc-event-hori.fc-type-freebusy .fc-event-title,
.fc-event-vert.fc-type-freebusy .fc-event-title {
position: absolute; position: absolute;
top: -5000px; top: -5000px;
} }
@ -1851,25 +1832,19 @@ a.dropdown-link:after {
opacity: 0.7; opacity: 0.7;
} }
.fc-event-ns-other.fc-invitation-declined .fc-event-title { .fc-event-ns-other.fc-invitation-declined .fc-title {
text-decoration: line-through; text-decoration: line-through;
} }
.fc-event-vert.fc-invitation-tentative .fc-event-head, .fc-event-vert.fc-invitation-tentative .fc-bg {
.fc-event-vert.fc-invitation-declined .fc-event-head,
.fc-event-vert.fc-invitation-needs-action .fc-event-head {
/* background-color: transparent !important; */
}
.fc-event-vert.fc-invitation-tentative .fc-event-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAOuJAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff; background: url(data:image/gif;base64,R0lGODlhCAAIAPABAOuJAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
} }
.fc-event-vert.fc-invitation-needs-action .fc-event-bg { .fc-event-vert.fc-invitation-needs-action .fc-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAFdXx////yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff; background: url(data:image/gif;base64,R0lGODlhCAAIAPABAFdXx////yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
} }
.fc-event-vert.fc-invitation-declined .fc-event-bg { .fc-event-vert.fc-invitation-declined .fc-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAMwAAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff; background: url(data:image/gif;base64,R0lGODlhCAAIAPABAMwAAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
} }
@ -1879,9 +1854,9 @@ a.dropdown-link:after {
color: #888; color: #888;
} }
.fc-view-table tr.fc-invitation-tentative td.fc-event-title, .fc-view-table tr.fc-invitation-tentative td.fc-title,
.fc-view-table tr.fc-invitation-declined td.fc-event-title, .fc-view-table tr.fc-invitation-declined td.fc-title,
.fc-view-table tr.fc-invitation-needs-action td.fc-event-title { .fc-view-table tr.fc-invitation-needs-action td.fc-title {
font-weight: normal; font-weight: normal;
} }
@ -1898,7 +1873,8 @@ a.dropdown-link:after {
-o-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6); -o-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6); box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
} }
.fc-event-title {
.fc-title {
font-weight: bold; font-weight: bold;
} }
@ -1908,36 +1884,36 @@ a.dropdown-link:after {
opacity: 0.6; opacity: 0.6;
} }
.cal-event-status-cancelled .fc-event-title { .cal-event-status-cancelled .fc-title {
text-decoration: line-through; text-decoration: line-through;
} }
.fc-event-hori .fc-event-title { .fc-event-hori .fc-title {
font-weight: normal; font-weight: normal;
white-space: nowrap; white-space: nowrap;
} }
.fc-event-hori .fc-event-time { .fc-event-hori .fc-time {
white-space: nowrap; white-space: nowrap;
font-weight: normal !important; font-weight: normal !important;
font-size: 10px; font-size: 10px;
padding-right: 0.6em; padding-right: 0.6em;
} }
.fc-grid .fc-event-time { .fc-grid .fc-time {
font-weight: normal !important; font-weight: normal !important;
padding-right: 0.3em; padding-right: 0.3em;
} }
.calendarmain .fc-event-vert .fc-event-inner { .calendarmain .fc-event-vert .fc-inner {
z-index: 0; z-index: 0;
} }
.fc-event-cateories { .fc-event-categories {
font-style:italic; font-style: italic;
} }
div.fc-event-location { .fc-event-location {
font-size: 90%; font-size: 90%;
} }
@ -2049,10 +2025,6 @@ div.fc-event-location {
width: 25%; width: 25%;
} }
.fc-view-table table.fc-list-smart {
/* table-layout: auto; */
}
.fc-listappend { .fc-listappend {
text-align: center; text-align: center;
margin: 1em 0; margin: 1em 0;

File diff suppressed because it is too large Load diff

View file

@ -45,13 +45,14 @@ function rcube_libcalendaring(settings)
var client_timezone = new Date().getTimezoneOffset(); var client_timezone = new Date().getTimezoneOffset();
// general datepicker settings // general datepicker settings
var datepicker_settings = { this.datepicker_settings = {
// translate from fullcalendar format to datepicker format // translate from fullcalendar format to datepicker format
dateFormat: settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'), dateFormat: settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/DD/, 'dd').replace(/Y/g, 'y').replace(/yyyy/g, 'yy'),
firstDay : settings.first_day, firstDay : settings.first_day,
dayNamesMin: settings.days_short, dayNamesMin: settings.days_short,
monthNames: settings.months, monthNames: settings.months,
monthNamesShort: settings.months, monthNamesShort: settings.months,
showWeek: settings.show_weekno >= 0,
changeMonth: false, changeMonth: false,
showOtherMonths: true, showOtherMonths: true,
selectOtherMonths: true selectOtherMonths: true
@ -76,19 +77,27 @@ function rcube_libcalendaring(settings)
if (!event.end) if (!event.end)
event.end = event.start; event.end = event.start;
var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000, // Support Moment.js objects
var start = 'toDate' in event.start ? event.start.toDate() : event.start,
end = 'toDate' in event.end ? event.end.toDate() : event.end;
var fromto, duration = end.getTime() / 1000 - start.getTime() / 1000,
until = voice ? ' ' + rcmail.gettext('until','libcalendaring') + ' ' : ' — '; until = voice ? ' ' + rcmail.gettext('until','libcalendaring') + ' ' : ' — ';
if (event.allDay) { if (event.allDay) {
fromto = this.format_datetime(event.start, 1, voice) // fullcalendar end dates of all-day events are exclusive
+ (duration > 86400 || event.start.getDay() != event.end.getDay() ? until + this.format_datetime(event.end, 1, voice) : ''); end = new Date(end.getTime() - 1000*60*60*24*1);
duration = end.getTime() / 1000 - start.getTime() / 1000;
fromto = this.format_datetime(start, 1, voice)
+ (duration > 86400 || start.getDay() != end.getDay() ? until + this.format_datetime(end, 1, voice) : '');
} }
else if (duration < 86400 && event.start.getDay() == event.end.getDay()) { else if (duration < 86400 && start.getDay() == end.getDay()) {
fromto = this.format_datetime(event.start, 0, voice) fromto = this.format_datetime(start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(event.end, 2, voice) : ''); + (duration > 0 ? until + this.format_datetime(end, 2, voice) : '');
} }
else { else {
fromto = this.format_datetime(event.start, 0, voice) fromto = this.format_datetime(start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(event.end, 0, voice) : ''); + (duration > 0 ? until + this.format_datetime(end, 0, voice) : '');
} }
return fromto; return fromto;
@ -154,7 +163,7 @@ function rcube_libcalendaring(settings)
this.parse_datetime = function(time, date) this.parse_datetime = function(time, date)
{ {
// we use the utility function from datepicker to parse dates // we use the utility function from datepicker to parse dates
var date = date ? $.datepicker.parseDate(datepicker_settings.dateFormat, date, datepicker_settings) : new Date(); var date = date ? $.datepicker.parseDate(this.datepicker_settings.dateFormat, date, this.datepicker_settings) : new Date();
var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/); var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/);
if (!isNaN(time_arr[0])) { if (!isNaN(time_arr[0])) {
@ -229,6 +238,9 @@ function rcube_libcalendaring(settings)
*/ */
this.date2ISO8601 = function(date) this.date2ISO8601 = function(date)
{ {
if ('toDate' in date)
return date.format('YYYY-MM-DD[T]HH:mm:ss'); // MomentJS
var zeropad = function(num) { return (num < 10 ? '0' : '') + num; }; var zeropad = function(num) { return (num < 10 ? '0' : '') + num; };
return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate()) return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate())
@ -242,7 +254,7 @@ function rcube_libcalendaring(settings)
{ {
var res = ''; var res = '';
if (!mode || mode == 1) { if (!mode || mode == 1) {
res += $.datepicker.formatDate(voice ? 'MM d yy' : datepicker_settings.dateFormat, date, datepicker_settings); res += $.datepicker.formatDate(voice ? 'MM d yy' : this.datepicker_settings.dateFormat, date, this.datepicker_settings);
} }
if (!mode) { if (!mode) {
res += voice ? ' ' + rcmail.gettext('at','libcalendaring') + ' ' : ' '; res += voice ? ' ' + rcmail.gettext('at','libcalendaring') + ' ' : ' ';
@ -299,8 +311,10 @@ function rcube_libcalendaring(settings)
*/ */
this.date2unixtime = function(date) this.date2unixtime = function(date)
{ {
var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; // adjust DST offset var dt = 'toDate' in date ? date.toDate() : date,
return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset); dst_offset = (client_timezone - dt.getTimezoneOffset()) * 60; // adjust DST offset
return Math.round(dt.getTime()/1000 + gmt_offset * 3600 + dst_offset);
} }
/** /**
@ -396,7 +410,7 @@ function rcube_libcalendaring(settings)
parent.find('.edit-alarm-related')[val === '@' ? 'hide' : 'show'](); parent.find('.edit-alarm-related')[val === '@' ? 'hide' : 'show']();
}); });
$(prefix+' .edit-alarm-date').removeClass('hasDatepicker').removeAttr('id').datepicker(datepicker_settings); $(prefix+' .edit-alarm-date').removeClass('hasDatepicker').removeAttr('id').datepicker(this.datepicker_settings);
if (rcmail.env.action != 'print') if (rcmail.env.action != 'print')
this.init_time_autocomplete($(prefix+' .edit-alarm-time')[0], {}); this.init_time_autocomplete($(prefix+' .edit-alarm-time')[0], {});
@ -847,9 +861,9 @@ function rcube_libcalendaring(settings)
return false; return false;
}); });
$('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) }); $('#edit-recurrence-enddate').datepicker(this.datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
$('#edit-recurrence-repeat-times').change(function(e){ $('#edit-recurrence-repeat-count').prop('checked', true); }); $('#edit-recurrence-repeat-times').change(function(e){ $('#edit-recurrence-repeat-count').prop('checked', true); });
$('#edit-recurrence-rdate-input').datepicker(datepicker_settings); $('#edit-recurrence-rdate-input').datepicker(this.datepicker_settings);
}; };
/** /**
@ -857,7 +871,7 @@ function rcube_libcalendaring(settings)
*/ */
this.set_recurrence_edit = function(rec) this.set_recurrence_edit = function(rec)
{ {
var recurrence = $('#edit-recurrence-frequency').val(rec.recurrence ? rec.recurrence.FREQ || (rec.recurrence.RDATE ? 'RDATE' : '') : '').change(), var date, recurrence = $('#edit-recurrence-frequency').val(rec.recurrence ? rec.recurrence.FREQ || (rec.recurrence.RDATE ? 'RDATE' : '') : '').change(),
interval = $('.recurrence-form select.edit-recurrence-interval').val(rec.recurrence ? rec.recurrence.INTERVAL || 1 : 1), interval = $('.recurrence-form select.edit-recurrence-interval').val(rec.recurrence ? rec.recurrence.INTERVAL || 1 : 1),
rrtimes = $('#edit-recurrence-repeat-times').val(rec.recurrence ? rec.recurrence.COUNT || 1 : 1), rrtimes = $('#edit-recurrence-repeat-times').val(rec.recurrence ? rec.recurrence.COUNT || 1 : 1),
rrenddate = $('#edit-recurrence-enddate').val(rec.recurrence && rec.recurrence.UNTIL ? this.format_datetime(this.parseISO8601(rec.recurrence.UNTIL), 1) : ''); rrenddate = $('#edit-recurrence-enddate').val(rec.recurrence && rec.recurrence.UNTIL ? this.format_datetime(this.parseISO8601(rec.recurrence.UNTIL), 1) : '');
@ -887,13 +901,15 @@ function rcube_libcalendaring(settings)
$('input.edit-recurrence-'+section+'-mode').val(['BYDAY']); $('input.edit-recurrence-'+section+'-mode').val(['BYDAY']);
} }
else if (rec.start) { else if (rec.start) {
$('#edit-recurrence-monthly-byday').val(weekdays[rec.start.getDay()]); date = 'toDate' in rec.start ? rec.start.toDate() : rec.start;
$('#edit-recurrence-monthly-byday').val(weekdays[date.getDay()]);
} }
if (rec.recurrence && rec.recurrence.BYMONTH) { if (rec.recurrence && rec.recurrence.BYMONTH) {
$('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(',')); $('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(','));
} }
else if (rec.start) { else if (rec.start) {
$('input.edit-recurrence-yearly-bymonth').val([String(rec.start.getMonth()+1)]); date = 'toDate' in rec.start ? rec.start.toDate() : rec.start;
$('input.edit-recurrence-yearly-bymonth').val([String(date.getMonth()+1)]);
} }
if (rec.recurrence && rec.recurrence.RDATE) { if (rec.recurrence && rec.recurrence.RDATE) {
$.each(rec.recurrence.RDATE, function(i,rdate){ $.each(rec.recurrence.RDATE, function(i,rdate){

View file

@ -207,14 +207,16 @@ class libcalendaring extends rcube_plugin
$this->date_format_defaults(); $this->date_format_defaults();
$settings = array(); $settings = array();
$keys = array('date_format', 'time_format', 'date_short', 'date_long'); $keys = array('date_format', 'time_format', 'date_short', 'date_long', 'date_agenda');
foreach ($keys as $key) { foreach ($keys as $key) {
$settings[$key] = (string)$this->rc->config->get('calendar_' . $key, $this->defaults['calendar_' . $key]); $settings[$key] = (string)$this->rc->config->get('calendar_' . $key, $this->defaults['calendar_' . $key]);
$settings[$key] = str_replace('Y', 'y', $settings[$key]); $settings[$key] = str_replace('y', 'Y', $settings[$key]);
$settings[$key] = preg_replace('/(?<!d)dd(?!d)/', 'DD', $settings[$key]);
$settings[$key] = preg_replace('/(?<!d)d(?!d)/', 'D', $settings[$key]);
} }
$settings['dates_long'] = str_replace(' yyyy', '[ yyyy]', $settings['date_long']) . "{ '&mdash;' " . $settings['date_long'] . '}'; $settings['dates_long'] = $settings['date_long'];// . " - " . $settings['date_long'];
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']); $settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
$settings['timezone'] = $this->timezone_offset; $settings['timezone'] = $this->timezone_offset;
$settings['dst'] = $this->dst_active; $settings['dst'] = $this->dst_active;

View file

@ -87,19 +87,6 @@ function rcube_tasklist_ui(settings)
var task_attendees = []; var task_attendees = [];
var attendees_list; var attendees_list;
var me = this; var me = this;
// general datepicker settings
var datepicker_settings = {
// translate from PHP format to datepicker format
dateFormat: settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'),
firstDay : settings.first_day,
// dayNamesMin: settings.days_short,
// monthNames: settings.months,
// monthNamesShort: settings.months,
changeMonth: false,
showOtherMonths: true,
selectOtherMonths: true
};
var extended_datepicker_settings; var extended_datepicker_settings;
/* public members */ /* public members */
@ -127,10 +114,6 @@ function rcube_tasklist_ui(settings)
/* imports */ /* imports */
var Q = this.quote_html; var Q = this.quote_html;
var text2html = this.text2html; var text2html = this.text2html;
var event_date_text = this.event_date_text;
var parse_datetime = this.parse_datetime;
var date2unixtime = this.date2unixtime;
var fromunixtime = this.fromunixtime;
var render_message_links = this.render_message_links; var render_message_links = this.render_message_links;
/** /**
@ -639,7 +622,7 @@ function rcube_tasklist_ui(settings)
}); });
}, 1); }, 1);
} }
}, datepicker_settings); }, me.datepicker_settings);
rcmail.addEventListener('kolab-tags-search', filter_tasks) rcmail.addEventListener('kolab-tags-search', filter_tasks)
.addEventListener('kolab-tags-drop-data', function(e) { return listdata[e.id]; }) .addEventListener('kolab-tags-drop-data', function(e) { return listdata[e.id]; })
@ -743,7 +726,7 @@ function rcube_tasklist_ui(settings)
me.init_alarms_edit('#taskedit-alarms'); me.init_alarms_edit('#taskedit-alarms');
me.init_recurrence_edit('#eventedit'); me.init_recurrence_edit('#eventedit');
$('#taskedit-date, #taskedit-startdate').datepicker(datepicker_settings); $('#taskedit-date, #taskedit-startdate').datepicker(me.datepicker_settings);
$('a.edit-nodate').click(function(){ $('a.edit-nodate').click(function(){
var sel = $(this).attr('rel'); var sel = $(this).attr('rel');
@ -2594,8 +2577,8 @@ function rcube_tasklist_ui(settings)
return false; return false;
} }
else if (data.startdate && data.date) { else if (data.startdate && data.date) {
var startdate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.startdate, datepicker_settings); var startdate = $.datepicker.parseDate(me.datepicker_settings.dateFormat, data.startdate, me.datepicker_settings);
var duedate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.date, datepicker_settings); var duedate = $.datepicker.parseDate(me.datepicker_settings.dateFormat, data.date, me.datepicker_settings);
if (startdate > duedate) { if (startdate > duedate) {
rcmail.alert_dialog(rcmail.gettext('invalidstartduedates', 'tasklist')); rcmail.alert_dialog(rcmail.gettext('invalidstartduedates', 'tasklist'));
return false; return false;