Added invitation delegation support in Web interface. See ChangeLog.
Monotone-Parent: 4d711e074341810486c1842c6a345777cc3664bb Monotone-Revision: 2fc8598099b516f243935e73039200f1c004784e Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2009-09-10T18:31:20 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
b63b53fecd
commit
9a9ecb1811
40
ChangeLog
40
ChangeLog
|
@ -1,3 +1,43 @@
|
|||
2009-09-10 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor
|
||||
-_handleAttendeesEdition]): the attendees list is now submited as
|
||||
a JSON string.
|
||||
([UIxComponentEditor -_loadAttendees]): constructs a dictionary
|
||||
with the attendees' information that will be passed as a JSON
|
||||
string to the template.
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartICalViewer.m
|
||||
([UIxMailPartICalViewer -currentAttendeeClass]): new method that
|
||||
returns the attendee's partstat as the CSS class and adds
|
||||
"attendeeUser" if the attendee is the active user.
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartICalActions.m (-): added delegateAction.
|
||||
|
||||
* UI/Contacts/UIxContactFoldersView.m ([UIxContactFoldersView
|
||||
-allContactSearchAction]): added the possibility to pass the form
|
||||
parameter "excludeLists" in order to avoid returning groups.
|
||||
|
||||
* SoObjects/SOGo/LDAPSource.m ([LDAPSource
|
||||
_convertLDAPEntryToContact:]): added a key named "isList" to the
|
||||
data representation of the LDAP entry if it matches specific objectClasses.
|
||||
|
||||
* SoObjects/Appointments/SOGoAptMailICalReply.m
|
||||
([SOGoAptMailICalReply -getBody]): trim spaces before returning
|
||||
the body.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentObject.m
|
||||
([SOGoAppointmentObject
|
||||
-_handleAttendee:withDelegate:ownerUser:statusChange:inEvent:]):
|
||||
added support for invitation delegation.
|
||||
([SOGoAppointementObject
|
||||
-_updateAttendee:withDelegate:ownerUser:forEventUID:withRecurrenceId:withSequence:forUID:shouldAddSentBy:]):
|
||||
fixed the case of chained delegates.
|
||||
([SOGoAppointmentObject
|
||||
-changeParticipationStatus:withDelegate:forRecurrenceId:]): when
|
||||
delegating an invitation, verify that the delegated is not already
|
||||
a participant nor a group of users.
|
||||
|
||||
2009-09-10 Cyril Robert <crobert@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/SOGoWebAppointmentFolder.m: New
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2009-09-10 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* iCalPerson.m ([iCalPerson -_valueOfMailtoAttribute:]): fixed the
|
||||
string range that was removing valid characters from a quoted string.
|
||||
|
||||
* NSString+NGCards.m ([NSString -rfc822Email]): new method that
|
||||
returns the string without the "mailto:" prefix.
|
||||
|
||||
2009-09-09 Cyril Robert <crobert@inverse.ca>
|
||||
|
||||
* NGVCard.m: Made use of NSDictionary+Utilities' userRecordAsLDIFEntry.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* NSString+NGCards.h - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2006 Inverse inc.
|
||||
* Copyright (C) 2006-2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -35,6 +35,7 @@
|
|||
- (NSArray *) asCardAttributeValues;
|
||||
- (NSString *) escapedForCards;
|
||||
- (NSString *) unescapedFromCard;
|
||||
- (NSString *) rfc822Email;
|
||||
|
||||
- (NSTimeInterval) durationAsTimeInterval;
|
||||
- (NSCalendarDate *) asCalendarDate;
|
||||
|
|
|
@ -329,4 +329,17 @@ static NSString *commaSeparator = nil;
|
|||
return components;
|
||||
}
|
||||
|
||||
- (NSString *) rfc822Email
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
idx = NSMaxRange([self rangeOfString:@":"]);
|
||||
|
||||
if ((idx > 0) && ([self length] > idx))
|
||||
return [self substringFromIndex: idx];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
mailTo = [self value: 0 ofAttribute: name];
|
||||
if ([mailTo hasPrefix: @"\""])
|
||||
mailTo
|
||||
= [mailTo substringWithRange: NSMakeRange (0, [mailTo length] - 2)];
|
||||
= [mailTo substringWithRange: NSMakeRange (1, [mailTo length] - 2)];
|
||||
|
||||
return mailTo;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,6 @@ Appointments_COMPONENTS += \
|
|||
SOGoAptMailDutchDeletion.wo \
|
||||
SOGoAptMailDutchUpdate.wo \
|
||||
SOGoAptMailEnglishInvitation.wo \
|
||||
SOGoAptMailEnglishICalReply.wo \
|
||||
SOGoAptMailEnglishDeletion.wo \
|
||||
SOGoAptMailEnglishUpdate.wo \
|
||||
SOGoAptMailFrenchInvitation.wo \
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
#import <SOPE/NGCards/NSString+NGCards.h>
|
||||
|
||||
#import <SoObjects/SOGo/iCalEntityObject+Utilities.h>
|
||||
#import <SoObjects/SOGo/LDAPUserManager.h>
|
||||
#import <SoObjects/SOGo/NSArray+Utilities.h>
|
||||
|
@ -400,8 +402,8 @@
|
|||
currentUID = [currentAttendee uid];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
}
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Update"
|
||||
|
@ -425,8 +427,8 @@
|
|||
currentUID = [currentAttendee uid];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,8 +485,8 @@
|
|||
currentUID = [currentAttendee uid];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
}
|
||||
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Update"
|
||||
|
@ -635,7 +637,7 @@
|
|||
|
||||
delegateEmail = [otherAttendee delegatedTo];
|
||||
if ([delegateEmail length])
|
||||
delegateEmail = [delegateEmail substringFromIndex: 7];
|
||||
delegateEmail = [delegateEmail rfc822Email];
|
||||
if ([delegateEmail length])
|
||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
||||
else
|
||||
|
@ -664,7 +666,22 @@
|
|||
}
|
||||
|
||||
if (removeDelegate)
|
||||
[event removeFromAttendees: otherDelegate];
|
||||
{
|
||||
while (otherDelegate)
|
||||
{
|
||||
[event removeFromAttendees: otherDelegate];
|
||||
|
||||
// Verify if the delegate was already delegated
|
||||
delegateEmail = [otherDelegate delegatedTo];
|
||||
if ([delegateEmail length])
|
||||
delegateEmail = [delegateEmail rfc822Email];
|
||||
|
||||
if ([delegateEmail length])
|
||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
||||
else
|
||||
otherDelegate = NO;
|
||||
}
|
||||
}
|
||||
if (addDelegate)
|
||||
[event addToAttendees: delegate];
|
||||
|
||||
|
@ -721,7 +738,50 @@
|
|||
ex = nil;
|
||||
|
||||
currentStatus = [attendee partStat];
|
||||
if ([currentStatus caseInsensitiveCompare: newStatus]
|
||||
|
||||
iCalPerson *otherAttendee, *otherDelegate;
|
||||
NSString *delegateEmail;
|
||||
BOOL addDelegate, removeDelegate;
|
||||
|
||||
otherAttendee = attendee;
|
||||
|
||||
delegateEmail = [otherAttendee delegatedTo];
|
||||
if ([delegateEmail length])
|
||||
delegateEmail = [delegateEmail rfc822Email];
|
||||
|
||||
if ([delegateEmail length])
|
||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
||||
else
|
||||
otherDelegate = NO;
|
||||
|
||||
/* We handle the addition/deletion of delegated users */
|
||||
addDelegate = NO;
|
||||
removeDelegate = NO;
|
||||
if (delegate)
|
||||
{
|
||||
if (otherDelegate)
|
||||
{
|
||||
// There was already a delegated
|
||||
if (![delegate hasSameEmailAddress: otherDelegate])
|
||||
{
|
||||
// The delegated has changed
|
||||
removeDelegate = YES;
|
||||
addDelegate = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
// There was no previous delegated
|
||||
addDelegate = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (otherDelegate)
|
||||
// The user has removed the delegated
|
||||
removeDelegate = YES;
|
||||
}
|
||||
|
||||
if (addDelegate || removeDelegate
|
||||
|| [currentStatus caseInsensitiveCompare: newStatus]
|
||||
!= NSOrderedSame)
|
||||
{
|
||||
[attendee setPartStat: newStatus];
|
||||
|
@ -745,7 +805,70 @@
|
|||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[attendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
}
|
||||
|
||||
[attendee setDelegatedTo: [delegate email]];
|
||||
|
||||
NSString *delegatedUID;
|
||||
NSMutableArray *delegates;
|
||||
|
||||
if (removeDelegate)
|
||||
{
|
||||
delegates = [NSMutableArray new];
|
||||
|
||||
while (otherDelegate)
|
||||
{
|
||||
[delegates addObject: otherDelegate];
|
||||
|
||||
delegatedUID = [otherDelegate uid];
|
||||
if (delegatedUID)
|
||||
// Delegated attendee is a local user; remove event from his calendar
|
||||
[self _removeEventFromUID: delegatedUID
|
||||
owner: [theOwnerUser login]
|
||||
withRecurrenceId: [event recurrenceId]];
|
||||
|
||||
[event removeFromAttendees: otherDelegate];
|
||||
|
||||
// Verify if the delegate was already delegated
|
||||
delegateEmail = [otherDelegate delegatedTo];
|
||||
if ([delegateEmail length])
|
||||
delegateEmail = [delegateEmail rfc822Email];
|
||||
|
||||
if ([delegateEmail length])
|
||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
||||
else
|
||||
otherDelegate = NO;
|
||||
}
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Deletion"
|
||||
forObject: [event itipEntryWithMethod: @"cancel"]
|
||||
previousObject: nil
|
||||
toAttendees: delegates];
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
||||
forObject: event
|
||||
to: delegates];
|
||||
[delegates release];
|
||||
}
|
||||
|
||||
if (addDelegate)
|
||||
{
|
||||
delegatedUID = [delegate uid];
|
||||
delegates = [NSArray arrayWithObject: delegate];
|
||||
[event addToAttendees: delegate];
|
||||
|
||||
if (delegatedUID)
|
||||
// Delegated attendee is a local user; add event to his calendar
|
||||
[self _addOrUpdateEvent: event
|
||||
forUID: delegatedUID
|
||||
owner: [theOwnerUser login]];
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||
forObject: [event itipEntryWithMethod: @"request"]
|
||||
previousObject: nil
|
||||
toAttendees: delegates];
|
||||
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
||||
forObject: event to: delegates];
|
||||
}
|
||||
|
||||
// We generate the updated iCalendar file and we save it
|
||||
// in the database.
|
||||
newContent = [[event parent] versitString];
|
||||
|
@ -794,7 +917,9 @@
|
|||
{
|
||||
att = [attendees objectAtIndex: i];
|
||||
uid = [att uid];
|
||||
if (uid && att != attendee)
|
||||
if (uid
|
||||
&& att != attendee
|
||||
&& ![uid isEqualToString: delegatedUID])
|
||||
[self _updateAttendee: attendee
|
||||
withDelegate: delegate
|
||||
ownerUser: theOwnerUser
|
||||
|
@ -1097,7 +1222,6 @@
|
|||
int i;
|
||||
|
||||
/* We update the copy of the organizer, only if it's a local user. */
|
||||
#warning add a check for only local users
|
||||
uid = [[event organizer] uid];
|
||||
if (uid)
|
||||
[self _updateAttendee: attendee
|
||||
|
@ -1200,7 +1324,8 @@
|
|||
- (NSException *) changeParticipationStatus: (NSString *) status
|
||||
withDelegate: (iCalPerson *) delegate
|
||||
{
|
||||
return [self changeParticipationStatus: status withDelegate: delegate
|
||||
return [self changeParticipationStatus: status
|
||||
withDelegate: delegate
|
||||
forRecurrenceId: nil];
|
||||
}
|
||||
|
||||
|
@ -1240,27 +1365,37 @@
|
|||
if (event)
|
||||
{
|
||||
// ownerUser will actually be the owner of the calendar
|
||||
// where the participation change on the event has
|
||||
// actually occured. The particpation change will of
|
||||
// course be on the attendee that is the owner of the
|
||||
// calendar where the participation change has occured.
|
||||
// where the participation change on the event occurs. The particpation
|
||||
// change will be on the attendee corresponding to the ownerUser.
|
||||
ownerUser = [SOGoUser userWithLogin: owner];
|
||||
|
||||
attendee = [event findParticipant: ownerUser];
|
||||
if (attendee)
|
||||
ex = [self _handleAttendee: attendee
|
||||
withDelegate: delegate
|
||||
ownerUser: ownerUser
|
||||
statusChange: _status
|
||||
inEvent: event];
|
||||
{
|
||||
if (delegate
|
||||
&& ![[delegate email] isEqualToString: [attendee delegatedTo]])
|
||||
{
|
||||
if ([event isParticipant: [[delegate email] rfc822Email]])
|
||||
ex = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"delegate is a participant"];
|
||||
else if ([SOGoGroup groupWithEmail: [[delegate email] rfc822Email]])
|
||||
ex = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"delegate is a group"];
|
||||
}
|
||||
if (ex == nil)
|
||||
ex = [self _handleAttendee: attendee
|
||||
withDelegate: delegate
|
||||
ownerUser: ownerUser
|
||||
statusChange: _status
|
||||
inEvent: event];
|
||||
}
|
||||
else
|
||||
ex = [NSException exceptionWithHTTPStatus: 404 // Not Found
|
||||
reason: @"user does not participate in this "
|
||||
@"calendar event"];
|
||||
reason: @"user does not participate in this calendar event"];
|
||||
}
|
||||
else
|
||||
ex = [NSException exceptionWithHTTPStatus: 500 // Server Error
|
||||
reason: @"unable to parse event record"];
|
||||
reason: @"unable to parse event record"];
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
<#IsSubject>Event Invitation Reply: <#summary/></#IsSubject>
|
||||
<#IsBody><#attendee/><#HasSentBy> (sent by <#sentBy/>)</#HasSentBy> has <#HasAccepted>accepted</#HasAccepted><#HasDeclined>declined</#HasDeclined><#HasNotAcceptedNotDeclined>not yet decided upon</#HasNotAcceptedNotDeclined> your event invitation.</#IsBody>
|
|
@ -1,39 +0,0 @@
|
|||
IsSubject: WOConditional {
|
||||
condition = isSubject;
|
||||
}
|
||||
|
||||
IsBody: WOConditional {
|
||||
condition = isSubject;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
summary: WOString {
|
||||
value = summary;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
attendee: WOString {
|
||||
value = attendeeName;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
HasAccepted: WOConditional {
|
||||
condition = hasAccepted;
|
||||
}
|
||||
|
||||
HasDeclined: WOConditional {
|
||||
condition = hasDeclined;
|
||||
}
|
||||
|
||||
HasNotAcceptedNotDeclined: WOConditional {
|
||||
condition = hasNotAcceptedNotDeclined;
|
||||
}
|
||||
|
||||
HasSentBy: WOConditional {
|
||||
condition = hasSentBy;
|
||||
}
|
||||
|
||||
sentBy: WOString {
|
||||
value = sentBy;
|
||||
escapeHTML = NO;
|
||||
}
|
|
@ -186,8 +186,13 @@ static NSCharacterSet *wsSet = nil;
|
|||
|
||||
- (NSString *) getBody
|
||||
{
|
||||
NSString *body;
|
||||
|
||||
isSubject = NO;
|
||||
return [[self generateResponse] contentAsString];
|
||||
|
||||
body = [[self generateResponse] contentAsString];
|
||||
|
||||
return [body stringByTrimmingCharactersInSet: wsSet];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -761,7 +761,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, NSStr
|
|||
ownerUser = from;
|
||||
language = [ownerUser language];
|
||||
/* create page name */
|
||||
pageName
|
||||
pageName
|
||||
= [NSString stringWithFormat: @"SOGoAptMail%@ICalReply", language];
|
||||
/* construct message content */
|
||||
p = [app pageWithName: pageName inContext: context];
|
||||
|
@ -778,13 +778,13 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, NSStr
|
|||
* at all. Mail.app shows the rich content alternative _only_
|
||||
* so we'll stick with multipart/mixed for the time being.
|
||||
*/
|
||||
[headerMap setObject: @"multipart/mixed" forKey: @"content-type"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
[headerMap setObject: [attendee mailAddress] forKey: @"from"];
|
||||
[headerMap setObject: [recipient mailAddress] forKey: @"to"];
|
||||
mailDate = [[NSCalendarDate date] rfc822DateString];
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: [p getSubject] forKey: @"subject"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
[headerMap setObject: @"multipart/mixed" forKey: @"content-type"];
|
||||
msg = [NGMimeMessage messageWithHeader: headerMap];
|
||||
|
||||
NSLog (@"sending 'REPLY' from %@ to %@",
|
||||
|
|
|
@ -251,6 +251,10 @@
|
|||
data = @"";
|
||||
[newRecord setObject: data forKey: @"c_telephonenumber"];
|
||||
|
||||
data = [oldRecord objectForKey: @"isGroup"];
|
||||
if (data)
|
||||
[newRecord setObject: data forKey: @"isGroup"];
|
||||
|
||||
contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
|
||||
if ([contactInfo length] > 0) {
|
||||
data = [oldRecord objectForKey: contactInfo];
|
||||
|
|
|
@ -658,14 +658,27 @@ static NSLock *lock;
|
|||
NSMutableDictionary *contactEntry;
|
||||
NSEnumerator *attributes;
|
||||
NSString *currentAttribute, *value;
|
||||
NSArray *classes;
|
||||
|
||||
contactEntry = [NSMutableDictionary dictionary];
|
||||
[contactEntry setObject: [ldapEntry dn] forKey: @"dn"];
|
||||
classes = [ldapEntry objectClasses];
|
||||
|
||||
if ([ldapEntry objectClasses])
|
||||
[contactEntry setObject: [ldapEntry objectClasses]
|
||||
forKey: @"objectClasses"];
|
||||
attributes = [[self _searchAttributes] objectEnumerator];
|
||||
if (classes)
|
||||
{
|
||||
[contactEntry setObject: classes
|
||||
forKey: @"objectClasses"];
|
||||
attributes = [[self _searchAttributes] objectEnumerator];
|
||||
|
||||
if ([classes containsObject: @"group"] ||
|
||||
[classes containsObject: @"groupOfNames"] ||
|
||||
[classes containsObject: @"groupOfUniqueNames"] ||
|
||||
[classes containsObject: @"posixGroup"])
|
||||
{
|
||||
[contactEntry setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"isGroup"];
|
||||
}
|
||||
}
|
||||
while ((currentAttribute = [attributes nextObject]))
|
||||
{
|
||||
value = [[ldapEntry attributeWithName: currentAttribute]
|
||||
|
@ -887,10 +900,12 @@ static NSLock *lock;
|
|||
|
||||
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail
|
||||
{
|
||||
#warning We should support MailFieldNames
|
||||
return [self lookupGroupEntryByAttribute: @"mail"
|
||||
andValue: theEmail];
|
||||
}
|
||||
|
||||
// This method should accept multiple attributes
|
||||
- (NGLdapEntry *) lookupGroupEntryByAttribute: (NSString *) theAttribute
|
||||
andValue: (NSString *) theValue
|
||||
{
|
||||
|
@ -911,9 +926,6 @@ static NSLock *lock;
|
|||
EOQualifier *qualifier;
|
||||
NSString *s;
|
||||
|
||||
// FIXME
|
||||
|
||||
// we should support MailFieldNames?
|
||||
s = [NSString stringWithFormat: @"(%@='%@')",
|
||||
theAttribute, SafeLDAPCriteria (theValue)];
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat: s];
|
||||
|
|
|
@ -204,7 +204,7 @@
|
|||
dn = [dns objectAtIndex: i];
|
||||
login = [um getLoginForDN: [dn lowercaseString]];
|
||||
//NSLog(@"member = %@", login);
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
if (user)
|
||||
[array addObject: user];
|
||||
}
|
||||
|
@ -213,7 +213,7 @@
|
|||
for (i = 0; i < [uids count]; i++)
|
||||
{
|
||||
login = [uids objectAtIndex: i];
|
||||
NSLog(@"member = %@", login);
|
||||
//NSLog(@"member = %@", login);
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
|
||||
if (user)
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
"You don't have the required privileges to perform the operation."
|
||||
= "You don't have the required privileges to perform the operation.";
|
||||
|
||||
"noEmailForDelegation" = "You must specify the address to which you want to delegate your invitation.";
|
||||
"delegate is a participant" = "The delegate is already a participant.";
|
||||
"delegate is a group" = "The specified address corresponds to a group. You can only delegate to a unique person.";
|
||||
|
||||
/* alarms */
|
||||
"Reminder:" = "Reminder:";
|
||||
"Start:" = "Start:";
|
||||
|
|
|
@ -195,11 +195,13 @@
|
|||
NSMutableDictionary *uniqueContacts;
|
||||
unsigned int i, j;
|
||||
NSSortDescriptor *commonNameDescriptor;
|
||||
BOOL excludeGroups;
|
||||
|
||||
searchText = [self queryParameterForKey: @"search"];
|
||||
if ([searchText length] > 0)
|
||||
{
|
||||
NSLog(@"Search all contacts: %@", searchText);
|
||||
excludeGroups = [[self queryParameterForKey: @"excludeGroups"] boolValue];
|
||||
NS_DURING
|
||||
folders = [[self clientObject] subFolders];
|
||||
NS_HANDLER
|
||||
|
@ -218,7 +220,7 @@
|
|||
{
|
||||
folder = [folders objectAtIndex: i];
|
||||
if ([folder isKindOfClass: [SOGoContactLDAPFolder class]])
|
||||
[sortedFolders insertObject: folder atIndex: 0];
|
||||
[sortedFolders insertObject: folder atIndex: 0];
|
||||
else
|
||||
[sortedFolders addObject: folder];
|
||||
}
|
||||
|
@ -234,8 +236,10 @@
|
|||
contact = [contacts objectAtIndex: j];
|
||||
mail = [contact objectForKey: @"c_mail"];
|
||||
//NSLog(@" found %@ (%@)", [contact objectForKey: @"displayName"], mail);
|
||||
if ([mail isNotNull] && [uniqueContacts objectForKey: mail] == nil)
|
||||
[uniqueContacts setObject: contact forKey: mail];
|
||||
if ([mail isNotNull]
|
||||
&& [uniqueContacts objectForKey: mail] == nil
|
||||
&& !(excludeGroups && [contact objectForKey: @"isGroup"]))
|
||||
[uniqueContacts setObject: contact forKey: mail];
|
||||
}
|
||||
}
|
||||
if ([uniqueContacts count] > 0)
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
|
@ -199,183 +201,95 @@
|
|||
return chosenEvent;
|
||||
}
|
||||
|
||||
#warning this is code copied from SOGoAppointmentObject...
|
||||
- (void) _updateAttendee: (iCalPerson *) attendee
|
||||
ownerUser: (SOGoUser *) theOwnerUser
|
||||
forEventUID: (NSString *) eventUID
|
||||
withRecurrenceId: (NSCalendarDate *) recurrenceId
|
||||
withSequence: (NSNumber *) sequence
|
||||
forUID: (NSString *) uid
|
||||
shouldAddSentBy: (BOOL) b
|
||||
{
|
||||
SOGoAppointmentObject *eventObject;
|
||||
iCalCalendar *calendar;
|
||||
iCalEvent *event;
|
||||
iCalPerson *otherAttendee;
|
||||
NSArray *events;
|
||||
NSString *iCalString, *recurrenceTime;
|
||||
|
||||
eventObject = [self _eventObjectWithUID: eventUID
|
||||
forUser: [SOGoUser userWithLogin: uid roles: nil]];
|
||||
if (![eventObject isNew])
|
||||
{
|
||||
if (recurrenceId == nil)
|
||||
{
|
||||
// We must update main event and all its occurences (if any).
|
||||
calendar = [eventObject calendar: NO secure: NO];
|
||||
event = (iCalEvent *)[calendar firstChildWithTag: [eventObject componentTag]];
|
||||
events = [calendar allObjects];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If recurrenceId is defined, find the specified occurence
|
||||
// within the repeating vEvent.
|
||||
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
||||
event = (iCalEvent *)[eventObject lookupOccurence: recurrenceTime];
|
||||
|
||||
if (event == nil)
|
||||
// If no occurence found, create one
|
||||
event = (iCalEvent *)[eventObject newOccurenceWithID: recurrenceTime];
|
||||
|
||||
events = [NSArray arrayWithObject: event];
|
||||
}
|
||||
|
||||
if ([[event sequence] compare: sequence]
|
||||
== NSOrderedSame)
|
||||
{
|
||||
SOGoUser *currentUser;
|
||||
int i;
|
||||
|
||||
currentUser = [context activeUser];
|
||||
|
||||
for (i = 0; i < [events count]; i++)
|
||||
{
|
||||
event = [events objectAtIndex: i];
|
||||
|
||||
otherAttendee = [event findParticipant: theOwnerUser];
|
||||
[otherAttendee setPartStat: [attendee partStat]];
|
||||
|
||||
// If one has accepted / declined an invitation on behalf of
|
||||
// the attendee, we add the user to the SENT-BY attribute.
|
||||
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
||||
{
|
||||
NSString *currentEmail;
|
||||
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
||||
[otherAttendee addAttribute: @"SENT-BY"
|
||||
value: [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
||||
// the event for B and then, B changes by himself his participation status,
|
||||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
}
|
||||
}
|
||||
iCalString = [[event parent] versitString];
|
||||
[eventObject saveContentString: iCalString];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (WOResponse *) _changePartStatusAction: (NSString *) newStatus
|
||||
withDelegate: (iCalPerson *) delegate
|
||||
{
|
||||
WOResponse *response;
|
||||
SOGoAppointmentObject *eventObject;
|
||||
iCalEvent *chosenEvent;
|
||||
iCalPerson *user;
|
||||
iCalCalendar *emailCalendar, *calendar;
|
||||
NSString *rsvp, *method, *organizerUID;
|
||||
//NSException *ex;
|
||||
|
||||
chosenEvent = [self _setupChosenEventAndEventObject: &eventObject];
|
||||
if (chosenEvent)
|
||||
{
|
||||
user = [chosenEvent findParticipant: [context activeUser]];
|
||||
[user setPartStat: newStatus];
|
||||
calendar = [chosenEvent parent];
|
||||
|
||||
emailCalendar = [[self _emailEvent] parent];
|
||||
method = [[emailCalendar method] lowercaseString];
|
||||
if ([method isEqualToString: @"request"])
|
||||
{
|
||||
[calendar setMethod: @""];
|
||||
rsvp = [[user rsvp] lowercaseString];
|
||||
}
|
||||
else
|
||||
rsvp = nil;
|
||||
|
||||
// We generate the updated iCalendar file and we save it
|
||||
// in the database.
|
||||
[eventObject saveContentString: [calendar versitString]];
|
||||
|
||||
// Send a notification to the organizer if necessary
|
||||
if ([rsvp isEqualToString: @"true"] &&
|
||||
[chosenEvent isStillRelevant])
|
||||
[eventObject sendResponseToOrganizer: chosenEvent
|
||||
from: [context activeUser]];
|
||||
|
||||
organizerUID = [[chosenEvent organizer] uid];
|
||||
if (organizerUID)
|
||||
// Update the event in the organizer's calendar
|
||||
[self _updateAttendee: user
|
||||
ownerUser: [context activeUser]
|
||||
forEventUID: [chosenEvent uid]
|
||||
withRecurrenceId: [chosenEvent recurrenceId]
|
||||
withSequence: [chosenEvent sequence]
|
||||
forUID: organizerUID
|
||||
shouldAddSentBy: YES];
|
||||
|
||||
// We update the calendar of all participants that are
|
||||
// local to the system. This is useful in case user A accepts
|
||||
// invitation from organizer B and users C, D, E who are also
|
||||
// attendees need to verify if A has accepted.
|
||||
NSArray *attendees;
|
||||
iCalPerson *att;
|
||||
NSString *uid;
|
||||
int i;
|
||||
|
||||
attendees = [chosenEvent attendees];
|
||||
|
||||
for (i = 0; i < [attendees count]; i++)
|
||||
{
|
||||
att = [attendees objectAtIndex: i];
|
||||
|
||||
if (att == user) continue;
|
||||
|
||||
uid = [[LDAPUserManager sharedUserManager]
|
||||
getUIDForEmail: [att rfc822Email]];
|
||||
|
||||
if (uid)
|
||||
{
|
||||
[self _updateAttendee: user
|
||||
ownerUser: [context activeUser]
|
||||
forEventUID: [chosenEvent uid]
|
||||
withRecurrenceId: [chosenEvent recurrenceId]
|
||||
withSequence: [chosenEvent sequence]
|
||||
forUID: uid
|
||||
shouldAddSentBy: YES];
|
||||
}
|
||||
}
|
||||
|
||||
response = [self responseWith204];
|
||||
response = (WOResponse*)[eventObject changeParticipationStatus: newStatus
|
||||
withDelegate: delegate
|
||||
forRecurrenceId: [chosenEvent recurrenceId]];
|
||||
// if (ex)
|
||||
// response = ex; //[self responseWithStatus: 500];
|
||||
// else
|
||||
if (!response)
|
||||
response = [self responseWith204];
|
||||
}
|
||||
else
|
||||
{
|
||||
response = [context response];
|
||||
[response setStatus: 409];
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
//- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
// inContext: (WOContext*) localContext
|
||||
//{
|
||||
// return YES;
|
||||
//}
|
||||
|
||||
- (WOResponse *) acceptAction
|
||||
{
|
||||
return [self _changePartStatusAction: @"ACCEPTED"];
|
||||
return [self _changePartStatusAction: @"ACCEPTED"
|
||||
withDelegate: nil];
|
||||
}
|
||||
|
||||
- (WOResponse *) declineAction
|
||||
{
|
||||
return [self _changePartStatusAction: @"DECLINED"];
|
||||
return [self _changePartStatusAction: @"DECLINED"
|
||||
withDelegate: nil];
|
||||
}
|
||||
|
||||
- (WOResponse *) delegateAction
|
||||
{
|
||||
// BOOL receiveUpdates;
|
||||
NSString *delegatedEmail, *delegatedUid;
|
||||
iCalPerson *delegatedAttendee;
|
||||
SOGoUser *user;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
|
||||
request = [context request];
|
||||
delegatedEmail = [request formValueForKey: @"to"];
|
||||
if ([delegatedEmail length])
|
||||
{
|
||||
user = [context activeUser];
|
||||
delegatedAttendee = [iCalPerson new];
|
||||
[delegatedAttendee setEmail: delegatedEmail];
|
||||
delegatedUid = [delegatedAttendee uid];
|
||||
if (delegatedUid)
|
||||
{
|
||||
SOGoUser *delegatedUser;
|
||||
delegatedUser = [SOGoUser userWithLogin: delegatedUid];
|
||||
[delegatedAttendee setCn: [delegatedUser cn]];
|
||||
}
|
||||
|
||||
[delegatedAttendee setRole: @"REQ-PARTICIPANT"];
|
||||
[delegatedAttendee setRsvp: @"TRUE"];
|
||||
[delegatedAttendee setParticipationStatus: iCalPersonPartStatNeedsAction];
|
||||
[delegatedAttendee setDelegatedFrom:
|
||||
[NSString stringWithFormat: @"mailto:%@", [[user allEmails] objectAtIndex: 0]]];
|
||||
|
||||
// receiveUpdates = [[request formValueForKey: @"receiveUpdates"] boolValue];
|
||||
// if (receiveUpdates)
|
||||
// [delegatedAttendee setRole: @"NON-PARTICIPANT"];
|
||||
|
||||
response = [self _changePartStatusAction: @"DELEGATED"
|
||||
withDelegate: delegatedAttendee];
|
||||
}
|
||||
else
|
||||
response = [NSException exceptionWithHTTPStatus: 400
|
||||
reason: @"missing 'to' parameter"];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WOResponse *) addToCalendarAction
|
||||
|
|
|
@ -376,6 +376,18 @@
|
|||
return [[self authorativeEvent] userIsParticipant: [context activeUser]];
|
||||
}
|
||||
|
||||
- (NSString *) currentAttendeeClass
|
||||
{
|
||||
NSString *cssClass;
|
||||
|
||||
cssClass = [[attendee partStatWithDefault] lowercaseString];
|
||||
|
||||
if ([[attendee rfc822Email] isEqualToString: [self loggedInUserEMail]])
|
||||
cssClass = [cssClass stringByAppendingString: @" attendeeUser"];
|
||||
|
||||
return cssClass;
|
||||
}
|
||||
|
||||
/* derived fields */
|
||||
|
||||
- (NSString *) organizerDisplayName
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
actionClass = "UIxMailPartICalActions";
|
||||
actionName = "decline";
|
||||
};
|
||||
delegate = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailPartICalActions";
|
||||
actionName = "delegate";
|
||||
};
|
||||
updateUserStatus = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailPartICalActions";
|
||||
|
|
|
@ -246,7 +246,7 @@
|
|||
"partStat_ACCEPTED" = "Accepted";
|
||||
"partStat_DECLINED" = "Declined";
|
||||
"partStat_TENTATIVE" = "Tentative";
|
||||
"partStat_DELEGATED" = "Delegated";
|
||||
"partStat_DELEGATED" = "Delegated to";
|
||||
"partStat_OTHER" = "Other";
|
||||
|
||||
/* Appointments (error messages) */
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#import <SoObjects/SOGo/SOGoDateFormatter.h>
|
||||
#import <SoObjects/SOGo/SOGoContentObject.h>
|
||||
#import <SoObjects/SOGo/SOGoPermissions.h>
|
||||
#import <SoObjects/Appointments/iCalPerson+SOGo.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
|
||||
#import <SoObjects/Appointments/SOGoAppointmentOccurence.h>
|
||||
|
@ -530,4 +531,52 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (id) delegateAction
|
||||
{
|
||||
// BOOL receiveUpdates;
|
||||
NSString *delegatedEmail, *delegatedUid;
|
||||
iCalPerson *delegatedAttendee;
|
||||
SOGoUser *user;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
|
||||
response = nil;
|
||||
request = [context request];
|
||||
delegatedEmail = [request formValueForKey: @"to"];
|
||||
if ([delegatedEmail length])
|
||||
{
|
||||
user = [context activeUser];
|
||||
delegatedAttendee = [iCalPerson new];
|
||||
[delegatedAttendee setEmail: delegatedEmail];
|
||||
delegatedUid = [delegatedAttendee uid];
|
||||
if (delegatedUid)
|
||||
{
|
||||
SOGoUser *delegatedUser;
|
||||
delegatedUser = [SOGoUser userWithLogin: delegatedUid];
|
||||
[delegatedAttendee setCn: [delegatedUser cn]];
|
||||
}
|
||||
|
||||
[delegatedAttendee setRole: @"REQ-PARTICIPANT"];
|
||||
[delegatedAttendee setRsvp: @"TRUE"];
|
||||
[delegatedAttendee setParticipationStatus: iCalPersonPartStatNeedsAction];
|
||||
[delegatedAttendee setDelegatedFrom:
|
||||
[NSString stringWithFormat: @"mailto:%@", [[user allEmails] objectAtIndex: 0]]];
|
||||
|
||||
// receiveUpdates = [[request formValueForKey: @"receiveUpdates"] boolValue];
|
||||
// if (receiveUpdates)
|
||||
// [delegatedAttendee setRole: @"NON-PARTICIPANT"];
|
||||
|
||||
response = (WOResponse*)[[self clientObject] changeParticipationStatus: @"DELEGATED"
|
||||
withDelegate: delegatedAttendee];
|
||||
}
|
||||
else
|
||||
response = [NSException exceptionWithHTTPStatus: 400
|
||||
reason: @"missing 'to' parameter"];
|
||||
|
||||
if (!response)
|
||||
response = [self responseWithStatus: 200];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
{
|
||||
iCalRepeatableEntityObject *component;
|
||||
id item;
|
||||
id attendee;
|
||||
|
||||
NSString *saveURL;
|
||||
NSMutableArray *calendarList;
|
||||
|
@ -59,13 +60,11 @@
|
|||
NSDictionary *cycle;
|
||||
NSString *cycleEnd;
|
||||
iCalPerson *organizer;
|
||||
iCalPerson *ownerAsAttendee;
|
||||
NSString *componentOwner;
|
||||
NSString *dateFormat;
|
||||
|
||||
NSString *attendeesNames;
|
||||
NSString *attendeesUIDs;
|
||||
NSString *attendeesEmails;
|
||||
NSString *attendeesStates;
|
||||
NSMutableDictionary *jsonAttendees;
|
||||
|
||||
NSString *reminder;
|
||||
NSString *reminderQuantity;
|
||||
|
@ -121,7 +120,6 @@
|
|||
- (NSString *) privacy;
|
||||
- (NSString *) itemPrivacyText;
|
||||
|
||||
- (NSArray *) statusTypes;
|
||||
- (void) setStatus: (NSString *) _status;
|
||||
- (NSString *) status;
|
||||
- (NSString *) itemStatusText;
|
||||
|
@ -142,14 +140,7 @@
|
|||
|
||||
- (BOOL) hasAttendees;
|
||||
|
||||
- (void) setAttendeesNames: (NSString *) newAttendeesNames;
|
||||
- (NSString *) attendeesNames;
|
||||
|
||||
- (void) setAttendeesUIDs: (NSString *) newAttendeesUIDs;
|
||||
- (NSString *) attendeesUIDs;
|
||||
|
||||
- (void) setAttendeesEmails: (NSString *) newAttendeesEmails;
|
||||
- (NSString *) attendeesEmails;
|
||||
- (NSString *) jsonAttendees;
|
||||
|
||||
- (NSString *) repeat;
|
||||
- (void) setRepeat: (NSString *) newRepeat;
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#import <SoObjects/SOGo/LDAPUserManager.h>
|
||||
#import <SoObjects/SOGo/NSArray+Utilities.h>
|
||||
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
|
||||
#import <SoObjects/SOGo/NSScanner+BSJSONAdditions.h>
|
||||
#import <SoObjects/SOGo/NSString+Utilities.h>
|
||||
#import <SoObjects/SOGo/SOGoUser.h>
|
||||
#import <SoObjects/SOGo/SOGoPermissions.h>
|
||||
|
@ -168,10 +169,9 @@ iRANGE(2);
|
|||
componentOwner = @"";
|
||||
organizer = nil;
|
||||
//organizerIdentity = nil;
|
||||
attendeesNames = nil;
|
||||
attendeesUIDs = nil;
|
||||
attendeesEmails = nil;
|
||||
attendeesStates = nil;
|
||||
ownerAsAttendee = nil;
|
||||
attendee = nil;
|
||||
jsonAttendees = nil;
|
||||
calendarList = nil;
|
||||
repeat = nil;
|
||||
reminder = nil;
|
||||
|
@ -202,16 +202,15 @@ iRANGE(2);
|
|||
[location release];
|
||||
[organizer release];
|
||||
//[organizerIdentity release];
|
||||
[ownerAsAttendee release];
|
||||
[comment release];
|
||||
[priority release];
|
||||
[categories release];
|
||||
[cycle release];
|
||||
[cycleEnd release];
|
||||
[attachUrl release];
|
||||
[attendeesNames release];
|
||||
[attendeesUIDs release];
|
||||
[attendeesEmails release];
|
||||
[attendeesStates release];
|
||||
[attendee release];
|
||||
[jsonAttendees release];
|
||||
[calendarList release];
|
||||
|
||||
[reminder release];
|
||||
|
@ -241,42 +240,44 @@ iRANGE(2);
|
|||
- (void) _loadAttendees
|
||||
{
|
||||
NSEnumerator *attendees;
|
||||
NSMutableDictionary *currentAttendeeData;
|
||||
iCalPerson *currentAttendee;
|
||||
NSMutableString *names, *uids, *emails, *states;
|
||||
NSString *uid;
|
||||
LDAPUserManager *um;
|
||||
|
||||
names = [NSMutableString string];
|
||||
uids = [NSMutableString string];
|
||||
emails = [NSMutableString string];
|
||||
states = [NSMutableString string];
|
||||
jsonAttendees = [NSMutableDictionary new];
|
||||
um = [LDAPUserManager sharedUserManager];
|
||||
|
||||
attendees = [[component attendees] objectEnumerator];
|
||||
while ((currentAttendee = [attendees nextObject]))
|
||||
{
|
||||
if ([[currentAttendee cn] length])
|
||||
[names appendFormat: @"%@,", [currentAttendee cn]];
|
||||
else
|
||||
[names appendFormat: @"%@,", [currentAttendee rfc822Email]];
|
||||
currentAttendeeData = [NSMutableDictionary dictionary];
|
||||
|
||||
[emails appendFormat: @"%@,", [currentAttendee rfc822Email]];
|
||||
if ([[currentAttendee cn] length])
|
||||
[currentAttendeeData setObject: [currentAttendee cn]
|
||||
forKey: @"name"];
|
||||
|
||||
[currentAttendeeData setObject: [currentAttendee rfc822Email]
|
||||
forKey: @"email"];
|
||||
|
||||
uid = [um getUIDForEmail: [currentAttendee rfc822Email]];
|
||||
if (uid != nil)
|
||||
[uids appendFormat: @"%@,", uid];
|
||||
else
|
||||
[uids appendString: @","];
|
||||
[states appendFormat: @"%@,",
|
||||
[[currentAttendee partStat] lowercaseString]];
|
||||
}
|
||||
[currentAttendeeData setObject: uid
|
||||
forKey: @"uid"];
|
||||
|
||||
if ([names length] > 0)
|
||||
{
|
||||
ASSIGN (attendeesNames, [names substringToIndex: [names length] - 1]);
|
||||
ASSIGN (attendeesUIDs, [uids substringToIndex: [uids length] - 1]);
|
||||
ASSIGN (attendeesEmails,
|
||||
[emails substringToIndex: [emails length] - 1]);
|
||||
ASSIGN (attendeesStates, [states substringToIndex: [states length] - 1]);
|
||||
[currentAttendeeData setObject: [[currentAttendee partStat] lowercaseString]
|
||||
forKey: @"partstat"];
|
||||
|
||||
if ([[currentAttendee delegatedTo] length])
|
||||
[currentAttendeeData setObject: [[currentAttendee delegatedTo] rfc822Email]
|
||||
forKey: @"delegated-to"];
|
||||
|
||||
if ([[currentAttendee delegatedFrom] length])
|
||||
[currentAttendeeData setObject: [[currentAttendee delegatedFrom] rfc822Email]
|
||||
forKey: @"delegated-from"];
|
||||
|
||||
[jsonAttendees setObject: currentAttendeeData
|
||||
forKey: [currentAttendee rfc822Email]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,6 +527,8 @@ iRANGE(2);
|
|||
{
|
||||
// iCalRecurrenceRule *rrule;
|
||||
SOGoObject *co;
|
||||
LDAPUserManager *um;
|
||||
NSString *owner, *ownerEmail;
|
||||
|
||||
if (!component)
|
||||
{
|
||||
|
@ -545,6 +548,7 @@ iRANGE(2);
|
|||
ASSIGN (categories,
|
||||
[[component categories] componentsWithSafeSeparator: ',']);
|
||||
ASSIGN (organizer, [component organizer]);
|
||||
|
||||
[self _loadCategories];
|
||||
[self _loadAttendees];
|
||||
[self _loadRRules];
|
||||
|
@ -555,6 +559,11 @@ iRANGE(2);
|
|||
if ([componentCalendar isKindOfClass: [SOGoCalendarComponent class]])
|
||||
componentCalendar = [componentCalendar container];
|
||||
[componentCalendar retain];
|
||||
|
||||
um = [LDAPUserManager sharedUserManager];
|
||||
owner = [componentCalendar ownerInContext: context];
|
||||
ownerEmail = [um getEmailForUID: owner];
|
||||
ASSIGN (ownerAsAttendee, [component findParticipantWithEmail: (id)ownerEmail]);
|
||||
}
|
||||
}
|
||||
// /* cycles */
|
||||
|
@ -750,44 +759,32 @@ iRANGE(2);
|
|||
return ([[component attendees] count] > 0);
|
||||
}
|
||||
|
||||
- (void) setAttendeesNames: (NSString *) newAttendeesNames
|
||||
- (void) setAttendee: (id) _attendee
|
||||
{
|
||||
ASSIGN (attendeesNames, newAttendeesNames);
|
||||
ASSIGN (attendee, _attendee);
|
||||
}
|
||||
|
||||
- (NSString *) attendeesNames
|
||||
- (id) attendee
|
||||
{
|
||||
return attendeesNames;
|
||||
return attendee;
|
||||
}
|
||||
|
||||
- (void) setAttendeesUIDs: (NSString *) newAttendeesUIDs
|
||||
- (NSString *) attendeeForDisplay
|
||||
{
|
||||
ASSIGN (attendeesUIDs, newAttendeesUIDs);
|
||||
NSString *fn, *result;
|
||||
|
||||
fn = [attendee cnWithoutQuotes];
|
||||
if ([fn length])
|
||||
result = fn;
|
||||
else
|
||||
result = [attendee rfc822Email];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *) attendeesUIDs
|
||||
- (NSString *) jsonAttendees
|
||||
{
|
||||
return attendeesUIDs;
|
||||
}
|
||||
|
||||
- (void) setAttendeesEmails: (NSString *) newAttendeesEmails
|
||||
{
|
||||
ASSIGN (attendeesEmails, newAttendeesEmails);
|
||||
}
|
||||
|
||||
- (NSString *) attendeesEmails
|
||||
{
|
||||
return attendeesEmails;
|
||||
}
|
||||
|
||||
- (void) setAttendeesStates: (NSString *) newAttendeesStates
|
||||
{
|
||||
ASSIGN (attendeesStates, newAttendeesStates);
|
||||
}
|
||||
|
||||
- (NSString *) attendeesStates
|
||||
{
|
||||
return attendeesStates;
|
||||
return [jsonAttendees jsonRepresentation];
|
||||
}
|
||||
|
||||
- (void) setLocation: (NSString *) _value
|
||||
|
@ -971,6 +968,10 @@ iRANGE(2);
|
|||
word = @"ACCEPTED";
|
||||
else if ([item intValue] == iCalPersonPartStatDeclined)
|
||||
word = @"DECLINED";
|
||||
else if ([item intValue] == iCalPersonPartStatDelegated)
|
||||
word = @"DELEGATED";
|
||||
else
|
||||
word = @"UNKNOWN";
|
||||
|
||||
return [self labelForKey: [NSString stringWithFormat: @"partStat_%@", word]];
|
||||
}
|
||||
|
@ -978,21 +979,18 @@ iRANGE(2);
|
|||
- (NSArray *) replyList
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSNumber numberWithInt: iCalPersonPartStatAccepted],
|
||||
[NSNumber numberWithInt: iCalPersonPartStatDeclined], nil];
|
||||
[NSNumber numberWithInt: iCalPersonPartStatAccepted],
|
||||
[NSNumber numberWithInt: iCalPersonPartStatDeclined],
|
||||
[NSNumber numberWithInt: iCalPersonPartStatDelegated],
|
||||
nil];
|
||||
}
|
||||
|
||||
- (NSNumber *) reply
|
||||
{
|
||||
iCalPersonPartStat participationStatus;
|
||||
LDAPUserManager *um;
|
||||
NSString *owner, *ownerEmail;
|
||||
|
||||
um = [LDAPUserManager sharedUserManager];
|
||||
owner = [componentCalendar ownerInContext: context];
|
||||
ownerEmail = [um getEmailForUID: owner];
|
||||
// We assume the owner is part of the participants
|
||||
participationStatus = [[component findParticipantWithEmail: (id)ownerEmail] participationStatus];
|
||||
participationStatus = [ownerAsAttendee participationStatus];
|
||||
|
||||
return [NSNumber numberWithInt: participationStatus];
|
||||
}
|
||||
|
||||
|
@ -1143,19 +1141,6 @@ iRANGE(2);
|
|||
return privacy;
|
||||
}
|
||||
|
||||
- (NSArray *) statusTypes
|
||||
{
|
||||
static NSArray *statusTypes = nil;
|
||||
|
||||
if (!statusTypes)
|
||||
{
|
||||
statusTypes = [NSArray arrayWithObjects: @"", @"TENTATIVE", @"CONFIRMED", @"CANCELLED", nil];
|
||||
[statusTypes retain];
|
||||
}
|
||||
|
||||
return statusTypes;
|
||||
}
|
||||
|
||||
- (void) setStatus: (NSString *) _status
|
||||
{
|
||||
ASSIGN (status, _status);
|
||||
|
@ -1499,26 +1484,35 @@ RANGE(2);
|
|||
|
||||
- (void) _handleAttendeesEdition
|
||||
{
|
||||
NSArray *names, *emails;
|
||||
NSMutableArray *newAttendees;
|
||||
unsigned int count, max;
|
||||
NSString *currentEmail;
|
||||
iCalPerson *currentAttendee;
|
||||
NSString *json;
|
||||
NSDictionary *attendeesData;
|
||||
NSArray *attendees;
|
||||
NSDictionary *currentData;
|
||||
NSScanner *jsonScanner;
|
||||
WORequest *request;
|
||||
|
||||
newAttendees = [NSMutableArray new];
|
||||
if ([attendeesNames length] > 0)
|
||||
request = [context request];
|
||||
json = [request formValueForKey: @"attendees"];
|
||||
attendees = [NSArray array];
|
||||
jsonScanner = [NSScanner scannerWithString: json];
|
||||
if ([jsonScanner scanJSONObject: &attendeesData])
|
||||
{
|
||||
names = [attendeesNames componentsSeparatedByString: @","];
|
||||
emails = [attendeesEmails componentsSeparatedByString: @","];
|
||||
max = [emails count];
|
||||
newAttendees = [NSMutableArray new];
|
||||
attendees = [attendeesData allValues];
|
||||
max = [attendees count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentEmail = [emails objectAtIndex: count];
|
||||
currentData = [attendees objectAtIndex: count];
|
||||
currentEmail = [currentData objectForKey: @"email"];
|
||||
currentAttendee = [component findParticipantWithEmail: currentEmail];
|
||||
if (!currentAttendee)
|
||||
{
|
||||
currentAttendee = [iCalPerson elementWithTag: @"attendee"];
|
||||
[currentAttendee setCn: [names objectAtIndex: count]];
|
||||
[currentAttendee setCn: [currentData objectForKey: @"name"]];
|
||||
[currentAttendee setEmail: currentEmail];
|
||||
[currentAttendee setRole: @"REQ-PARTICIPANT"];
|
||||
[currentAttendee setRsvp: @"TRUE"];
|
||||
|
@ -1527,10 +1521,11 @@ RANGE(2);
|
|||
}
|
||||
[newAttendees addObject: currentAttendee];
|
||||
}
|
||||
[component setAttendees: newAttendees];
|
||||
[newAttendees release];
|
||||
}
|
||||
|
||||
[component setAttendees: newAttendees];
|
||||
[newAttendees release];
|
||||
else
|
||||
NSLog(@"Error scanning following JSON:\n%@", json);
|
||||
}
|
||||
|
||||
- (void) _handleOrganizer
|
||||
|
|
|
@ -230,6 +230,11 @@
|
|||
pageName = "UIxAppointmentEditor";
|
||||
actionName = "decline";
|
||||
};
|
||||
delegate = {
|
||||
protectedBy = "RespondToComponent";
|
||||
actionClass = "UIxAppointmentEditor";
|
||||
actionName = "delegate";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" standalone="yes"?>
|
||||
<!DOCTYPE container>
|
||||
<container
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:rsrc="OGo:url"
|
||||
xmlns:label="OGo:label">
|
||||
|
||||
<var:if condition="isSubject">
|
||||
[Event Invitation Reply] <var:string value="summary" const:escapeHTML="NO" />
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isSubject" const:negate="YES">
|
||||
<var:string value="attendeeName" /><var:if condition="hasSentBy"> (sent by <var:string value="sentBy" />)</var:if> has <var:if condition="attendee.partStatWithDefault" const:value="DELEGATED">delegated the invitation to <var:string value="attendee.delegatedTo.rfc822Email" />.</var:if><var:if condition="attendee.partStatWithDefault" const:value="DELEGATED" const:negate="YES"><var:if condition="hasAccepted">accepted</var:if><var:if condition="hasDeclined">declined</var:if><var:if condition="hasNotAcceptedNotDeclined">not yet decided upon</var:if> your event invitation.</var:if>
|
||||
</var:if>
|
||||
</container>
|
|
@ -10,7 +10,7 @@
|
|||
<!-- TODO: add iMIP actions -->
|
||||
|
||||
<input id="iCalendarAttachment" type="hidden"
|
||||
var:value="pathToAttachment"/>
|
||||
var:value="pathToAttachment"/>
|
||||
|
||||
<var:if condition="couldParseCalendar" const:negate="1">
|
||||
<fieldset>
|
||||
|
@ -23,10 +23,13 @@
|
|||
</var:if>
|
||||
|
||||
<var:if condition="couldParseCalendar">
|
||||
<div class="popupMenu" id="contactsMenu">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<fieldset>
|
||||
<legend>
|
||||
<var:string label:value="Appointment"/>:
|
||||
<var:string value="inEvent.summary" /> <!-- TODO: shorted title -->
|
||||
<strong><var:string value="inEvent.summary" /></strong> <!-- TODO: shorted title -->
|
||||
|
||||
<var:if condition="isLoggedInUserTheOrganizer">
|
||||
(<var:string label:value="organized_by_you"/>)
|
||||
|
@ -51,6 +54,25 @@
|
|||
<input id="iCalendarDecline" class="button"
|
||||
type="button" label:value="Decline"/>
|
||||
</var:if>
|
||||
<var:if condition="currentUserAttendee.partStatWithDefault"
|
||||
const:value="DELEGATED" const:negate="YES">
|
||||
<input id="editDelegate" class="button"
|
||||
type="button" label:value="Delegate ..." />
|
||||
<span id="delegateEditor" style="display: none;">
|
||||
<var:string label:value="Delegate to" />
|
||||
<input name="delegatedTo" id="delegatedTo" type="text" />
|
||||
<input class="button" type="button" id="iCalendarDelegate" name="delegateOK" value="OK" />
|
||||
</span>
|
||||
</var:if>
|
||||
<var:if condition="currentUserAttendee.partStatWithDefault"
|
||||
const:value="DELEGATED">
|
||||
<span id="delegateEditor">
|
||||
<var:string label:value="Delegate to" />
|
||||
<input name="delegatedTo" id="delegatedTo" type="text" var:value="currentUserAttendee.delegatedTo.rfc822Email" var:uid="currentUserAttendee.delegatedTo.rfc822Email" style="display: none;" />
|
||||
<a var:href="currentUserAttendee.delegatedTo" name="delegatedToLink" id="delegatedToLink"><var:string value="currentUserAttendee.delegatedTo.rfc822Email" /></a>
|
||||
<input class="button" type="button" id="iCalendarDelegate" name="delegateOK" value="OK" />
|
||||
</span>
|
||||
</var:if>
|
||||
<!-- <input id="iCalendarTentative" class="button"
|
||||
type="button" label:value="Tentative"/> -->
|
||||
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
||||
|
@ -197,11 +219,12 @@
|
|||
|
||||
<tr>
|
||||
<td valign="top"><var:string label:value="Attendees"/>:</td>
|
||||
<td>
|
||||
<td id="iCalAttendees">
|
||||
<var:foreach list="authorativeEvent.participants" item="attendee">
|
||||
<a var:href="attendee.email"><var:string value="attendeeForDisplay"/></a>
|
||||
(<var:string label:value="$attendee.partStatWithDefault" />)
|
||||
<br />
|
||||
<var:if condition="attendee.delegatedTo" const:negate="YES"><!-- don't show attendees that delegated the invitation --><span var:class="currentAttendeeClass"><a var:href="attendee.email">
|
||||
<var:string value="attendeeForDisplay"/></a>
|
||||
(<var:string label:value="$attendee.partStatWithDefault" /><var:if condition="attendee.delegatedTo"> <var:string label:value="to" /> <var:string value="attendee.delegatedTo.rfc822Email" /></var:if><var:if condition="attendee.delegatedFrom">, <var:string label:value="delegated from" /> <var:string value="attendee.delegatedFrom.rfc822Email" /></var:if>)</span>
|
||||
<br /></var:if>
|
||||
</var:foreach>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
<div><table id="freeBusyAttendees" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr class="futureAttendee"
|
||||
><td class="attendees"><input type="text" class="textField"
|
||||
readonly="readonly" label:value="newAttendee" /></td
|
||||
><td class="attendees"><a href="#" class="button"
|
||||
readonly="readonly"><var:string label:value="newAttendee" /></a></td
|
||||
></tr>
|
||||
<tr class="attendeeModel"
|
||||
><td class="attendees"><input type="text" class="textField" /></td
|
||||
|
|
|
@ -12,13 +12,14 @@
|
|||
title="name"
|
||||
var:toolbar="toolbar"
|
||||
const:cssFiles="UIxComponentEditor.css"
|
||||
const:jsFiles="skycalendar.js,UIxComponentEditor.js">
|
||||
const:jsFiles="skycalendar.js,UIxComponentEditor.js,SOGoAutoCompletion.js">
|
||||
|
||||
<script type="text/javascript">
|
||||
var activeCalendar = '<var:string value="clientObject.container.nameInContainer"/>';
|
||||
var activeComponent = '<var:string value="clientObject.nameInContainer"/>';
|
||||
var readOnly = <var:if condition="eventIsReadOnly">true</var:if><var:if condition="eventIsReadOnly"
|
||||
const:negate="YES">false</var:if>;
|
||||
var attendees = <var:string value="jsonAttendees" const:escapeHTML="NO" />;
|
||||
</script>
|
||||
|
||||
<var:if condition="eventIsReadOnly" const:negate="YES">
|
||||
|
@ -106,14 +107,7 @@
|
|||
<input type="hidden" name="attach" id="attach" var:value="attach"/>
|
||||
<input type="hidden" name="privacy" id="privacy"
|
||||
var:value="privacy"/>
|
||||
<input type="hidden" name="attendeesNames" id="attendeesNames"
|
||||
var:value="attendeesNames"/>
|
||||
<input type="hidden" name="attendeesUIDs" id="attendeesUIDs"
|
||||
var:value="attendeesUIDs"/>
|
||||
<input type="hidden" name="attendeesEmails" id="attendeesEmails"
|
||||
var:value="attendeesEmails"/>
|
||||
<input type="hidden" name="attendeesStates" id="attendeesStates"
|
||||
var:value="attendeesStates"/>
|
||||
<input type="hidden" name="attendees" id="attendees" />
|
||||
<input type="hidden" name="calendarFoldersList"
|
||||
id="calendarFoldersList"
|
||||
var:value="calendarsFoldersList"/>
|
||||
|
@ -166,6 +160,9 @@
|
|||
</form>
|
||||
</var:if>
|
||||
<var:if condition="eventIsReadOnly">
|
||||
<div class="popupMenu" id="contactsMenu">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<label class="calendarName"><var:string var:value="componentCalendarName" />
|
||||
</label>
|
||||
<div id="eventView">
|
||||
|
@ -215,6 +212,23 @@
|
|||
string="itemReplyText"
|
||||
var:selection="reply" /></span>
|
||||
</label>
|
||||
<var:if condition="ownerAsAttendee.delegatedTo" const:negate="YES">
|
||||
<label id="delegateEditor" style="display: none;">
|
||||
<span class="content">
|
||||
<input name="delegatedTo" id="delegatedTo" type="text" var:value="ownerAsAttendee.delegatedTo" var:uid="delegatedTo" />
|
||||
<br />
|
||||
<input type="checkbox" name="delegateReceiveUpdates" /> <var:string label:value="Keep sending me updates" />
|
||||
</span>
|
||||
</label>
|
||||
</var:if><var:if condition="ownerAsAttendee.delegatedTo">
|
||||
<label id="delegateEditor">
|
||||
<span class="content">
|
||||
<input name="delegatedTo" id="delegatedTo" type="text" var:value="ownerAsAttendee.delegatedTo.rfc822Email" var:uid="ownerAsAttendee.delegatedTo.rfc822Email" />
|
||||
<br />
|
||||
<input type="checkbox" name="delegateReceiveUpdates" /> <var:string label:value="Keep sending me updates" />
|
||||
</span>
|
||||
</label>
|
||||
</var:if>
|
||||
<!--TODO: I'm not sure how to send this
|
||||
<label><var:string label:value="Reminder:" />
|
||||
<span class="content"><var:popup list="reminderList" item="item"
|
||||
|
@ -235,6 +249,9 @@
|
|||
</label>
|
||||
<label id="attendeesLabel">
|
||||
<span class="content"><div id="attendeesMenu" class="fakeTextArea">
|
||||
<var:foreach list="component.participants" item="attendee">
|
||||
<var:if condition="attendee.delegatedTo" const:negate="YES"><div var:class="attendee.partStatWithDefault.lowercaseString"><a var:href="attendee.email" var:email="attendee.email.rfc822Email"><var:string value="attendeeForDisplay" /></a><var:if condition="attendee.delegatedFrom"> (<var:string label:value="delegated from" /> <var:string value="attendee.delegatedFrom.rfc822Email" />)</var:if></div></var:if>
|
||||
</var:foreach>
|
||||
</div></span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -50,6 +50,6 @@
|
|||
/></span
|
||||
></var:if>
|
||||
</var:foreach>
|
||||
<img id="progressIndicator" rsrc:src="busy.gif" />
|
||||
<img id="progressIndicator" rsrc:src="busy.gif" />
|
||||
</div>
|
||||
</var:if>
|
||||
|
|
|
@ -310,44 +310,6 @@ tr.mailer_listcell_regular td a
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
IMG.mailerReadIcon
|
||||
{
|
||||
/* TODO
|
||||
*/
|
||||
}
|
||||
|
||||
DIV.mailer_readicon
|
||||
{
|
||||
/* TODO: use Thunderbird icon */
|
||||
background-image: url(icon_read.gif);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px 4px;
|
||||
}
|
||||
|
||||
DIV.mailer_readicon a
|
||||
{
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin: 0px auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
DIV.mailerUnreadIcon
|
||||
{
|
||||
/* TODO: use Thunderbird icon */
|
||||
background-image: url(icon_unread.gif);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px 4px;
|
||||
}
|
||||
|
||||
DIV.mailer_unreadicon a
|
||||
{
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin: 0px auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* fields (key/value UI), eg used in mail viewer */
|
||||
INPUT#editDraftButton
|
||||
{
|
||||
|
@ -814,3 +776,40 @@ DIV.copy
|
|||
background-image: url(message-copy.gif) !important;
|
||||
background-position: 1px -2px !important;
|
||||
}
|
||||
|
||||
/* UIxMailPartICalViewer */
|
||||
|
||||
#iCalAttendees SPAN
|
||||
{ background-repeat: no-repeat;
|
||||
background-position: 5px center;
|
||||
padding-left: 22px;
|
||||
padding-right: 4px; }
|
||||
|
||||
#iCalAttendees .accepted
|
||||
{ background-image: url("accepted.png"); }
|
||||
|
||||
#iCalAttendees .needs-action
|
||||
{ background-image: url("needs-action.png"); }
|
||||
|
||||
#iCalAttendees .declined
|
||||
{ background-image: url("declined.png"); }
|
||||
|
||||
#iCalAttendees .delegated
|
||||
{ background-image: url("delegated.png"); }
|
||||
|
||||
#iCalAttendees .attendeeUser,
|
||||
#iCalAttendees .attendeeUser A
|
||||
{ font-weight: bold; }
|
||||
|
||||
#delegateEditor
|
||||
{ padding-left: 5px; }
|
||||
|
||||
#delegatedTo
|
||||
{ width: 220px; }
|
||||
|
||||
#delegatedTo
|
||||
{ background-image: url("abcard.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 4px center;
|
||||
padding: 2px 2px 2px 24px;
|
||||
width: 220px; }
|
|
@ -511,9 +511,15 @@ function onMailboxMenuMove(event) {
|
|||
rows[i].hide();
|
||||
uids.push(uid);
|
||||
paths.push(path);
|
||||
// Remove references to closed popups
|
||||
for (var j = Mailer.popups.length - 1; j > -1; j--)
|
||||
if (!Mailer.popups[j].open || Mailer.popups[j].closed)
|
||||
Mailer.popups.splice(j,1);
|
||||
// Close message popup if opened
|
||||
for (var j = 0; j < Mailer.popups.length; j++)
|
||||
if (Mailer.popups[j].messageUID == path) {
|
||||
Mailer.popups[j].close();
|
||||
Mailer.popups.splice(j,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +676,7 @@ function messageListCallback(http) {
|
|||
addressHeaderCell.setAttribute("id", newRows[0].cells[addrIndex].getAttribute("id"));
|
||||
table.replaceChild(tmp.firstChild.tBodies[0], tbody);
|
||||
configureMessageListEvents(table);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Add table
|
||||
div.update(http.responseText);
|
||||
|
@ -1012,6 +1018,46 @@ function configureiCalLinksInMessage() {
|
|||
onICalendarButtonClick.bindAsEventListener(button));
|
||||
}
|
||||
}
|
||||
|
||||
var button = $("iCalendarDelegate");
|
||||
if (button) {
|
||||
button.observe("click", onICalendarDelegate);
|
||||
var delegatedTo = $("delegatedTo");
|
||||
delegatedTo.addInterface(SOGoAutoCompletionInterface);
|
||||
delegatedTo.uidField = "c_mail";
|
||||
delegatedTo.excludeGroups = true;
|
||||
|
||||
var editDelegate = $("editDelegate");
|
||||
if (editDelegate)
|
||||
// The user delegates the invitation
|
||||
editDelegate.observe("click", function(event) {
|
||||
$("delegateEditor").show();
|
||||
$("delegatedTo").focus();
|
||||
this.hide();
|
||||
});
|
||||
|
||||
var delegatedToLink = $("delegatedToLink");
|
||||
if (delegatedToLink) {
|
||||
// The user already delegated the invitation and wants
|
||||
// to change the delegated attendee
|
||||
delegatedToLink.stopObserving("click");
|
||||
delegatedToLink.observe("click", function(event) {
|
||||
$("delegatedTo").show();
|
||||
$("delegatedTo").focus();
|
||||
this.hide();
|
||||
Event.stop(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onICalendarDelegate(event) {
|
||||
var link = $("iCalendarAttachment").value;
|
||||
if (link) {
|
||||
var currentMsg = Mailer.currentMailbox + "/"
|
||||
+ Mailer.currentMessages[Mailer.currentMailbox];
|
||||
delegateInvitation(link, ICalendarButtonCallback, currentMsg);
|
||||
}
|
||||
}
|
||||
|
||||
function onICalendarButtonClick(event) {
|
||||
|
@ -1041,8 +1087,13 @@ function ICalendarButtonCallback(http) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (http.status == 403) {
|
||||
var data = http.responseText;
|
||||
var msg = data.replace(/^(.*\n)*.*<p>((.*\n)*.*)<\/p>(.*\n)*.*$/, "$2");
|
||||
window.alert(clabels[msg]?clabels[msg]:msg);
|
||||
}
|
||||
else
|
||||
window.alert("received code: " + http.status);
|
||||
window.alert("received code: " + http.status + "\nerror: " + http.responseText);
|
||||
}
|
||||
|
||||
function resizeMailContent() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// using this interface.
|
||||
var SOGoAutoCompletionInterface = {
|
||||
uidField: "c_name",
|
||||
excludeGroups: false,
|
||||
animationParent: null,
|
||||
selectedIndex: -1,
|
||||
delay: 0.750,
|
||||
|
@ -90,7 +91,9 @@ var SOGoAutoCompletionInterface = {
|
|||
if (input.value.trim().length > 2) {
|
||||
var urlstr = (UserFolderURL + "Contacts/allContactSearch?search="
|
||||
+ encodeURIComponent(input.value));
|
||||
if (input.animationParent)
|
||||
if (input.excludeGroups)
|
||||
urlstr += "&excludeGroups=1";
|
||||
if (input.animationParent)
|
||||
startAnimation(input.animationParent);
|
||||
document.contactLookupAjaxRequest =
|
||||
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
|
||||
|
|
|
@ -183,15 +183,17 @@ function deleteEvent() {
|
|||
return false;
|
||||
}
|
||||
|
||||
function modifyEvent(sender, modification) {
|
||||
function modifyEvent(sender, modification, parameters) {
|
||||
var currentLocation = '' + window.location;
|
||||
var arr = currentLocation.split("/");
|
||||
arr[arr.length-1] = modification;
|
||||
|
||||
document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
|
||||
modifyEventCallback,
|
||||
modification);
|
||||
|
||||
modification,
|
||||
parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -225,6 +227,11 @@ function modifyEventCallback(http) {
|
|||
window.setTimeout("window.close();", 100);
|
||||
}
|
||||
}
|
||||
else if (http.status == 403) {
|
||||
var data = http.responseText;
|
||||
var msg = data.replace(/^(.*\n)*.*<p>((.*\n)*.*)<\/p>(.*\n)*.*$/, "$2");
|
||||
window.alert(clabels[msg]?clabels[msg]:msg);
|
||||
}
|
||||
else {
|
||||
// log("showing alert...");
|
||||
window.alert(labels["eventPartStatModificationError"]);
|
||||
|
|
|
@ -124,7 +124,8 @@ A#attendeesHref
|
|||
DIV#attendeesMenu LI
|
||||
{ padding-left: 10px; }
|
||||
|
||||
DIV#attendeesMenu .attendee
|
||||
DIV#attendeesMenu .attendee,
|
||||
DIV#attendeesMenu DIV
|
||||
{ background-repeat: no-repeat;
|
||||
background-position: 5px center;
|
||||
padding-left: 22px; }
|
||||
|
@ -138,10 +139,12 @@ DIV#attendeesMenu .needs-action
|
|||
DIV#attendeesMenu .declined
|
||||
{ background-image: url("declined.png"); }
|
||||
|
||||
DIV#attendeesMenu .delegated
|
||||
{ background-image: url("delegated.png"); }
|
||||
|
||||
DIV#attendeesMenu .delegate
|
||||
{ margin-left: 10px; }
|
||||
|
||||
/* read-only view */
|
||||
DIV#attendeesMenu DIV
|
||||
{ cursor: pointer;
|
||||
padding-left: 20px; }
|
||||
|
||||
DIV#attendeesMenu DIV:hover
|
||||
{ text-decoration: underline; }
|
||||
{ padding-left: 20px; }
|
||||
|
|
|
@ -99,44 +99,6 @@ function validateAptEditor() {
|
|||
return true;
|
||||
}
|
||||
|
||||
function toggleDetails() {
|
||||
var div = $("details");
|
||||
var buttons = $("buttons");
|
||||
var buttonsHeight = buttons.clientHeight * 3;
|
||||
|
||||
if (div.style.visibility) {
|
||||
div.style.visibility = null;
|
||||
window.resizeBy(0, -(div.clientHeight + buttonsHeight));
|
||||
$("detailsButton").innerHTML = labels["Show Details"];
|
||||
} else {
|
||||
div.style.visibility = 'visible;';
|
||||
window.resizeBy(0, (div.clientHeight + buttonsHeight));
|
||||
$("detailsButton").innerHTML = labels["Hide Details"];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function toggleCycleVisibility(node, nodeName, hiddenValue) {
|
||||
var spanNode = $(nodeName);
|
||||
var newVisibility = ((node.value == hiddenValue) ? null : 'visible;');
|
||||
spanNode.style.visibility = newVisibility;
|
||||
|
||||
if (nodeName == 'cycleSelectionFirstLevel') {
|
||||
var otherSpanNode = $('cycleSelectionSecondLevel');
|
||||
if (!newVisibility)
|
||||
{
|
||||
otherSpanNode.superVisibility = otherSpanNode.style.visibility;
|
||||
otherSpanNode.style.visibility = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
otherSpanNode.style.visibility = otherSpanNode.superVisibility;
|
||||
otherSpanNode.superVisibility = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAttendeesMenuPrepareVisibility()
|
||||
{
|
||||
var composeToUndecidedAttendees = $('composeToUndecidedAttendees');
|
||||
|
@ -201,8 +163,10 @@ function addContact(tag, fullContactName, contactId, contactName, contactEmail)
|
|||
}
|
||||
|
||||
function saveEvent(sender) {
|
||||
if (validateAptEditor())
|
||||
if (validateAptEditor()) {
|
||||
document.forms['editform'].attendees.value = attendees.toJSON();
|
||||
document.forms['editform'].submit();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -335,51 +299,22 @@ function initTimeWidgets(widgets) {
|
|||
}
|
||||
|
||||
function refreshAttendeesRO () {
|
||||
var attendeesNames = $("attendeesNames").value;
|
||||
var attendeesEmails = $("attendeesEmails").value.split(",");
|
||||
var attendeesStates = $("attendeesStates").value.split(",");
|
||||
var attendeesMenu = $("attendeesMenu");
|
||||
var attendeesLabel = $("attendeesLabel");
|
||||
|
||||
if (attendeesMenu) {
|
||||
for (var i = 0; i < attendeesMenu.childNodes.length; i++)
|
||||
attendeesMenu.removeChild (attendeesMenu.childNodes[i]);
|
||||
}
|
||||
|
||||
if (attendeesNames.length > 0) {
|
||||
// Update attendees link and show label
|
||||
if (attendeesLabel)
|
||||
attendeesLabel.setStyle({ display: "block" });
|
||||
if ($("attendeesDiv"))
|
||||
$("attendeesDiv").setStyle({display: "block"});
|
||||
|
||||
// Update attendees in menu
|
||||
attendeesNames = attendeesNames.split(",");
|
||||
for (var i = 0; i < attendeesEmails.length; i++) {
|
||||
var node = document.createElement("div");
|
||||
if (attendeesMenu)
|
||||
attendeesMenu.appendChild(node);
|
||||
$(node).writeAttribute("email", attendeesEmails[i]);
|
||||
$(node).addClassName("attendee");
|
||||
$(node).addClassName(attendeesStates[i]);
|
||||
node.appendChild(document.createTextNode(attendeesNames[i]));
|
||||
$(node).observe("click", onMailTo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Hide link of attendees
|
||||
attendeesLabel.setStyle({ display: "none" });
|
||||
if ($("attendeesDiv"))
|
||||
$("attendeesDiv").setStyle({display: "none"});
|
||||
}
|
||||
|
||||
var attendeesDiv = $("attendeesDiv");
|
||||
|
||||
attendeesLabel.setStyle({ display: "block" });
|
||||
attendeesDiv.setStyle({display: "block"});
|
||||
|
||||
// Register "click" event on each attendee's email
|
||||
var attendees = attendeesMenu.getElementsByTagName('a');
|
||||
$A(attendees).each(function(attendee) {
|
||||
$(attendee).observe("click", onMailTo);
|
||||
});
|
||||
}
|
||||
|
||||
function refreshAttendees() {
|
||||
function refreshAttendees(newAttendees) {
|
||||
var attendeesLabel = $("attendeesLabel");
|
||||
var attendeesNames = $("attendeesNames").value;
|
||||
var attendeesEmails = $("attendeesEmails").value.split(",");
|
||||
var attendeesStates = $("attendeesStates").value.split(",");
|
||||
var attendeesHref = $("attendeesHref");
|
||||
var attendeesMenu = $("attendeesMenu");
|
||||
|
||||
|
@ -398,24 +333,36 @@ function refreshAttendees() {
|
|||
if (menuItems && attendeesMenu)
|
||||
for (var i = 0; i < menuItems.length; i++)
|
||||
attendeesMenu.removeChild(menuItems[i]);
|
||||
|
||||
if (attendeesNames.length > 0) {
|
||||
// Update attendees link and show label
|
||||
attendeesHref.appendChild(document.createTextNode(attendeesNames));
|
||||
attendeesLabel.setStyle({ display: "block" });
|
||||
|
||||
if (newAttendees)
|
||||
attendees = $H(newAttendees.evalJSON(true));
|
||||
|
||||
// Update attendees in menu
|
||||
attendeesNames = attendeesNames.split(",");
|
||||
for (var i = 0; i < attendeesEmails.length; i++) {
|
||||
var node = document.createElement("li");
|
||||
if (attendeesMenu)
|
||||
attendeesMenu.appendChild(node);
|
||||
$(node).writeAttribute("email", attendeesEmails[i]);
|
||||
$(node).addClassName("attendee");
|
||||
$(node).addClassName(attendeesStates[i]);
|
||||
node.appendChild(document.createTextNode(attendeesNames[i]));
|
||||
$(node).observe("click", onMailTo);
|
||||
}
|
||||
if (attendees.keys().length > 0) {
|
||||
// Update attendees link and show label
|
||||
var names = new Array();
|
||||
attendees.values().each(function(attendee) {
|
||||
attendee = $H(attendee);
|
||||
var name = attendee.get('name') || attendee.get('email');
|
||||
if (!attendee.get('delegated-to'))
|
||||
names.push(name);
|
||||
|
||||
if (attendeesMenu) {
|
||||
var delegatedTo = attendee.get('delegated-to');
|
||||
if (!attendee.get('delegated-from') || delegatedTo) {
|
||||
var node = document.createElement("li");
|
||||
attendeesMenu.appendChild(node);
|
||||
setupAttendeeNode(node, attendee);
|
||||
}
|
||||
if (delegatedTo) {
|
||||
var delegate = attendees.get(delegatedTo);
|
||||
var node = document.createElement("li");
|
||||
attendeesMenu.appendChild(node);
|
||||
setupAttendeeNode(node, $H(delegate), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
attendeesHref.appendChild(document.createTextNode(names.join(", ")));
|
||||
attendeesLabel.setStyle({ display: "block" });
|
||||
}
|
||||
else {
|
||||
// Hide link of attendees
|
||||
|
@ -423,6 +370,25 @@ function refreshAttendees() {
|
|||
}
|
||||
}
|
||||
|
||||
function setupAttendeeNode(aNode, aAttendee, isDelegate) {
|
||||
// Construct the display string from common name and/or email address.
|
||||
var name = aAttendee.get('name');
|
||||
var email = aAttendee.get('email');
|
||||
// if (name)
|
||||
// name += ' <' + email + '>';
|
||||
// else
|
||||
// name = email;
|
||||
name = name || email;
|
||||
|
||||
$(aNode).writeAttribute("email", email);
|
||||
$(aNode).addClassName("attendee");
|
||||
$(aNode).addClassName(aAttendee.get('partstat'));
|
||||
if (isDelegate)
|
||||
$(aNode).addClassName("delegate");
|
||||
aNode.appendChild(document.createTextNode(name));
|
||||
$(aNode).observe("click", onMailTo);
|
||||
}
|
||||
|
||||
function initializeAttendeesHref() {
|
||||
var attendeesHref = $("attendeesHref");
|
||||
var attendeesLabel = $("attendeesLabel");
|
||||
|
@ -443,6 +409,8 @@ function onMailTo(event) {
|
|||
var target = getTarget(event);
|
||||
var address = target.firstChild.nodeValue.trim() + " <" + target.readAttribute("email") + ">";
|
||||
openMailTo(address);
|
||||
Event.stop(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMenus() {
|
||||
|
@ -473,6 +441,10 @@ function onAppointmentEditorLoad() {
|
|||
'minute': $("endTime_time_minute")}};
|
||||
initTimeWidgets(widgets);
|
||||
}
|
||||
|
||||
// Extend JSON representation of attendees
|
||||
attendees = $H(attendees);
|
||||
|
||||
initializeAttendeesHref();
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,14 @@ TABLE#freeBusyAttendees TR.futureAttendee INPUT
|
|||
{ background-image: none;
|
||||
color: #aaa; }
|
||||
|
||||
TABLE#freeBusyAttendees TR.futureAttendee TD,
|
||||
TABLE#freeBusyData TR.futureData TD
|
||||
{ border: 0;
|
||||
line-height: 3em; }
|
||||
|
||||
TABLE#freeBusyAttendees TR.futureAttendee TD A
|
||||
{ margin-left: 24px; }
|
||||
|
||||
SPAN.freeBusyZoneElement
|
||||
{ display: block;
|
||||
float: left;
|
||||
|
|
|
@ -13,11 +13,7 @@ var attendeesEditor = {
|
|||
delay: 500,
|
||||
delayedSearch: false,
|
||||
currentField: null,
|
||||
selectedIndex: -1,
|
||||
names: null,
|
||||
UIDs: null,
|
||||
emails: null,
|
||||
states: null
|
||||
selectedIndex: -1
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,12 +44,12 @@ function onContactKeydown(event) {
|
|||
var row = $(this).up("tr").next();
|
||||
this.blur(); // triggers checkAttendee function call
|
||||
var input = row.down("input");
|
||||
if (input.readOnly)
|
||||
newAttendee(null);
|
||||
else {
|
||||
if (input) {
|
||||
input.focussed = true;
|
||||
input.activate();
|
||||
}
|
||||
else
|
||||
newAttendee(null);
|
||||
}
|
||||
else if (event.keyCode == 0
|
||||
|| event.keyCode == 8 // Backspace
|
||||
|
@ -579,15 +575,12 @@ function onNextSlotClick (event) {
|
|||
|
||||
function onEditorOkClick(event) {
|
||||
preventDefault(event);
|
||||
|
||||
attendeesEditor.names = new Array();
|
||||
attendeesEditor.UIDs = new Array();
|
||||
attendeesEditor.emails = new Array();
|
||||
attendeesEditor.states = new Array();
|
||||
|
||||
|
||||
var attendees = window.opener.attendees;
|
||||
var newAttendees = new Hash();
|
||||
var table = $("freeBusy");
|
||||
var inputs = table.getElementsByTagName("input");
|
||||
for (var i = 0; i < inputs.length - 2; i++) {
|
||||
for (var i = 0; i < inputs.length - 1; i++) {
|
||||
var row = $(inputs[i]).up("tr");
|
||||
var name = extractEmailName(inputs[i].value);
|
||||
var email = extractEmailAddress(inputs[i].value);
|
||||
|
@ -599,24 +592,15 @@ function onEditorOkClick(event) {
|
|||
name = inputs[i].uid;
|
||||
else
|
||||
name = email;
|
||||
var state = "needs-action";
|
||||
if (row.hasClassName("accepted"))
|
||||
state = "accepted";
|
||||
else if (row.hasClassName("declined"))
|
||||
state = "declined";
|
||||
var pos = attendeesEditor.emails.indexOf(email);
|
||||
if (pos == -1)
|
||||
pos = attendeesEditor.emails.length;
|
||||
attendeesEditor.names[pos] = name;
|
||||
attendeesEditor.UIDs[pos] = uid;
|
||||
attendeesEditor.emails[pos] = email;
|
||||
attendeesEditor.states[pos] = state;
|
||||
var attendee = attendees.get(email);
|
||||
if (!attendee)
|
||||
attendee = new Hash({'email': email,
|
||||
'name': name,
|
||||
'uid': uid,
|
||||
'partstat': 'needs-action'});
|
||||
newAttendees.set(email, attendee);
|
||||
}
|
||||
parent$("attendeesNames").value = attendeesEditor.names.join(",");
|
||||
parent$("attendeesUIDs").value = attendeesEditor.UIDs.join(",");
|
||||
parent$("attendeesEmails").value = attendeesEditor.emails.join(",");
|
||||
parent$("attendeesStates").value = attendeesEditor.states.join(",");
|
||||
window.opener.refreshAttendees();
|
||||
window.opener.refreshAttendees(newAttendees.toJSON());
|
||||
|
||||
updateParentDateFields("startTime", "startTime");
|
||||
updateParentDateFields("endTime", "endTime");
|
||||
|
@ -746,15 +730,11 @@ function prepareTableRows() {
|
|||
}
|
||||
|
||||
function prepareAttendees() {
|
||||
var value = parent$("attendeesNames").value;
|
||||
var tableAttendees = $("freeBusyAttendees");
|
||||
var tableData = $("freeBusyData");
|
||||
if (value.length > 0) {
|
||||
attendeesEditor.names = parent$("attendeesNames").value.split(",");
|
||||
attendeesEditor.UIDs = parent$("attendeesUIDs").value.split(",");
|
||||
attendeesEditor.emails = parent$("attendeesEmails").value.split(",");
|
||||
attendeesEditor.states = parent$("attendeesStates").value.split(",");
|
||||
var attendees = window.opener.attendees;
|
||||
|
||||
if (attendees && attendees.keys()) {
|
||||
var tbodyAttendees = tableAttendees.tBodies[0];
|
||||
var modelAttendee = tbodyAttendees.rows[tbodyAttendees.rows.length - 1];
|
||||
var newAttendeeRow = tbodyAttendees.rows[tbodyAttendees.rows.length - 2];
|
||||
|
@ -763,42 +743,38 @@ function prepareAttendees() {
|
|||
var modelData = tbodyData.rows[tbodyData.rows.length - 1];
|
||||
var newDataRow = tbodyData.rows[tbodyData.rows.length - 2];
|
||||
|
||||
for (var i = 0; i < attendeesEditor.names.length; i++) {
|
||||
var row = modelAttendee.cloneNode(true);
|
||||
tbodyAttendees.insertBefore(row, newAttendeeRow);
|
||||
$(row).removeClassName("attendeeModel");
|
||||
$(row).addClassName(attendeesEditor.states[i]);
|
||||
var input = $(row).down("input");
|
||||
var value = "";
|
||||
if (attendeesEditor.names[i].length > 0
|
||||
&& attendeesEditor.names[i] != attendeesEditor.emails[i])
|
||||
value += attendeesEditor.names[i] + " ";
|
||||
value += "<" + attendeesEditor.emails[i] + ">";
|
||||
input.value = value;
|
||||
if (attendeesEditor.UIDs[i].length > 0)
|
||||
input.uid = attendeesEditor.UIDs[i];
|
||||
input.setAttribute("name", "");
|
||||
input.setAttribute("modified", "0");
|
||||
input.observe("blur", checkAttendee);
|
||||
input.observe("keydown", onContactKeydown);
|
||||
attendees.values().each(function(attendee) {
|
||||
attendee = $H(attendee);
|
||||
var row = modelAttendee.cloneNode(true);
|
||||
tbodyAttendees.insertBefore(row, newAttendeeRow);
|
||||
$(row).removeClassName("attendeeModel");
|
||||
$(row).addClassName(attendee.get('partstat'));
|
||||
var input = $(row).down("input");
|
||||
var value = attendee.get('name');
|
||||
if (value)
|
||||
value += " ";
|
||||
else
|
||||
value = "";
|
||||
value += "<" + attendee.get('email') + ">";
|
||||
input.value = value;
|
||||
if (attendee.get('uid'))
|
||||
input.uid = attendee.get('uid');
|
||||
input.setAttribute("name", "");
|
||||
input.setAttribute("modified", "0");
|
||||
input.observe("blur", checkAttendee);
|
||||
input.observe("keydown", onContactKeydown);
|
||||
|
||||
row = modelData.cloneNode(true);
|
||||
tbodyData.insertBefore(row, newDataRow);
|
||||
$(row).removeClassName("dataModel");
|
||||
row = modelData.cloneNode(true);
|
||||
tbodyData.insertBefore(row, newDataRow);
|
||||
$(row).removeClassName("dataModel");
|
||||
|
||||
displayFreeBusyForNode(input);
|
||||
}
|
||||
}
|
||||
else {
|
||||
attendeesEditor.names = new Array();
|
||||
attendeesEditor.UIDs = new Array();
|
||||
attendeesEditor.emails = new Array();
|
||||
//newAttendee(null);
|
||||
displayFreeBusyForNode(input);
|
||||
});
|
||||
}
|
||||
|
||||
var inputs = tableAttendees.select("input");
|
||||
inputs[inputs.length - 2].setAttribute("autocomplete", "off");
|
||||
inputs[inputs.length - 2].observe("click", newAttendee);
|
||||
// Activate "Add attendee" button
|
||||
var links = tableAttendees.select("TR.futureAttendee TD A");
|
||||
links.first().observe("click", newAttendee);
|
||||
}
|
||||
|
||||
function onWindowResize(event) {
|
||||
|
|
|
@ -85,9 +85,29 @@ DIV.fakeTextArea
|
|||
border-width: 2px;
|
||||
border-style: inset;
|
||||
padding: 2px;
|
||||
height: 100px;
|
||||
white-space: pre-wrap; }
|
||||
height: 100px; }
|
||||
|
||||
DIV#descriptionDiv,
|
||||
DIV#attendeesDiv
|
||||
{ height: 120px; }
|
||||
|
||||
DIV#descriptionDiv DIV.fakeTextArea
|
||||
{ line-height: 1.5em;
|
||||
padding: 2px 4px;
|
||||
white-space: pre-wrap; }
|
||||
|
||||
#delegateEditor
|
||||
{ padding-bottom: 1em; }
|
||||
|
||||
#delegatedTo
|
||||
{ background-image: url("abcard.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 4px center;
|
||||
padding: 2px 2px 2px 24px;
|
||||
width: 260px; }
|
||||
|
||||
IMG#progressIndicator
|
||||
{ float: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
margin: 0 5px; }
|
||||
|
|
|
@ -130,15 +130,25 @@ function onComponentEditorLoad(event) {
|
|||
list.fire("mousedown");
|
||||
}
|
||||
|
||||
if ($("itemPrivacyList")) {
|
||||
var menuItems = $("itemPrivacyList").childNodesWithTag("li");
|
||||
var tmp = $("itemPrivacyList");
|
||||
if (tmp) {
|
||||
var menuItems = tmp.childNodesWithTag("li");
|
||||
for (var i = 0; i < menuItems.length; i++)
|
||||
menuItems[i].observe("mousedown",
|
||||
onMenuSetClassification.bindAsEventListener(menuItems[i]),
|
||||
false);
|
||||
}
|
||||
|
||||
var tmp = $("repeatHref");
|
||||
tmp = $("replyList");
|
||||
if (tmp) {
|
||||
tmp.observe("change", onReplyChange);
|
||||
tmp = $("delegatedTo");
|
||||
tmp.addInterface(SOGoAutoCompletionInterface);
|
||||
tmp.uidField = "c_mail";
|
||||
tmp.excludeGroups = true;
|
||||
tmp.animationParent=$("delegateEditor");
|
||||
}
|
||||
tmp = $("repeatHref");
|
||||
if (tmp)
|
||||
tmp.observe("click", onPopupRecurrenceWindow);
|
||||
tmp = $("repeatList");
|
||||
|
@ -182,6 +192,21 @@ function onSummaryChange (e) {
|
|||
document.title = $("summary").value;
|
||||
}
|
||||
|
||||
function onReplyChange(event) {
|
||||
var delegateEditor = $("delegateEditor");
|
||||
if (this.value == 2) {
|
||||
// Delegated
|
||||
delegateEditor.show();
|
||||
$("delegatedTo").focus();
|
||||
}
|
||||
else {
|
||||
delegateEditor.hide();
|
||||
}
|
||||
onWindowResize(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onWindowResize(event) {
|
||||
var comment = $("commentArea");
|
||||
if (comment) {
|
||||
|
@ -269,14 +294,19 @@ function onOkButtonClick (e) {
|
|||
var item = $("replyList");
|
||||
var value = parseInt(item.options[item.selectedIndex].value);
|
||||
var action = "";
|
||||
var parameters = "";
|
||||
|
||||
if (value == 0)
|
||||
action = 'accept';
|
||||
else if (value == 1)
|
||||
action = 'decline';
|
||||
else if (value == 2) {
|
||||
var url = ApplicationBaseURL + activeCalendar + '/' + activeComponent;
|
||||
document.modifyEventAjaxRequest = delegateInvitation(url, modifyEventCallback);
|
||||
}
|
||||
|
||||
if (action != "")
|
||||
modifyEvent (item, action);
|
||||
modifyEvent (item, action, parameters);
|
||||
}
|
||||
|
||||
function onCancelButtonClick (e) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
HTML, BODY
|
||||
{ background-color: #fff;
|
||||
font-size: normal;
|
||||
font-family: sans-serif; }
|
||||
font-family: sans-serif; }
|
Binary file not shown.
After Width: | Height: | Size: 540 B |
|
@ -759,7 +759,7 @@ DIV.resize-handle
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
max-height: 2em; }
|
||||
max-height: 2em; } /* will be set in JavaScript when setting drag handles */
|
||||
|
||||
@media print
|
||||
{
|
||||
|
@ -779,8 +779,8 @@ DIV.resize-handle
|
|||
|
||||
.genericHoverClass
|
||||
{
|
||||
background-color: #f0f0f0 !important;
|
||||
color: #000000 !important;
|
||||
background-color: #0033cc !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
DIV#uploadDialog,DIV#uploadResults
|
||||
|
|
|
@ -1602,6 +1602,26 @@ function createFolderCallback(http) {
|
|||
}
|
||||
}
|
||||
|
||||
/* invitation delegation */
|
||||
function delegateInvitation(componentUrl, callbackFunction, callbackData) {
|
||||
var input = $("delegatedTo");
|
||||
var delegatedTo = null;
|
||||
if (input.uid != null)
|
||||
delegatedTo = input.uid;
|
||||
else if (input.value.blank())
|
||||
alert(clabels["noEmailForDelegation"]);
|
||||
else
|
||||
delegatedTo = input.value;
|
||||
|
||||
if (delegatedTo) {
|
||||
var receiveUpdates = false; //confirm("Do you want to keep receiving updates on the event?");
|
||||
var urlstr = componentUrl + "/delegate";
|
||||
var parameters = "to=" + delegatedTo + "&receiveUpdates=" + (receiveUpdates?"YES":"NO");
|
||||
return triggerAjaxRequest(urlstr, callbackFunction, callbackData, parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
}
|
||||
}
|
||||
|
||||
function onFinalLoadHandler(event) {
|
||||
var safetyNet = $("javascriptSafetyNet");
|
||||
if (safetyNet)
|
||||
|
@ -1623,7 +1643,6 @@ function getMenus() {
|
|||
}
|
||||
|
||||
function onHeaderClick(event) {
|
||||
window.alert("generic headerClick");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -204,8 +204,10 @@ sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/create-accou
|
|||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/day-view-multicolumn.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/day-view.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/declined.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/delegated.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/dialog-left.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/dialog-right.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/dot.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/edit.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/empty.gif
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/event-gradient.png
|
||||
|
@ -217,7 +219,6 @@ sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon-forward
|
|||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon-forwarded.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon-new.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon-replied.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon_read.gif
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/icon_unread.gif
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/important.png
|
||||
sogo: image-file-in-usr-lib usr/lib/GNUstep/SOGo/WebServerResources/inverse.png
|
||||
|
|
Loading…
Reference in New Issue