diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index 0941b8b32b..96e0940a51 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -673,10 +673,62 @@ class calendar_ui $sidebox->exec('calendar.calendar_ui.sidebox_etemplate', $content, $sel_options, $readonlys); } + /** + * Send updated event information to the client via ajax + * + * This allows to pass only changed information for a single (recurring) event + * and update the UI without a refreshing any more than needed. If adding, + * a notification via egw_framework::refresh_opener() is still needed but + * edits, updates and deletes will be automatic. + * If the event is recurring, we send the next month's worth of recurrences + * for lack of a better way to determine how much to send. + * + * @param int $event_id + * @param egw_time $recurrence_date + */ + public function update_client($event_id, egw_time $recurrence_date = null) + { + // Directly update stored data. + // Make sure we have the whole event + $event = $this->bo->read($event_id, $recurrence_date); + $response = egw_json_response::get(); + + if(!$event) + { + // Sending null will trigger a removal + $response->call('egw.dataStoreUID','calendar::'.$event_id,null); + return false; + } + + if(!$event['recur_type'] || $recurrence_date) + { + $this->to_client($event); + $response->call('egw.dataStoreUID','calendar::'.$event['row_id'],$event); + } + // If it's recurring, try to send the next month or so + else if($event['recur_type'] ) + { + $this_month = new egw_time('next month'); + $rrule = calendar_rrule::event2rrule($event, true); + $rrule->rewind(); + do + { + $occurrence = $rrule->current(); + $converted = $this->bo->read($event['id'], $occurrence); + $this->to_client($converted); + $response->call('egw.dataStoreUID','calendar::'.$converted['row_id'],$converted); + $rrule->next(); + } + while ($rrule->valid() && $occurrence <= $this_month ); + } + } + /** * Prepare an array of event information for sending to the client * - * This involves changing timestamps into strings with timezone + * This involves changing timestamps into strings with timezone so javascript + * does not change them, and making sure we have everything the client needs + * for proper display. * * @param type $event */ diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index 6b145468a7..084178a86e 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -1013,14 +1013,7 @@ class calendar_uiforms extends calendar_ui $response = egw_json_response::get(); if($response && !$content['id'] && $event['id']) { - // Directly update stored data. - // Make sure we have the whole event, not just form data - $event = $this->bo->read($event['id']); - - // Copy, so as to not change things for subsequent processing - $converted = $event; - $this->to_client($converted); - $response->call('egw.dataStoreUID','calendar::'.$converted['row_id'],$converted); + $this->update_client($event['id']); } if (in_array($button,array('cancel','save','delete','delete_exceptions','delete_keep_exceptions')) && $noerror) { @@ -2843,24 +2836,14 @@ class calendar_uiforms extends calendar_ui $message = false; $conflicts=$this->bo->update($event,false, true, false, true, $message); + $this->update_client($event['id'],$d); $response = egw_json_response::get(); if(!is_array($conflicts) && $conflicts) { if(is_int($conflicts)) { $event['id'] = $conflicts; - } - if(!$event['recur_type'] && !$old_event['recur_type']) - { - // Directly update stored data. If event is still visible, it will - // be notified & update itself. - $this->to_client($event); - error_log(__METHOD__ . ':' . __LINE__ . ' updated calendar::'.$converted['id']); - $response->call('egw.dataStoreUID','calendar::'.$event['id'].($date?':'.$date:''),$event); - } - else - { - $response->call('egw.refresh', '','calendar',$event['id'],'edit'); + $response->call('egw.refresh', '','calendar',$event['id'],'add'); } } else if ($conflicts) @@ -2879,6 +2862,7 @@ class calendar_uiforms extends calendar_ui { $response->call('egw.message', implode('
', $message)); } + if($event['id'] != $eventId ) $this->update_client($_eventId); if ($status_reset_to_unknown) { foreach((array)$event['participants'] as $uid => $status) @@ -2931,8 +2915,7 @@ class calendar_uiforms extends calendar_ui // Directly update stored data. If event is still visible, it will // be notified & update itself. - $this->to_client($event); - egw_json_response::get()->call('egw.dataStoreUID','calendar::'.$event['id'].($date?':'.$date:''),$event); + $this->update_client($_eventId); } /** @@ -2940,8 +2923,8 @@ class calendar_uiforms extends calendar_ui */ public function ajax_delete($eventId) { - list($eventId, $date) = explode(':',$eventId); - $event=$this->bo->read($eventId); + list($id, $date) = explode(':',$eventId); + $event=$this->bo->read($id); $response = egw_json_response::get(); if ($this->bo->delete($event['id'], (int)$date)) @@ -2958,7 +2941,7 @@ class calendar_uiforms extends calendar_ui } else { - $response->apply('egw.message', lang('Error'),'error'); + $response->apply('egw.message', Array(lang('Error')),'error'); } } diff --git a/calendar/js/app.js b/calendar/js/app.js index 30735490db..6aed323d95 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -274,14 +274,22 @@ app.classes.calendar = AppJS.extend( if(event && event.data && event.data.date || _type === 'delete') { // Intelligent refresh without reloading everything + var recurrences = Object.keys(egw.dataSearchUIDs(new RegExp('^calendar::'+_id+':'))) + var ids = event && event.data.recur_type && typeof _id === 'string' && _id.indexOf(':') < 0 || recurrences.length ? + recurrences : + ['calendar::'+_id]; + if(_type === 'delete') { - egw.dataStoreUID('calendar::'+_id, null); + for(var i in ids) + { + egw.dataStoreUID(ids[i], null); + } } // Updates are handled by events themselves through egw.data else if (_type !== 'update') { - this._update_events(this.state, ['calendar::'+_id]); + this._update_events(this.state, ids); } return false; } diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index 86f5fac0a3..fbe2d748d2 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -796,15 +796,15 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Get the top level element - timegrid or so var objectManager = this.getParent().getParent()._actionObject || egw_getAppObjectManager(true).getObjectById(this._parent._parent._parent.id) || egw_getAppObjectManager(true); - this._actionObject = objectManager.getObjectById('calendar::'+this.options.value.id); + this._actionObject = objectManager.getObjectById('calendar::'+this.options.value.row_id); } if (this._actionObject == null) { // Add a new container to the object manager which will hold the widget // objects this._actionObject = objectManager.insertObject(false, new egwActionObject( - 'calendar::'+this.options.value.id, objectManager, new et2_event_action_object_impl(this,this.getDOMNode()), - this._actionManager || objectManager.manager.getActionById(this.options.value.id) || objectManager.manager + 'calendar::'+this.options.value.row_id, objectManager, new et2_event_action_object_impl(this,this.getDOMNode()), + this._actionManager || objectManager.manager.getActionById(this.options.value.row_id) || objectManager.manager )); } else