See ChangeLog
Monotone-Parent: c4a5b31204ccd4c09e85262d9b5609b788a8380a Monotone-Revision: 9057f51730136ddbcf1d8e64c8029ea9a4e6c991 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2009-04-22T21:02:11 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
143c91bc2d
commit
6e5d968de3
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
2009-04-22 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/Scheduler/UIxCalListingActions.m ([UIxCalListingActions
|
||||
-alarmsListAction]): only return the alarms active for the next 48
|
||||
hours and exclude any recurring event (for now).
|
||||
|
||||
* UI/Scheduler/UIxAppointmentEditor.m ([UIxAppointmentEditor
|
||||
-viewAction]): if the form parameter "resetAlarm" is true, set the
|
||||
property X-WebStatus to "triggered" in the event's alarm.
|
||||
|
||||
* UI/Scheduler/UIxTaskEditor.m ([UIxTaskEditor -viewAction]): new
|
||||
method that returns some of the task properties. Currently only
|
||||
used for the alarms. Behavior is similar to UIxAppointmentEditor.
|
||||
|
||||
* SoObjects/Appointments/iCalEvent+SOGo.m ([iCalEvent
|
||||
-quickRecord]): don't update the c_nextalarm field if the event is
|
||||
recurrent or if the property X-WebStatus is set to "triggered" in
|
||||
the alarm's trigger definition.
|
||||
|
||||
* SoObjects/Appointments/iCalToDo+SOGo.m ([iCalToDo
|
||||
-quickRecord]): idem.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
([SOGoAppointmentFolder -fetchAlarmInfosFrom:to:]): new method
|
||||
that returns attributes of events and todos for which there's an
|
||||
active alarm within the next 48 hours.
|
||||
|
||||
2009-04-21 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
|
||||
* Added Welsh translation - patches from the
|
||||
|
|
|
@ -96,6 +96,9 @@
|
|||
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate
|
||||
to: (NSCalendarDate *) _endDate;
|
||||
|
||||
- (NSArray *) fetchAlarmInfosFrom: (NSNumber *) _startUTCDate
|
||||
to: (NSNumber *) _endUTCDate;
|
||||
|
||||
/* URL generation */
|
||||
|
||||
- (NSString *) baseURLForAptWithUID: (NSString *) _uid
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2007-2008 Inverse inc.
|
||||
Copyright (C) 2007-2009 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
@ -2290,6 +2290,34 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
includeProtectedInformation: NO];
|
||||
}
|
||||
|
||||
- (NSArray *) fetchAlarmInfosFrom: (NSNumber *) _startUTCDate
|
||||
to: (NSNumber *) _endUTCDate
|
||||
{
|
||||
static NSArray *nameFields = nil;
|
||||
EOQualifier *qualifier;
|
||||
GCSFolder *folder;
|
||||
NSArray *records;
|
||||
NSString *sql;
|
||||
|
||||
if (!nameFields)
|
||||
nameFields = [[NSArray alloc] initWithObjects: @"c_name", @"c_nextalarm", @"c_iscycle", nil];
|
||||
|
||||
folder = [self ocsFolder];
|
||||
if (!folder)
|
||||
{
|
||||
[self errorWithFormat:@"(%s): missing folder for fetch!",
|
||||
__PRETTY_FUNCTION__];
|
||||
return nil;
|
||||
}
|
||||
|
||||
sql = [NSString stringWithFormat: @"((c_nextalarm <= %u) AND (c_nextalarm >= %u)) OR ((c_nextalarm > 0) AND (c_enddate > %u))",
|
||||
[_endUTCDate unsignedIntValue], [_startUTCDate unsignedIntValue], [_startUTCDate unsignedIntValue]];
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat: sql];
|
||||
records = [folder fetchFields: nameFields matchingQualifier: qualifier];
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/* URL generation */
|
||||
|
||||
- (NSString *) baseURLForAptWithUID: (NSString *)_uid
|
||||
|
|
|
@ -206,14 +206,18 @@
|
|||
if ([self hasAlarms])
|
||||
{
|
||||
// We currently have the following limitations for alarms:
|
||||
// - the event must not be recurrent;
|
||||
// - only the first alarm is considered;
|
||||
// - the alarm's action must be of type DISPLAY;
|
||||
// - the alarm's trigger value type must be DURATION.
|
||||
// - the alarm's trigger value type must be DURATION;
|
||||
//
|
||||
// Morever, we don't update the quick table if the property X-WebStatus
|
||||
// of the trigger is set to "triggered".
|
||||
|
||||
iCalAlarm *anAlarm;
|
||||
iCalTrigger *aTrigger;
|
||||
NSCalendarDate *relationDate;
|
||||
NSString *relation;
|
||||
NSString *relation, *webstatus;
|
||||
NSTimeInterval anInterval;
|
||||
|
||||
anAlarm = [[self alarms] objectAtIndex: 0];
|
||||
|
@ -222,45 +226,22 @@
|
|||
anInterval = [[aTrigger value] durationAsTimeInterval];
|
||||
|
||||
if ([[anAlarm action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame &&
|
||||
[[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
|
||||
[[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame &&
|
||||
![self isRecurrent])
|
||||
{
|
||||
if ([self isRecurrent])
|
||||
webstatus = [aTrigger value: 0 ofAttribute: @"x-webstatus"];
|
||||
if (!webstatus ||
|
||||
[webstatus caseInsensitiveCompare: @"TRIGGERED"] != NSOrderedSame)
|
||||
{
|
||||
if ([self isStillRelevant])
|
||||
{
|
||||
NSArray *occurrences;
|
||||
NSCalendarDate *now, *later;
|
||||
NGCalendarDateRange *range;
|
||||
|
||||
// We only compute the next occurrence of the repeating event
|
||||
// for the next 48 hours
|
||||
now = [NSCalendarDate calendarDate];
|
||||
later = [now addTimeInterval: (60*60*48)];
|
||||
range = [NGCalendarDateRange calendarDateRangeWithStartDate: now
|
||||
endDate: later];
|
||||
occurrences = [self recurrenceRangesWithinCalendarDateRange: range];
|
||||
if ([occurrences count] > 0)
|
||||
{
|
||||
range = [occurrences objectAtIndex: 0];
|
||||
if ([relation caseInsensitiveCompare: @"END"] == NSOrderedSame)
|
||||
relationDate = [range endDate];
|
||||
else
|
||||
relationDate = [range startDate];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Event is not reccurent
|
||||
if ([relation caseInsensitiveCompare: @"END"] == NSOrderedSame)
|
||||
relationDate = endDate;
|
||||
else
|
||||
relationDate = startDate;
|
||||
|
||||
// Compute the next alarm date with respect to the reference date
|
||||
if ([relationDate isNotNull])
|
||||
nextAlarmDate = [relationDate addTimeInterval: anInterval];
|
||||
}
|
||||
|
||||
// Compute the next alarm date with respect to the reference date
|
||||
if ([relationDate isNotNull])
|
||||
nextAlarmDate = [relationDate addTimeInterval: anInterval];
|
||||
}
|
||||
}
|
||||
if ([nextAlarmDate isNotNull])
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
|
@ -41,7 +44,7 @@
|
|||
- (NSMutableDictionary *) quickRecord
|
||||
{
|
||||
NSMutableDictionary *row;
|
||||
NSCalendarDate *startDate, *dueDate;
|
||||
NSCalendarDate *startDate, *dueDate, *nextAlarmDate;
|
||||
NSArray *attendees;
|
||||
NSString *uid, *title, *location, *status;
|
||||
NSNumber *sequence;
|
||||
|
@ -55,6 +58,7 @@
|
|||
|
||||
startDate = [self startDate];
|
||||
dueDate = [self due];
|
||||
nextAlarmDate = nil;
|
||||
uid = [self uid];
|
||||
title = [self summary];
|
||||
if (![title isNotNull])
|
||||
|
@ -167,6 +171,46 @@
|
|||
[row setObject:partstates forKey: @"c_partstates"];
|
||||
[partstates release];
|
||||
|
||||
if ([self hasAlarms])
|
||||
{
|
||||
// We currently have the following limitations for alarms:
|
||||
// - the component must not be recurrent;
|
||||
// - only the first alarm is considered;
|
||||
// - the alarm's action must be of type DISPLAY;
|
||||
// - the alarm's trigger value type must be DURATION;
|
||||
//
|
||||
// Morever, we don't update the quick table if the property X-WebStatus
|
||||
// of the trigger is set to "triggered".
|
||||
|
||||
iCalAlarm *anAlarm;
|
||||
iCalTrigger *aTrigger;
|
||||
NSString *webstatus;
|
||||
NSTimeInterval anInterval;
|
||||
|
||||
anAlarm = [[self alarms] objectAtIndex: 0];
|
||||
aTrigger = [anAlarm trigger];
|
||||
anInterval = [[aTrigger value] durationAsTimeInterval];
|
||||
|
||||
if ([[anAlarm action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame &&
|
||||
[[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame &&
|
||||
![self isRecurrent])
|
||||
{
|
||||
webstatus = [aTrigger value: 0 ofAttribute: @"x-webstatus"];
|
||||
if (!webstatus ||
|
||||
[webstatus caseInsensitiveCompare: @"TRIGGERED"] != NSOrderedSame)
|
||||
{
|
||||
// Compute the next alarm date with respect to the due date
|
||||
if ([dueDate isNotNull])
|
||||
nextAlarmDate = [dueDate addTimeInterval: anInterval];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([nextAlarmDate isNotNull])
|
||||
[row setObject: [NSNumber numberWithInt: [nextAlarmDate timeIntervalSince1970]]
|
||||
forKey: @"c_nextalarm"];
|
||||
else
|
||||
[row setObject: [NSNumber numberWithInt: 0] forKey: @"c_nextalarm"];
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,3 +41,9 @@
|
|||
|
||||
"You are not allowed to access this module or this system. Please contact your system administrator." = "U hebt geen toegang tot deze module of dit systeem. Neem contact op met uw systeem beheerder.";
|
||||
"You don't have the required privileges to perform the operation." = "Voor deze actie heeft u niet de benodigde rechten.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Alarm:";
|
||||
"Start:" = "Begin:";
|
||||
"Due Date:" = "Verloopdatum:";
|
||||
"Location:" = "Plaats:";
|
||||
|
|
|
@ -46,3 +46,9 @@
|
|||
= "You are not allowed to access this module or this system. Please contact your system administrator.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "You don't have the required privileges to perform the operation.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Reminder:";
|
||||
"Start:" = "Start:";
|
||||
"Due Date:" = "Due Date:";
|
||||
"Location:" = "Location:";
|
|
@ -43,3 +43,9 @@
|
|||
= "Vous n'êtes pas autorisé à accéder à ce module ou ce système. Veuillez contacter votre administrateur système.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "Vous n'avez pas les privilèges requis pour compléter l'opération.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Rappel :";
|
||||
"Start:" = "Début :";
|
||||
"Due Date:" = "Échéance :";
|
||||
"Location:" = "Lieu :";
|
||||
|
|
|
@ -46,3 +46,9 @@
|
|||
= "You are not allowed to access this module or this system. Please contact your system administrator.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "Sie haben nicht die benötigte Berechtigung für diesen Befehl.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Alarm:";
|
||||
"Start:" = "Beginn:";
|
||||
"Due Date:" = "Fällig:";
|
||||
"Location:" = "Ort:";
|
||||
|
|
|
@ -40,3 +40,9 @@
|
|||
= "Non sei abilitato ad accedere a questo modulo. Contatta il tuo amministratore di sistema.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "Non disponi dei privilegi richiesti per eseguire questa operazione.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Promemoria:";
|
||||
"Start:" = "Inizio:";
|
||||
"Due Date:" = "Scadenza:";
|
||||
"Location:" = "Luogo:";
|
||||
|
|
|
@ -50,3 +50,9 @@
|
|||
= "You are not allowed to access this module or this system. Please contact your system administrator.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "You don't have the required privileges to perform the operation.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Recordatorio:";
|
||||
"Start:" = "Desde:";
|
||||
"Due Date:" = "Vencimiento:";
|
||||
"Location:" = "Lugar:";
|
|
@ -46,3 +46,9 @@
|
|||
= "Nid oes gennych caniatad mynediad i'r modiwl hwn na'r system hwn. Cysylltwch a'r Gweinyddwr Systemau os gwelwch yn dda.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "Nid oes gennych y breintiau gofynnol i berfformio'r gweithrediad.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Atgoffa:";
|
||||
"Start:" = "Dechrau:";
|
||||
"Due Date:" = "Dyddiad dyledus:";
|
||||
"Location:" = "Lleoliad:";
|
|
@ -34,9 +34,11 @@
|
|||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
|
||||
|
@ -394,6 +396,7 @@
|
|||
SOGoUser *user;
|
||||
SOGoCalendarComponent *co;
|
||||
iCalEvent *master;
|
||||
BOOL resetAlarm;
|
||||
signed int daylightOffset;
|
||||
|
||||
[self event];
|
||||
|
@ -406,6 +409,19 @@
|
|||
[eventDate setTimeZone: timeZone];
|
||||
co = [self clientObject];
|
||||
|
||||
resetAlarm = [[[context request] formValueForKey: @"resetAlarm"] boolValue];
|
||||
if (resetAlarm && [event hasAlarms] && ![event hasRecurrenceRules])
|
||||
{
|
||||
iCalAlarm *anAlarm;
|
||||
iCalTrigger *aTrigger;
|
||||
|
||||
anAlarm = [[event alarms] objectAtIndex: 0];
|
||||
aTrigger = [anAlarm trigger];
|
||||
[aTrigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
|
||||
|
||||
[co saveComponent: event];
|
||||
}
|
||||
|
||||
if ([co isNew] && [co isKindOfClass: [SOGoAppointmentOccurence class]])
|
||||
{
|
||||
// This is a new exception in a recurrent event -- compute the daylight
|
||||
|
@ -421,6 +437,7 @@
|
|||
}
|
||||
}
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[event tag], @"component",
|
||||
[dateFormatter formattedDate: eventDate], @"startDate",
|
||||
[dateFormatter formattedTime: eventDate], @"startTime",
|
||||
([event hasRecurrenceRules]? @"1": @"0"), @"isReccurent",
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#import <SoObjects/SOGo/NSObject+Utilities.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
|
||||
|
||||
#import <UI/Common/WODirectAction+SOGo.h>
|
||||
|
||||
|
@ -367,7 +368,7 @@ static NSArray *tasksFields = nil;
|
|||
//
|
||||
// We return:
|
||||
//
|
||||
// {complete Event ID (full path) => Fire date (UTC)}
|
||||
// [[calendar name (full path), complete Event ID (full path), Fire date (UTC)], ..]
|
||||
//
|
||||
// Called when each module is loaded or whenever a calendar component is created, modified, deleted
|
||||
// or whenever there's a {un}subscribe to a calendar.
|
||||
|
@ -375,11 +376,9 @@ static NSArray *tasksFields = nil;
|
|||
// Workflow :
|
||||
//
|
||||
// - for ALL subscribed and ACTIVE calendars
|
||||
// - returns alarms for which the (event end date > browserTime) OR (browserTime < c_nextalarm)
|
||||
// - if it's a recurring event and that condition isn't met
|
||||
// - set date range from X (now) until Y (now+2 days)
|
||||
// - compute the c_nextalarm and if it is met, store it in c_nextalarm
|
||||
//
|
||||
// - returns alarms that will occur in the next 48 hours or the non-triggered alarms
|
||||
// for non-completed events
|
||||
// - recurring events are currently ignored
|
||||
//
|
||||
- (WOResponse *) alarmsListAction
|
||||
{
|
||||
|
@ -388,9 +387,11 @@ static NSArray *tasksFields = nil;
|
|||
NSMutableArray *allAlarms;
|
||||
NSEnumerator *folders;
|
||||
WOResponse *response;
|
||||
int browserTime;
|
||||
unsigned int browserTime, laterTime;
|
||||
|
||||
// We look for alarms in the next 48 hours
|
||||
browserTime = [[[context request] formValueForKey: @"browserTime"] intValue];
|
||||
laterTime = browserTime + 60*60*48;
|
||||
clientObject = [self clientObject];
|
||||
allAlarms = [NSMutableArray array];
|
||||
|
||||
|
@ -399,34 +400,32 @@ static NSArray *tasksFields = nil;
|
|||
{
|
||||
if ([currentFolder isActive])
|
||||
{
|
||||
NSDictionary *entry;;
|
||||
NSDictionary *entry;
|
||||
NSArray *alarms;
|
||||
int i, v;
|
||||
BOOL isCycle;
|
||||
int i;
|
||||
|
||||
// Let's compute everything +2 days in case we hit recurring components
|
||||
alarms = [currentFolder fetchFields: [NSArray arrayWithObjects: @"c_nextalarm", @"c_iscycle", nil]
|
||||
from: [NSCalendarDate date]
|
||||
to: [[NSCalendarDate date] dateByAddingYears: 0 months: 0 days: 2 hours: 0 minutes: 0 seconds: 0]
|
||||
title: nil
|
||||
component: nil
|
||||
additionalFilters: nil
|
||||
includeProtectedInformation: NO];
|
||||
alarms = [currentFolder fetchAlarmInfosFrom: [NSNumber numberWithInt: browserTime]
|
||||
to: [NSNumber numberWithInt: laterTime]];
|
||||
|
||||
for (i = 0; i < [alarms count]; i++)
|
||||
{
|
||||
entry = [alarms objectAtIndex: i];
|
||||
v = [[entry objectForKey: @"c_nextalarm"] intValue];
|
||||
|
||||
if (([[entry objectForKey: @"c_enddate"] intValue] > browserTime) ||
|
||||
browserTime < v)
|
||||
isCycle = [[entry objectForKey: @"c_iscycle"] boolValue];
|
||||
|
||||
if (!isCycle)
|
||||
{
|
||||
[allAlarms addObject: [NSDictionary dictionaryWithObject: [entry objectForKey: @"c_nextalarm"]
|
||||
forKey: [entry objectForKey: @"c_name"]]];
|
||||
[allAlarms addObject: [NSArray arrayWithObjects:
|
||||
[currentFolder nameInContainer],
|
||||
[entry objectForKey: @"c_name"],
|
||||
[entry objectForKey: @"c_nextalarm"],
|
||||
nil]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
response = [self responseWithStatus: 200];
|
||||
[response appendContentString: [allAlarms jsonRepresentation]];
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
#import <NGObjWeb/SoObject.h>
|
||||
#import <NGObjWeb/SoPermissions.h>
|
||||
#import <NGObjWeb/SoSecurityManager.h>
|
||||
|
@ -28,12 +30,16 @@
|
|||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
||||
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
|
||||
#import <SoObjects/SOGo/SOGoUser.h>
|
||||
#import <SoObjects/SOGo/SOGoContentObject.h>
|
||||
#import <SoObjects/SOGo/SOGoDateFormatter.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
|
||||
#import <SoObjects/Appointments/SOGoTaskObject.h>
|
||||
|
||||
|
@ -377,6 +383,59 @@
|
|||
// return [self jsCloseWithRefreshMethod: @"refreshTasks()"];
|
||||
// }
|
||||
|
||||
- (id <WOActionResults>) viewAction
|
||||
{
|
||||
WOResponse *result;
|
||||
NSDictionary *data;
|
||||
NSCalendarDate *startDate, *dueDate;
|
||||
NSTimeZone *timeZone;
|
||||
SOGoDateFormatter *dateFormatter;
|
||||
SOGoUser *user;
|
||||
BOOL resetAlarm;
|
||||
|
||||
[self todo];
|
||||
|
||||
result = [self responseWithStatus: 200];
|
||||
user = [context activeUser];
|
||||
timeZone = [user timeZone];
|
||||
dateFormatter = [user dateFormatterInContext: context];
|
||||
startDate = [todo startDate];
|
||||
[startDate setTimeZone: timeZone];
|
||||
dueDate = [todo due];
|
||||
[dueDate setTimeZone: timeZone];
|
||||
|
||||
resetAlarm = [[[context request] formValueForKey: @"resetAlarm"] boolValue];
|
||||
if (resetAlarm && [todo hasAlarms] && ![todo hasRecurrenceRules])
|
||||
{
|
||||
iCalAlarm *anAlarm;
|
||||
iCalTrigger *aTrigger;
|
||||
SOGoCalendarComponent *co;
|
||||
|
||||
anAlarm = [[todo alarms] objectAtIndex: 0];
|
||||
aTrigger = [anAlarm trigger];
|
||||
[aTrigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
|
||||
|
||||
co = [self clientObject];
|
||||
[co saveComponent: todo];
|
||||
}
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[todo tag], @"component",
|
||||
(startDate? [dateFormatter formattedDate: startDate] : @""), @"startDate",
|
||||
(startDate? [dateFormatter formattedTime: startDate] : @""), @"startTime",
|
||||
(dueDate? [dateFormatter formattedDate: dueDate] : @""), @"dueDate",
|
||||
(dueDate? [dateFormatter formattedTime: dueDate] : @""), @"dueTime",
|
||||
([todo hasRecurrenceRules]? @"1": @"0"), @"isReccurent",
|
||||
[todo summary], @"summary",
|
||||
[todo location], @"location",
|
||||
[todo comment], @"description",
|
||||
nil];
|
||||
|
||||
[result appendContentString: [data jsonRepresentation]];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
inContext: (WOContext*) context
|
||||
{
|
||||
|
|
|
@ -216,6 +216,11 @@
|
|||
};
|
||||
};
|
||||
methods = {
|
||||
view = {
|
||||
protectedBy = "ViewAllComponent";
|
||||
pageName = "UIxTaskEditor";
|
||||
actionName = "view";
|
||||
};
|
||||
edit = {
|
||||
protectedBy = "ViewAllComponent";
|
||||
pageName = "UIxTaskEditor";
|
||||
|
|
|
@ -1081,7 +1081,7 @@ function _drawMonthCalendarEvents(events, eventsData) {
|
|||
|
||||
function newMonthEventDIV(eventRep, event) {
|
||||
var eventText;
|
||||
if (event[7])
|
||||
if (event[7]) // all-day event
|
||||
eventText = event[3];
|
||||
else
|
||||
eventText = eventRep.starthour + " - " + event[3];
|
||||
|
@ -1209,7 +1209,7 @@ function _loadEventHref(href) {
|
|||
document.eventsListAjaxRequest.aborted = true;
|
||||
document.eventsListAjaxRequest.abort();
|
||||
}
|
||||
var url = ApplicationBaseURL + "/" + href;
|
||||
var url = ApplicationBaseURL + href;
|
||||
document.eventsListAjaxRequest
|
||||
= triggerAjaxRequest(url, eventsListCallback, href);
|
||||
|
||||
|
@ -1279,7 +1279,9 @@ function refreshEvents() {
|
|||
titleSearch = "&search=" + escape(value.utf8encode());
|
||||
else
|
||||
titleSearch = "";
|
||||
|
||||
|
||||
refreshAlarms();
|
||||
|
||||
return _loadEventHref("eventslist?asc=" + sorting["ascending"]
|
||||
+ "&sort=" + sorting["attribute"]
|
||||
+ "&day=" + currentDay
|
||||
|
@ -1288,6 +1290,7 @@ function refreshEvents() {
|
|||
}
|
||||
|
||||
function refreshTasks() {
|
||||
refreshAlarms();
|
||||
return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,10 @@ var lastClickedRow = -1;
|
|||
// logArea = null;
|
||||
var allDocumentElements = null;
|
||||
|
||||
// Alarms
|
||||
var nextAlarm = null;
|
||||
var Alarms = new Array();
|
||||
|
||||
// Ajax requests counts
|
||||
var activeAjaxRequests = 0;
|
||||
var removeFolderRequestCount = 0;
|
||||
|
@ -1215,6 +1219,103 @@ function initTabs() {
|
|||
}
|
||||
}
|
||||
|
||||
function reverseSortByAlarmTime(a, b) {
|
||||
var x = parseInt(a[2]);
|
||||
var y = parseInt(b[2]);
|
||||
return (y - x);
|
||||
}
|
||||
|
||||
function refreshAlarms() {
|
||||
var url;
|
||||
var now = new Date();
|
||||
var utc = Math.floor(now.getTime()/1000);
|
||||
|
||||
if (document.alarmsListAjaxRequest) {
|
||||
document.alarmsListAjaxRequest.aborted = true;
|
||||
document.alarmsListAjaxRequest.abort();
|
||||
}
|
||||
url = UserFolderURL + "Calendar/alarmslist?browserTime=" + utc;
|
||||
document.alarmsListAjaxRequest
|
||||
= triggerAjaxRequest(url, refreshAlarmsCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function refreshAlarmsCallback(http) {
|
||||
if (http.readyState == 4
|
||||
&& http.status == 200) {
|
||||
document.alarmsListAjaxRequest = null;
|
||||
|
||||
if (http.responseText.length > 0) {
|
||||
Alarms = http.responseText.evalJSON(true);
|
||||
Alarms.sort(reverseSortByAlarmTime);
|
||||
triggerNextAlarm();
|
||||
}
|
||||
}
|
||||
else
|
||||
log ("refreshAlarmsCallback Ajax error");
|
||||
}
|
||||
|
||||
function triggerNextAlarm() {
|
||||
if (Alarms.length > 0) {
|
||||
var next = Alarms.pop();
|
||||
var now = new Date();
|
||||
var utc = Math.floor(now.getTime()/1000);
|
||||
var url = next[0] + '/' + next[1];
|
||||
var alarmTime = parseInt(next[2]);
|
||||
var delay = alarmTime;
|
||||
if (alarmTime > 0) delay -= utc;
|
||||
var d = new Date(alarmTime*1000);
|
||||
log ("now = " + now.toUTCString());
|
||||
log ("next event " + url + " in " + delay + " seconds (on " + d.toUTCString() + ")");
|
||||
showAlarm.delay(delay, url);
|
||||
}
|
||||
}
|
||||
|
||||
function showAlarm(url) {
|
||||
url = UserFolderURL + "Calendar/" + url + "/view?resetAlarm=yes";
|
||||
if (document.viewAlarmAjaxRequest) {
|
||||
document.viewAlarmAjaxRequest.aborted = true;
|
||||
document.viewAlarmAjaxRequest.abort();
|
||||
}
|
||||
document.viewAlarmAjaxRequest = triggerAjaxRequest(url, showAlarmCallback);
|
||||
}
|
||||
|
||||
function showAlarmCallback(http) {
|
||||
if (http.readyState == 4
|
||||
&& http.status == 200) {
|
||||
if (http.responseText.length) {
|
||||
var data = http.responseText.evalJSON(true);
|
||||
var msg = clabels["Reminder:"] + " " + data["summary"] + "\n";
|
||||
if (data["startDate"]) {
|
||||
msg += clabels["Start:"] + " " + data["startDate"];
|
||||
if (parseInt(data["isAllDay"]) == 0)
|
||||
msg += " - " + data["startTime"];
|
||||
msg += "\n";
|
||||
}
|
||||
if (data["dueDate"]) {
|
||||
msg += clabels["Due Date:"] + " " + data["dueDate"];
|
||||
if (data["dueTime"])
|
||||
msg += " - " + data["dueTime"];
|
||||
msg += "\n";
|
||||
}
|
||||
if (data["location"].length)
|
||||
msg += "\n" + clabels["Location:"] + " " + data["location"];
|
||||
if (data["description"].length)
|
||||
msg += "\n\n" + data["description"];
|
||||
|
||||
window.alert(msg);
|
||||
}
|
||||
else
|
||||
log("showAlarmCallback ajax error: no data received");
|
||||
}
|
||||
else {
|
||||
log("showAlarmCallback ajax error (" + http.status + "): " + http.url);
|
||||
}
|
||||
|
||||
triggerNextAlarm();
|
||||
}
|
||||
|
||||
function initMenus() {
|
||||
var menus = getMenus();
|
||||
if (menus) {
|
||||
|
@ -1435,6 +1536,7 @@ function onLoadHandler(event) {
|
|||
queryParameters = parseQueryParameters('' + window.location);
|
||||
if (!$(document.body).hasClassName("popup")) {
|
||||
initLogConsole();
|
||||
refreshAlarms();
|
||||
}
|
||||
initCriteria();
|
||||
configureSearchField();
|
||||
|
|
Loading…
Reference in New Issue