Fix support for recurrent tasks (cont'd)

Fixes #3864
pull/225/head
Francis Lachapelle 2016-11-01 14:52:18 -04:00
parent 188dd986d2
commit 1ee7693432
6 changed files with 78 additions and 10 deletions

3
NEWS
View File

@ -18,7 +18,8 @@ Bug fixes
- [web] fixed vCard generation for tags with no type (#3826)
- [web] only show the organizer field of an IMIP REPLY if one is defined
- [web] fixed saving the note of a card (#3849)
- [web] fixed support for recurrent tasks
- [web] fixed support for recurrent tasks (#3864)
- [web] restored support for alarms in tasks
- [web] improved validation of mail account delegators
- [web] fixed auto-completion of list members (#3870)
- [web] added missing options to subscribed addressbooks (#3850)

View File

@ -1007,13 +1007,13 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
master = [[[component parent] events] objectAtIndex: 0];
masterEndDate = [master endDate];
endDate = [component endDate];
endDate = [(iCalEvent*) component endDate];
}
else
{
master = [[[component parent] todos] objectAtIndex: 0];
masterEndDate = [master due];
endDate = [component due];
endDate = [(iCalToDo*) component due];
}
delta = [masterEndDate timeIntervalSinceDate: [master startDate]];
@ -1027,7 +1027,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
if (recordIndex > -1)
{
if ([dateRange containsDate: [component startDate]] ||
[dateRange containsDate: endDate])
(endDate && [dateRange containsDate: endDate]))
{
// We must pass nil to :container here in order to avoid re-entrancy issues.
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil]];

View File

@ -1,6 +1,6 @@
/* iCalToDot+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2008-2014 Inverse inc.
* Copyright (C) 2008-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -32,6 +32,7 @@
#import <SoObjects/SOGo/WOContext+SOGo.h>
#import <SOGo/CardElement+SOGo.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@ -367,7 +368,11 @@
- (NSTimeInterval) occurenceInterval
{
return [[self due] timeIntervalSinceDate: [self startDate]];
if ([self due])
return [[self due] timeIntervalSinceDate: [self startDate]];
else
// When no due date is defined, base recurrence calculation on a 60-minute duration
return 3600;
}
@end

View File

@ -661,7 +661,7 @@
</div>
<div class="sg-tile-icons">
<md-icon ng-show="::task.c_iscycle">repeat</md-icon>
<md-icon ng-show="::event.c_nextalarm">alarm</md-icon>
<md-icon ng-show="::task.c_nextalarm">alarm</md-icon>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>

View File

@ -181,7 +181,69 @@
<div flex="50" class="sg-padded--left">{{editor.component.percentComplete}} <var:string label:value="% complete"/></div>
</div>
</div>
<!-- repeat -->
<div class="sg-form-section"
ng-show="editor.component.start">
<div layout="row" layout-align="start center">
<md-input-container class="md-block md-flex">
<label><var:string label:value="Repeat"/></label>
<md-select ng-model="editor.component.repeat.frequency" ng-disabled="editor.component.occurrenceId">
<var:foreach list="repeatList" item="item">
<md-option var:value="item"><var:string var:value="itemRepeatText"/></md-option>
</var:foreach>
</md-select>
</md-input-container>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-disabled="editor.component.occurrenceId"
ng-show="editor.component.repeat.frequency != 'never'"
ng-click="editor.toggleRecurrenceEditor()">
<md-icon ng-class="{'md-rotate-45': editor.showRecurrenceEditor}">add</md-icon>
</md-button>
</div>
<div ng-show="editor.showRecurrenceEditor" flex-offset="5">
<var:component className="UIxRecurrenceEditor" />
</div>
<!-- end repeat -->
<div layout="row">
<md-input-container class="md-block" flex="50" flex-xs="100"
ng-show="editor.component.repeat.frequency != 'never'">
<label><var:string label:value="End Repeat"/></label>
<md-select ng-model="editor.component.repeat.end"
ng-disabled="editor.component.occurrenceId">
<md-option value="never"><var:string label:value="Never"/></md-option>
<md-option value="count"><var:string label:value="After"/></md-option>
<md-option value="until"><var:string label:value="On Date"/></md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block md-input-number"
ng-show="editor.component.repeat.end == 'count'">
<label><var:string label:value="times"/></label>
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<md-datepicker name="repeat_until"
ng-model="editor.component.repeat.until"
md-min-date="editor.component.end"
label:md-placeholder="On Date"><!-- date picker --></md-datepicker>
<div ng-messages="eventForm.repeat_until.$error">
<div ng-message="mindate"><var:string label:value="validate_untilbeforeend"/></div>
</div>
</md-input-container>
</div>
</div>
<div class="sg-form-section"
ng-show="editor.component.start">
<!-- reminder -->
<md-checkbox ng-model="editor.component.$hasAlarm"
label:aria-label="Reminder">
<var:string label:value="Reminder"/>
</md-checkbox>
<div flex-offset="5"
ng-show="editor.component.$hasAlarm">
<var:component className="UIxReminderEditor" />
</div>
</div>
</md-dialog-content>
<!-- cancel/reset/save -->
<md-dialog-actions>

View File

@ -1129,7 +1129,7 @@
else if (this.repeat.frequency && this.repeat.frequency != 'never') {
component.repeat = { frequency: this.repeat.frequency };
}
if (this.repeat.frequency) {
if (component.startDate && this.repeat.frequency) {
if (this.repeat.end == 'until' && this.repeat.until)
component.repeat.until = this.repeat.until.stringWithSeparator('-');
else if (this.repeat.end == 'count' && this.repeat.count)
@ -1150,7 +1150,7 @@
delete component.completedDate;
// Verify alarm
if (this.$hasAlarm) {
if (component.startDate && this.$hasAlarm) {
if (this.alarm.action && this.alarm.action == 'email' &&
!(this.attendees && this.attendees.length > 0)) {
// No attendees; email reminder must be sent to organizer only