diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index 5446573d60..d455e58bfa 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -642,16 +642,20 @@ class calendar_ui * * @param int $event_id * @param Api\DateTime $recurrence_date + * @param array $old_event * * @return boolean True if the event was updated, false if it could not be - * updated or was removed. + * updated or was removed. */ - public function update_client($event_id, Api\DateTime $recurrence_date = null) + public function update_client($event_id, Api\DateTime $recurrence_date = null, array $old_event = array()) { - if(!$event_id) return false; - if(is_string($event_id) && strpos($event_id,':') !== FALSE) + if(!$event_id) { - list($event_id, $date) = explode(':',$event_id); + return false; + } + if(is_string($event_id) && strpos($event_id, ':') !== FALSE) + { + list($event_id, $date) = explode(':', $event_id); $recurrence_date = new Api\DateTime($date); } @@ -698,6 +702,21 @@ class calendar_ui else if($event['recur_type'] ) { $this_month = new Api\DateTime('next month'); + $data = []; + if($old_event && ($old_event['start'] != $event['start'] || $old_event['recur_enddate'] != $event['recur_enddate'])) + { + // Set up to clear old events in case recurrence start/end date changed + $old_rrule = calendar_rrule::event2rrule($old_event, true); + + $old_rrule->rewind(); + do + { + $occurrence = $old_rrule->current(); + $data['calendar::' . $old_event['id'] . ':' . $occurrence->format('ts')] = null; + $old_rrule->next(); + } + while($old_rrule->valid() && $occurrence <= $this_month); + } $rrule = calendar_rrule::event2rrule($event, true); $rrule->rewind(); do @@ -705,10 +724,17 @@ class calendar_ui $occurrence = $rrule->current(); $converted = $this->bo->read($event['id'], $occurrence); $this->to_client($converted); - $response->generic('data', array('uid' => 'calendar::'.$converted['row_id'], 'data' => $converted)); + $data['calendar::' . $converted['row_id']] = $converted; $rrule->next(); } - while ($rrule->valid() && $occurrence <= $this_month ); + while($rrule->valid() && $occurrence <= $this_month); + + // Now we have to go through and send each one individually, since client side data can't handle more than one + foreach($data as $uid => $cal_data) + { + $response->apply('egw.dataStoreUID', [$uid, $cal_data]); + } + $response->apply('app.calendar.update_events', [array_keys($data)]); } return true; } diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index a71a56af23..015c5be07a 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -1007,7 +1007,7 @@ class calendar_uiforms extends calendar_ui $response = Api\Json\Response::get(); if($response && $update_type != 'delete' && !$client_updated) { - $client_updated = $this->update_client($event['id']); + $client_updated = $this->update_client($event['id'], null, $old_event); } $msg = $message . ($msg ? ', ' . $msg : ''); diff --git a/calendar/js/app.ts b/calendar/js/app.ts index 1892521640..38181192d5 100644 --- a/calendar/js/app.ts +++ b/calendar/js/app.ts @@ -651,22 +651,34 @@ export class CalendarApp extends EgwApp } // Do we already have "fresh" data? Most user actions give fresh data in response - let existing = egw.dataGetUIDdata('calendar::'+pushData.id); + let existing = egw.dataGetUIDdata('calendar::' + pushData.id); if(existing && Math.abs(existing.timestamp - new Date().valueOf()) < 1000) { // Update directly - this._update_events(this.state, ['calendar::'+pushData.id]); + this._update_events(this.state, ['calendar::' + pushData.id]); return; - }; + } + ; // Ask for the real data, we don't have it - egw.request("calendar.calendar_ui.ajax_get", [[pushData.id]]).then((data) => + let process_data = (data) => { // Store it, which will call all registered listeners egw.dataStoreUID(data.uid, data.data); // Any existing events were updated. Run this to catch new events or events moved into view this._update_events(this.state, [data.uid]); + } + egw.request("calendar.calendar_ui.ajax_get", [[pushData.id]]).then((data) => + { + if(typeof data.uid !== "undefined") + { + return process_data(data) + } + for(let e of data) + { + process_data(e); + } }); } @@ -3736,13 +3748,22 @@ export class CalendarApp extends EgwApp else if(typeof framework !== 'undefined') { framework.applications.calendar.sidemenuEntry.hideAjaxLoader(); - egw.loading_prompt('calendar',false) + egw.loading_prompt('calendar', false) } - }, this,null + }, this, null ); } + /** + * We have a list of calendar UIDs of events that need updating. + * Public wrapper for _update_events so we can call it from server + */ + update_events(uids : string[]) + { + return this._update_events(this.state, uids); + } + /** * We have a list of calendar UIDs of events that need updating. *