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()
{
$events = $this->driver->load_events(
rcube_utils::get_input_value('start', 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)),
rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)
);
$start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GET);
$end = rcube_utils::get_input_value('end', 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);
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));
exit;
}
@ -1767,8 +1776,6 @@ class calendar extends rcube_plugin
// configuration
$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['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['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']);
@ -1889,24 +1896,31 @@ class calendar extends rcube_plugin
$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['allDay'] = !empty($event['allday']);
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(
'_id' => $event['calendar'] . ':' . $event['id'], // unique identifier for fullcalendar
'start' => $this->lib->adjust_timezone($event['start'], $event['allday'])->format('c'),
'end' => $this->lib->adjust_timezone($event['end'], $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'),
// 'changed' might be empty for event recurrences (Bug #2185)
'changed' => $event['changed'] ? $this->lib->adjust_timezone($event['changed'])->format('c') : null,
'created' => $event['created'] ? $this->lib->adjust_timezone($event['created'])->format('c') : null,
'title' => strval($event['title']),
'description' => strval($event['description']),
'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;
}
@ -2056,7 +2070,11 @@ class calendar extends rcube_plugin
// convert dates into DateTime objects in user's current timezone
$event['start'] = new DateTime($event['start'], $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)
if ($action == 'move') {
@ -2433,14 +2451,15 @@ class calendar extends rcube_plugin
$skin_path = $this->local_skin_path();
$this->include_stylesheet($skin_path . '/fullcalendar.css');
$this->include_stylesheet($skin_path . '/print.css');
// Add JS files to the page header
$this->include_script('print.js');
$this->include_script('lib/js/moment.js');
$this->include_script('lib/js/fullcalendar.js');
$this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css'));
$this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list'));
$this->rc->output->set_pagetitle($title);
$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 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
var fullcalendar_defaults = {
aspectRatio: 1,
@ -96,42 +82,52 @@ function rcube_calendar_ui(settings)
firstDay : settings.first_day,
firstHour : settings.first_hour,
slotMinutes : 60/settings.timeslots,
timeFormat: {
'': settings.time_format,
agenda: settings.time_format + '{ - ' + settings.time_format + '}',
list: settings.time_format + '{ - ' + settings.time_format + '}',
table: settings.time_format + '{ - ' + settings.time_format + '}'
views: {
basic: {
timeFormat: 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,
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
listRange: settings.agenda_range,
listSections: settings.agenda_sections,
tableCols: ['handle', 'date', 'time', 'title', 'location'],
*/
defaultView: rcmail.env.view || settings.default_view,
allDayText: rcmail.gettext('all-day', 'calendar'),
weekNumbers: settings.show_weekno > 0,
weekNumberTitle: rcmail.gettext('weekshort', 'calendar') + ' ',
buttonText: {
prev: ' ◄ ',
next: ' ► ',
today: settings['today'],
day: rcmail.gettext('day', 'calendar'),
week: rcmail.gettext('week', '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: {
until: rcmail.gettext('until', 'calendar'),
past: rcmail.gettext('pastevents', 'calendar'),
@ -144,6 +140,7 @@ function rcube_calendar_ui(settings)
future: rcmail.gettext('futureevents', 'calendar'),
week: rcmail.gettext('weekofyear', 'calendar')
},
*/
currentTimeIndicator: settings.time_indicator,
// event rendering
eventRender: function(event, element, view) {
@ -153,14 +150,15 @@ function rcube_calendar_ui(settings)
}
if (view.name != 'month') {
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')
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)
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))
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) {
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
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);
}
};
@ -184,7 +182,6 @@ function rcube_calendar_ui(settings)
var Q = this.quote_html;
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 parseISO8601 = this.parseISO8601;
@ -226,8 +223,8 @@ function rcube_calendar_ui(settings)
// clone the given date object and optionally adjust time
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
if (adjust == 1) {
d.setHours(0);
@ -238,7 +235,7 @@ function rcube_calendar_ui(settings)
d.setHours(23);
d.setMinutes(59);
}
return d;
};
@ -256,6 +253,11 @@ function rcube_calendar_ui(settings)
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)
{
return me.format_datetime(date, mode, voice);
@ -633,11 +635,19 @@ function rcube_calendar_ui(settings)
var priority = $('#edit-priority').val(event.priority);
var sensitivity = $('#edit-sensitivity').val(event.sensitivity);
var syncstart = $('#edit-recurrence-syncstart input');
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
var startdate = $('#edit-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
var starttime = $('#edit-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
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();
var end = 'toDate' in event.end ? event.end : moment(event.end);
var start = 'toDate' in event.start ? event.start : moment(event.start);
var duration = Math.round((end.format('x') - start.format('x')) / 1000);
// 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 notify = $('#edit-attendees-donotify').get(0);
var invite = $('#edit-attendees-invite').get(0);
@ -769,8 +779,8 @@ function rcube_calendar_ui(settings)
// init dialog buttons
var buttons = [],
save_func = function() {
var start = parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
var start = me.parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = me.parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
// basic input validatetion
if (start.getTime() > end.getTime()) {
@ -1146,11 +1156,14 @@ function rcube_calendar_ui(settings)
// set form elements
var allday = $('#edit-allday').get(0);
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
freebusy_ui.startdate = $('#schedule-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
freebusy_ui.starttime = $('#schedule-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
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();
var end = 'toDate' in event.end ? event.end : moment(event.end);
var start = 'toDate' in event.start ? event.start : moment(event.start);
var duration = Math.round((end.format('x') - start.format('x')) / 1000);
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) {
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++) {
curdate.setTime(t);
datestr = fc.fullCalendar('formatDate', curdate, date_format);
datestr = format_date(curdate, date_format);
if (datestr != lastdate) {
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;
}
// set css class according to working hours
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>';
t += interval * 60000;
@ -1674,10 +1687,10 @@ function rcube_calendar_ui(settings)
}
me.selected_event.start = start;
me.selected_event.end = end;
freebusy_ui.startdate.val($.fullCalendar.formatDate(start, settings['date_format']));
freebusy_ui.starttime.val($.fullCalendar.formatDate(start, settings['time_format']));
freebusy_ui.enddate.val($.fullCalendar.formatDate(end, settings['date_format']));
freebusy_ui.endtime.val($.fullCalendar.formatDate(end, settings['time_format']));
freebusy_ui.startdate.val(format_date(start, settings.date_format));
freebusy_ui.starttime.val(format_date(start, settings.time_format));
freebusy_ui.enddate.val(format_date(end, settings.date_format));
freebusy_ui.endtime.val(format_date(end, settings.time_format));
freebusy_ui.needsupdate = true;
};
@ -1793,8 +1806,8 @@ function rcube_calendar_ui(settings)
if (me.selected_event) {
var allday = $('#edit-allday').get(0);
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.end = parse_datetime(allday.checked ? '13:00' : $('#edit-endtime').val(), $('#edit-enddate').val());
me.selected_event.start = me.parse_datetime(allday.checked ? '12:00' : $('#edit-starttime').val(), $('#edit-startdate').val());
me.selected_event.end = me.parse_datetime(allday.checked ? '13:00' : $('#edit-endtime').val(), $('#edit-enddate').val());
if (event_attendees)
freebusy_ui.needsupdate = true;
$('#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) {
var title = rcmail.get_label(event.status, 'calendar');
element.addClass('status-' + event.status);
element.find('.fc-event-head').hide();
element.find('.fc-event-title').text(title);
element.find('.fc-title').text(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);
}
};
// add the given date to the RDATE list
var add_rdate = function(date)
{
var li = $('<li>')
.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');
$('<a>').attr('href', '#del')
@ -2459,19 +2471,20 @@ function rcube_calendar_ui(settings)
{
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar/event', $.extend({ action:action, e:data }, (add || {})));
// render event temporarily into the calendar
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)
event.start = data.start;
if (data.end)
event.end = data.end;
if (data.allday !== undefined)
event.allDay = data.allday;
if (data.allDay !== undefined)
event.allDay = data.allDay;
event.editable = false;
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);
// 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) {
ev.temp = true;
ev.editable = false;
event.className += ' fc-event-temp';
event.className.push('fc-event-temp');
fc.fullCalendar('updateEvent', ev);
});
}
@ -2632,7 +2645,7 @@ function rcube_calendar_ui(settings)
fc.fullCalendar('refetchEvents');
}
}).addClass('event-update-confirm').show();
return false;
}
// show regular confirm box when deleting
@ -2643,7 +2656,7 @@ function rcube_calendar_ui(settings)
// do update
update_event(action, data);
return true;
};
@ -2700,7 +2713,7 @@ function rcube_calendar_ui(settings)
modal: true,
width: 680,
height: h,
title: $.fullCalendar.formatDate(date, 'dddd ' + settings['date_long']),
title: format_date(date, 'dddd ' + settings.date_long),
buttons: [{
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
@ -2720,7 +2733,7 @@ function rcube_calendar_ui(settings)
year: date.getFullYear(),
eventSources: sources
}));
this.fisheye_date = date;
};
@ -2839,7 +2852,7 @@ function rcube_calendar_ui(settings)
this.print_calendars = function(view)
{
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 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);
@ -2849,9 +2862,7 @@ function rcube_calendar_ui(settings)
this.add_event = function(templ) {
if (this.selected_calendar) {
var now = new Date();
var date = fc.fullCalendar('getDate');
if (typeof date != 'Date')
date = now;
var date = fc.fullCalendar('getDate').toDate();
date.setHours(now.getHours()+1);
date.setMinutes(0);
var end = new Date(date.getTime());
@ -2941,9 +2952,10 @@ function rcube_calendar_ui(settings)
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
// 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('addEventSource', me.calendars[id]);
};
@ -3093,7 +3105,7 @@ function rcube_calendar_ui(settings)
attachmt = $('#event-export-attachments').get(0).checked;
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)
start = 'today -' + range + ' months';
@ -3229,16 +3241,13 @@ function rcube_calendar_ui(settings)
return false;
}
});
fc.fullCalendar('refetchEvents', source, true);
}
else if (!source.active) {
source.active = true;
fc.fullCalendar('addEventSource', source);
$('#rcmlical' + source.id + ' input').prop('checked', true);
}
else
fc.fullCalendar('refetchEvents', source, true);
fc.fullCalendar('refetchEventSources', source);
fetch_counts();
}
// add/update single event object
@ -3261,7 +3270,7 @@ function rcube_calendar_ui(settings)
}
// refetch all calendars
else if (p.refetch) {
fc.fullCalendar('refetchEvents', undefined, true);
fc.fullCalendar('refetchEvents');
fetch_counts();
}
};
@ -3271,8 +3280,8 @@ function rcube_calendar_ui(settings)
{
var view = fc.fullCalendar('getView');
query.start = date2unixtime(view.visStart);
query.end = date2unixtime(view.visEnd);
query.start = date2unixtime(view.start.toDate());
query.end = date2unixtime(view.end.toDate());
if (this.search_query)
query.q = this.search_query;
@ -3327,7 +3336,7 @@ function rcube_calendar_ui(settings)
var query = { view: fc.fullCalendar('getView').name },
date = fc.fullCalendar('getDate');
if (date)
query.date = date2unixtime(date);
query.date = date2unixtime(date.toDate());
rcmail.redirect(rcmail.url('', query));
}
@ -3337,7 +3346,7 @@ function rcube_calendar_ui(settings)
var query = { view: current_view },
date = fc.fullCalendar('getDate');
if (date)
query.date = date2unixtime(date);
query.date = date2unixtime(date.toDate());
if (window.history.replaceState)
window.history.replaceState({}, document.title, rcmail.url('', query).replace('&_action=', ''));
@ -3388,9 +3397,10 @@ function rcube_calendar_ui(settings)
this.search_query = q;
// change to list view
fc.fullCalendar('option', 'listSections', 'month')
.fullCalendar('option', 'listRange', Math.max(60, settings['agenda_range']))
.fullCalendar('changeView', 'table');
fc.fullCalendar('option', 'listSections', 'month');
fc.fullCalendar('option', 'listRange', Math.max(60, settings.agenda_range));
// TODO: fullcalendar 3.9 has dateOrRange argument here, shall we use it?
fc.fullCalendar('changeView', 'listYear');
update_agenda_toolbar();
@ -3416,8 +3426,8 @@ function rcube_calendar_ui(settings)
fc.find('.fc-list-content > .fc-listappend').hide();
// restore original event sources and view mode from fullcalendar
fc.fullCalendar('option', 'listSections', settings['agenda_sections'])
.fullCalendar('option', 'listRange', settings['agenda_range']);
fc.fullCalendar('option', 'listSections', settings.agenda_sections);
fc.fullCalendar('option', 'listRange', settings.agenda_range);
update_agenda_toolbar();
@ -3478,7 +3488,7 @@ function rcube_calendar_ui(settings)
.append($('<span class="inner">').text(rcmail.gettext(elastic ? 'earlierevents' : 'searchearlierdates', 'calendar')))
.appendTo(lc)
.click(function() {
fc.fullCalendar('incrementDate', 0, -1, 0);
fc.fullCalendar('incrementDate', "-P1M");
});
lc.append(" ");
@ -3489,11 +3499,12 @@ function rcube_calendar_ui(settings)
.click(function() {
var range = fc.fullCalendar('option', 'listRange');
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();
}
else
fc.fullCalendar('incrementDate', 0, 1, 0);
fc.fullCalendar('incrementDate', "P1M");
});
}
}
@ -3532,7 +3543,7 @@ function rcube_calendar_ui(settings)
me.calendars[id] = $.extend({
url: rcmail.url('calendar/load_events', { source: id }),
className: 'fc-event-cal-'+id,
className: ['fc-event-cal-' + id],
id: id
}, cal);
@ -3767,7 +3778,7 @@ function rcube_calendar_ui(settings)
if (rcmail.env.itip_events && rcmail.env.itip_events.length) {
me.calendars['--invitation--itip'] = {
events: rcmail.env.itip_events,
className: 'fc-event-cal---invitation--itip',
className: ['fc-event-cal---invitation--itip'],
color: '#fff',
textColor: '#333',
editable: false,
@ -3782,7 +3793,7 @@ function rcube_calendar_ui(settings)
header: {
right: 'prev,next today',
center: 'title',
left: 'agendaDay,agendaWeek,month,table'
left: 'agendaDay,agendaWeek,month,listYear'
},
date: viewdate.getDate(),
month: viewdate.getMonth(),
@ -3799,64 +3810,68 @@ function rcube_calendar_ui(settings)
me.events_loaded($(this).fullCalendar('clientEvents').length);
},
// callback for date range selection
select: function(start, end, allDay, e, view) {
var range_select = (!allDay || start.getDate() != end.getDate())
select: function(start, end, e, view) {
var range_select = (start.hasTime() || start != end)
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)
view.calendar.unselect();
},
// callback for clicks in all-day box
dayClick: function(date, allDay, e, view) {
dayClick: function(date, e, view) {
var now = new Date().getTime();
if (now - day_clicked_ts < 400 && day_clicked == date.getTime()) { // emulate double-click on day
var enddate = new Date(); enddate.setTime(date.getTime() + DAY_MS - 60000);
return event_edit_dialog('new', { start:date, end:enddate, allDay:allDay, calendar:me.selected_calendar });
if (now - day_clicked_ts < 400 && day_clicked == date.toDate().getTime()) { // emulate double-click on day
var enddate = new Date();
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) {
view.calendar.gotoDate(date);
if (day_clicked && new Date(day_clicked).getMonth() != date.getMonth())
view.calendar.select(date, date, allDay);
if (day_clicked && new Date(day_clicked).getMonth() != date.toDate().getMonth())
view.calendar.select(date, date);
}
day_clicked = date.getTime();
day_clicked = date.toDate().getTime();
day_clicked_ts = now;
},
// callback when an event was dragged and finally dropped
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
if (event.end == null || event.end.getTime() < event.start.getTime()) {
event.end = new Date(event.start.getTime() + (allDay ? DAY_MS : HOUR_MS));
eventDrop: function(event, delta, revertFunc) {
var allday = !event.start.hasTime();
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
if (allDay && !event.allDay) {
event.start.setHours(12);
event.start.setMinutes(0);
event.start.setSeconds(0);
event.end.setHours(13);
event.end.setMinutes(0);
event.end.setSeconds(0);
if (allday && !event.allDay) {
event.start.hours(12);
event.start.minutes(0);
event.start.seconds(0);
event.end.hours(13);
event.end.minutes(0);
event.end.seconds(0);
}
// moved from all-day section: set times to working hours
else if (event.allDay && !allDay) {
var newstart = event.start.getTime();
else if (event.allDay && !allday) {
var newstart = event.start.format('x');
revertFunc(); // revert to get original duration
var numdays = Math.max(1, Math.round((event.end.getTime() - event.start.getTime()) / DAY_MS)) - 1;
event.start = new Date(newstart);
event.end = new Date(newstart + numdays * DAY_MS);
event.end.setHours(settings['work_end'] || 18);
event.end.setMinutes(0);
if (event.end.getTime() < event.start.getTime())
var numdays = Math.max(1, Math.round((event.end.format('x') - event.start.format('x')) / DAY_MS)) - 1;
event.start = moment(newstart);
event.end = moment(newstart + numdays * DAY_MS);
event.end.hours(settings.work_end || 18);
event.end.minutes(0);
if (event.end.diff(event.start) < 0)
event.end = new Date(newstart + HOUR_MS);
}
// send move request to server
var data = {
id: event.id,
calendar: event.calendar,
start: date2servertime(event.start),
end: date2servertime(event.end),
allday: allDay?1:0
allDay: allday?1:0
};
update_event_confirm('move', event, data);
},
@ -3864,9 +3879,9 @@ function rcube_calendar_ui(settings)
eventResize: function(event, delta) {
// sanitize event dates
if (event.allDay)
event.start.setHours(12);
if (!event.end || event.end.getTime() < event.start.getTime())
event.end = new Date(event.start.getTime() + HOUR_MS);
event.start.hours(12);
if (!event.end || event.end.diff(event.start) < 0)
event.end = new Date(event.start.format('x') + HOUR_MS);
// send resize request to server
var data = {
@ -3874,39 +3889,35 @@ function rcube_calendar_ui(settings)
calendar: event.calendar,
start: date2servertime(event.start),
end: date2servertime(event.end),
allday: event.allDay?1:0
allDay: event.allDay?1:0
};
update_event_confirm('resize', event, data);
},
viewDisplay: function(view) {
$('#agendaoptions')[view.name == 'table' ? 'show' : 'hide']();
viewRender: function(view) {
$('#agendaoptions')[view.name == 'listYear' ? 'show' : 'hide']();
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)
me.view_resize();
current_view = view.name;
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
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);
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format']));
$('#edit-enddate').val(format_date(newend, me.settings.date_format));
event_times_changed();
};
// 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.
// This is a temporary fix until http://bugs.jqueryui.com/ticket/8420 is resolved.
var iso8601Week = datepicker_settings.calculateWeek = function(date) {
var mondayOffset = Math.abs(1 - datepicker_settings.firstDay);
var iso8601Week = me.datepicker_settings.calculateWeek = function(date) {
var mondayOffset = Math.abs(1 - me.datepicker_settings.firstDay);
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
minical = $('#datepicker').datepicker($.extend(datepicker_settings, {
minical = $('#datepicker').datepicker($.extend(me.datepicker_settings, {
inline: true,
changeMonth: true,
changeYear: true,
onSelect: function(dateText, inst) {
ignore_click = true;
var d = minical.datepicker('getDate'); //parse_datetime('0:0', dateText);
fc.fullCalendar('gotoDate', d).fullCalendar('select', d, d, true);
var d = minical.datepicker('getDate');
fc.fullCalendar('gotoDate', d)
fc.fullCalendar('select', d, d);
setTimeout(function() { pretty_select($('select', minical)); }, 25);
},
onChangeMonthYear: function(year, month, inst) {
@ -3936,9 +3948,13 @@ function rcube_calendar_ui(settings)
setTimeout(function() { pretty_select($('select', minical)); }, 25);
},
beforeShowDay: function(date) {
// TODO: this pretty_select() calls should be implemented in a different way
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 : ''), ''];
}
})) // 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'))
base_date.setYear(minical.data('year'));
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),
target_kw = parseInt(cell.html()),
wdiff = target_kw - base_kw;
@ -3960,9 +3976,10 @@ function rcube_calendar_ui(settings)
else if (wdiff < -10)
base_date.setYear(base_date.getFullYear() + 1);
// 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);
fc.fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
fc.fullCalendar('gotoDate', date)
fc.fullCalendar('changeView', 'agendaWeek');
minical.datepicker('setDate', date);
setTimeout(function() { pretty_select($('select', minical)); }, 25);
}
@ -4011,11 +4028,11 @@ function rcube_calendar_ui(settings)
$('#edit-recurrence-syncstart').hide();
};
$('#eventedit:not([data-notabs])').tabs({activate: tab_change}); // Larry
$('#eventedit a.nav-link').on('show.bs.tab', tab_change); // Elastic
$('#eventedit:not([data-notabs])').tabs({activate: tab_change}); // Larry
$('#eventedit a.nav-link').on('show.bs.tab', tab_change); // Elastic
$('#edit-enddate').datepicker(datepicker_settings);
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
$('#edit-enddate').datepicker(me.datepicker_settings);
$('#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-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
$('#edit-starttime').change(function(e) {
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);
$('#edit-endtime').val($.fullCalendar.formatDate(newend, me.settings['time_format']));
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format']));
$('#edit-endtime').val(format_date(newend, me.settings.time_format));
$('#edit-enddate').val(format_date(newend, me.settings.date_format));
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
var ac_props;
@ -4176,14 +4193,16 @@ function rcube_calendar_ui(settings)
});
$('#agenda-listrange').change(function(e){
settings['agenda_range'] = parseInt($(this).val());
fc.fullCalendar('option', 'listRange', settings['agenda_range']).fullCalendar('render');
settings.agenda_range = parseInt($(this).val());
fc.fullCalendar('option', 'listRange', settings.agenda_range)
fc.fullCalendar('render');
// TODO: save new settings in prefs
}).val(settings['agenda_range']);
}).val(settings.agenda_range);
$('#agenda-listsections').change(function(e){
settings['agenda_sections'] = $(this).val();
fc.fullCalendar('option', 'listSections', settings['agenda_sections']).fullCalendar('render');
settings.agenda_sections = $(this).val();
fc.fullCalendar('option', 'listSections', settings.agenda_sections);
fc.fullCalendar('render');
// TODO: save new settings in prefs
}).val(fc.fullCalendar('option', 'listSections'));
@ -4199,10 +4218,6 @@ function rcube_calendar_ui(settings)
// fetch counts for some calendars
fetch_counts();
// add proprietary css styles if not IE
if (!bw.ie)
$('div.fc-content').addClass('rcube-fc-content');
// Save-as-event dialog content
if (rcmail.env.action == 'dialog-ui') {
var date = new Date(), event = {allDay: false, calendar: me.selected_calendar};
@ -4324,10 +4339,10 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// Elastic mods
if ($('#calendar').data('elastic-mode')) {
var selector = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-left'),
nav = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-right');
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-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),
activate = function(button) {
selector.children('.active').removeClass('active');
@ -4352,19 +4367,19 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
});
$.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'})
.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');
$('.content-frame-navigation a.button.date').appendTo('.content > .searchbar');
// Mobile header title
if (window.MutationObserver) {
var title = $('.fc-header-title'),
var title = $('.fc-header-toolbar > .fc-center h2'),
mobile_header = $('#layout > .content > .header > .header-title'),
callback = function() {
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;
}
#resource-freebusy-calendar .fc-content .fc-event-bg {
#resource-freebusy-calendar .fc-content .fc-bg {
background: 0;
}
@ -1636,32 +1636,16 @@ a.dropdown-link:after {
/* fullcalendar style overrides */
.rcube-fc-content {
overflow: hidden;
border: 0;
border-radius: 4px;
}
.calendarmain .fc-content {
position: absolute !important;
top: 40px;
left: 0;
right: 0;
bottom: 0;
.calendarmain .fc-body {
background: #fff;
}
.calendarmain.quickview-active .fc-content {
.calendarmain.quickview-active .fc-body {
background-image: url('images/focusview.png');
background-position: center;
background-repeat: no-repeat;
}
#fish-eye-view .fc-content {
top: 2px;
bottom: 2px;
}
#quickview-calendar {
padding: 8px;
overflow: hidden;
@ -1704,15 +1688,12 @@ a.dropdown-link:after {
margin-right: 0;
}
.calendarmain #calendar .fc-header-left .fc-button {
display: inline-block;
margin: 0;
text-align: center;
.calendarmain #calendar .fc-left .fc-button {
font-size: 10px;
color: #555;
min-width: 50px;
max-width: 75px;
height: 13px;
height: 43px;
line-height: 1em;
overflow: hidden;
text-overflow: ellipsis;
@ -1727,63 +1708,87 @@ a.dropdown-link:after {
-webkit-box-shadow: none;
-moz-box-shadow: 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;
text-shadow: 0px 1px 1px #666;
background-color: rgba(30,150,192, 0.5);
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;
color: #222;
text-shadow: none;
background-color: transparent;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaDay {
.calendarmain #calendar .fc-left .fc-agendaDay-button {
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;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek {
.calendarmain #calendar .fc-left .fc-agendaWeek-button {
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;
}
.calendarmain #calendar .fc-header-left .fc-button-month {
.calendarmain #calendar .fc-left .fc-month-button {
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;
}
.calendarmain #calendar .fc-header-left .fc-button-table {
.calendarmain #calendar .fc-left .fc-listYear-button {
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;
}
.calendarmain #calendar .fc-header-right {
padding-right: 252px;
.calendarmain #calendar .fc-header-toolbar .fc-right {
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 {
padding-top: 5px;
}
#calendar .fc-toolbar.fc-header-toolbar {
margin-bottom: 4px;
margin-right: 250px;
}
.fc-event {
font-size: 1em !important;
}
@ -1791,18 +1796,6 @@ a.dropdown-link:after {
.fc-event-hori.fc-type-freebusy,
.fc-event-vert.fc-type-freebusy {
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;
-webkit-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;
}
.fc-event-hori.fc-type-freebusy .fc-event-skin,
.fc-event-hori.fc-type-freebusy .fc-event-inner,
.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 {
.fc-event-hori.fc-type-freebusy .fc-title,
.fc-event-vert.fc-type-freebusy .fc-title {
position: absolute;
top: -5000px;
}
@ -1851,25 +1832,19 @@ a.dropdown-link:after {
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;
}
.fc-event-vert.fc-invitation-tentative .fc-event-head,
.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 {
.fc-event-vert.fc-invitation-tentative .fc-bg {
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;
}
.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;
}
@ -1879,9 +1854,9 @@ a.dropdown-link:after {
color: #888;
}
.fc-view-table tr.fc-invitation-tentative td.fc-event-title,
.fc-view-table tr.fc-invitation-declined td.fc-event-title,
.fc-view-table tr.fc-invitation-needs-action td.fc-event-title {
.fc-view-table tr.fc-invitation-tentative td.fc-title,
.fc-view-table tr.fc-invitation-declined td.fc-title,
.fc-view-table tr.fc-invitation-needs-action td.fc-title {
font-weight: normal;
}
@ -1898,7 +1873,8 @@ a.dropdown-link:after {
-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);
}
.fc-event-title {
.fc-title {
font-weight: bold;
}
@ -1908,36 +1884,36 @@ a.dropdown-link:after {
opacity: 0.6;
}
.cal-event-status-cancelled .fc-event-title {
.cal-event-status-cancelled .fc-title {
text-decoration: line-through;
}
.fc-event-hori .fc-event-title {
.fc-event-hori .fc-title {
font-weight: normal;
white-space: nowrap;
}
.fc-event-hori .fc-event-time {
.fc-event-hori .fc-time {
white-space: nowrap;
font-weight: normal !important;
font-size: 10px;
padding-right: 0.6em;
}
.fc-grid .fc-event-time {
.fc-grid .fc-time {
font-weight: normal !important;
padding-right: 0.3em;
}
.calendarmain .fc-event-vert .fc-event-inner {
.calendarmain .fc-event-vert .fc-inner {
z-index: 0;
}
.fc-event-cateories {
font-style:italic;
.fc-event-categories {
font-style: italic;
}
div.fc-event-location {
.fc-event-location {
font-size: 90%;
}
@ -2049,10 +2025,6 @@ div.fc-event-location {
width: 25%;
}
.fc-view-table table.fc-list-smart {
/* table-layout: auto; */
}
.fc-listappend {
text-align: center;
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();
// general datepicker settings
var datepicker_settings = {
this.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'),
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,
dayNamesMin: settings.days_short,
monthNames: settings.months,
monthNamesShort: settings.months,
showWeek: settings.show_weekno >= 0,
changeMonth: false,
showOtherMonths: true,
selectOtherMonths: true
@ -76,19 +77,27 @@ function rcube_libcalendaring(settings)
if (!event.end)
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') + ' ' : ' — ';
if (event.allDay) {
fromto = this.format_datetime(event.start, 1, voice)
+ (duration > 86400 || event.start.getDay() != event.end.getDay() ? until + this.format_datetime(event.end, 1, voice) : '');
// fullcalendar end dates of all-day events are exclusive
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()) {
fromto = this.format_datetime(event.start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(event.end, 2, voice) : '');
else if (duration < 86400 && start.getDay() == end.getDay()) {
fromto = this.format_datetime(start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(end, 2, voice) : '');
}
else {
fromto = this.format_datetime(event.start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(event.end, 0, voice) : '');
fromto = this.format_datetime(start, 0, voice)
+ (duration > 0 ? until + this.format_datetime(end, 0, voice) : '');
}
return fromto;
@ -154,7 +163,7 @@ function rcube_libcalendaring(settings)
this.parse_datetime = function(time, date)
{
// 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(/[:.]/);
if (!isNaN(time_arr[0])) {
@ -229,6 +238,9 @@ function rcube_libcalendaring(settings)
*/
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; };
return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate())
@ -242,7 +254,7 @@ function rcube_libcalendaring(settings)
{
var res = '';
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) {
res += voice ? ' ' + rcmail.gettext('at','libcalendaring') + ' ' : ' ';
@ -299,8 +311,10 @@ function rcube_libcalendaring(settings)
*/
this.date2unixtime = function(date)
{
var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; // adjust DST offset
return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset);
var dt = 'toDate' in date ? date.toDate() : date,
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']();
});
$(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')
this.init_time_autocomplete($(prefix+' .edit-alarm-time')[0], {});
@ -847,9 +861,9 @@ function rcube_libcalendaring(settings)
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-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)
{
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),
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) : '');
@ -887,13 +901,15 @@ function rcube_libcalendaring(settings)
$('input.edit-recurrence-'+section+'-mode').val(['BYDAY']);
}
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) {
$('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(','));
}
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) {
$.each(rec.recurrence.RDATE, function(i,rdate){

View file

@ -207,14 +207,16 @@ class libcalendaring extends rcube_plugin
$this->date_format_defaults();
$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) {
$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['timezone'] = $this->timezone_offset;
$settings['dst'] = $this->dst_active;

View file

@ -87,19 +87,6 @@ function rcube_tasklist_ui(settings)
var task_attendees = [];
var attendees_list;
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;
/* public members */
@ -127,10 +114,6 @@ function rcube_tasklist_ui(settings)
/* imports */
var Q = this.quote_html;
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;
/**
@ -639,7 +622,7 @@ function rcube_tasklist_ui(settings)
});
}, 1);
}
}, datepicker_settings);
}, me.datepicker_settings);
rcmail.addEventListener('kolab-tags-search', filter_tasks)
.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_recurrence_edit('#eventedit');
$('#taskedit-date, #taskedit-startdate').datepicker(datepicker_settings);
$('#taskedit-date, #taskedit-startdate').datepicker(me.datepicker_settings);
$('a.edit-nodate').click(function(){
var sel = $(this).attr('rel');
@ -2594,8 +2577,8 @@ function rcube_tasklist_ui(settings)
return false;
}
else if (data.startdate && data.date) {
var startdate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.startdate, datepicker_settings);
var duedate = $.datepicker.parseDate(datepicker_settings.dateFormat, data.date, datepicker_settings);
var startdate = $.datepicker.parseDate(me.datepicker_settings.dateFormat, data.startdate, me.datepicker_settings);
var duedate = $.datepicker.parseDate(me.datepicker_settings.dateFormat, data.date, me.datepicker_settings);
if (startdate > duedate) {
rcmail.alert_dialog(rcmail.gettext('invalidstartduedates', 'tasklist'));
return false;