From 86a0032cc1284321269e356d9c8b8f614b80a888 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Mon, 27 Jul 2015 16:02:05 -0400 Subject: [PATCH] Handle the edition of recurring event occurrences --- UI/Scheduler/English.lproj/Localizable.strings | 2 ++ UI/Scheduler/UIxAppointmentEditor.m | 12 +++++++++++- UI/Scheduler/UIxCalListingActions.m | 16 ++++++++++++---- UI/Scheduler/UIxComponentEditor.h | 1 + UI/Scheduler/UIxComponentEditor.m | 5 +++++ .../SchedulerUI/UIxAppointmentViewTemplate.wox | 14 ++++++++++---- .../js/Scheduler/Calendar.service.js | 4 ++-- .../js/Scheduler/Component.service.js | 17 +++++++++++++---- .../js/Scheduler/ComponentController.js | 11 ++++++++++- 9 files changed, 66 insertions(+), 16 deletions(-) diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index df66e1c78..4dd435c3e 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -521,6 +521,8 @@ vtodo_class2 = "(Confidential task)"; "editRepeatingItem" = "The item you are editing is a repeating item. Do you want to edit all occurences of it or only this single instance?"; "button_thisOccurrenceOnly" = "This occurence only"; "button_allOccurrences" = "All occurences"; +"Edit This Occurrence" = "Edit This Occurrence"; +"Edit All Occurrences" = "Edit All Occurrences"; /* Properties dialog */ "Name:" = "Name:"; diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index e2968a3df..7ed3a349a 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -551,6 +551,7 @@ * @apiSuccess {_} . _From [UIxAppointmentEditor viewAction]_ * * @apiSuccess (Success 200) {String} id Event ID + * @apiSuccess (Success 200) {String} [occurrenceId] Occurrence ID * @apiSuccess (Success 200) {String} pid Calendar ID (event's folder) * @apiSuccess (Success 200) {String} calendar Human readable name of calendar * @apiSuccess (Success 200) {String} startDate Start date (ISO8601) @@ -683,7 +684,6 @@ } data = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [co nameInContainer], @"id", [componentCalendar nameInContainer], @"pid", [componentCalendar displayName], @"calendar", [NSNumber numberWithBool: [self isReadOnly]], @"isReadOnly", @@ -692,6 +692,16 @@ [self alarm], @"alarm", nil]; + if ([self isChildOccurrence]) + { + [data setObject: [[co container] nameInContainer] forKey: @"id"]; + [data setObject: [co nameInContainer] forKey: @"occurrenceId"]; + } + else + { + [data setObject: [co nameInContainer] forKey: @"id"]; + } + attachUrls = [self attachUrls]; if ([attachUrls count]) [data setObject: attachUrls forKey: @"attachUrls"]; diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index 5d3e2aa04..34179ed6b 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -696,7 +696,7 @@ static NSArray *tasksFields = nil; * @apiSuccess (Success 200) {String} events.c_owner Event's owner * @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic * @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm - * @apiSuccess (Success 200) {String} events.c_recurrence_id Recurrence ID if event is cyclic + * @apiSuccess (Success 200) {String} [events.c_recurrence_id] Recurrence ID if event is cyclic * @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception * @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event * @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event @@ -723,6 +723,10 @@ static NSArray *tasksFields = nil; while ((oldEvent = [events nextObject])) { newEvent = [NSMutableArray arrayWithArray: oldEvent]; + if (![[oldEvent objectAtIndex: eventRecurrenceIdIndex] isKindOfClass: [NSNull class]]) + [newEvent replaceObjectAtIndex: eventRecurrenceIdIndex + withObject: [NSString stringWithFormat: @"occurence%@", + [oldEvent objectAtIndex: eventRecurrenceIdIndex]]]; isAllDay = [[oldEvent objectAtIndex: eventIsAllDayIndex] boolValue]; interval = [[oldEvent objectAtIndex: eventStartDateIndex] intValue]; [newEvent addObject: [self _formattedDateForSeconds: interval @@ -1213,7 +1217,7 @@ _computeBlocksPosition (NSArray *blocks) * @apiSuccess (Success 200) {String} events.c_owner Event's owner * @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic * @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm - * @apiSuccess (Success 200) {String} events.c_recurrence_id Recurrence ID if event is cyclic + * @apiSuccess (Success 200) {String} [events.c_recurrence_id] Recurrence ID if event is cyclic * @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception * @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event * @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event @@ -1383,7 +1387,7 @@ _computeBlocksPosition (NSArray *blocks) * @apiSuccess (Success 200) {Number} tasks.erasable 1 if task is erasable by the active user * @apiSuccess (Success 200) {String} tasks.c_priority Priority (0-9) * @apiSuccess (Success 200) {String} tasks.c_owner Username of owner - * @apiSuccess (Success 200) {String} tasks.c_recurrence_id Recurrence ID if task is cyclic + * @apiSuccess (Success 200) {String} [tasks.c_recurrence_id] Recurrence ID if task is cyclic * @apiSuccess (Success 200) {Number} tasks.isException 1 if task is cyclic and an exception * @apiSuccess (Success 200) {String} tasks.status Either completed, overdue, duetoday, or duelater * @apiSuccess (Success 200) {String} tasks.formatted_enddate Localized end date @@ -1422,10 +1426,14 @@ _computeBlocksPosition (NSArray *blocks) while ((task = [tasks nextObject])) { - statusCode = [[task objectAtIndex: 3] intValue]; + statusCode = [[task objectAtIndex: taskStatusIndex] intValue]; if (statusCode != 1 || showCompleted) { filteredTask = [NSMutableArray arrayWithArray: task]; + if (![[task objectAtIndex: taskRecurrenceIdIndex] isKindOfClass: [NSNull class]]) + [filteredTask replaceObjectAtIndex: taskRecurrenceIdIndex + withObject: [NSString stringWithFormat: @"occurence%@", + [task objectAtIndex: taskRecurrenceIdIndex]]]; endDateStamp = [[task objectAtIndex: taskEndDateIndex] intValue]; statusFlag = [self _getStatusClassForStatusCode: statusCode andEndDateStamp: endDateStamp]; diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index 4d8d75ab5..238afebca 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -34,6 +34,7 @@ } - (BOOL) isReadOnly; +- (BOOL) isChildOccurrence; - (void) setAttributes: (NSDictionary *) attributes; - (NSDictionary *) alarm; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index f8207f045..e1eb457a1 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -158,6 +158,11 @@ static NSArray *reminderValues = nil; [componentCalendar retain]; } +- (BOOL) isChildOccurrence +{ + return [[self clientObject] isKindOfClass: [SOGoComponentOccurence class]]; +} + //- (NSString *) title //{ // SOGoCalendarComponent *co; diff --git a/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox b/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox index eae9c5eb0..b4bdd2eaf 100644 --- a/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox +++ b/UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox @@ -110,12 +110,18 @@ - -
- + +
+ -
+ + + + + + +
diff --git a/UI/WebServerResources/js/Scheduler/Calendar.service.js b/UI/WebServerResources/js/Scheduler/Calendar.service.js index 0f521318a..d993e69f2 100644 --- a/UI/WebServerResources/js/Scheduler/Calendar.service.js +++ b/UI/WebServerResources/js/Scheduler/Calendar.service.js @@ -274,8 +274,8 @@ * @desc Fetch a component attributes from the server. * @returns a promise of the HTTP operation */ - Calendar.prototype.$getComponent = function(componentId) { - return Calendar.$Component.$find(this.id, componentId); + Calendar.prototype.$getComponent = function(componentId, recurrenceId) { + return Calendar.$Component.$find(this.id, componentId, recurrenceId); }; /** diff --git a/UI/WebServerResources/js/Scheduler/Component.service.js b/UI/WebServerResources/js/Scheduler/Component.service.js index 17690510d..71bfe6ecd 100644 --- a/UI/WebServerResources/js/Scheduler/Component.service.js +++ b/UI/WebServerResources/js/Scheduler/Component.service.js @@ -124,10 +124,16 @@ * @desc Fetch a component from a specific calendar. * @param {string} calendarId - the calendar ID * @param {string} componentId - the component ID + * @param {string} [occurrenceId] - the component ID * @see {@link Calendar.$getComponent} */ - Component.$find = function(calendarId, componentId) { - var futureComponentData = this.$$resource.fetch([calendarId, componentId].join('/'), 'view'); + Component.$find = function(calendarId, componentId, occurrenceId) { + var futureComponentData, path = [calendarId, componentId]; + + if (occurrenceId) + path.push(occurrenceId); + + futureComponentData = this.$$resource.fetch(path.join('/'), 'view'); return new Component(futureComponentData); }; @@ -608,12 +614,15 @@ * @desc Save the component to the server. */ Component.prototype.$save = function() { - var _this = this, options; + var _this = this, options, path = [this.pid, this.id]; if (this.isNew) options = { action: 'saveAs' + this.type.capitalize() }; - return Component.$$resource.save([this.pid, this.id].join('/'), this.$omit(), options) + if (this.occurrenceId) + path.push(this.occurrenceId); + + return Component.$$resource.save(path.join('/'), this.$omit(), options) .then(function(data) { // Make a copy of the data for an eventual reset _this.$shadowData = _this.$omit(true); diff --git a/UI/WebServerResources/js/Scheduler/ComponentController.js b/UI/WebServerResources/js/Scheduler/ComponentController.js index 7a9837cf5..a508b000a 100644 --- a/UI/WebServerResources/js/Scheduler/ComponentController.js +++ b/UI/WebServerResources/js/Scheduler/ComponentController.js @@ -13,10 +13,11 @@ vm.component = stateComponent; vm.close = close; vm.edit = edit; + vm.editAllOccurrences = editAllOccurrences; // Load all attributes of component if (angular.isUndefined(vm.component.$futureComponentData)) { - component = Calendar.$get(vm.component.c_folder).$getComponent(vm.component.c_name); + component = Calendar.$get(vm.component.c_folder).$getComponent(vm.component.c_name, vm.component.c_recurrence_id); component.$futureComponentData.then(function() { vm.component = component; }); @@ -26,6 +27,14 @@ $mdDialog.hide(); } + function editAllOccurrences() { + component = Calendar.$get(vm.component.pid).$getComponent(vm.component.id); + component.$futureComponentData.then(function() { + vm.component = component; + edit(); + }); + } + function edit() { var type = (vm.component.component == 'vevent')? 'Appointment':'Task'; $mdDialog.hide().then(function() {