From fb95e89345996977897d10af633f38e0fb98dc6a Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 31 Aug 2011 23:40:24 +0200 Subject: [PATCH] Improve calendar refreshing after saving an event (#383) --- plugins/calendar/calendar.php | 60 ++++++++++++++++++++------------- plugins/calendar/calendar_ui.js | 58 ++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index bcfe046c..ba446b64 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -557,24 +557,24 @@ class calendar extends rcube_plugin $event['id'] = $event['uid']; $this->cleanup_event($event); } - $reload = true; + $reload = $success && $event['recurrence'] ? 2 : 1; break; case "edit": $this->prepare_event($event, $action); if ($success = $this->driver->edit_event($event)) $this->cleanup_event($event); - $reload = true; + $reload = $success && $event['recurrence'] ? 2 : 1; break; case "resize": $success = $this->driver->resize_event($event); - $reload = true; + $reload = ($event['savemode'] == 'all' || $event['savemode'] == 'future') ? 2 : 1; break; case "move": $success = $this->driver->move_event($event); - $reload = true; + $reload = $success && ($event['savemode'] == 'all' || $event['savemode'] == 'future') ? 2 : 1; break; case "remove": @@ -591,7 +591,7 @@ class calendar extends rcube_plugin } $success = $this->driver->remove_event($event, $undo_time < 1); - $reload = true; + $reload = (!$success || $event['savemode'] == 'all' || $event['savemode'] == 'future') ? 2 : 1; if ($undo_time > 0 && $success) { $_SESSION['calendar_event_undo'] = array('ts' => time(), 'data' => $event); @@ -628,7 +628,6 @@ class calendar extends rcube_plugin case "undo": // Restore deleted event $event = $_SESSION['calendar_event_undo']['data']; - $reload = true; if ($event) $success = $this->driver->restore_event($event); @@ -637,6 +636,7 @@ class calendar extends rcube_plugin $this->rc->session->remove('calendar_event_undo'); $this->rc->output->show_message('calendar.successrestore', 'confirmation'); $got_msg = true; + $reload = 2; } break; @@ -724,9 +724,15 @@ class calendar extends rcube_plugin // unlock client $this->rc->output->command('plugin.unlock_saving'); - // FIXME: update a single event object on the client instead of reloading the entire source - if ($reload) - $this->rc->output->command('plugin.refresh_calendar', array('source' => $event['calendar'], 'refetch' => $success)); + // update event object on the client or trigger a complete refretch if too complicated + if ($reload) { + $args = array('source' => $event['calendar']); + if ($reload > 1) + $args['refetch'] = true; + else if ($success && $action != 'remove') + $args['update'] = $this->_client_event($this->driver->get_event($event)); + $this->rc->output->command('plugin.refresh_calendar', $args); + } } /** @@ -873,24 +879,32 @@ class calendar extends rcube_plugin { $json = array(); foreach ($events as $event) { - // compose a human readable strings for alarms_text and recurrence_text - if ($event['alarms']) - $event['alarms_text'] = $this->_alarms_text($event['alarms']); - if ($event['recurrence']) - $event['recurrence_text'] = $this->_recurrence_text($event['recurrence']); - - $json[] = array( - 'start' => gmdate('c', $this->fromGMT($event['start'])), // client treats date strings as they were in users's timezone - 'end' => gmdate('c', $this->fromGMT($event['end'])), // so shift timestamps to users's timezone and render a date string - 'description' => strval($event['description']), - 'location' => strval($event['location']), - 'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords($event['categories'], true), - 'allDay' => ($event['allday'] == 1), - ) + $event; + $json[] = $this->_client_event($event); } return json_encode($json); } + /** + * Convert an event object to be used on the client + */ + private function _client_event($event) + { + // compose a human readable strings for alarms_text and recurrence_text + if ($event['alarms']) + $event['alarms_text'] = $this->_alarms_text($event['alarms']); + if ($event['recurrence']) + $event['recurrence_text'] = $this->_recurrence_text($event['recurrence']); + + return array( + 'start' => gmdate('c', $this->fromGMT($event['start'])), // client treats date strings as they were in users's timezone + 'end' => gmdate('c', $this->fromGMT($event['end'])), // so shift timestamps to users's timezone and render a date string + 'description' => strval($event['description']), + 'location' => strval($event['location']), + 'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords($event['categories'], true), + 'allDay' => ($event['allday'] == 1), + ) + $event; + } + /** * Generate reduced and streamlined output for pending alarms diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index baa4bfc2..008ac29a 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -1429,10 +1429,12 @@ function rcube_calendar_ui(settings) rcmail.http_post('event', { action:action, e:data }); // render event temporarily into the calendar - if (data.start && data.end && action != 'remove') { + if ((data.start && data.end) || data.id) { var event = data.id ? $.extend(fc.fullCalendar('clientEvents', data.id)[0], data) : data; - event.start = fromunixtime(data.start); - event.end = fromunixtime(data.end); + if (data.start) + event.start = fromunixtime(data.start); + if (data.end) + event.end = fromunixtime(data.end); if (data.allday !== undefined) event.allDay = data.allday; event.editable = false; @@ -1534,7 +1536,7 @@ function rcube_calendar_ui(settings) $dialog.dialog({ modal: true, - width: 420, + width: 460, dialogClass: 'warning', title: rcmail.gettext((action == 'remove' ? 'removeeventconfirm' : 'changeeventconfirm'), 'calendar'), buttons: buttons, @@ -2347,24 +2349,42 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { rcmail.register_command('reset-search', function(){ cal.reset_quicksearch(); }, true); // register callback commands - rcmail.addEventListener('plugin.refresh_calendar', function(p){ - var source = cal.calendars[p.source]; - if (p.refetch && source) { - // activate event source if new event was added to an invisible calendar - if (!source.active) { - source.active = true; - $('#calendar').fullCalendar('addEventSource', source); - $('#' + rcmail.get_folder_li(source.id, 'rcmlical').id + ' input').prop('checked', true); - } - else - $('#calendar').fullCalendar('refetchEvents', source); - } - // remove temp events - $('#calendar').fullCalendar('removeEvents', function(e){ return e.temp; }); - }); rcmail.addEventListener('plugin.display_alarms', function(alarms){ cal.display_alarms(alarms); }); rcmail.addEventListener('plugin.destroy_source', function(p){ cal.calendar_destroy_source(p.id); }); rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.saving_lock); }); + rcmail.addEventListener('plugin.refresh_calendar', function(p){ + var fc = $('#calendar'); + var source = cal.calendars[p.source]; + + if (source && (p.refetch || (p.update && !source.active))) { + // activate event source if new event was added to an invisible calendar + if (!source.active) { + source.active = true; + fc.fullCalendar('addEventSource', source); + $('#' + rcmail.get_folder_li(source.id, 'rcmlical').id + ' input').prop('checked', true); + } + else + fc.fullCalendar('refetchEvents', source); + } + // add/update single event object + else if (source && p.update) { + var event = p.update; + event.temp = false; + event.editable = source.editable; + var existing = fc.fullCalendar('clientEvents', event.id); + if (existing.length) { + $.extend(existing[0], event); + fc.fullCalendar('updateEvent', existing[0]); + } + else { + event.source = source; // link with source + fc.fullCalendar('renderEvent', event); + } + } + + // remove temp events + fc.fullCalendar('removeEvents', function(e){ return e.temp; }); + }); // let's go var cal = new rcube_calendar_ui(rcmail.env.calendar_settings);