merge of '29dc700a0a33827e16bd46a8d97f89d5f11630e9'
and 'b539ed81e839a831ce07b7618690feb8ac799176' Monotone-Parent: 29dc700a0a33827e16bd46a8d97f89d5f11630e9 Monotone-Parent: b539ed81e839a831ce07b7618690feb8ac799176 Monotone-Revision: a322b26bc82b5d04dfdd3997d676eec971639aec Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T18:52:51 Monotone-Branch: ca.inverse.sogo
80
ChangeLog
|
@ -4,6 +4,86 @@
|
||||||
refresh the tasks list when receiving the AJAX response instead of
|
refresh the tasks list when receiving the AJAX response instead of
|
||||||
emptying the list before sending the AJAX request.
|
emptying the list before sending the AJAX request.
|
||||||
|
|
||||||
|
2010-05-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* UI/WebServerResources/UIxAttendeesEditor.js (onContactKeydown):
|
||||||
|
the code for the "enter" and "tab" has been merged, since it was
|
||||||
|
similar. We also resolve individual contacts from list entries.
|
||||||
|
(resolveListAttendees): new function that fetches the indivual
|
||||||
|
entries from contacts lists.
|
||||||
|
(resolveListAttendeesCallback): callback for the above, that
|
||||||
|
create rows and input fields corresponding to the returned
|
||||||
|
entries, and trigger a contact search on each of them.
|
||||||
|
(performSearch): take an "input" field as argument since
|
||||||
|
"attendeesEditor.currentField" is no longer used.
|
||||||
|
(performSearchCallbacks): roles and partstats are now stored in
|
||||||
|
individual attributes rather than in the element class. We also
|
||||||
|
now behave differently depending on whether the event owner is
|
||||||
|
returned or another type of user, in order to match Lightning's
|
||||||
|
behaviour.
|
||||||
|
(newAttendee): no longer a callback, and now takes an optional
|
||||||
|
argument that indicates with attendee row precedes the one being
|
||||||
|
created. Also the new row is returned.
|
||||||
|
(checkAttendee): no longer a callback. Now takes an "input"
|
||||||
|
argument.
|
||||||
|
(onInputBlur): new callback that invokes "checkAttendee" and
|
||||||
|
handle the cleanup of the entries menu.
|
||||||
|
(displayFreeBusyForNode): use DOM methods rather than "innerHTML"
|
||||||
|
to modify the cell contents.
|
||||||
|
(updateFreeBusyDataCallback): freebusy requests are no longer
|
||||||
|
sequential.
|
||||||
|
(prepareAttendees): we now modify the DOM attributes rather than
|
||||||
|
the HTML attributes.
|
||||||
|
|
||||||
|
* UI/Contacts/UIxListView.m (-propertiesAction): we now invoke
|
||||||
|
-[self responseWithStatus:andJSONRepresentation:] to build the
|
||||||
|
resulting WOResponse.
|
||||||
|
|
||||||
|
* UI/Contacts/UIxContactFoldersView.m (-allContactSearchAction):
|
||||||
|
the type of returned component can now be deduced from the value
|
||||||
|
of "c_component" rather than from the c_name extension... Also, we
|
||||||
|
avoid autoreleasing variables where it's not needed.
|
||||||
|
(-contactSearchAction): removed obsolete method.
|
||||||
|
|
||||||
|
* SoObjects/Contacts/SOGoContactGCSFolder.m (+initialize): new
|
||||||
|
method initializing "folderListingFields" as a static NSArray
|
||||||
|
rather than as macro. Added "c_component" to the list of fields to
|
||||||
|
retrieve.
|
||||||
|
|
||||||
|
* UI/Scheduler/UIxComponentEditor.m (-ownerLogin): new accessor
|
||||||
|
the differenciate between the type of users in the list of
|
||||||
|
attendees.
|
||||||
|
|
||||||
|
* UI/WebServerResources/UIxAttendeesEditor.js
|
||||||
|
(performSearchCallback): differenciate between the organizer user
|
||||||
|
and other attendees, as in Lightning.
|
||||||
|
|
||||||
|
* UI/WebServerResources/UIxAppointmentEditor.js
|
||||||
|
(setupAttendeeNode): removed useless calls to $().
|
||||||
|
|
||||||
|
* UI/Scheduler/UIxComponentEditor.m
|
||||||
|
(-ownerIsAttendee:andClientObject:)
|
||||||
|
(delegateIsAttendee:andClientObject:): handle the case where the
|
||||||
|
user is found but has no RSVP or one with "FALSE" as value.
|
||||||
|
(-userHasRSVP): renamed from "userIsAttendee", since we don't
|
||||||
|
enable users without a RSVP set as "TRUE" to repond to
|
||||||
|
invitations.
|
||||||
|
(-currentAttendeeClasses): new method.
|
||||||
|
|
||||||
|
* UI/MailPartViewers/UIxMailPartICalActions.m (-tentativeAction):
|
||||||
|
new action method for the "TENTATIVE" partstat.
|
||||||
|
|
||||||
|
* SoObjects/Appointments/iCalEntityObject+SOGo.m
|
||||||
|
(-userIsParticipant:): renamed to "userIsAttendee:". We now
|
||||||
|
request the list of attendees rather than the list of
|
||||||
|
participants.
|
||||||
|
(-userAsParticipant:): renamed to "userAsAttendee:". Again, we
|
||||||
|
return the attendee matching the user, whether he/she is a
|
||||||
|
participant or not.
|
||||||
|
|
||||||
|
* SoObjects/SOGo/iCalEntityObject+Utilities.[hm]: removed useless
|
||||||
|
module, since it implemented methods already found elsewhere.
|
||||||
|
|
||||||
2010-05-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2010-05-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* UI/WebServerResources/ContactsUI.js (initContacts): we must
|
* UI/WebServerResources/ContactsUI.js (initContacts): we must
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
2010-05-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* iCalPerson.m (-setParticipationStatus:, -participationStatus):
|
||||||
|
added handling of the new partstat value
|
||||||
|
"iCalPersonPartStatUndefined".
|
||||||
|
|
||||||
|
* iCalEntityObject.m (-resources): removed useless method.
|
||||||
|
(-nonParticipants): new method returning ATTENDEE objects having
|
||||||
|
their ROLE attribute set to "NON-PARTICIPANT".
|
||||||
|
(-isAttendee:): new method.
|
||||||
|
(-findAttendeeWithEmail): new method replacing
|
||||||
|
"findParticipantWithEmail:".
|
||||||
|
|
||||||
2010-04-28 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2010-04-28 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* iCalRecurrenceRule.m (-iCalRepresentationForWeekDay:): made
|
* iCalRecurrenceRule.m (-iCalRepresentationForWeekDay:): made
|
||||||
|
@ -34,7 +47,7 @@
|
||||||
|
|
||||||
* iCalWeeklyRecurrenceCalculator.m
|
* iCalWeeklyRecurrenceCalculator.m
|
||||||
(-recurrenceRangesWithinCalendarDateRange:): make use of the new
|
(-recurrenceRangesWithinCalendarDateRange:): make use of the new
|
||||||
iCalByDayMask class.
|
iCalByDayMask class.
|
||||||
(-lastInstanceStartDate): make use of the previous method when a
|
(-lastInstanceStartDate): make use of the previous method when a
|
||||||
BYxxx mask is defined in the rule.
|
BYxxx mask is defined in the rule.
|
||||||
|
|
||||||
|
|
|
@ -109,15 +109,16 @@ typedef enum
|
||||||
- (void) addToAttendees: (iCalPerson *) _person;
|
- (void) addToAttendees: (iCalPerson *) _person;
|
||||||
- (NSArray *) attendees;
|
- (NSArray *) attendees;
|
||||||
- (void) setAttendees: (NSArray *) attendees;
|
- (void) setAttendees: (NSArray *) attendees;
|
||||||
|
- (BOOL) isAttendee: (id) _email;
|
||||||
|
|
||||||
- (void) removeFromAttendees: (iCalPerson *) oldAttendee;
|
- (void) removeFromAttendees: (iCalPerson *) oldAttendee;
|
||||||
- (void) removeAllAttendees;
|
- (void) removeAllAttendees;
|
||||||
|
|
||||||
/* categorize attendees into participants and resources */
|
/* categorize attendees into participants and non-participants */
|
||||||
- (NSArray *) participants;
|
- (NSArray *) participants;
|
||||||
- (NSArray *) resources;
|
- (NSArray *) nonParticipants;
|
||||||
- (BOOL) isParticipant: (id) _email;
|
- (BOOL) isParticipant: (id) _email;
|
||||||
- (iCalPerson *) findParticipantWithEmail: (id) _email;
|
- (iCalPerson *) findAttendeeWithEmail: (id) email;
|
||||||
|
|
||||||
- (void) removeAllAlarms;
|
- (void) removeAllAlarms;
|
||||||
- (void) addToAlarms: (id) _alarm;
|
- (void) addToAlarms: (id) _alarm;
|
||||||
|
|
|
@ -330,6 +330,40 @@
|
||||||
return [self childrenWithTag: @"attendee"];
|
return [self childrenWithTag: @"attendee"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) isAttendee: (id) _email
|
||||||
|
{
|
||||||
|
NSArray *attEmails;
|
||||||
|
|
||||||
|
_email = [_email lowercaseString];
|
||||||
|
attEmails = [[self attendees] valueForKey:@"rfc822Email"];
|
||||||
|
attEmails = [attEmails valueForKey: @"lowercaseString"];
|
||||||
|
return [attEmails containsObject:_email];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (iCalPerson *) findAttendeeWithEmail: (id) email
|
||||||
|
{
|
||||||
|
NSArray *attendees;
|
||||||
|
unsigned int count, max;
|
||||||
|
NSString *lowerEmail, *currentEmail;
|
||||||
|
iCalPerson *attendee, *currentAttendee;
|
||||||
|
|
||||||
|
attendee = nil;
|
||||||
|
|
||||||
|
lowerEmail = [email lowercaseString];
|
||||||
|
attendees = [self attendees];
|
||||||
|
max = [attendees count];
|
||||||
|
|
||||||
|
for (count = 0; attendee == nil && count < max; count++)
|
||||||
|
{
|
||||||
|
currentAttendee = [attendees objectAtIndex: count];
|
||||||
|
currentEmail = [[currentAttendee rfc822Email] lowercaseString];
|
||||||
|
if ([currentEmail isEqualToString: lowerEmail])
|
||||||
|
attendee = currentAttendee;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attendee;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) removeAllAlarms
|
- (void) removeAllAlarms
|
||||||
{
|
{
|
||||||
[children removeObjectsInArray: [self alarms]];
|
[children removeObjectsInArray: [self alarms]];
|
||||||
|
@ -406,48 +440,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stuff */
|
/* stuff */
|
||||||
|
|
||||||
- (NSArray *) participants
|
|
||||||
{
|
|
||||||
return [self _filteredAttendeesThinkingOfPersons: YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *) resources
|
|
||||||
{
|
|
||||||
return [self _filteredAttendeesThinkingOfPersons: NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *) _filteredAttendeesThinkingOfPersons: (BOOL) _persons
|
|
||||||
{
|
|
||||||
NSArray *list;
|
|
||||||
NSMutableArray *filtered;
|
|
||||||
unsigned count, max;
|
|
||||||
iCalPerson *person;
|
|
||||||
NSString *role;
|
|
||||||
|
|
||||||
if (_persons)
|
|
||||||
{
|
|
||||||
list = [self attendees];
|
|
||||||
max = [list count];
|
|
||||||
filtered = [NSMutableArray arrayWithCapacity: max];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
person = (iCalPerson *) [list objectAtIndex: count];
|
|
||||||
role = [[person role] uppercaseString];
|
|
||||||
if (![role hasPrefix: @"NON-PART"])
|
|
||||||
[filtered addObject: person];
|
|
||||||
}
|
|
||||||
|
|
||||||
list = filtered;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
list = [self childrenWithTag: @"attendee"
|
|
||||||
andAttribute: @"role"
|
|
||||||
havingValue: @"non-part"];
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) isOrganizer: (id) _email
|
- (BOOL) isOrganizer: (id) _email
|
||||||
{
|
{
|
||||||
NSString *organizerMail;
|
NSString *organizerMail;
|
||||||
|
@ -458,6 +450,35 @@
|
||||||
isEqualToString: [_email lowercaseString]];
|
isEqualToString: [_email lowercaseString]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) participants
|
||||||
|
{
|
||||||
|
NSArray *list;
|
||||||
|
NSMutableArray *filtered;
|
||||||
|
unsigned count, max;
|
||||||
|
iCalPerson *person;
|
||||||
|
NSString *role;
|
||||||
|
|
||||||
|
list = [self attendees];
|
||||||
|
max = [list count];
|
||||||
|
filtered = [NSMutableArray arrayWithCapacity: max];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
person = [list objectAtIndex: count];
|
||||||
|
role = [[person role] uppercaseString];
|
||||||
|
if (![role hasPrefix: @"NON-PARTICIPANT"])
|
||||||
|
[filtered addObject: person];
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *) nonParticipants
|
||||||
|
{
|
||||||
|
return [self childrenWithTag: @"attendee"
|
||||||
|
andAttribute: @"role"
|
||||||
|
havingValue: @"non-participant"];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL) isParticipant: (id) _email
|
- (BOOL) isParticipant: (id) _email
|
||||||
{
|
{
|
||||||
NSArray *partEmails;
|
NSArray *partEmails;
|
||||||
|
@ -468,26 +489,6 @@
|
||||||
return [partEmails containsObject:_email];
|
return [partEmails containsObject:_email];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (iCalPerson *) findParticipantWithEmail: (id) _email
|
|
||||||
{
|
|
||||||
NSArray *ps;
|
|
||||||
unsigned i, count;
|
|
||||||
|
|
||||||
_email = [_email lowercaseString];
|
|
||||||
ps = [self participants];
|
|
||||||
count = [ps count];
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
iCalPerson *p;
|
|
||||||
|
|
||||||
p = [ps objectAtIndex:i];
|
|
||||||
if ([[[p rfc822Email] lowercaseString] isEqualToString:_email])
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil; /* not found */
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSComparisonResult) _compareValue: (id) selfValue
|
- (NSComparisonResult) _compareValue: (id) selfValue
|
||||||
withValue: (id) otherValue
|
withValue: (id) otherValue
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#import "CardElement.h"
|
#import "CardElement.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
iCalPersonPartStatUndefined = -1, /* empty/undefined */
|
||||||
iCalPersonPartStatNeedsAction = 0, /* NEEDS-ACTION (DEFAULT) */
|
iCalPersonPartStatNeedsAction = 0, /* NEEDS-ACTION (DEFAULT) */
|
||||||
iCalPersonPartStatAccepted = 1, /* ACCEPTED */
|
iCalPersonPartStatAccepted = 1, /* ACCEPTED */
|
||||||
iCalPersonPartStatDeclined = 2, /* DECLINED */
|
iCalPersonPartStatDeclined = 2, /* DECLINED */
|
||||||
|
|
|
@ -133,6 +133,9 @@
|
||||||
NSString *stat;
|
NSString *stat;
|
||||||
|
|
||||||
switch (_status) {
|
switch (_status) {
|
||||||
|
case iCalPersonPartStatUndefined:
|
||||||
|
stat = @"";
|
||||||
|
break;
|
||||||
case iCalPersonPartStatAccepted:
|
case iCalPersonPartStatAccepted:
|
||||||
stat = @"ACCEPTED";
|
stat = @"ACCEPTED";
|
||||||
break;
|
break;
|
||||||
|
@ -170,7 +173,9 @@
|
||||||
NSString *stat;
|
NSString *stat;
|
||||||
|
|
||||||
stat = [[self partStat] uppercaseString];
|
stat = [[self partStat] uppercaseString];
|
||||||
if (![stat length] || [stat isEqualToString:@"NEEDS-ACTION"])
|
if (![stat length])
|
||||||
|
return iCalPersonPartStatUndefined;
|
||||||
|
else if ([stat isEqualToString:@"NEEDS-ACTION"])
|
||||||
return iCalPersonPartStatNeedsAction;
|
return iCalPersonPartStatNeedsAction;
|
||||||
else if ([stat isEqualToString:@"ACCEPTED"])
|
else if ([stat isEqualToString:@"ACCEPTED"])
|
||||||
return iCalPersonPartStatAccepted;
|
return iCalPersonPartStatAccepted;
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2010-05-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* VSSaxDriver.m (_endComponent:value:): avoid a crash occurring
|
||||||
|
when an inconsistency is found in the stack of containers.
|
||||||
|
|
||||||
2009-12-22 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2009-12-22 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* VSSaxDriver.m (_endComponent:value:): worked-around the lameness
|
* VSSaxDriver.m (_endComponent:value:): worked-around the lameness
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#import "VSSaxDriver.h"
|
#import "VSSaxDriver.h"
|
||||||
#import <SaxObjC/SaxException.h>
|
#import <SaxObjC/SaxException.h>
|
||||||
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
||||||
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
#import <NGExtensions/NSString+Encoding.h>
|
#import <NGExtensions/NSString+Encoding.h>
|
||||||
#import <NGCards/NSString+NGCards.h>
|
#import <NGCards/NSString+NGCards.h>
|
||||||
#import "common.h"
|
#import "common.h"
|
||||||
|
@ -653,6 +654,7 @@ static NSCharacterSet *whitespaceCharSet = nil;
|
||||||
value: (NSString *) tagValue
|
value: (NSString *) tagValue
|
||||||
{
|
{
|
||||||
NSString *mtName;
|
NSString *mtName;
|
||||||
|
int max;
|
||||||
|
|
||||||
mtName = [[self _mapTagName: tagValue] uppercaseString];
|
mtName = [[self _mapTagName: tagValue] uppercaseString];
|
||||||
if ([cardStack count] > 0)
|
if ([cardStack count] > 0)
|
||||||
|
@ -692,11 +694,19 @@ static NSCharacterSet *whitespaceCharSet = nil;
|
||||||
stringByAppendingString: mtName]];
|
stringByAppendingString: mtName]];
|
||||||
}
|
}
|
||||||
[self _endGroupElementTag: mtName];
|
[self _endGroupElementTag: mtName];
|
||||||
[cardStack removeLastObject];
|
|
||||||
|
max = [cardStack count];
|
||||||
|
if (max > 0)
|
||||||
|
{
|
||||||
|
[cardStack removeLastObject];
|
||||||
|
max--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self errorWithFormat: @"serious inconsistency among begin/end tags"];
|
||||||
|
|
||||||
/* report parsed elements */
|
/* report parsed elements */
|
||||||
|
|
||||||
if ([cardStack count] == 0)
|
if (max == 0)
|
||||||
[self reportQueuedTags];
|
[self reportQueuedTags];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
|
|
||||||
#import <SOPE/NGCards/NSString+NGCards.h>
|
#import <SOPE/NGCards/NSString+NGCards.h>
|
||||||
|
|
||||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
|
||||||
#import <SOGo/SOGoUserManager.h>
|
#import <SOGo/SOGoUserManager.h>
|
||||||
#import <SOGo/NSArray+Utilities.h>
|
#import <SOGo/NSArray+Utilities.h>
|
||||||
#import <SOGo/NSObject+DAV.h>
|
#import <SOGo/NSObject+DAV.h>
|
||||||
|
@ -591,13 +590,13 @@
|
||||||
SOGoUser *currentUser;
|
SOGoUser *currentUser;
|
||||||
|
|
||||||
currentUser = [context activeUser];
|
currentUser = [context activeUser];
|
||||||
otherAttendee = [event findParticipant: theOwnerUser];
|
otherAttendee = [event userAsAttendee: theOwnerUser];
|
||||||
|
|
||||||
delegateEmail = [otherAttendee delegatedTo];
|
delegateEmail = [otherAttendee delegatedTo];
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
delegateEmail = [delegateEmail rfc822Email];
|
delegateEmail = [delegateEmail rfc822Email];
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
||||||
else
|
else
|
||||||
otherDelegate = NO;
|
otherDelegate = NO;
|
||||||
|
|
||||||
|
@ -635,7 +634,7 @@
|
||||||
delegateEmail = [delegateEmail rfc822Email];
|
delegateEmail = [delegateEmail rfc822Email];
|
||||||
|
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
||||||
else
|
else
|
||||||
otherDelegate = NO;
|
otherDelegate = NO;
|
||||||
}
|
}
|
||||||
|
@ -708,7 +707,7 @@
|
||||||
delegateEmail = [delegateEmail rfc822Email];
|
delegateEmail = [delegateEmail rfc822Email];
|
||||||
|
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
||||||
else
|
else
|
||||||
otherDelegate = NO;
|
otherDelegate = NO;
|
||||||
|
|
||||||
|
@ -792,7 +791,7 @@
|
||||||
delegateEmail = [delegateEmail rfc822Email];
|
delegateEmail = [delegateEmail rfc822Email];
|
||||||
|
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
otherDelegate = [event findParticipantWithEmail: delegateEmail];
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
||||||
else
|
else
|
||||||
otherDelegate = NO;
|
otherDelegate = NO;
|
||||||
}
|
}
|
||||||
|
@ -860,7 +859,7 @@
|
||||||
shouldAddSentBy: YES];
|
shouldAddSentBy: YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We update the calendar of all participants that are
|
// We update the calendar of all attendees that are
|
||||||
// local to the system. This is useful in case user A accepts
|
// local to the system. This is useful in case user A accepts
|
||||||
// invitation from organizer B and users C, D, E who are also
|
// invitation from organizer B and users C, D, E who are also
|
||||||
// attendees need to verify if A has accepted.
|
// attendees need to verify if A has accepted.
|
||||||
|
@ -1075,7 +1074,7 @@
|
||||||
[self sendReceiptEmailUsingTemplateNamed: (isUpdate
|
[self sendReceiptEmailUsingTemplateNamed: (isUpdate
|
||||||
? @"Update" : @"Invitation")
|
? @"Update" : @"Invitation")
|
||||||
forObject: emailEvent
|
forObject: emailEvent
|
||||||
to: [newEvent participants]];
|
to: [newEvent attendees]];
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1119,7 @@
|
||||||
|
|
||||||
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
||||||
forObject: event
|
forObject: event
|
||||||
to: [event participants]];
|
to: [event attendees]];
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1160,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find attendee within event
|
// Find attendee within event
|
||||||
localAttendee = [event findParticipantWithEmail: [attendee rfc822Email]];
|
localAttendee = [event findAttendeeWithEmail: [attendee rfc822Email]];
|
||||||
if (localAttendee)
|
if (localAttendee)
|
||||||
{
|
{
|
||||||
// Update the attendee's status
|
// Update the attendee's status
|
||||||
|
@ -1230,7 +1229,7 @@
|
||||||
[[event parent] setMethod: @""];
|
[[event parent] setMethod: @""];
|
||||||
ownerUser = [SOGoUser userWithLogin: [[SOGoUserManager sharedUserManager]
|
ownerUser = [SOGoUser userWithLogin: [[SOGoUserManager sharedUserManager]
|
||||||
getUIDForEmail: originator]];
|
getUIDForEmail: originator]];
|
||||||
attendee = [event findParticipant: ownerUser];
|
attendee = [event userAsAttendee: ownerUser];
|
||||||
eventUID = [event uid];
|
eventUID = [event uid];
|
||||||
|
|
||||||
delegate = nil;
|
delegate = nil;
|
||||||
|
@ -1240,7 +1239,7 @@
|
||||||
delegateEmail = [delegateEmail substringFromIndex: 7];
|
delegateEmail = [delegateEmail substringFromIndex: 7];
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
delegate
|
delegate
|
||||||
= [event findParticipantWithEmail: delegateEmail];
|
= [event findAttendeeWithEmail: delegateEmail];
|
||||||
}
|
}
|
||||||
|
|
||||||
recipientsEnum = [recipients objectEnumerator];
|
recipientsEnum = [recipients objectEnumerator];
|
||||||
|
@ -1326,7 +1325,7 @@
|
||||||
// change will be on the attendee corresponding to the ownerUser.
|
// change will be on the attendee corresponding to the ownerUser.
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
|
|
||||||
attendee = [event findParticipant: ownerUser];
|
attendee = [event userAsAttendee: ownerUser];
|
||||||
if (attendee)
|
if (attendee)
|
||||||
{
|
{
|
||||||
if (delegate
|
if (delegate
|
||||||
|
@ -1338,9 +1337,9 @@
|
||||||
if (delegatedUser != nil && [event userIsOrganizer: delegatedUser])
|
if (delegatedUser != nil && [event userIsOrganizer: delegatedUser])
|
||||||
ex = [NSException exceptionWithHTTPStatus: 403
|
ex = [NSException exceptionWithHTTPStatus: 403
|
||||||
reason: @"delegate is organizer"];
|
reason: @"delegate is organizer"];
|
||||||
if ([event isParticipant: [[delegate email] rfc822Email]])
|
if ([event isAttendee: [[delegate email] rfc822Email]])
|
||||||
ex = [NSException exceptionWithHTTPStatus: 403
|
ex = [NSException exceptionWithHTTPStatus: 403
|
||||||
reason: @"delegate is a participant"];
|
reason: @"delegate is a attendee"];
|
||||||
else if ([SOGoGroup groupWithEmail: [[delegate email] rfc822Email]
|
else if ([SOGoGroup groupWithEmail: [[delegate email] rfc822Email]
|
||||||
inDomain: [ownerUser domain]])
|
inDomain: [ownerUser domain]])
|
||||||
ex = [NSException exceptionWithHTTPStatus: 403
|
ex = [NSException exceptionWithHTTPStatus: 403
|
||||||
|
@ -1411,7 +1410,7 @@
|
||||||
to: attendees];
|
to: attendees];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ([occurence userIsParticipant: ownerUser])
|
else if ([occurence userIsAttendee: ownerUser])
|
||||||
// The current user deletes the occurence; let the organizer know that
|
// The current user deletes the occurence; let the organizer know that
|
||||||
// the user has declined this occurence.
|
// the user has declined this occurence.
|
||||||
[self changeParticipationStatus: @"DECLINED" withDelegate: nil
|
[self changeParticipationStatus: @"DECLINED" withDelegate: nil
|
||||||
|
@ -1439,7 +1438,7 @@
|
||||||
NSArray *allEvents;
|
NSArray *allEvents;
|
||||||
int count, max;
|
int count, max;
|
||||||
iCalEvent *currentEvent;
|
iCalEvent *currentEvent;
|
||||||
iCalPerson *ownerParticipant;
|
iCalPerson *ownerAttendee;
|
||||||
NSString *key;
|
NSString *key;
|
||||||
SOGoUser *ownerUser;
|
SOGoUser *ownerUser;
|
||||||
|
|
||||||
|
@ -1452,14 +1451,14 @@
|
||||||
for (count = 0; count < max; count++)
|
for (count = 0; count < max; count++)
|
||||||
{
|
{
|
||||||
currentEvent = [allEvents objectAtIndex: count];
|
currentEvent = [allEvents objectAtIndex: count];
|
||||||
ownerParticipant = [currentEvent userAsParticipant: ownerUser];
|
ownerAttendee = [currentEvent userAsAttendee: ownerUser];
|
||||||
if (ownerParticipant)
|
if (ownerAttendee)
|
||||||
{
|
{
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
key = @"master";
|
key = @"master";
|
||||||
else
|
else
|
||||||
key = [[currentEvent recurrenceId] iCalFormattedDateTimeString];
|
key = [[currentEvent recurrenceId] iCalFormattedDateTimeString];
|
||||||
[partStats setObject: ownerParticipant forKey: key];
|
[partStats setObject: ownerAttendee forKey: key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#import <NGMime/NGMimeMultipartBody.h>
|
#import <NGMime/NGMimeMultipartBody.h>
|
||||||
#import <NGMail/NGMimeMessage.h>
|
#import <NGMail/NGMimeMessage.h>
|
||||||
|
|
||||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
|
||||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||||
#import <SOGo/NSDictionary+Utilities.h>
|
#import <SOGo/NSDictionary+Utilities.h>
|
||||||
#import <SOGo/NSObject+DAV.h>
|
#import <SOGo/NSObject+DAV.h>
|
||||||
|
@ -825,7 +824,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
p = [app pageWithName: pageName inContext: context];
|
p = [app pageWithName: pageName inContext: context];
|
||||||
[p setApt: (iCalEvent *) event];
|
[p setApt: (iCalEvent *) event];
|
||||||
|
|
||||||
attendee = [event findParticipant: from];
|
attendee = [event userAsAttendee: from];
|
||||||
[p setAttendee: attendee];
|
[p setAttendee: attendee];
|
||||||
|
|
||||||
/* construct message */
|
/* construct message */
|
||||||
|
@ -897,7 +896,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
if (![event userIsOrganizer: ownerUser])
|
if (![event userIsOrganizer: ownerUser])
|
||||||
{
|
{
|
||||||
organizer = [event organizer];
|
organizer = [event organizer];
|
||||||
attendee = [event findParticipant: ownerUser];
|
attendee = [event userAsAttendee: ownerUser];
|
||||||
[event setAttendees: [NSArray arrayWithObject: attendee]];
|
[event setAttendees: [NSArray arrayWithObject: attendee]];
|
||||||
[self sendIMIPReplyForEvent: event from: from to: organizer];
|
[self sendIMIPReplyForEvent: event from: from to: organizer];
|
||||||
}
|
}
|
||||||
|
@ -981,7 +980,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
user = [SOGoUser userWithLogin: uid];
|
user = [SOGoUser userWithLogin: uid];
|
||||||
component = [self component: NO secure: NO];
|
component = [self component: NO secure: NO];
|
||||||
|
|
||||||
return [component findParticipant: user];
|
return [component userAsAttendee: user];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (iCalPerson *) iCalPersonWithUID: (NSString *) uid
|
- (iCalPerson *) iCalPersonWithUID: (NSString *) uid
|
||||||
|
@ -1061,7 +1060,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
if ([component userIsOrganizer: ownerUser])
|
if ([component userIsOrganizer: ownerUser])
|
||||||
role = SOGoCalendarRole_Organizer;
|
role = SOGoCalendarRole_Organizer;
|
||||||
else if ([component userIsParticipant: ownerUser])
|
else if ([component userIsAttendee: ownerUser])
|
||||||
role = SOGoCalendarRole_Participant;
|
role = SOGoCalendarRole_Participant;
|
||||||
else
|
else
|
||||||
role = SOGoRole_None;
|
role = SOGoRole_None;
|
||||||
|
@ -1119,7 +1118,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
|
||||||
aclUser = [SOGoUser userWithLogin: uid];
|
aclUser = [SOGoUser userWithLogin: uid];
|
||||||
if ([component userIsOrganizer: aclUser])
|
if ([component userIsOrganizer: aclUser])
|
||||||
[roles addObject: SOGoCalendarRole_Organizer];
|
[roles addObject: SOGoCalendarRole_Organizer];
|
||||||
else if ([component userIsParticipant: aclUser])
|
else if ([component userIsAttendee: aclUser])
|
||||||
[roles addObject: SOGoCalendarRole_Participant];
|
[roles addObject: SOGoCalendarRole_Participant];
|
||||||
accessRole
|
accessRole
|
||||||
= [container roleForComponentsWithAccessClass: [component symbolicAccessClass]
|
= [container roleForComponentsWithAccessClass: [component symbolicAccessClass]
|
||||||
|
|
|
@ -34,10 +34,10 @@ extern NSNumber *iCalDistantFutureNumber;
|
||||||
|
|
||||||
+ (void) initializeSOGoExtensions;
|
+ (void) initializeSOGoExtensions;
|
||||||
|
|
||||||
- (BOOL) userIsParticipant: (SOGoUser *) user;
|
- (BOOL) userIsAttendee: (SOGoUser *) user;
|
||||||
- (BOOL) userIsOrganizer: (SOGoUser *) user;
|
- (BOOL) userIsOrganizer: (SOGoUser *) user;
|
||||||
|
|
||||||
- (iCalPerson *) userAsParticipant: (SOGoUser *) user;
|
- (iCalPerson *) userAsAttendee: (SOGoUser *) user;
|
||||||
|
|
||||||
- (NSArray *) attendeeUIDs;
|
- (NSArray *) attendeeUIDs;
|
||||||
- (BOOL) isStillRelevant;
|
- (BOOL) isStillRelevant;
|
||||||
|
|
|
@ -57,40 +57,40 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) userIsParticipant: (SOGoUser *) user
|
- (BOOL) userIsAttendee: (SOGoUser *) user
|
||||||
{
|
{
|
||||||
NSEnumerator *participants;
|
NSEnumerator *attendees;
|
||||||
iCalPerson *currentParticipant;
|
iCalPerson *currentAttendee;
|
||||||
BOOL isParticipant;
|
BOOL isAttendee;
|
||||||
|
|
||||||
isParticipant = NO;
|
isAttendee = NO;
|
||||||
|
|
||||||
participants = [[self participants] objectEnumerator];
|
attendees = [[self attendees] objectEnumerator];
|
||||||
currentParticipant = [participants nextObject];
|
currentAttendee = [attendees nextObject];
|
||||||
while (!isParticipant
|
while (!isAttendee
|
||||||
&& currentParticipant)
|
&& currentAttendee)
|
||||||
if ([user hasEmail: [currentParticipant rfc822Email]])
|
if ([user hasEmail: [currentAttendee rfc822Email]])
|
||||||
isParticipant = YES;
|
isAttendee = YES;
|
||||||
else
|
else
|
||||||
currentParticipant = [participants nextObject];
|
currentAttendee = [attendees nextObject];
|
||||||
|
|
||||||
return isParticipant;
|
return isAttendee;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (iCalPerson *) userAsParticipant: (SOGoUser *) user
|
- (iCalPerson *) userAsAttendee: (SOGoUser *) user
|
||||||
{
|
{
|
||||||
NSEnumerator *participants;
|
NSEnumerator *attendees;
|
||||||
iCalPerson *currentParticipant, *userParticipant;
|
iCalPerson *currentAttendee, *userAttendee;
|
||||||
|
|
||||||
userParticipant = nil;
|
userAttendee = nil;
|
||||||
|
|
||||||
participants = [[self participants] objectEnumerator];
|
attendees = [[self attendees] objectEnumerator];
|
||||||
while (!userParticipant
|
while (!userAttendee
|
||||||
&& (currentParticipant = [participants nextObject]))
|
&& (currentAttendee = [attendees nextObject]))
|
||||||
if ([user hasEmail: [currentParticipant rfc822Email]])
|
if ([user hasEmail: [currentAttendee rfc822Email]])
|
||||||
userParticipant = currentParticipant;
|
userAttendee = currentAttendee;
|
||||||
|
|
||||||
return userParticipant;
|
return userAttendee;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) userIsOrganizer: (SOGoUser *) user
|
- (BOOL) userIsOrganizer: (SOGoUser *) user
|
||||||
|
|
|
@ -46,13 +46,20 @@
|
||||||
|
|
||||||
#import "SOGoContactGCSFolder.h"
|
#import "SOGoContactGCSFolder.h"
|
||||||
|
|
||||||
#define folderListingFields [NSArray arrayWithObjects: @"c_name", @"c_cn", \
|
static NSArray *folderListingFields = nil;
|
||||||
@"c_givenname", @"c_sn", @"c_screenname", \
|
|
||||||
@"c_o", @"c_mail", @"c_telephonenumber", \
|
|
||||||
nil]
|
|
||||||
|
|
||||||
@implementation SOGoContactGCSFolder
|
@implementation SOGoContactGCSFolder
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if (!folderListingFields)
|
||||||
|
folderListingFields = [[NSArray alloc] initWithObjects: @"c_name",
|
||||||
|
@"c_cn", @"c_givenname", @"c_sn",
|
||||||
|
@"c_screenname", @"c_o",
|
||||||
|
@"c_mail", @"c_telephonenumber",
|
||||||
|
@"c_component", nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (Class) objectClassForContent: (NSString *) content
|
- (Class) objectClassForContent: (NSString *) content
|
||||||
{
|
{
|
||||||
CardGroup *cardEntry;
|
CardGroup *cardEntry;
|
||||||
|
|
|
@ -34,7 +34,6 @@ SOGo_HEADER_FILES = \
|
||||||
SOGoDateFormatter.h \
|
SOGoDateFormatter.h \
|
||||||
SOGoPermissions.h \
|
SOGoPermissions.h \
|
||||||
SOGoStartupLogger.h \
|
SOGoStartupLogger.h \
|
||||||
iCalEntityObject+Utilities.h \
|
|
||||||
NSArray+DAV.h \
|
NSArray+DAV.h \
|
||||||
NSArray+Utilities.h \
|
NSArray+Utilities.h \
|
||||||
NSCalendarDate+SOGo.h \
|
NSCalendarDate+SOGo.h \
|
||||||
|
@ -103,7 +102,6 @@ SOGo_OBJC_FILES = \
|
||||||
SQLSource.m \
|
SQLSource.m \
|
||||||
SOGoUserProfile.m \
|
SOGoUserProfile.m \
|
||||||
SOGoSQLUserProfile.m \
|
SOGoSQLUserProfile.m \
|
||||||
iCalEntityObject+Utilities.m \
|
|
||||||
NSArray+DAV.m \
|
NSArray+DAV.m \
|
||||||
NSArray+Utilities.m \
|
NSArray+Utilities.m \
|
||||||
NSCalendarDate+SOGo.m \
|
NSCalendarDate+SOGo.m \
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* iCalEntityObject+Utilities.h - this file is part of SOGo
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Inverse inc.
|
|
||||||
*
|
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This file is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ICALENTITYOBJECT_UTILITIES_H
|
|
||||||
#define ICALENTITYOBJECT_UTILITIES_H
|
|
||||||
|
|
||||||
#import <NGCards/iCalEntityObject.h>
|
|
||||||
|
|
||||||
@class iCalPerson;
|
|
||||||
@class SOGoUser;
|
|
||||||
|
|
||||||
@interface iCalEntityObject (SOGoAddition)
|
|
||||||
|
|
||||||
- (iCalPerson *) findParticipant: (SOGoUser *) user;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif /* ICALENTITYOBJECT_UTILITIES_H */
|
|
|
@ -1,53 +0,0 @@
|
||||||
/* iCalEntityObject+Utilities.m - this file is part of SOGo
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Inverse inc.
|
|
||||||
*
|
|
||||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This file is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/NSArray.h>
|
|
||||||
#import <Foundation/NSEnumerator.h>
|
|
||||||
|
|
||||||
#import <NGCards/iCalPerson.h>
|
|
||||||
|
|
||||||
#import "SOGoUser.h"
|
|
||||||
|
|
||||||
#import "iCalEntityObject+Utilities.h"
|
|
||||||
|
|
||||||
#warning we should move this into Appointments.
|
|
||||||
|
|
||||||
@implementation iCalEntityObject (SOGoAddition)
|
|
||||||
|
|
||||||
- (iCalPerson *) findParticipant: (SOGoUser *) user
|
|
||||||
{
|
|
||||||
iCalPerson *participant, *currentParticipant;
|
|
||||||
NSEnumerator *participants;
|
|
||||||
|
|
||||||
participant = nil;
|
|
||||||
participants = [[self attendees] objectEnumerator];
|
|
||||||
currentParticipant = [participants nextObject];
|
|
||||||
while (currentParticipant && !participant)
|
|
||||||
if ([user hasEmail: [currentParticipant rfc822Email]])
|
|
||||||
participant = currentParticipant;
|
|
||||||
else
|
|
||||||
currentParticipant = [participants nextObject];
|
|
||||||
|
|
||||||
return participant;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -78,8 +78,11 @@
|
||||||
us = [activeUser userSettings];
|
us = [activeUser userSettings];
|
||||||
moduleSettings = [us objectForKey: module];
|
moduleSettings = [us objectForKey: module];
|
||||||
if (!moduleSettings)
|
if (!moduleSettings)
|
||||||
moduleSettings = [NSMutableDictionary dictionary];
|
{
|
||||||
[us setObject: moduleSettings forKey: module];
|
moduleSettings = [NSMutableDictionary new];
|
||||||
|
[us setObject: moduleSettings forKey: module];
|
||||||
|
[moduleSettings release];
|
||||||
|
}
|
||||||
contextIsSetup = YES;
|
contextIsSetup = YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,44 +152,6 @@
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *) _responseForResults: (NSArray *) results
|
|
||||||
{
|
|
||||||
NSEnumerator *contacts;
|
|
||||||
NSString *email, *info;
|
|
||||||
NSDictionary *contact;
|
|
||||||
NSMutableArray *formattedContacts;
|
|
||||||
NSMutableDictionary *formattedContact;
|
|
||||||
|
|
||||||
formattedContacts = [NSMutableArray arrayWithCapacity: [results count]];
|
|
||||||
if ([results count] > 0)
|
|
||||||
{
|
|
||||||
contacts = [results objectEnumerator];
|
|
||||||
contact = [contacts nextObject];
|
|
||||||
while (contact)
|
|
||||||
{
|
|
||||||
email = [contact objectForKey: @"c_email"];
|
|
||||||
if ([email length])
|
|
||||||
{
|
|
||||||
formattedContact = [NSMutableDictionary dictionary];
|
|
||||||
[formattedContact setObject: [contact objectForKey: @"c_uid"]
|
|
||||||
forKey: @"uid"];
|
|
||||||
[formattedContact setObject: [contact objectForKey: @"cn"]
|
|
||||||
forKey: @"name"];
|
|
||||||
[formattedContact setObject: email
|
|
||||||
forKey: @"email"];
|
|
||||||
info = [contact objectForKey: @"c_info"];
|
|
||||||
if (info != nil)
|
|
||||||
[formattedContact setObject: info
|
|
||||||
forKey: @"contactInfo"];
|
|
||||||
[formattedContacts addObject: formattedContact];
|
|
||||||
}
|
|
||||||
contact = [contacts nextObject];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return formattedContacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id <WOActionResults>) allContactSearchAction
|
- (id <WOActionResults>) allContactSearchAction
|
||||||
{
|
{
|
||||||
id <WOActionResults> result;
|
id <WOActionResults> result;
|
||||||
|
@ -196,7 +161,7 @@
|
||||||
NSArray *folders, *contacts, *descriptors, *sortedContacts;
|
NSArray *folders, *contacts, *descriptors, *sortedContacts;
|
||||||
NSMutableArray *sortedFolders;
|
NSMutableArray *sortedFolders;
|
||||||
NSMutableDictionary *contact, *uniqueContacts;
|
NSMutableDictionary *contact, *uniqueContacts;
|
||||||
unsigned int i, j;
|
unsigned int i, j, max;
|
||||||
NSSortDescriptor *commonNameDescriptor;
|
NSSortDescriptor *commonNameDescriptor;
|
||||||
BOOL excludeGroups, excludeLists;
|
BOOL excludeGroups, excludeLists;
|
||||||
|
|
||||||
|
@ -217,9 +182,10 @@
|
||||||
else
|
else
|
||||||
[localException raise];
|
[localException raise];
|
||||||
NS_ENDHANDLER;
|
NS_ENDHANDLER;
|
||||||
sortedFolders = [NSMutableArray arrayWithCapacity: [folders count]];
|
max = [folders count];
|
||||||
|
sortedFolders = [NSMutableArray arrayWithCapacity: max];
|
||||||
uniqueContacts = [NSMutableDictionary dictionary];
|
uniqueContacts = [NSMutableDictionary dictionary];
|
||||||
for (i = 0; i < [folders count]; i++)
|
for (i = 0; i < max; i++)
|
||||||
{
|
{
|
||||||
folder = [folders objectAtIndex: i];
|
folder = [folders objectAtIndex: i];
|
||||||
/* We first search in LDAP folders (in case of duplicated entries in GCS folders) */
|
/* We first search in LDAP folders (in case of duplicated entries in GCS folders) */
|
||||||
|
@ -228,7 +194,7 @@
|
||||||
else
|
else
|
||||||
[sortedFolders addObject: folder];
|
[sortedFolders addObject: folder];
|
||||||
}
|
}
|
||||||
for (i = 0; i < [sortedFolders count]; i++)
|
for (i = 0; i < max; i++)
|
||||||
{
|
{
|
||||||
folder = [sortedFolders objectAtIndex: i];
|
folder = [sortedFolders objectAtIndex: i];
|
||||||
//NSLog(@" Address book: %@ (%@)", [folder displayName], [folder class]);
|
//NSLog(@" Address book: %@ (%@)", [folder displayName], [folder class]);
|
||||||
|
@ -245,8 +211,8 @@
|
||||||
&& [uniqueContacts objectForKey: mail] == nil
|
&& [uniqueContacts objectForKey: mail] == nil
|
||||||
&& !(excludeGroups && [contact objectForKey: @"isGroup"]))
|
&& !(excludeGroups && [contact objectForKey: @"isGroup"]))
|
||||||
[uniqueContacts setObject: contact forKey: mail];
|
[uniqueContacts setObject: contact forKey: mail];
|
||||||
else if (!excludeLists
|
else if (!excludeLists && [[contact objectForKey: @"c_component"]
|
||||||
&& [[contact objectForKey: @"c_name"] hasSuffix: @".vlf"])
|
isEqualToString: @"vlist"])
|
||||||
{
|
{
|
||||||
[contact setObject: [folder nameInContainer]
|
[contact setObject: [folder nameInContainer]
|
||||||
forKey: @"container"];
|
forKey: @"container"];
|
||||||
|
@ -254,14 +220,16 @@
|
||||||
forKey: [contact objectForKey: @"c_name"]];
|
forKey: [contact objectForKey: @"c_name"]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ([uniqueContacts count] > 0)
|
if ([uniqueContacts count] > 0)
|
||||||
{
|
{
|
||||||
// Sort the contacts by display name
|
// Sort the contacts by display name
|
||||||
commonNameDescriptor = [[[NSSortDescriptor alloc] initWithKey: @"c_cn"
|
commonNameDescriptor = [[NSSortDescriptor alloc] initWithKey: @"c_cn"
|
||||||
ascending:YES] autorelease];
|
ascending:YES];
|
||||||
descriptors = [NSArray arrayWithObjects: commonNameDescriptor, nil];
|
descriptors = [NSArray arrayWithObjects: commonNameDescriptor, nil];
|
||||||
sortedContacts = [[uniqueContacts allValues] sortedArrayUsingDescriptors: descriptors];
|
[commonNameDescriptor release];
|
||||||
|
sortedContacts = [[uniqueContacts allValues]
|
||||||
|
sortedArrayUsingDescriptors: descriptors];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sortedContacts = [NSArray array];
|
sortedContacts = [NSArray array];
|
||||||
|
@ -269,7 +237,7 @@
|
||||||
sortedContacts, @"contacts",
|
sortedContacts, @"contacts",
|
||||||
nil];
|
nil];
|
||||||
result = [self responseWithStatus: 200];
|
result = [self responseWithStatus: 200];
|
||||||
[(WOResponse*)result appendContentString: [data jsonRepresentation]];
|
[(WOResponse*) result appendContentString: [data jsonRepresentation]];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
result = [NSException exceptionWithHTTPStatus: 400
|
result = [NSException exceptionWithHTTPStatus: 400
|
||||||
|
@ -278,36 +246,6 @@
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id <WOActionResults>) contactSearchAction
|
|
||||||
{
|
|
||||||
NSDictionary *data;
|
|
||||||
NSArray *contacts;
|
|
||||||
NSString *searchText, *domain;
|
|
||||||
id <WOActionResults> result;
|
|
||||||
SOGoUserManager *um;
|
|
||||||
|
|
||||||
searchText = [self queryParameterForKey: @"search"];
|
|
||||||
if ([searchText length] > 0)
|
|
||||||
{
|
|
||||||
um = [SOGoUserManager sharedUserManager];
|
|
||||||
domain = [[context activeUser] domain];
|
|
||||||
contacts
|
|
||||||
= [self _responseForResults: [um fetchContactsMatching: searchText
|
|
||||||
inDomain: domain]];
|
|
||||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
searchText, @"searchText",
|
|
||||||
contacts, @"contacts",
|
|
||||||
nil];
|
|
||||||
result = [self responseWithStatus: 200];
|
|
||||||
[(WOResponse*)result appendContentString: [data jsonRepresentation]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = [NSException exceptionWithHTTPStatus: 400
|
|
||||||
reason: @"missing 'search' parameter"];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *) _subFoldersFromFolder: (SOGoParentFolder *) parentFolder
|
- (NSArray *) _subFoldersFromFolder: (SOGoParentFolder *) parentFolder
|
||||||
{
|
{
|
||||||
NSMutableArray *folders;
|
NSMutableArray *folders;
|
||||||
|
@ -375,8 +313,7 @@
|
||||||
|
|
||||||
- (NSString *) currentContactFolderId
|
- (NSString *) currentContactFolderId
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat: @"/%@",
|
return [NSString stringWithFormat: @"/%@", [currentFolder nameInContainer]];
|
||||||
[currentFolder nameInContainer]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) currentContactFolderName
|
- (NSString *) currentContactFolderName
|
||||||
|
@ -391,7 +328,8 @@
|
||||||
|
|
||||||
- (NSString *) currentContactFolderClass
|
- (NSString *) currentContactFolderClass
|
||||||
{
|
{
|
||||||
return ([currentFolder isKindOfClass: [SOGoContactSourceFolder class]]? @"remote" : @"local");
|
return ([currentFolder isKindOfClass: [SOGoContactSourceFolder class]]
|
||||||
|
? @"remote" : @"local");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) verticalDragHandleStyle
|
- (NSString *) verticalDragHandleStyle
|
||||||
|
@ -401,7 +339,8 @@
|
||||||
[self _setupContext];
|
[self _setupContext];
|
||||||
vertical = [moduleSettings objectForKey: @"DragHandleVertical"];
|
vertical = [moduleSettings objectForKey: @"DragHandleVertical"];
|
||||||
|
|
||||||
return ((vertical && [vertical intValue] > 0) ? (id)[vertical stringByAppendingFormat: @"px"] : nil);
|
return ((vertical && [vertical intValue] > 0)
|
||||||
|
? (id)[vertical stringByAppendingFormat: @"px"] : nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) horizontalDragHandleStyle
|
- (NSString *) horizontalDragHandleStyle
|
||||||
|
@ -411,7 +350,8 @@
|
||||||
[self _setupContext];
|
[self _setupContext];
|
||||||
horizontal = [moduleSettings objectForKey: @"DragHandleHorizontal"];
|
horizontal = [moduleSettings objectForKey: @"DragHandleHorizontal"];
|
||||||
|
|
||||||
return ((horizontal && [horizontal intValue] > 0) ? (id)[horizontal stringByAppendingFormat: @"px"] : nil);
|
return ((horizontal && [horizontal intValue] > 0)
|
||||||
|
? (id)[horizontal stringByAppendingFormat: @"px"] : nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) contactsListContentStyle
|
- (NSString *) contactsListContentStyle
|
||||||
|
@ -421,7 +361,8 @@
|
||||||
[self _setupContext];
|
[self _setupContext];
|
||||||
height = [moduleSettings objectForKey: @"DragHandleVertical"];
|
height = [moduleSettings objectForKey: @"DragHandleVertical"];
|
||||||
|
|
||||||
return ((height && [height intValue] > 0) ? [NSString stringWithFormat: @"%ipx", ([height intValue] - 27)] : nil);
|
return ((height && [height intValue] > 0)
|
||||||
|
? [NSString stringWithFormat: @"%ipx", ([height intValue] - 27)] : nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (WOResponse *) saveDragHandleStateAction
|
- (WOResponse *) saveDragHandleStateAction
|
||||||
|
|
|
@ -143,29 +143,23 @@
|
||||||
|
|
||||||
- (WOResponse *) propertiesAction
|
- (WOResponse *) propertiesAction
|
||||||
{
|
{
|
||||||
|
NSArray *references;
|
||||||
NSMutableArray *data;
|
NSMutableArray *data;
|
||||||
NGVCardReference *card;
|
NGVCardReference *card;
|
||||||
WOResponse *rc;
|
int count, max;
|
||||||
int i, count;
|
|
||||||
|
|
||||||
data = [NSMutableArray array];
|
list = [[self clientObject] vList];
|
||||||
co = [self clientObject];
|
references = [list cardReferences];
|
||||||
list = [co vList];
|
max = [references count];
|
||||||
|
data = [NSMutableArray arrayWithCapacity: max];
|
||||||
count = [[list cardReferences] count];
|
for (count = 0; count < max; count++)
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
card = [[list cardReferences] objectAtIndex: i];
|
card = [references objectAtIndex: count];
|
||||||
[data addObject: [NSArray arrayWithObjects: [card reference], [card fn],
|
[data addObject: [NSArray arrayWithObjects: [card reference],
|
||||||
[card email], nil]];
|
[card fn], [card email], nil]];
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = [context response];
|
return [self responseWithStatus: 200 andJSONRepresentation: data];
|
||||||
[rc setHeader: @"text/plain; charset=utf-8"
|
|
||||||
forKey: @"content-type"];
|
|
||||||
[rc appendContentString: [data jsonRepresentation]];
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -23,11 +23,6 @@
|
||||||
pageName = "UIxContactFoldersView";
|
pageName = "UIxContactFoldersView";
|
||||||
actionName = "mailerContacts";
|
actionName = "mailerContacts";
|
||||||
};
|
};
|
||||||
contactSearch = {
|
|
||||||
protectedBy = "<public>";
|
|
||||||
pageName = "UIxContactFoldersView";
|
|
||||||
actionName = "contactSearch";
|
|
||||||
};
|
|
||||||
allContactSearch = {
|
allContactSearch = {
|
||||||
protectedBy = "<public>";
|
protectedBy = "<public>";
|
||||||
pageName = "UIxContactFoldersView";
|
pageName = "UIxContactFoldersView";
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
- (WOResponse *) acceptAction;
|
- (WOResponse *) acceptAction;
|
||||||
- (WOResponse *) declineAction;
|
- (WOResponse *) declineAction;
|
||||||
|
- (WOResponse *) tentativeAction;
|
||||||
|
- (WOResponse *) delegateAction;
|
||||||
- (WOResponse *) addToCalendarAction;
|
- (WOResponse *) addToCalendarAction;
|
||||||
- (WOResponse *) deleteFromCalendarAction;
|
- (WOResponse *) deleteFromCalendarAction;
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
#import <Mailer/SOGoMailObject.h>
|
#import <Mailer/SOGoMailObject.h>
|
||||||
#import <SOGo/SOGoParentFolder.h>
|
#import <SOGo/SOGoParentFolder.h>
|
||||||
#import <SOGo/SOGoUser.h>
|
#import <SOGo/SOGoUser.h>
|
||||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
|
||||||
#import <Mailer/SOGoMailBodyPart.h>
|
#import <Mailer/SOGoMailBodyPart.h>
|
||||||
|
|
||||||
#import "UIxMailPartICalActions.h"
|
#import "UIxMailPartICalActions.h"
|
||||||
|
@ -261,6 +260,12 @@
|
||||||
withDelegate: nil];
|
withDelegate: nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (WOResponse *) tentativeAction
|
||||||
|
{
|
||||||
|
return [self _changePartStatusAction: @"TENTATIVE"
|
||||||
|
withDelegate: nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (WOResponse *) delegateAction
|
- (WOResponse *) delegateAction
|
||||||
{
|
{
|
||||||
// BOOL receiveUpdates;
|
// BOOL receiveUpdates;
|
||||||
|
@ -369,7 +374,7 @@
|
||||||
address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0];
|
address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0];
|
||||||
emailFrom = [address baseEMail];
|
emailFrom = [address baseEMail];
|
||||||
|
|
||||||
return [event findParticipantWithEmail: emailFrom];
|
return [event findAttendeeWithEmail: emailFrom];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) _updateParticipantStatusInEvent: (iCalEvent *) calendarEvent
|
- (BOOL) _updateParticipantStatusInEvent: (iCalEvent *) calendarEvent
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
#import <SOGo/SOGoUser.h>
|
#import <SOGo/SOGoUser.h>
|
||||||
#import <SOGo/SOGoUserFolder.h>
|
#import <SOGo/SOGoUserFolder.h>
|
||||||
#import <SOGo/SOGoUserDefaults.h>
|
#import <SOGo/SOGoUserDefaults.h>
|
||||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
|
||||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||||
#import <Appointments/SOGoAppointmentFolder.h>
|
#import <Appointments/SOGoAppointmentFolder.h>
|
||||||
#import <Appointments/SOGoAppointmentObject.h>
|
#import <Appointments/SOGoAppointmentObject.h>
|
||||||
|
@ -378,7 +377,7 @@
|
||||||
|
|
||||||
- (BOOL) isLoggedInUserAnAttendee
|
- (BOOL) isLoggedInUserAnAttendee
|
||||||
{
|
{
|
||||||
return [[self authorativeEvent] userIsParticipant: [context activeUser]];
|
return [[self authorativeEvent] userIsAttendee: [context activeUser]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) currentAttendeeClass
|
- (NSString *) currentAttendeeClass
|
||||||
|
@ -451,7 +450,7 @@
|
||||||
{
|
{
|
||||||
iCalPerson *currentUser;
|
iCalPerson *currentUser;
|
||||||
|
|
||||||
currentUser = [[self authorativeEvent] findParticipant: [context activeUser]];
|
currentUser = [[self authorativeEvent] userAsAttendee: [context activeUser]];
|
||||||
|
|
||||||
return currentUser;
|
return currentUser;
|
||||||
}
|
}
|
||||||
|
@ -463,7 +462,7 @@
|
||||||
should translate the email to an internal uid and then retrieve
|
should translate the email to an internal uid and then retrieve
|
||||||
all emails addresses for matching the participant.
|
all emails addresses for matching the participant.
|
||||||
|
|
||||||
Note: -findParticipantWithEmail: does not parse the email!
|
Note: -findAttendeeWithEmail: does not parse the email!
|
||||||
*/
|
*/
|
||||||
iCalEvent *e;
|
iCalEvent *e;
|
||||||
iCalPerson *p;
|
iCalPerson *p;
|
||||||
|
@ -473,9 +472,9 @@
|
||||||
e = [self storedEvent];
|
e = [self storedEvent];
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
p = [e findParticipantWithEmail: [self replySenderBaseEMail]];
|
p = [e findAttendeeWithEmail: [self replySenderBaseEMail]];
|
||||||
if (!p)
|
if (!p)
|
||||||
p = [e findParticipantWithEmail:[self replySenderEMail]];
|
p = [e findAttendeeWithEmail:[self replySenderEMail]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
@ -496,7 +495,7 @@
|
||||||
address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0];
|
address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0];
|
||||||
emailFrom = [address baseEMail];
|
emailFrom = [address baseEMail];
|
||||||
|
|
||||||
return [event findParticipantWithEmail: emailFrom];
|
return [event findAttendeeWithEmail: emailFrom];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) hasSenderStatusChanged
|
- (BOOL) hasSenderStatusChanged
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
actionClass = "UIxMailPartICalActions";
|
actionClass = "UIxMailPartICalActions";
|
||||||
actionName = "decline";
|
actionName = "decline";
|
||||||
};
|
};
|
||||||
|
tentative = {
|
||||||
|
protectedBy = "View";
|
||||||
|
actionClass = "UIxMailPartICalActions";
|
||||||
|
actionName = "tentative";
|
||||||
|
};
|
||||||
delegate = {
|
delegate = {
|
||||||
protectedBy = "View";
|
protectedBy = "View";
|
||||||
actionClass = "UIxMailPartICalActions";
|
actionClass = "UIxMailPartICalActions";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "A data que você informou ocorre antes da data ini
|
||||||
= "Você tem certeza que quer apagar o calendário \"%{0}\"?";
|
= "Você tem certeza que quer apagar o calendário \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Participante Requerido";
|
"Participant" = "Participante";
|
||||||
"Optional participant" = "Participante Opcional";
|
"Optional Participant" = "Participante Opcional";
|
||||||
|
"Non Participant" = "Não Participante";
|
||||||
"Chair" = "Cadeira";
|
"Chair" = "Cadeira";
|
||||||
|
|
||||||
"Needs action" = "Ações necessárias";
|
"Needs action" = "Ações necessárias";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "Zadané datum konce je před začátkem události.
|
||||||
= "Opravdu chcete smazat kalendář \"%{0}\"?";
|
= "Opravdu chcete smazat kalendář \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Vyžadovaný účastník";
|
"Participant" = "Účastník";
|
||||||
"Optional participant" = "Nepovinný účastník";
|
"Optional Participant" = "Nepovinný účastník";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Židle";
|
"Chair" = "Židle";
|
||||||
|
|
||||||
"Needs action" = "Vyžaduje akci";
|
"Needs action" = "Vyžaduje akci";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "Het begin vindt plaats vóór het einde.";
|
||||||
= "Weet u zeker dat u de agenda \"%{0}\" wilt verwijderen?";
|
= "Weet u zeker dat u de agenda \"%{0}\" wilt verwijderen?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Vereiste deelnemer";
|
"Participant" = "Deelnemer";
|
||||||
"Optional participant" = "Gewenste deelnemer";
|
"Optional Participant" = "Gewenste deelnemer";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Voorzitter";
|
"Chair" = "Voorzitter";
|
||||||
|
|
||||||
"Needs action" = "Actie vereist";
|
"Needs action" = "Actie vereist";
|
||||||
|
|
|
@ -246,10 +246,10 @@
|
||||||
|
|
||||||
/* Appointments (participation state) */
|
/* Appointments (participation state) */
|
||||||
|
|
||||||
"partStat_NEEDS-ACTION" = "Needs action";
|
"partStat_NEEDS-ACTION" = "I will confirm later";
|
||||||
"partStat_ACCEPTED" = "I will attend";
|
"partStat_ACCEPTED" = "I will attend";
|
||||||
"partStat_DECLINED" = "I will not attend";
|
"partStat_DECLINED" = "I will not attend";
|
||||||
"partStat_TENTATIVE" = "I will confirm later";
|
"partStat_TENTATIVE" = "I might attend";
|
||||||
"partStat_DELEGATED" = "I delegate";
|
"partStat_DELEGATED" = "I delegate";
|
||||||
"partStat_OTHER" = "Other";
|
"partStat_OTHER" = "Other";
|
||||||
|
|
||||||
|
@ -460,8 +460,9 @@ validate_endbeforestart = "The end date that you entered occurs before the st
|
||||||
= "Are you sure you want to delete the calendar \"%{0}\"?";
|
= "Are you sure you want to delete the calendar \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Required participant";
|
"Participant" = "Participant";
|
||||||
"Optional participant" = "Optional participant";
|
"Optional Participant" = "Optional Participant";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Chair";
|
"Chair" = "Chair";
|
||||||
|
|
||||||
"Needs action" = "Needs action";
|
"Needs action" = "Needs action";
|
||||||
|
|
|
@ -246,10 +246,10 @@
|
||||||
|
|
||||||
/* Appointments (participation state) */
|
/* Appointments (participation state) */
|
||||||
|
|
||||||
"partStat_NEEDS-ACTION" = "Décision attendue";
|
"partStat_NEEDS-ACTION" = "Je confirmerai plus tard";
|
||||||
"partStat_ACCEPTED" = "Je participerai";
|
"partStat_ACCEPTED" = "Je participerai";
|
||||||
"partStat_DECLINED" = "Je ne participerai pas";
|
"partStat_DECLINED" = "Je ne participerai pas";
|
||||||
"partStat_TENTATIVE" = "Je confirmerai plus tard";
|
"partStat_TENTATIVE" = "Je participerai peut-être";
|
||||||
"partStat_DELEGATED" = "Je délègue";
|
"partStat_DELEGATED" = "Je délègue";
|
||||||
"partStat_OTHER" = "???";
|
"partStat_OTHER" = "???";
|
||||||
|
|
||||||
|
@ -460,9 +460,10 @@ validate_endbeforestart = "La date de fin est avant la date de début.";
|
||||||
= "Voulez-vous vraiment supprimer l'agenda «%{0}»?";
|
= "Voulez-vous vraiment supprimer l'agenda «%{0}»?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Participant obligatoire";
|
"Participant" = "Invité";
|
||||||
"Optional participant" = "Participant facultatif";
|
"Optional Participant" = "Invité optionnel";
|
||||||
"Chair" = "Chaise";
|
"Non Participant" = "Non-invité";
|
||||||
|
"Chair" = "Président";
|
||||||
|
|
||||||
"Needs action" = "En attente";
|
"Needs action" = "En attente";
|
||||||
"Accepted" = "Accepté";
|
"Accepted" = "Accepté";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "Ihr Beginn ist nach dem Ende";
|
||||||
= "Wollen Sie diesen Kalender wirklich löschen \"%{0}\"?";
|
= "Wollen Sie diesen Kalender wirklich löschen \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "notwendiger Teilnehmer";
|
"Participant" = "Teilnehmer";
|
||||||
"Optional participant" = "optionaler Teilnehmer";
|
"Optional Participant" = "optionaler Teilnehmer";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Vorsitz";
|
"Chair" = "Vorsitz";
|
||||||
|
|
||||||
"Needs action" = "Benötigt Eingriff";
|
"Needs action" = "Benötigt Eingriff";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "A megadott befejező dátum korábbi, mint a kezd
|
||||||
= "Biztosan törli ezt a naptárat: \"%{0}\"?";
|
= "Biztosan törli ezt a naptárat: \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Kötelező résztvevő";
|
"Participant" = "Kötelező résztvevő";
|
||||||
"Optional participant" = "Nem kötelező résztvevő";
|
"Optional Participant" = "Nem kötelező résztvevő";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Szék";
|
"Chair" = "Szék";
|
||||||
|
|
||||||
"Needs action" = "Foglalkozni kell vele";
|
"Needs action" = "Foglalkozni kell vele";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "La data finale specificata è precedente alla data
|
||||||
= "Sei sicuro di voler cancellare il calendario \"%{0}\"?";
|
= "Sei sicuro di voler cancellare il calendario \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Richiede partecipanti";
|
"Participant" = "Partecipanti";
|
||||||
"Optional participant" = "Partecipanti opzionali";
|
"Optional Participant" = "Partecipanti opzionali";
|
||||||
|
"Non Participant" = "Non Partecipanti";
|
||||||
"Chair" = "Sedia";
|
"Chair" = "Sedia";
|
||||||
|
|
||||||
"Needs action" = "Richiede un'azione";
|
"Needs action" = "Richiede un'azione";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "The end date that you entered occurs before the st
|
||||||
= "Вы уверены что хотите удалить календарь \"%{0}\"?";
|
= "Вы уверены что хотите удалить календарь \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Required participant";
|
"Participant" = "Participant";
|
||||||
"Optional participant" = "Optional participant";
|
"Optional Participant" = "Optional Participant";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Chair";
|
"Chair" = "Chair";
|
||||||
|
|
||||||
"Needs action" = "Needs action";
|
"Needs action" = "Needs action";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "Su fecha/hora de comienzo es posterio a la de fina
|
||||||
= "¿Está seguro/a que desea borrar el calendario \"%{0}\"?";
|
= "¿Está seguro/a que desea borrar el calendario \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Asistente obligatorio";
|
"Participant" = "Asistente";
|
||||||
"Optional participant" = "Asistentes opcionales";
|
"Optional Participant" = "Asistentes opcionales";
|
||||||
|
"Non Participant" = "Non Particpant";
|
||||||
"Chair" = "Presidente";
|
"Chair" = "Presidente";
|
||||||
|
|
||||||
"Needs action" = "Requiere intervención";
|
"Needs action" = "Requiere intervención";
|
||||||
|
|
|
@ -460,8 +460,9 @@ validate_endbeforestart = "Angivet slutdatumet inträffar före angivet start
|
||||||
= "Är du säker på att du vill ta bort kalendern \"%{0}\"?";
|
= "Är du säker på att du vill ta bort kalendern \"%{0}\"?";
|
||||||
|
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Deltagande krävs";
|
"Participant" = "Deltagande krävs";
|
||||||
"Optional participant" = "Deltagande valfritt";
|
"Optional Participant" = "Deltagande valfritt";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Stol";
|
"Chair" = "Stol";
|
||||||
|
|
||||||
"Needs action" = "Behöver åtgärd";
|
"Needs action" = "Behöver åtgärd";
|
||||||
|
|
|
@ -522,22 +522,32 @@
|
||||||
[event setTransparency: (isTransparent? @"TRANSPARENT" : @"OPAQUE")];
|
[event setTransparency: (isTransparent? @"TRANSPARENT" : @"OPAQUE")];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add tentatively
|
- (id) _statusChangeAction: (NSString *) newStatus
|
||||||
|
{
|
||||||
|
[[self clientObject] changeParticipationStatus: newStatus
|
||||||
|
withDelegate: nil];
|
||||||
|
|
||||||
|
return [self responseWith204];
|
||||||
|
}
|
||||||
|
|
||||||
- (id) acceptAction
|
- (id) acceptAction
|
||||||
{
|
{
|
||||||
[[self clientObject] changeParticipationStatus: @"ACCEPTED"
|
return [self _statusChangeAction: @"ACCEPTED"];
|
||||||
withDelegate: nil];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) declineAction
|
- (id) declineAction
|
||||||
{
|
{
|
||||||
[[self clientObject] changeParticipationStatus: @"DECLINED"
|
return [self _statusChangeAction: @"DECLINED"];
|
||||||
withDelegate: nil];
|
}
|
||||||
|
|
||||||
return self;
|
- (id) needsActionAction
|
||||||
|
{
|
||||||
|
return [self _statusChangeAction: @"NEEDS-ACTION"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) tentativeAction
|
||||||
|
{
|
||||||
|
return [self _statusChangeAction: @"TENTATIVE"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) delegateAction
|
- (id) delegateAction
|
||||||
|
@ -584,7 +594,7 @@
|
||||||
reason: @"missing 'to' parameter"];
|
reason: @"missing 'to' parameter"];
|
||||||
|
|
||||||
if (!response)
|
if (!response)
|
||||||
response = [self responseWithStatus: 200];
|
response = [self responseWith204];
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
#import <Appointments/SOGoAppointmentObject.h>
|
#import <Appointments/SOGoAppointmentObject.h>
|
||||||
#import <Appointments/SOGoAppointmentOccurence.h>
|
#import <Appointments/SOGoAppointmentOccurence.h>
|
||||||
#import <Appointments/SOGoTaskObject.h>
|
#import <Appointments/SOGoTaskObject.h>
|
||||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
|
||||||
#import <SOGo/NSArray+Utilities.h>
|
#import <SOGo/NSArray+Utilities.h>
|
||||||
#import <SOGo/NSDictionary+BSJSONAdditions.h>
|
#import <SOGo/NSDictionary+BSJSONAdditions.h>
|
||||||
#import <SOGo/NSDictionary+Utilities.h>
|
#import <SOGo/NSDictionary+Utilities.h>
|
||||||
|
@ -268,6 +267,8 @@ iRANGE(2);
|
||||||
|
|
||||||
[currentAttendeeData setObject: [[currentAttendee partStat] lowercaseString]
|
[currentAttendeeData setObject: [[currentAttendee partStat] lowercaseString]
|
||||||
forKey: @"partstat"];
|
forKey: @"partstat"];
|
||||||
|
[currentAttendeeData setObject: [[currentAttendee role] lowercaseString]
|
||||||
|
forKey: @"role"];
|
||||||
|
|
||||||
if ([[currentAttendee delegatedTo] length])
|
if ([[currentAttendee delegatedTo] length])
|
||||||
[currentAttendeeData setObject: [[currentAttendee delegatedTo] rfc822Email]
|
[currentAttendeeData setObject: [[currentAttendee delegatedTo] rfc822Email]
|
||||||
|
@ -587,7 +588,7 @@ iRANGE(2);
|
||||||
um = [SOGoUserManager sharedUserManager];
|
um = [SOGoUserManager sharedUserManager];
|
||||||
owner = [componentCalendar ownerInContext: context];
|
owner = [componentCalendar ownerInContext: context];
|
||||||
ownerEmail = [um getEmailForUID: owner];
|
ownerEmail = [um getEmailForUID: owner];
|
||||||
ASSIGN (ownerAsAttendee, [component findParticipantWithEmail: (id)ownerEmail]);
|
ASSIGN (ownerAsAttendee, [component findAttendeeWithEmail: (id)ownerEmail]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// /* cycles */
|
// /* cycles */
|
||||||
|
@ -990,14 +991,26 @@ iRANGE(2);
|
||||||
{
|
{
|
||||||
NSString *word;
|
NSString *word;
|
||||||
|
|
||||||
if ([item intValue] == iCalPersonPartStatAccepted)
|
switch ([item intValue])
|
||||||
word = @"ACCEPTED";
|
{
|
||||||
else if ([item intValue] == iCalPersonPartStatDeclined)
|
case iCalPersonPartStatAccepted:
|
||||||
word = @"DECLINED";
|
word = @"ACCEPTED";
|
||||||
else if ([item intValue] == iCalPersonPartStatDelegated)
|
break;
|
||||||
word = @"DELEGATED";
|
case iCalPersonPartStatDeclined:
|
||||||
else
|
word = @"DECLINED";
|
||||||
word = @"UNKNOWN";
|
break;
|
||||||
|
case iCalPersonPartStatNeedsAction:
|
||||||
|
word = @"NEEDS-ACTION";
|
||||||
|
break;
|
||||||
|
case iCalPersonPartStatTentative:
|
||||||
|
word = @"TENTATIVE";
|
||||||
|
break;
|
||||||
|
case iCalPersonPartStatDelegated:
|
||||||
|
word = @"DELEGATED";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
word = @"UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
return [self labelForKey: [NSString stringWithFormat: @"partStat_%@", word]];
|
return [self labelForKey: [NSString stringWithFormat: @"partStat_%@", word]];
|
||||||
}
|
}
|
||||||
|
@ -1005,8 +1018,10 @@ iRANGE(2);
|
||||||
- (NSArray *) replyList
|
- (NSArray *) replyList
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObjects:
|
return [NSArray arrayWithObjects:
|
||||||
[NSNumber numberWithInt: iCalPersonPartStatAccepted],
|
[NSNumber numberWithInt: iCalPersonPartStatAccepted],
|
||||||
[NSNumber numberWithInt: iCalPersonPartStatDeclined],
|
[NSNumber numberWithInt: iCalPersonPartStatDeclined],
|
||||||
|
[NSNumber numberWithInt: iCalPersonPartStatNeedsAction],
|
||||||
|
[NSNumber numberWithInt: iCalPersonPartStatTentative],
|
||||||
[NSNumber numberWithInt: iCalPersonPartStatDelegated],
|
[NSNumber numberWithInt: iCalPersonPartStatDelegated],
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
|
@ -1508,7 +1523,7 @@ RANGE(2);
|
||||||
unsigned int count, max;
|
unsigned int count, max;
|
||||||
NSString *currentEmail;
|
NSString *currentEmail;
|
||||||
iCalPerson *currentAttendee;
|
iCalPerson *currentAttendee;
|
||||||
NSString *json;
|
NSString *json, *role, *partstat;
|
||||||
NSDictionary *attendeesData;
|
NSDictionary *attendeesData;
|
||||||
NSArray *attendees;
|
NSArray *attendees;
|
||||||
NSDictionary *currentData;
|
NSDictionary *currentData;
|
||||||
|
@ -1529,17 +1544,33 @@ RANGE(2);
|
||||||
{
|
{
|
||||||
currentData = [attendees objectAtIndex: count];
|
currentData = [attendees objectAtIndex: count];
|
||||||
currentEmail = [currentData objectForKey: @"email"];
|
currentEmail = [currentData objectForKey: @"email"];
|
||||||
currentAttendee = [component findParticipantWithEmail: currentEmail];
|
role = [[currentData objectForKey: @"role"] uppercaseString];
|
||||||
|
if (!role)
|
||||||
|
role = @"REQ-PARTICIPANT";
|
||||||
|
if ([role isEqualToString: @"NON-PARTICIPANT"])
|
||||||
|
partstat = @"";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partstat = [[currentData objectForKey: @"partstat"]
|
||||||
|
uppercaseString];
|
||||||
|
if (!partstat)
|
||||||
|
partstat = @"NEEDS-ACTION";
|
||||||
|
}
|
||||||
|
currentAttendee = [component findAttendeeWithEmail: currentEmail];
|
||||||
if (!currentAttendee)
|
if (!currentAttendee)
|
||||||
{
|
{
|
||||||
currentAttendee = [iCalPerson elementWithTag: @"attendee"];
|
currentAttendee = [iCalPerson elementWithTag: @"attendee"];
|
||||||
[currentAttendee setCn: [currentData objectForKey: @"name"]];
|
[currentAttendee setCn: [currentData objectForKey: @"name"]];
|
||||||
[currentAttendee setEmail: currentEmail];
|
[currentAttendee setEmail: currentEmail];
|
||||||
[currentAttendee setRole: @"REQ-PARTICIPANT"];
|
// [currentAttendee
|
||||||
[currentAttendee setRsvp: @"TRUE"];
|
// setParticipationStatus: iCalPersonPartStatNeedsAction];
|
||||||
[currentAttendee
|
|
||||||
setParticipationStatus: iCalPersonPartStatNeedsAction];
|
|
||||||
}
|
}
|
||||||
|
[currentAttendee
|
||||||
|
setRsvp: ([role isEqualToString: @"NON-PARTICIPANT"]
|
||||||
|
? @"FALSE"
|
||||||
|
: @"TRUE")];
|
||||||
|
[currentAttendee setRole: role];
|
||||||
|
[currentAttendee setPartStat: partstat];
|
||||||
[newAttendees addObject: currentAttendee];
|
[newAttendees addObject: currentAttendee];
|
||||||
}
|
}
|
||||||
[component setAttendees: newAttendees];
|
[component setAttendees: newAttendees];
|
||||||
|
@ -1965,8 +1996,7 @@ RANGE(2);
|
||||||
isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]];
|
isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]];
|
||||||
|
|
||||||
if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]]
|
if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]]
|
||||||
|| ([[component attendees] count]
|
|| ([component userIsAttendee: ownerUser]
|
||||||
&& [component userIsParticipant: ownerUser]
|
|
||||||
&& !isOrganizer
|
&& !isOrganizer
|
||||||
// Lightning does not manage participation status within tasks,
|
// Lightning does not manage participation status within tasks,
|
||||||
// so we also ignore the participation status of tasks in the
|
// so we also ignore the participation status of tasks in the
|
||||||
|
@ -1991,14 +2021,12 @@ RANGE(2);
|
||||||
{
|
{
|
||||||
SoSecurityManager *sm;
|
SoSecurityManager *sm;
|
||||||
NSString *toolbarFilename, *adminToolbar;
|
NSString *toolbarFilename, *adminToolbar;
|
||||||
SOGoUser *currentUser;
|
|
||||||
|
|
||||||
if ([clientObject isKindOfClass: [SOGoAppointmentObject class]])
|
if ([clientObject isKindOfClass: [SOGoAppointmentObject class]])
|
||||||
adminToolbar = @"SOGoAppointmentObject.toolbar";
|
adminToolbar = @"SOGoAppointmentObject.toolbar";
|
||||||
else
|
else
|
||||||
adminToolbar = @"SOGoTaskObject.toolbar";
|
adminToolbar = @"SOGoTaskObject.toolbar";
|
||||||
|
|
||||||
currentUser = [context activeUser];
|
|
||||||
sm = [SoSecurityManager sharedSecurityManager];
|
sm = [SoSecurityManager sharedSecurityManager];
|
||||||
|
|
||||||
if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
|
if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
|
||||||
|
@ -2035,36 +2063,45 @@ RANGE(2);
|
||||||
|
|
||||||
|
|
||||||
- (int) ownerIsAttendee: (SOGoUser *) ownerUser
|
- (int) ownerIsAttendee: (SOGoUser *) ownerUser
|
||||||
andClientObject: (SOGoContentObject
|
andClientObject: (SOGoContentObject
|
||||||
<SOGoComponentOccurence> *) clientObject
|
<SOGoComponentOccurence> *) clientObject
|
||||||
{
|
{
|
||||||
BOOL isOrganizer;
|
BOOL isOrganizer;
|
||||||
int rc = 0;
|
iCalPerson *ownerAttendee;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
isOrganizer = [component userIsOrganizer: ownerUser];
|
isOrganizer = [component userIsOrganizer: ownerUser];
|
||||||
if (isOrganizer)
|
if (isOrganizer)
|
||||||
isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]];
|
isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]];
|
||||||
|
|
||||||
if ([[component attendees] count]
|
if (!isOrganizer && ![[component tag] isEqualToString: @"VTODO"])
|
||||||
&& [component userIsParticipant: ownerUser]
|
{
|
||||||
&& !isOrganizer
|
ownerAttendee = [component userAsAttendee: ownerUser];
|
||||||
&& ![[component tag] isEqualToString: @"VTODO"])
|
if (ownerAttendee)
|
||||||
rc = 1;
|
{
|
||||||
|
if ([[ownerAttendee rsvp] isEqualToString: @"true"])
|
||||||
|
rc = 1;
|
||||||
|
else
|
||||||
|
rc = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int) delegateIsAttendee: (SOGoUser *) ownerUser
|
- (int) delegateIsAttendee: (SOGoUser *) ownerUser
|
||||||
andClientObject: (SOGoContentObject
|
andClientObject: (SOGoContentObject
|
||||||
<SOGoComponentOccurence> *) clientObject
|
<SOGoComponentOccurence> *) clientObject
|
||||||
{
|
{
|
||||||
SoSecurityManager *sm;
|
SoSecurityManager *sm;
|
||||||
SOGoUser *currentUser;
|
iCalPerson *ownerAttendee;
|
||||||
int rc = 0;
|
int rc;
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
currentUser = [context activeUser];
|
|
||||||
sm = [SoSecurityManager sharedSecurityManager];
|
sm = [SoSecurityManager sharedSecurityManager];
|
||||||
|
|
||||||
if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
|
if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
|
||||||
onObject: clientObject
|
onObject: clientObject
|
||||||
inContext: context])
|
inContext: context])
|
||||||
|
@ -2072,11 +2109,15 @@ RANGE(2);
|
||||||
andClientObject: clientObject];
|
andClientObject: clientObject];
|
||||||
else if (![sm validatePermission: SOGoCalendarPerm_RespondToComponent
|
else if (![sm validatePermission: SOGoCalendarPerm_RespondToComponent
|
||||||
onObject: clientObject
|
onObject: clientObject
|
||||||
inContext: context]
|
inContext: context])
|
||||||
&& [[component attendees] count]
|
{
|
||||||
&& [component userIsParticipant: ownerUser]
|
ownerAttendee = [component userAsAttendee: ownerUser];
|
||||||
&& ![component userIsOrganizer: ownerUser])
|
if ([[ownerAttendee rsvp] isEqualToString: @"true"]
|
||||||
rc = 1;
|
&& ![component userIsOrganizer: ownerUser])
|
||||||
|
rc = 1;
|
||||||
|
else
|
||||||
|
rc = 2;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rc = 2; // not invited, just RO
|
rc = 2; // not invited, just RO
|
||||||
|
|
||||||
|
@ -2090,9 +2131,8 @@ RANGE(2);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
clientObject = [self clientObject];
|
clientObject = [self clientObject];
|
||||||
ownerUser = [SOGoUser userWithLogin: [clientObject ownerInContext: context]
|
ownerUser
|
||||||
roles: nil];
|
= [SOGoUser userWithLogin: [clientObject ownerInContext: context]];
|
||||||
|
|
||||||
if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]])
|
if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]])
|
||||||
rc = 2;
|
rc = 2;
|
||||||
else
|
else
|
||||||
|
@ -2113,9 +2153,54 @@ RANGE(2);
|
||||||
return [self getEventRWType] != 0;
|
return [self getEventRWType] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) userIsAttendee
|
- (BOOL) userHasRSVP
|
||||||
{
|
{
|
||||||
return [self getEventRWType] == 1;
|
return ([self getEventRWType] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) currentAttendeeClasses
|
||||||
|
{
|
||||||
|
NSMutableArray *classes;
|
||||||
|
iCalPerson *ownerAttendee;
|
||||||
|
SOGoUser *ownerUser;
|
||||||
|
NSString *role, *partStat;
|
||||||
|
SOGoCalendarComponent *co;
|
||||||
|
|
||||||
|
classes = [NSMutableArray arrayWithCapacity: 5];
|
||||||
|
|
||||||
|
/* rsvp class */
|
||||||
|
if (![[attendee rsvp] isEqualToString: @"true"])
|
||||||
|
[classes addObject: @"not-rsvp"];
|
||||||
|
|
||||||
|
/* partstat class */
|
||||||
|
partStat = [[attendee partStat] lowercaseString];
|
||||||
|
if (![partStat length])
|
||||||
|
partStat = @"no-partstat";
|
||||||
|
[classes addObject: partStat];
|
||||||
|
|
||||||
|
/* role class */
|
||||||
|
role = [[attendee role] lowercaseString];
|
||||||
|
if (![partStat length])
|
||||||
|
role = @"no-role";
|
||||||
|
[classes addObject: role];
|
||||||
|
|
||||||
|
/* attendee class */
|
||||||
|
if ([[attendee delegatedFrom] length] > 0)
|
||||||
|
[classes addObject: @"delegate"];
|
||||||
|
|
||||||
|
/* current attendee class */
|
||||||
|
co = [self clientObject];
|
||||||
|
ownerUser = [SOGoUser userWithLogin: [co ownerInContext: context]];
|
||||||
|
ownerAttendee = [component userAsAttendee: ownerUser];
|
||||||
|
if (attendee == ownerAttendee)
|
||||||
|
[classes addObject: @"attendeeUser"];
|
||||||
|
|
||||||
|
return [classes componentsJoinedByString: @" "];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) ownerLogin
|
||||||
|
{
|
||||||
|
return [[self clientObject] ownerInContext: context];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -462,6 +462,7 @@ validate_endbeforestart = "Mae'r dyddiad gorffen sydd wedi'i roi yn digwydd c
|
||||||
/* Legend */
|
/* Legend */
|
||||||
"Required participant" = "Cyfranogwr gofynnol";
|
"Required participant" = "Cyfranogwr gofynnol";
|
||||||
"Optional participant" = "Cyfranogwr opsiynol";
|
"Optional participant" = "Cyfranogwr opsiynol";
|
||||||
|
"Non Participant" = "Non Participant";
|
||||||
"Chair" = "Cadair";
|
"Chair" = "Cadair";
|
||||||
|
|
||||||
"Needs action" = "Angen gweithred";
|
"Needs action" = "Angen gweithred";
|
||||||
|
|
|
@ -235,6 +235,16 @@
|
||||||
pageName = "UIxAppointmentEditor";
|
pageName = "UIxAppointmentEditor";
|
||||||
actionName = "delegate";
|
actionName = "delegate";
|
||||||
};
|
};
|
||||||
|
tentative = {
|
||||||
|
protectedBy = "RespondToComponent";
|
||||||
|
pageName = "UIxAppointmentEditor";
|
||||||
|
actionName = "tentative";
|
||||||
|
};
|
||||||
|
needsaction = {
|
||||||
|
protectedBy = "RespondToComponent";
|
||||||
|
pageName = "UIxAppointmentEditor";
|
||||||
|
actionName = "needsAction";
|
||||||
|
};
|
||||||
adjust = {
|
adjust = {
|
||||||
protectedBy = "ModifyComponent";
|
protectedBy = "ModifyComponent";
|
||||||
actionClass = "UIxAppointmentActions";
|
actionClass = "UIxAppointmentActions";
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
<var:if condition="hasCalendarAccess">
|
<var:if condition="hasCalendarAccess">
|
||||||
<div class="uix_ical_toolbar" id="iCalendarToolbar">
|
<div class="uix_ical_toolbar" id="iCalendarToolbar">
|
||||||
<p>
|
<p>
|
||||||
|
<var:if condition="currentUserAttendee.rsvp" const:value="true">
|
||||||
<var:if condition="currentUserAttendee.partStatWithDefault"
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
||||||
const:value="ACCEPTED" const:negate="YES">
|
const:value="ACCEPTED" const:negate="YES">
|
||||||
<a href="#" class="button actionButton" id="iCalendarAccept">
|
<a href="#" class="button actionButton" id="iCalendarAccept">
|
||||||
|
@ -56,6 +57,11 @@
|
||||||
<span><var:string label:value="Decline" /></span></a>
|
<span><var:string label:value="Decline" /></span></a>
|
||||||
</var:if>
|
</var:if>
|
||||||
<var:if condition="currentUserAttendee.partStatWithDefault"
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
||||||
|
const:value="TENTATIVE" const:negate="YES">
|
||||||
|
<a href="#" class="button actionButton" id="iCalendarTentative">
|
||||||
|
<span><var:string label:value="Tentative" /></span></a>
|
||||||
|
</var:if>
|
||||||
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
||||||
const:value="DELEGATED" const:negate="YES">
|
const:value="DELEGATED" const:negate="YES">
|
||||||
<a href="#" class="button actionButton" id="editDelegate">
|
<a href="#" class="button actionButton" id="editDelegate">
|
||||||
<span><var:string label:value="Delegate ..." /></span></a>
|
<span><var:string label:value="Delegate ..." /></span></a>
|
||||||
|
@ -76,6 +82,7 @@
|
||||||
<span><var:string label:value="OK" /></span></a>
|
<span><var:string label:value="OK" /></span></a>
|
||||||
</span>
|
</span>
|
||||||
</var:if>
|
</var:if>
|
||||||
|
</var:if>
|
||||||
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
||||||
<a href="#" class="button actionButton" id="iCalendarAddToCalendar">
|
<a href="#" class="button actionButton" id="iCalendarAddToCalendar">
|
||||||
<span><var:string label:value="Add to calendar" /></span></a>
|
<span><var:string label:value="Add to calendar" /></span></a>
|
||||||
|
@ -223,7 +230,9 @@
|
||||||
<td valign="top"><var:string label:value="Attendees"/>:</td>
|
<td valign="top"><var:string label:value="Attendees"/>:</td>
|
||||||
<td id="iCalAttendees">
|
<td id="iCalAttendees">
|
||||||
<var:foreach list="authorativeEvent.participants" item="attendee">
|
<var:foreach list="authorativeEvent.participants" item="attendee">
|
||||||
<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:if condition="attendee.delegatedTo" const:negate="YES"><!-- don't show attendees that delegated the invitation --><span var:class="currentAttendeeClass"
|
||||||
|
><div class="status-icon"><!-- space --></div
|
||||||
|
><a var:href="attendee.email">
|
||||||
<var:string value="attendeeForDisplay"/></a>
|
<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>
|
(<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>
|
<br /></var:if>
|
||||||
|
|
|
@ -22,29 +22,23 @@
|
||||||
<div id="freeBusyViewButtons">
|
<div id="freeBusyViewButtons">
|
||||||
<var:string label:value="Suggest time slot:"/>
|
<var:string label:value="Suggest time slot:"/>
|
||||||
<span class="buttons"><a id="nextSlot" href="#" class="button"
|
<span class="buttons"><a id="nextSlot" href="#" class="button"
|
||||||
><span><var:string label:value="Next slot" /></span></a>
|
><span><var:string label:value="Next slot" /></span></a>
|
||||||
<a id="previousSlot" href="#" class="button"
|
<a id="previousSlot" href="#" class="button"
|
||||||
><span><var:string label:value="Previous slot" /></span></a></span>
|
><span><var:string label:value="Previous slot" /></span></a></span>
|
||||||
<input class="checkbox" type="checkbox"
|
<input class="checkbox" type="checkbox"
|
||||||
checked="1" id="onlyOfficeHours" /><var:string label:value="Only office hours" />
|
checked="1" id="onlyOfficeHours" /><var:string label:value="Only office hours" />
|
||||||
</div>
|
</div>
|
||||||
<div id="freeBusyView">
|
<div id="freeBusyView">
|
||||||
<table id="freeBusy" cellspacing="0" cellpadding="0"
|
<table id="freeBusy" cellspacing="0" cellpadding="0">
|
||||||
xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:var="http://www.skyrix.com/od/binding"
|
|
||||||
xmlns:const="http://www.skyrix.com/od/constant"
|
|
||||||
xmlns:uix="OGo:uix"
|
|
||||||
xmlns:rsrc="OGo:url"
|
|
||||||
xmlns:label="OGo:label">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td><!--space --></td>
|
<td><!--space --></td>
|
||||||
<td class="freeBusyHeader">
|
<td class="freeBusyHeader">
|
||||||
<div><table id="freeBusyHeader" cellspacing="0" cellpadding="0">
|
<div><table id="freeBusyHeader" cellspacing="0" cellpadding="0">
|
||||||
<tr class="freeBusyHeader1"><!--space --></tr>
|
<tr class="freeBusyHeader1"><!--space --></tr>
|
||||||
<tr class="freeBusyHeader2"><!--space --></tr>
|
<tr class="freeBusyHeader2"><!--space --></tr>
|
||||||
<tr id="currentEventPosition" class="freeBusyHeader3"><!--space --></tr>
|
<tr id="currentEventPosition" class="freeBusyHeader3"><!--space --></tr>
|
||||||
</table></div>
|
</table></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -52,25 +46,28 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="freeBusyAttendees">
|
<td class="freeBusyAttendees">
|
||||||
<div><table id="freeBusyAttendees" cellspacing="0" cellpadding="0">
|
<div><table id="freeBusyAttendees" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="futureAttendee"
|
<tr class="futureAttendee"
|
||||||
><td class="attendees"><a href="#" class="button"
|
><td class="attendeeStatus"><div><!-- space --></div></td
|
||||||
readonly="readonly"><span
|
><td class="attendees"><a href="#" class="button"
|
||||||
><var:string label:value="newAttendee" /></span></a></td
|
readonly="readonly"><span
|
||||||
></tr>
|
><var:string label:value="newAttendee" /></span></a></td
|
||||||
<tr class="attendeeModel"
|
></tr>
|
||||||
><td class="attendees"><input type="text" class="textField" /></td
|
<tr class="attendeeModel"
|
||||||
></tr>
|
><td class="attendeeStatus"><div><!-- space --></div></td
|
||||||
</tbody>
|
><td class="attendees"
|
||||||
</table></div>
|
><input type="text" class="textField" /></td
|
||||||
|
></tr>
|
||||||
|
</tbody>
|
||||||
|
</table></div>
|
||||||
</td>
|
</td>
|
||||||
<td class="freeBusyData">
|
<td class="freeBusyData">
|
||||||
<div><table id="freeBusyData" cellspacing="0" cellpadding="0">
|
<div><table id="freeBusyData" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="futureData"></tr>
|
<tr class="futureData"></tr>
|
||||||
<tr class="dataModel"></tr>
|
<tr class="dataModel"></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table></div>
|
</table></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -78,27 +75,38 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="freeBusyFooter">
|
<div id="freeBusyFooter">
|
||||||
<div id="legend" onmousedown="return false;">
|
<div id="legend" onmousedown="return false;">
|
||||||
<ul>
|
<ul class="roles-legend">
|
||||||
|
<li role="req-participant"><span class="role-icon"><!-- space --></span
|
||||||
|
><var:string label:value="Participant"/></li>
|
||||||
|
<li role="opt-participant"><span class="role-icon"><!-- space --></span
|
||||||
|
><var:string label:value="Optional Participant"/></li>
|
||||||
|
<li role="non-participant"><span class="role-icon"><!-- space --></span
|
||||||
|
><var:string label:value="Non Participant"/></li>
|
||||||
|
<li role="chair"><span class="role-icon"><!-- space --></span
|
||||||
|
><var:string label:value="Chair"/></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="freebusy-legend">
|
||||||
<li><span class="colorBox free"><!-- spacer --></span
|
<li><span class="colorBox free"><!-- spacer --></span
|
||||||
><var:string label:value="Free" /></li>
|
><var:string label:value="Free" /></li>
|
||||||
<li><span class="colorBox busy"><!-- spacer --></span
|
<li><span class="colorBox busy"><!-- spacer --></span
|
||||||
><var:string label:value="Busy" /></li>
|
><var:string label:value="Busy" /></li>
|
||||||
<!-- li><span class="colorBox maybe-busy">\- spacer -\->/span -->
|
<!-- li><span class="colorBox maybe-busy">\- spacer -\->/span -->
|
||||||
<!-- >var:string label:value="Maybe busy" />/li> -->
|
<!-- >var:string label:value="Maybe busy" />/li> -->
|
||||||
<li><span class="colorBox noFreeBusy"><!-- spacer --></span
|
<li><span class="colorBox noFreeBusy"><!-- spacer --></span
|
||||||
><var:string label:value="No free-busy information" /></li>
|
><var:string label:value="No free-busy information" /></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="freeBusyReplicas">
|
<div id="freeBusyReplicas">
|
||||||
<div><span><var:string label:value="Start:"
|
<div><span><var:string label:value="Start:"
|
||||||
/></span><var:component className="UIxTimeDateControl"
|
/></span><var:component className="UIxTimeDateControl"
|
||||||
const:controlID="startTime"
|
const:controlID="startTime"
|
||||||
date="aptStartDate"
|
date="aptStartDate"
|
||||||
const:dayStartHour="0"
|
const:dayStartHour="0"
|
||||||
const:dayEndHour="23"
|
const:dayEndHour="23"
|
||||||
/></div>
|
/></div>
|
||||||
<div><span><var:string label:value="End:"
|
<div><span><var:string label:value="End:"
|
||||||
/></span><var:component className="UIxTimeDateControl"
|
/></span><var:component className="UIxTimeDateControl"
|
||||||
const:controlID="endTime"
|
const:controlID="endTime"
|
||||||
date="aptEndDate"
|
date="aptEndDate"
|
||||||
const:dayStartHour="0"
|
const:dayStartHour="0"
|
||||||
|
@ -108,9 +116,9 @@
|
||||||
<div id="windowButtons">
|
<div id="windowButtons">
|
||||||
<hr />
|
<hr />
|
||||||
<a id="okButton" href="#" class="button actionButton"
|
<a id="okButton" href="#" class="button actionButton"
|
||||||
><span><var:string label:value="OK"/></span></a>
|
><span><var:string label:value="OK"/></span></a>
|
||||||
<a id="cancelButton" href="#" class="button"
|
<a id="cancelButton" href="#" class="button"
|
||||||
><span><var:string label:value="Cancel"/></span></a>
|
><span><var:string label:value="Cancel"/></span></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
var activeComponent = '<var:if condition="isChildOccurence"><var:string value="clientObject.container.nameInContainer"/>/</var:if><var:string value="clientObject.nameInContainer"/>';
|
var activeComponent = '<var:if condition="isChildOccurence"><var:string value="clientObject.container.nameInContainer"/>/</var:if><var:string value="clientObject.nameInContainer"/>';
|
||||||
var readOnly = <var:if condition="eventIsReadOnly">true</var:if><var:if condition="eventIsReadOnly"
|
var readOnly = <var:if condition="eventIsReadOnly">true</var:if><var:if condition="eventIsReadOnly"
|
||||||
const:negate="YES">false</var:if>;
|
const:negate="YES">false</var:if>;
|
||||||
var attendees = <var:string value="jsonAttendees" const:escapeHTML="NO" />;
|
var attendees = <var:string value="jsonAttendees" const:escapeHTML="NO"/>;
|
||||||
|
var ownerLogin = '<var:string value="ownerLogin"/>';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<var:if condition="eventIsReadOnly" const:negate="YES">
|
<var:if condition="eventIsReadOnly" const:negate="YES">
|
||||||
|
@ -203,11 +204,9 @@
|
||||||
<span class="content"><var:string value="organizerName"/></span>
|
<span class="content"><var:string value="organizerName"/></span>
|
||||||
</label>
|
</label>
|
||||||
</var:if>
|
</var:if>
|
||||||
<var:if condition="userIsAttendee">
|
<var:if condition="userHasRSVP">
|
||||||
<label><var:string label:value="Reply:" />
|
<label><var:string label:value="Reply:" />
|
||||||
<span class="content"><var:popup list="replyList" item="item"
|
<span class="content"><var:popup list="replyList" item="item"
|
||||||
const:disabledValue="-"
|
|
||||||
label:noSelectionString="partStat_NEEDS-ACTION"
|
|
||||||
const:name="replyList"
|
const:name="replyList"
|
||||||
const:id="replyList"
|
const:id="replyList"
|
||||||
string="itemReplyText"
|
string="itemReplyText"
|
||||||
|
@ -251,8 +250,17 @@
|
||||||
</label>
|
</label>
|
||||||
<label id="attendeesLabel">
|
<label id="attendeesLabel">
|
||||||
<span class="content"><div id="attendeesMenu" class="fakeTextArea">
|
<span class="content"><div id="attendeesMenu" class="fakeTextArea">
|
||||||
<var:foreach list="component.participants" item="attendee">
|
<var:foreach list="component.attendees" 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:if condition="attendee.delegatedTo" const:negate="YES"
|
||||||
|
><div var:class="currentAttendeeClasses"
|
||||||
|
><div const:class="statusIcon"><!-- space --></div
|
||||||
|
><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>
|
</var:foreach>
|
||||||
</div></span>
|
</div></span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -331,7 +339,7 @@
|
||||||
var:value="reminderReference"/>
|
var:value="reminderReference"/>
|
||||||
|
|
||||||
<div id="windowButtons">
|
<div id="windowButtons">
|
||||||
<var:if condition="userIsAttendee"><a id="okButton" href="#" class="button actionButton"
|
<var:if condition="userHasRSVP"><a id="okButton" href="#" class="button actionButton"
|
||||||
><span><var:string label:value="OK"/></span></a></var:if>
|
><span><var:string label:value="OK"/></span></a></var:if>
|
||||||
<a id="cancelButton" href="#" class="button"
|
<a id="cancelButton" href="#" class="button"
|
||||||
><span><var:string label:value="Cancel"/></span></a>
|
><span><var:string label:value="Cancel"/></span></a>
|
||||||
|
|
|
@ -796,22 +796,34 @@ TR#messageCountHeader TD
|
||||||
{ padding: 0; }
|
{ padding: 0; }
|
||||||
|
|
||||||
#iCalAttendees SPAN
|
#iCalAttendees SPAN
|
||||||
|
{ line-height: 19px; }
|
||||||
|
|
||||||
|
#iCalAttendees DIV.status-icon
|
||||||
{ background-repeat: no-repeat;
|
{ background-repeat: no-repeat;
|
||||||
background-position: 5px 1px;
|
float: left;
|
||||||
padding-left: 22px;
|
padding: 0px;
|
||||||
padding-right: 4px; }
|
clear: both;
|
||||||
|
width: 12px;
|
||||||
|
height: 18px;
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-left: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
background-image: url("attendee-partstats.png"); }
|
||||||
|
|
||||||
#iCalAttendees .accepted
|
#iCalAttendees .accepted DIV.status-icon
|
||||||
{ background-image: url("accepted.png"); }
|
{ background-position: 0px 0px; }
|
||||||
|
|
||||||
#iCalAttendees .needs-action
|
#iCalAttendees .declined DIV.status-icon
|
||||||
{ background-image: url("needs-action.png"); }
|
{ background-position: -12px 0px; }
|
||||||
|
|
||||||
#iCalAttendees .declined
|
#iCalAttendees .needs-action DIV.status-icon
|
||||||
{ background-image: url("declined.png"); }
|
{ background-position: -24px 0px; }
|
||||||
|
|
||||||
#iCalAttendees .delegated
|
#iCalAttendees .tentative DIV.status-icon
|
||||||
{ background-image: url("delegated.png"); }
|
{ background-position: -36px 0px; }
|
||||||
|
|
||||||
|
#iCalAttendees .delegated DIV.status-icon
|
||||||
|
{ background-position: -48px 0px; }
|
||||||
|
|
||||||
#iCalAttendees .attendeeUser,
|
#iCalAttendees .attendeeUser,
|
||||||
#iCalAttendees .attendeeUser A
|
#iCalAttendees .attendeeUser A
|
||||||
|
|
|
@ -1330,18 +1330,23 @@ DIV.event.alarm DIV.text
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: top right; }
|
background-position: top right; }
|
||||||
|
|
||||||
|
DIV.eventInside.tentative,
|
||||||
DIV.eventInside.needs-action
|
DIV.eventInside.needs-action
|
||||||
{ border: 1px dotted #666;
|
{ -moz-opacity: 0.7;
|
||||||
-moz-opacity: 0.6;
|
|
||||||
opacity: 0.7; }
|
opacity: 0.7; }
|
||||||
|
|
||||||
|
DIV.eventInside.needs-action
|
||||||
|
{ border: 2px dotted #000; }
|
||||||
|
|
||||||
|
DIV.eventInside.tentative DIV.text,
|
||||||
DIV.eventInside.needs-action DIV.text
|
DIV.eventInside.needs-action DIV.text
|
||||||
{ top: 0px;
|
{ top: 0px;
|
||||||
left: 0px; }
|
left: 2px; }
|
||||||
|
|
||||||
|
DIV.eventInside.delegated,
|
||||||
DIV.eventInside.declined
|
DIV.eventInside.declined
|
||||||
{ -moz-opacity: 0.3;
|
{ -moz-opacity: 0.4;
|
||||||
opacity: 0.3; }
|
opacity: 0.4; }
|
||||||
|
|
||||||
/* event DnD */
|
/* event DnD */
|
||||||
DIV.event DIV.topDragGrip,
|
DIV.event DIV.topDragGrip,
|
||||||
|
|
|
@ -25,7 +25,7 @@ var calendarEvents = null;
|
||||||
|
|
||||||
var preventAutoScroll = false;
|
var preventAutoScroll = false;
|
||||||
|
|
||||||
var userStates = [ "needs-action", "accepted", "declined", "tentative" ];
|
var userStates = [ "needs-action", "accepted", "declined", "tentative", "delegated" ];
|
||||||
|
|
||||||
var calendarHeaderAdjusted = false;
|
var calendarHeaderAdjusted = false;
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ function closeInvitationWindow() {
|
||||||
|
|
||||||
function modifyEventCallback(http) {
|
function modifyEventCallback(http) {
|
||||||
if (http.readyState == 4) {
|
if (http.readyState == 4) {
|
||||||
if (http.status == 200) {
|
if (isHttpStatus204(http.status) || http.status == 200) {
|
||||||
var mailInvitation = queryParameters["mail-invitation"];
|
var mailInvitation = queryParameters["mail-invitation"];
|
||||||
if (mailInvitation && mailInvitation.toLowerCase() == "yes")
|
if (mailInvitation && mailInvitation.toLowerCase() == "yes")
|
||||||
closeInvitationWindow();
|
closeInvitationWindow();
|
||||||
|
|
|
@ -122,42 +122,53 @@ A#attendeesHref
|
||||||
text-decoration: underline; }
|
text-decoration: underline; }
|
||||||
|
|
||||||
DIV#attendeesMenu LI
|
DIV#attendeesMenu LI
|
||||||
{ padding-left: 10px; }
|
{ padding-left: 10px;
|
||||||
|
width: auto; }
|
||||||
|
|
||||||
DIV#attendeesMenu .attendee,
|
DIV#attendeesMenu .attendeeUser
|
||||||
DIV#attendeesMenu DIV
|
{ font-weight: bold; }
|
||||||
|
|
||||||
|
DIV#attendeesMenu .opt-participant
|
||||||
|
{ font-style: italic; }
|
||||||
|
|
||||||
|
DIV#attendeesMenu .non-participant A
|
||||||
|
{ color: #888; }
|
||||||
|
|
||||||
|
#attendeesLabel DIV#attendeesMenu > DIV
|
||||||
|
{ margin-left: 4px; }
|
||||||
|
|
||||||
|
#attendeesLabel DIV#attendeesMenu > DIV,
|
||||||
|
DIV#attendeesMenu .attendee
|
||||||
|
{ height: 18px; }
|
||||||
|
|
||||||
|
#attendeesLabel DIV#attendeesMenu .statusIcon
|
||||||
|
{ margin-top: 4px; }
|
||||||
|
|
||||||
|
DIV#attendeesMenu .statusIcon
|
||||||
{ background-repeat: no-repeat;
|
{ background-repeat: no-repeat;
|
||||||
background-position: 5px center;
|
float: left;
|
||||||
padding-left: 22px; }
|
width: 12px;
|
||||||
|
height: 14px;
|
||||||
|
margin-right: 4px;
|
||||||
|
background-image: url("attendee-partstats.png"); }
|
||||||
|
|
||||||
DIV#attendeesMenu .accepted
|
DIV#attendeesMenu .accepted .statusIcon
|
||||||
{ background-image: url("accepted.png"); }
|
{ background-position: 0px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .accepted:hover
|
DIV#attendeesMenu .declined .statusIcon
|
||||||
{ background-image: url("accepted.selected.png"); }
|
{ background-position: -12px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .needs-action
|
DIV#attendeesMenu .needs-action .statusIcon
|
||||||
{ background-image: url("needs-action.png"); }
|
{ background-position: -24px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .needs-action:hover
|
DIV#attendeesMenu .tentative .statusIcon
|
||||||
{ background-image: url("needs-action.selected.png"); }
|
{ background-position: -36px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .declined
|
DIV#attendeesMenu .delegated .statusIcon
|
||||||
{ background-image: url("declined.png"); }
|
{ background-position: -48px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .declined:hover
|
DIV#attendeesMenu .no-partstat .statusIcon
|
||||||
{ background-image: url("declined.selected.png"); }
|
{ background-position: -60px 0px; }
|
||||||
|
|
||||||
DIV#attendeesMenu .delegated
|
|
||||||
{ background-image: url("delegated.png"); }
|
|
||||||
|
|
||||||
DIV#attendeesMenu .delegated:hover
|
|
||||||
{ background-image: url("delegated.selected.png"); }
|
|
||||||
|
|
||||||
DIV#attendeesMenu .delegate
|
DIV#attendeesMenu .delegate
|
||||||
{ background-position: 15px center;
|
{ padding-left: 16px !important; }
|
||||||
padding-left: 32px; }
|
|
||||||
|
|
||||||
/* read-only view */
|
|
||||||
DIV#attendeesMenu DIV
|
|
||||||
{ padding-left: 20px; }
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ function addContact(tag, fullContactName, contactId, contactName, contactEmail)
|
||||||
|
|
||||||
function saveEvent(sender) {
|
function saveEvent(sender) {
|
||||||
if (validateAptEditor()) {
|
if (validateAptEditor()) {
|
||||||
document.forms['editform'].attendees.value = attendees.toJSON();
|
document.forms['editform'].attendees.value = $(attendees).toJSON();
|
||||||
document.forms['editform'].submit();
|
document.forms['editform'].submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ function initTimeWidgets(widgets) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshAttendeesRO () {
|
function refreshAttendeesRO() {
|
||||||
var attendeesMenu = $("attendeesMenu");
|
var attendeesMenu = $("attendeesMenu");
|
||||||
var attendeesLabel = $("attendeesLabel");
|
var attendeesLabel = $("attendeesLabel");
|
||||||
var attendeesDiv = $("attendeesDiv");
|
var attendeesDiv = $("attendeesDiv");
|
||||||
|
@ -323,7 +323,7 @@ function refreshAttendees(newAttendees) {
|
||||||
var attendeesMenu = $("attendeesMenu");
|
var attendeesMenu = $("attendeesMenu");
|
||||||
|
|
||||||
if (!attendeesHref)
|
if (!attendeesHref)
|
||||||
return refreshAttendeesRO ();
|
return refreshAttendeesRO();
|
||||||
|
|
||||||
if (attendeesMenu)
|
if (attendeesMenu)
|
||||||
attendeesMenu = $("attendeesMenu").down("ul");
|
attendeesMenu = $("attendeesMenu").down("ul");
|
||||||
|
@ -337,9 +337,10 @@ function refreshAttendees(newAttendees) {
|
||||||
if (menuItems && attendeesMenu)
|
if (menuItems && attendeesMenu)
|
||||||
for (var i = 0; i < menuItems.length; i++)
|
for (var i = 0; i < menuItems.length; i++)
|
||||||
attendeesMenu.removeChild(menuItems[i]);
|
attendeesMenu.removeChild(menuItems[i]);
|
||||||
|
|
||||||
if (newAttendees)
|
if (newAttendees) {
|
||||||
attendees = $H(newAttendees.evalJSON(true));
|
attendees = $H(newAttendees.evalJSON());
|
||||||
|
}
|
||||||
|
|
||||||
if (attendees.keys().length > 0) {
|
if (attendees.keys().length > 0) {
|
||||||
// Update attendees link and show label
|
// Update attendees link and show label
|
||||||
|
@ -353,13 +354,13 @@ function refreshAttendees(newAttendees) {
|
||||||
if (attendeesMenu) {
|
if (attendeesMenu) {
|
||||||
var delegatedTo = attendee.get('delegated-to');
|
var delegatedTo = attendee.get('delegated-to');
|
||||||
if (!attendee.get('delegated-from') || delegatedTo) {
|
if (!attendee.get('delegated-from') || delegatedTo) {
|
||||||
var node = document.createElement("li");
|
var node = createElement("li");
|
||||||
attendeesMenu.appendChild(node);
|
attendeesMenu.appendChild(node);
|
||||||
setupAttendeeNode(node, attendee);
|
setupAttendeeNode(node, attendee);
|
||||||
}
|
}
|
||||||
if (delegatedTo) {
|
if (delegatedTo) {
|
||||||
var delegate = attendees.get(delegatedTo);
|
var delegate = attendees.get(delegatedTo);
|
||||||
var node = document.createElement("li");
|
var node = createElement("li");
|
||||||
attendeesMenu.appendChild(node);
|
attendeesMenu.appendChild(node);
|
||||||
setupAttendeeNode(node, $H(delegate), true);
|
setupAttendeeNode(node, $H(delegate), true);
|
||||||
}
|
}
|
||||||
|
@ -384,13 +385,18 @@ function setupAttendeeNode(aNode, aAttendee, isDelegate) {
|
||||||
// name = email;
|
// name = email;
|
||||||
name = name || email;
|
name = name || email;
|
||||||
|
|
||||||
$(aNode).writeAttribute("email", email);
|
aNode.writeAttribute("email", email);
|
||||||
$(aNode).addClassName("attendee");
|
aNode.addClassName("attendee");
|
||||||
$(aNode).addClassName(aAttendee.get('partstat'));
|
var partstat = aAttendee.get('partstat');
|
||||||
|
if (!partstat)
|
||||||
|
partstat = "no-partstat";
|
||||||
|
aNode.addClassName(partstat);
|
||||||
if (isDelegate)
|
if (isDelegate)
|
||||||
$(aNode).addClassName("delegate");
|
aNode.addClassName("delegate");
|
||||||
|
var statusIconNode = createElement("div", null, "statusIcon");
|
||||||
|
aNode.appendChild(statusIconNode);
|
||||||
aNode.appendChild(document.createTextNode(name));
|
aNode.appendChild(document.createTextNode(name));
|
||||||
$(aNode).observe("click", onMailTo);
|
aNode.observe("click", onMailTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeAttendeesHref() {
|
function initializeAttendeesHref() {
|
||||||
|
@ -410,8 +416,8 @@ function onAttendeesHrefClick(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMailTo(event) {
|
function onMailTo(event) {
|
||||||
var target = getTarget(event);
|
var target = $(getTarget(event));
|
||||||
var address = target.firstChild.nodeValue.trim() + " <" + target.readAttribute("email") + ">";
|
var address = target.lastChild.nodeValue.trim() + " <" + target.readAttribute("email") + ">";
|
||||||
openMailTo(address);
|
openMailTo(address);
|
||||||
Event.stop(event);
|
Event.stop(event);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -48,20 +48,62 @@ TABLE#freeBusy TD.freeBusyAttendees DIV
|
||||||
TABLE#freeBusy TD.freeBusyData DIV
|
TABLE#freeBusy TD.freeBusyData DIV
|
||||||
{ overflow: scroll; }
|
{ overflow: scroll; }
|
||||||
|
|
||||||
TABLE#freeBusyAttendees TR.needs-action TD.attendees
|
TABLE#freeBusyAttendees TD.attendeeStatus
|
||||||
{ background-image: url("needs-action.png");
|
{ width: 24px;
|
||||||
background-repeat: no-repeat;
|
min-width: 24px;
|
||||||
background-position: 5px center; }
|
max-width: 24px; }
|
||||||
|
|
||||||
TABLE#freeBusyAttendees TR.declined TD.attendees
|
TABLE#freeBusyAttendees TD.attendeeStatus DIV
|
||||||
{ background-image: url("declined.png");
|
{ width: 12px;
|
||||||
background-repeat: no-repeat;
|
min-width: 12px;
|
||||||
background-position: 5px center; }
|
max-width: 24px;
|
||||||
|
background-image: none; }
|
||||||
|
|
||||||
TABLE#freeBusyAttendees TR.accepted TD.attendees
|
UL.roles-legend SPAN.role-icon
|
||||||
{ background-image: url("accepted.png");
|
{ display: block;
|
||||||
background-repeat: no-repeat;
|
float: left; }
|
||||||
background-position: 5px center; }
|
|
||||||
|
UL.roles-legend SPAN.role-icon,
|
||||||
|
TABLE#freeBusyAttendees TR.attendee-row TD.attendeeStatus DIV
|
||||||
|
{ background-repeat: no-repeat;
|
||||||
|
width: 24px;
|
||||||
|
height: 20px;
|
||||||
|
background-image: url("attendee-roles.png"); }
|
||||||
|
|
||||||
|
LI[role="req-participant"] > SPAN.role-icon,
|
||||||
|
TABLE#freeBusyAttendees TR[role="req-participant"].attendee-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: 0px 4px; }
|
||||||
|
|
||||||
|
LI[role="opt-participant"] > SPAN.role-icon,
|
||||||
|
TABLE#freeBusyAttendees TR[role="opt-participant"].attendee-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -24px 4px; }
|
||||||
|
|
||||||
|
LI[role="non-participant"] > SPAN.role-icon,
|
||||||
|
TABLE#freeBusyAttendees TR[role="non-participant"].attendee-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -72px 4px; }
|
||||||
|
|
||||||
|
LI[role="chair"] > SPAN.role-icon,
|
||||||
|
TABLE#freeBusyAttendees TR[role="chair"].attendee-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -48px 4px; }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TR.organizer-row TD.attendeeStatus DIV
|
||||||
|
{ background-repeat: no-repeat;
|
||||||
|
width: 12px;
|
||||||
|
height: 18px;
|
||||||
|
margin-left: 6px;
|
||||||
|
background-image: url("attendee-partstats.png"); }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TR[partstat="accepted"].organizer-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: 0px 4px; }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TR[partstat="declined"].organizer-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -12px 4px; }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TR[partstat="needs-action"].organizer-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -24px 4px; }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TR[partstat="tentative"].organizer-row TD.attendeeStatus DIV
|
||||||
|
{ background-position: -36px 4px; }
|
||||||
|
|
||||||
TABLE#freeBusyHeader TR.freeBusyHeader2 TH
|
TABLE#freeBusyHeader TR.freeBusyHeader2 TH
|
||||||
{ font-weight: normal; }
|
{ font-weight: normal; }
|
||||||
|
@ -112,8 +154,7 @@ TABLE#freeBusyAttendees TD.attendees INPUT
|
||||||
background-position: 4px center;
|
background-position: 4px center;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
width: 12em;
|
width: 12em;
|
||||||
padding-left: 24px;
|
padding-left: 24px; }
|
||||||
margin-left: 2em; }
|
|
||||||
|
|
||||||
TABLE#freeBusyAttendees TR.futureAttendee INPUT
|
TABLE#freeBusyAttendees TR.futureAttendee INPUT
|
||||||
{ background-image: none;
|
{ background-image: none;
|
||||||
|
@ -124,9 +165,6 @@ TABLE#freeBusyData TR.futureData TD
|
||||||
{ border: 0;
|
{ border: 0;
|
||||||
line-height: 3em; }
|
line-height: 3em; }
|
||||||
|
|
||||||
TABLE#freeBusyAttendees TR.futureAttendee TD A
|
|
||||||
{ margin-left: 20px; }
|
|
||||||
|
|
||||||
SPAN.freeBusyZoneElement
|
SPAN.freeBusyZoneElement
|
||||||
{ display: block;
|
{ display: block;
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -165,32 +203,29 @@ DIV#legend
|
||||||
DIV#legend UL
|
DIV#legend UL
|
||||||
{ cursor: default;
|
{ cursor: default;
|
||||||
float: left;
|
float: left;
|
||||||
width: 30%;
|
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
margin-right: 10px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
line-height: 1.5em;
|
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
list-style-image: none; }
|
list-style-image: none; }
|
||||||
|
|
||||||
DIV#legend UL LI
|
DIV#legend LI
|
||||||
{ white-space: nowrap;
|
{ height: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px; }
|
padding: 0px; }
|
||||||
|
|
||||||
DIV#legend UL IMG
|
UL.freebusy-legend SPAN.colorBox
|
||||||
{ margin-right: .5em; }
|
|
||||||
|
|
||||||
DIV#legend UL LI SPAN.colorBox
|
|
||||||
{ float: left;
|
{ float: left;
|
||||||
margin-right: .5em; }
|
margin-top: 5px;
|
||||||
|
margin-right: 2px;
|
||||||
SPAN.colorBox
|
display: block;
|
||||||
{ display: block;
|
border: 1px solid #999;
|
||||||
float: right;
|
border-left: 1px solid #ccc;
|
||||||
border: 1px solid #333;
|
border-right: 1px solid #ccc;
|
||||||
margin: .12em;
|
border-bottom: 1px solid #eee;
|
||||||
width: 1em;
|
width: 32px;
|
||||||
height: .75em; }
|
height: 10px; }
|
||||||
|
|
||||||
SPAN.colorBox.busy,
|
SPAN.colorBox.busy,
|
||||||
SPAN.freeBusyZoneElement.busy
|
SPAN.freeBusyZoneElement.busy
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
|
||||||
|
var OwnerLogin = "";
|
||||||
|
|
||||||
var resultsDiv;
|
var resultsDiv;
|
||||||
var address;
|
var address;
|
||||||
var awaitingFreeBusyRequests = new Array();
|
|
||||||
var additionalDays = 2;
|
var additionalDays = 2;
|
||||||
|
|
||||||
var isAllDay = parent$("isAllDay").checked + 0;
|
var isAllDay = parent$("isAllDay").checked + 0;
|
||||||
|
@ -11,12 +12,9 @@ var displayEndHour = 23;
|
||||||
|
|
||||||
var attendeesEditor = {
|
var attendeesEditor = {
|
||||||
delay: 500,
|
delay: 500,
|
||||||
delayedSearch: false,
|
|
||||||
currentField: null,
|
|
||||||
selectedIndex: -1
|
selectedIndex: -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function handleAllDay () {
|
function handleAllDay () {
|
||||||
window.timeWidgets['end']['hour'].value = 17;
|
window.timeWidgets['end']['hour'].value = 17;
|
||||||
window.timeWidgets['end']['minute'].value = 0;
|
window.timeWidgets['end']['minute'].value = 0;
|
||||||
|
@ -31,67 +29,135 @@ function handleAllDay () {
|
||||||
|
|
||||||
/* address completion */
|
/* address completion */
|
||||||
|
|
||||||
|
function resolveListAttendees(input, append) {
|
||||||
|
var urlstr = (UserFolderURL
|
||||||
|
+ "Contacts/"
|
||||||
|
+ escape(input.container) + "/"
|
||||||
|
+ escape(input.cname) + "/properties");
|
||||||
|
triggerAjaxRequest(urlstr, resolveListAttendeesCallback,
|
||||||
|
{ "input": input, "append": append });
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveListAttendeesCallback(http) {
|
||||||
|
if (http.readyState == 4 && http.status == 200) {
|
||||||
|
var input = http.callbackData["input"];
|
||||||
|
var append = http.callbackData["append"];
|
||||||
|
var contacts = http.responseText.evalJSON(true);
|
||||||
|
for (var i = 0; i < contacts.length; i++) {
|
||||||
|
var contact = contacts[i];
|
||||||
|
var fullName = contact[1];
|
||||||
|
if (fullName && fullName.length > 0) {
|
||||||
|
fullName += " <" + contact[2] + ">";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fullName = contact[2];
|
||||||
|
}
|
||||||
|
input.uid = null;
|
||||||
|
input.cname = null;
|
||||||
|
input.container = null;
|
||||||
|
input.isList = false;
|
||||||
|
input.value = contact[2];
|
||||||
|
input.confirmedValue = null;
|
||||||
|
input.hasfreebusy = false;
|
||||||
|
input.modified = true;
|
||||||
|
// input.focussed = true;
|
||||||
|
// input.activate();
|
||||||
|
input.checkAfterLookup = true;
|
||||||
|
performSearch(input);
|
||||||
|
if (i < (contacts.length - 1)) {
|
||||||
|
var nextRow = newAttendee(input.parentNode.parentNode);
|
||||||
|
input = nextRow.down("input");
|
||||||
|
} else if (append) {
|
||||||
|
var row = input.parentNode.parentNode;
|
||||||
|
var tBody = row.parentNode;
|
||||||
|
if (row.rowIndex == (tBody.rows.length - 3)) {
|
||||||
|
if (input.selectText) {
|
||||||
|
input.selectText(0, 0);
|
||||||
|
} else if (input.createTextRange) {
|
||||||
|
input.createTextRange().moveStart();
|
||||||
|
}
|
||||||
|
newAttendee();
|
||||||
|
} else {
|
||||||
|
var nextRow = tBody.rows[row.rowIndex + 1];
|
||||||
|
var input = nextRow.down("input");
|
||||||
|
input.selectText(0, input.value.length);
|
||||||
|
input.focussed = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (input.selectText) {
|
||||||
|
input.selectText(0, 0);
|
||||||
|
} else if (input.createTextRange) {
|
||||||
|
input.createTextRange().moveStart();
|
||||||
|
}
|
||||||
|
input.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onContactKeydown(event) {
|
function onContactKeydown(event) {
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
this.focussed = true;
|
this.focussed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.keyCode == 9) { // Tab
|
if (event.keyCode == 9 || event.keyCode == 13) { // Tab
|
||||||
preventDefault(event);
|
preventDefault(event);
|
||||||
if (this.confirmedValue)
|
if (this.confirmedValue)
|
||||||
this.value = this.confirmedValue;
|
this.value = this.confirmedValue;
|
||||||
this.hasfreebusy = false;
|
this.hasfreebusy = false;
|
||||||
var row = $(this).up("tr").next();
|
var row = $(this).up("tr").next();
|
||||||
this.blur(); // triggers checkAttendee function call
|
if (this.isList) {
|
||||||
var input = row.down("input");
|
resolveListAttendees(this, true);
|
||||||
if (input) {
|
event.stop();
|
||||||
input.focussed = true;
|
} else {
|
||||||
input.activate();
|
checkAttendee(this);
|
||||||
|
// this.blur(); // triggers checkAttendee function call
|
||||||
|
var input = row.down("input");
|
||||||
|
if (input) {
|
||||||
|
input.focussed = true;
|
||||||
|
input.activate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
newAttendee();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
newAttendee(null);
|
|
||||||
}
|
}
|
||||||
else if (event.keyCode == 0
|
else if (event.keyCode == 0
|
||||||
|| event.keyCode == 8 // Backspace
|
|| event.keyCode == 8 // Backspace
|
||||||
|| event.keyCode == 32 // Space
|
|| event.keyCode == 32 // Space
|
||||||
|| event.keyCode > 47) {
|
|| event.keyCode > 47) {
|
||||||
this.setAttribute("modified", "1");
|
this.modified = true;
|
||||||
this.confirmedValue = null;
|
this.confirmedValue = null;
|
||||||
|
this.cname = null;
|
||||||
this.uid = null;
|
this.uid = null;
|
||||||
|
this.container = null;
|
||||||
this.hasfreebusy = false;
|
this.hasfreebusy = false;
|
||||||
attendeesEditor.currentField = this;
|
if (this.searchTimeout) {
|
||||||
if (this.value.length > 0 && !attendeesEditor.delayedSearch) {
|
window.clearTimeout(this.searchTimeout);
|
||||||
attendeesEditor.delayedSearch = true;
|
}
|
||||||
setTimeout("performSearch()", attendeesEditor.delay);
|
if (this.value.length > 0) {
|
||||||
|
var thisInput = this;
|
||||||
|
this.searchTimeout = setTimeout(function()
|
||||||
|
{performSearch(thisInput);
|
||||||
|
thisInput = null;},
|
||||||
|
attendeesEditor.delay);
|
||||||
}
|
}
|
||||||
else if (this.value.length == 0) {
|
else if (this.value.length == 0) {
|
||||||
if (document.currentPopupMenu)
|
if (document.currentPopupMenu)
|
||||||
hideMenu(document.currentPopupMenu);
|
hideMenu(document.currentPopupMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.keyCode == 13) {
|
|
||||||
preventDefault(event);
|
|
||||||
if (this.confirmedValue)
|
|
||||||
this.value = this.confirmedValue;
|
|
||||||
$(this).selectText(0, this.value.length);
|
|
||||||
if (document.currentPopupMenu)
|
|
||||||
hideMenu(document.currentPopupMenu);
|
|
||||||
attendeesEditor.selectedIndex = -1;
|
|
||||||
if (this.uid) {
|
|
||||||
this.hasfreebusy = false;
|
|
||||||
this.writeAttribute("modified", "1");
|
|
||||||
this.blur(); // triggers checkAttendee function call
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ($('attendeesMenu').getStyle('visibility') == 'visible') {
|
else if ($('attendeesMenu').getStyle('visibility') == 'visible') {
|
||||||
attendeesEditor.currentField = this;
|
|
||||||
if (event.keyCode == Event.KEY_UP) { // Up arrow
|
if (event.keyCode == Event.KEY_UP) { // Up arrow
|
||||||
if (attendeesEditor.selectedIndex > 0) {
|
if (attendeesEditor.selectedIndex > 0) {
|
||||||
var attendees = $('attendeesMenu').select("li");
|
var attendees = $('attendeesMenu').select("li");
|
||||||
attendees[attendeesEditor.selectedIndex--].removeClassName("selected");
|
attendees[attendeesEditor.selectedIndex--].removeClassName("selected");
|
||||||
attendees[attendeesEditor.selectedIndex].addClassName("selected");
|
var attendee = attendees[attendeesEditor.selectedIndex];
|
||||||
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].readAttribute("address");
|
attendee.addClassName("selected");
|
||||||
this.uid = attendees[attendeesEditor.selectedIndex].uid;
|
this.value = this.confirmedValue = attendee.address;
|
||||||
|
this.uid = attendee.uid;
|
||||||
|
this.isList = attendee.isList;
|
||||||
|
this.cname = attendee.cname;
|
||||||
|
this.container = attendee.container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
|
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
|
||||||
|
@ -100,30 +166,27 @@ function onContactKeydown(event) {
|
||||||
if (attendeesEditor.selectedIndex >= 0)
|
if (attendeesEditor.selectedIndex >= 0)
|
||||||
attendees[attendeesEditor.selectedIndex].removeClassName("selected");
|
attendees[attendeesEditor.selectedIndex].removeClassName("selected");
|
||||||
attendeesEditor.selectedIndex++;
|
attendeesEditor.selectedIndex++;
|
||||||
attendees[attendeesEditor.selectedIndex].addClassName("selected");
|
var attendee = attendees[attendeesEditor.selectedIndex];
|
||||||
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].readAttribute("address");
|
attendee.addClassName("selected");
|
||||||
this.uid = attendees[attendeesEditor.selectedIndex].uid;
|
this.value = this.confirmedValue = attendee.address;
|
||||||
|
this.isList = attendee.isList;
|
||||||
|
this.uid = attendee.uid;
|
||||||
|
this.cname = attendee.cname;
|
||||||
|
this.container = attendee.container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function performSearch() {
|
function performSearch(input) {
|
||||||
// Perform address completion
|
// Perform address completion
|
||||||
if (attendeesEditor.currentField) {
|
if (input.value.trim().length > 0) {
|
||||||
if (document.contactLookupAjaxRequest) {
|
var urlstr = (UserFolderURL
|
||||||
// Abort any pending request
|
+ "Contacts/allContactSearch?excludeGroups=1&search="
|
||||||
document.contactLookupAjaxRequest.aborted = true;
|
+ escape(input.value));
|
||||||
document.contactLookupAjaxRequest.abort();
|
triggerAjaxRequest(urlstr, performSearchCallback, input);
|
||||||
}
|
|
||||||
if (attendeesEditor.currentField.value.trim().length > 0) {
|
|
||||||
var urlstr = ( UserFolderURL + "Contacts/contactSearch?search="
|
|
||||||
+ escape(attendeesEditor.currentField.value) );
|
|
||||||
document.contactLookupAjaxRequest =
|
|
||||||
triggerAjaxRequest(urlstr, performSearchCallback, attendeesEditor.currentField);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
attendeesEditor.delayedSearch = false;
|
input.searchTimeout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function performSearchCallback(http) {
|
function performSearchCallback(http) {
|
||||||
|
@ -138,6 +201,7 @@ function performSearchCallback(http) {
|
||||||
var data = http.responseText.evalJSON(true);
|
var data = http.responseText.evalJSON(true);
|
||||||
|
|
||||||
if (data.contacts.length > 1) {
|
if (data.contacts.length > 1) {
|
||||||
|
list.input = input;
|
||||||
$(list.childNodesWithTag("li")).each(function(item) {
|
$(list.childNodesWithTag("li")).each(function(item) {
|
||||||
item.remove();
|
item.remove();
|
||||||
});
|
});
|
||||||
|
@ -145,25 +209,42 @@ function performSearchCallback(http) {
|
||||||
// Populate popup menu
|
// Populate popup menu
|
||||||
for (var i = 0; i < data.contacts.length; i++) {
|
for (var i = 0; i < data.contacts.length; i++) {
|
||||||
var contact = data.contacts[i];
|
var contact = data.contacts[i];
|
||||||
var completeEmail = contact["name"] + " <" + contact["email"] + ">";
|
var isList = (contact["c_component"] &&
|
||||||
var node = new Element('li', { 'address': completeEmail });
|
contact["c_component"] == "vlist");
|
||||||
|
var completeEmail = contact["c_cn"].trim();
|
||||||
|
if (!isList) {
|
||||||
|
if (completeEmail)
|
||||||
|
completeEmail += " <" + contact["c_mail"] + ">";
|
||||||
|
else
|
||||||
|
completeEmail = contact["c_mail"];
|
||||||
|
}
|
||||||
|
var node = createElement('li');
|
||||||
|
list.appendChild(node);
|
||||||
|
node.address = completeEmail;
|
||||||
|
log("node.address: " + node.address);
|
||||||
|
node.uid = contact["c_uid"];
|
||||||
|
node.isList = isList;
|
||||||
|
if (isList) {
|
||||||
|
node.cname = contact["c_name"];
|
||||||
|
node.container = contact["container"];
|
||||||
|
}
|
||||||
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
|
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
|
||||||
var matchBefore = completeEmail.substring(0, matchPosition);
|
var matchBefore = completeEmail.substring(0, matchPosition);
|
||||||
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
|
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
|
||||||
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
|
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
|
||||||
list.appendChild(node);
|
|
||||||
node.uid = contact["uid"];
|
|
||||||
node.appendChild(document.createTextNode(matchBefore));
|
node.appendChild(document.createTextNode(matchBefore));
|
||||||
node.appendChild(new Element('strong').update(matchText));
|
node.appendChild(new Element('strong').update(matchText));
|
||||||
node.appendChild(document.createTextNode(matchAfter));
|
node.appendChild(document.createTextNode(matchAfter));
|
||||||
if (contact["contactInfo"])
|
if (contact["contactInfo"])
|
||||||
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
|
node.appendChild(document.createTextNode(" (" +
|
||||||
$(node).observe("mousedown", onAttendeeResultClick);
|
contact["contactInfo"] + ")"));
|
||||||
|
node.observe("mousedown",
|
||||||
|
onAttendeeResultClick.bindAsEventListener(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show popup menu
|
// Show popup menu
|
||||||
var offsetScroll = Element.cumulativeScrollOffset(attendeesEditor.currentField);
|
var offsetScroll = Element.cumulativeScrollOffset(input);
|
||||||
var offset = Element.cumulativeOffset(attendeesEditor.currentField);
|
var offset = Element.cumulativeOffset(input);
|
||||||
var top = offset[1] - offsetScroll[1] + node.offsetHeight + 3;
|
var top = offset[1] - offsetScroll[1] + node.offsetHeight + 3;
|
||||||
var height = 'auto';
|
var height = 'auto';
|
||||||
var heightDiff = window.height() - offset[1];
|
var heightDiff = window.height() - offset[1];
|
||||||
|
@ -189,37 +270,73 @@ function performSearchCallback(http) {
|
||||||
if (data.contacts.length == 1) {
|
if (data.contacts.length == 1) {
|
||||||
// Single result
|
// Single result
|
||||||
var contact = data.contacts[0];
|
var contact = data.contacts[0];
|
||||||
if (contact["uid"].length > 0)
|
input.uid = contact["c_uid"];
|
||||||
input.uid = contact["uid"];
|
var row = $(input.parentNode.parentNode);
|
||||||
var completeEmail = contact["name"] + " <" + contact["email"] + ">";
|
if (input.uid == OwnerLogin) {
|
||||||
if (contact["name"].substring(0, input.value.length).toUpperCase()
|
row.removeAttribute("role");
|
||||||
== input.value.toUpperCase())
|
row.setAttribute("partstat", "accepted");
|
||||||
|
row.addClassName("organizer-row");
|
||||||
|
row.removeClassName("attendee-row");
|
||||||
|
row.isOrganizer = true;
|
||||||
|
} else {
|
||||||
|
row.removeAttribute("partstat");
|
||||||
|
row.setAttribute("role", "req-participant");
|
||||||
|
row.addClassName("attendee-row");
|
||||||
|
row.removeClassName("organizer-row");
|
||||||
|
row.isOrganizer = false;
|
||||||
|
}
|
||||||
|
var isList = (contact["c_component"] &&
|
||||||
|
contact["c_component"] == "vlist");
|
||||||
|
if (isList) {
|
||||||
|
input.cname = contact["c_name"];
|
||||||
|
input.container = contact["container"];
|
||||||
|
}
|
||||||
|
var completeEmail = contact["c_cn"].trim();
|
||||||
|
if (!isList) {
|
||||||
|
if (completeEmail)
|
||||||
|
completeEmail += " <" + contact["c_mail"] + ">";
|
||||||
|
else
|
||||||
|
completeEmail = contact["c_mail"];
|
||||||
|
}
|
||||||
|
if ((input.value == contact["c_mail"])
|
||||||
|
|| (contact["c_cn"].substring(0, input.value.length).toUpperCase()
|
||||||
|
== input.value.toUpperCase())) {
|
||||||
input.value = completeEmail;
|
input.value = completeEmail;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// The result matches email address, not user name
|
// The result matches email address, not user name
|
||||||
input.value += ' >> ' + completeEmail;
|
input.value += ' >> ' + completeEmail;
|
||||||
|
input.isList = isList;
|
||||||
input.confirmedValue = completeEmail;
|
input.confirmedValue = completeEmail;
|
||||||
var end = input.value.length;
|
var end = input.value.length;
|
||||||
$(input).selectText(start, end);
|
$(input).selectText(start, end);
|
||||||
|
|
||||||
attendeesEditor.selectedIndex = -1;
|
attendeesEditor.selectedIndex = -1;
|
||||||
|
|
||||||
|
if (input.checkAfterLookup) {
|
||||||
|
input.checkAfterLookup = false;
|
||||||
|
input.modified = true;
|
||||||
|
input.hasfreebusy = false;
|
||||||
|
checkAttendee(input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (document.currentPopupMenu)
|
if (document.currentPopupMenu)
|
||||||
hideMenu(document.currentPopupMenu);
|
hideMenu(document.currentPopupMenu);
|
||||||
document.contactLookupAjaxRequest = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAttendeeResultClick(event) {
|
function onAttendeeResultClick(event) {
|
||||||
if (attendeesEditor.currentField) {
|
var input = this.parentNode.input;
|
||||||
attendeesEditor.currentField.uid = this.uid;
|
input.uid = this.uid;
|
||||||
attendeesEditor.currentField.value = $(this).readAttribute("address");
|
input.cname = this.cname;
|
||||||
attendeesEditor.currentField.confirmedValue = attendeesEditor.currentField.value;
|
input.container = this.container;
|
||||||
attendeesEditor.currentField.blur(); // triggers checkAttendee function call
|
input.isList = this.isList;
|
||||||
}
|
input.confirmedValue = input.value = this.address;
|
||||||
|
checkAttendee(input);
|
||||||
|
this.parentNode.input = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetFreeBusyZone() {
|
function resetFreeBusyZone() {
|
||||||
|
@ -284,19 +401,66 @@ function redisplayFreeBusyZone() {
|
||||||
scrollToEvent();
|
scrollToEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
function newAttendee(event) {
|
function onAttendeeStatusClick(event) {
|
||||||
|
rotateAttendeeStatus(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateAttendeeStatus(row) {
|
||||||
|
var values;
|
||||||
|
var attributeName;
|
||||||
|
if (row.isOrganizer) {
|
||||||
|
values = [ "accepted", "declined", "tentative", "needs-action" ];
|
||||||
|
attributeName = "partstat";
|
||||||
|
} else {
|
||||||
|
values = [ "req-participant", "opt-participant",
|
||||||
|
"chair", "non-participant" ];
|
||||||
|
attributeName = "role";
|
||||||
|
}
|
||||||
|
var value = row.getAttribute(attributeName);
|
||||||
|
var idx = (value ? values.indexOf(value) : -1);
|
||||||
|
if (idx == -1 || idx > (values.length - 2)) {
|
||||||
|
idx = 0;
|
||||||
|
} else {
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
row.setAttribute(attributeName, values[idx]);
|
||||||
|
if (Prototype.Browser.IE) {
|
||||||
|
/* This hack enables a refresh of the row element right after the
|
||||||
|
click. Otherwise, this occurs only when leaving the element with
|
||||||
|
them mouse cursor. */
|
||||||
|
row.className = row.className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNewAttendeeClick(event) {
|
||||||
|
newAttendee();
|
||||||
|
event.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function newAttendee(previousAttendee) {
|
||||||
var table = $("freeBusyAttendees");
|
var table = $("freeBusyAttendees");
|
||||||
var tbody = table.tBodies[0];
|
var tbody = table.tBodies[0];
|
||||||
var model = tbody.rows[tbody.rows.length - 1];
|
var model = tbody.rows[tbody.rows.length - 1];
|
||||||
var futureRow = tbody.rows[tbody.rows.length - 2];
|
var nextRowIndex = tbody.rows.length - 2;
|
||||||
var newRow = model.cloneNode(true);
|
if (previousAttendee) {
|
||||||
tbody.insertBefore(newRow, futureRow);
|
nextRowIndex = previousAttendee.rowIndex + 1;
|
||||||
|
}
|
||||||
|
var nextRow = tbody.rows[nextRowIndex];
|
||||||
|
var newRow = $(model.cloneNode(true));
|
||||||
|
tbody.insertBefore(newRow, nextRow);
|
||||||
|
var result = newRow;
|
||||||
|
|
||||||
|
var statusTD = newRow.down(".attendeeStatus");
|
||||||
|
if (statusTD) {
|
||||||
|
var boundOnStatusClick = onAttendeeStatusClick.bindAsEventListener(newRow);
|
||||||
|
statusTD.observe("click", boundOnStatusClick, false);
|
||||||
|
}
|
||||||
|
|
||||||
$(newRow).removeClassName("attendeeModel");
|
$(newRow).removeClassName("attendeeModel");
|
||||||
|
|
||||||
var input = $(newRow).down("input");
|
var input = newRow.down("input");
|
||||||
input.observe("keydown", onContactKeydown);
|
input.observe("keydown", onContactKeydown.bindAsEventListener(input));
|
||||||
input.observe("blur", checkAttendee);
|
input.observe("blur", onInputBlur);
|
||||||
|
|
||||||
input.focussed = true;
|
input.focussed = true;
|
||||||
input.activate();
|
input.activate();
|
||||||
|
@ -304,91 +468,98 @@ function newAttendee(event) {
|
||||||
table = $("freeBusyData");
|
table = $("freeBusyData");
|
||||||
tbody = table.tBodies[0];
|
tbody = table.tBodies[0];
|
||||||
model = tbody.rows[tbody.rows.length - 1];
|
model = tbody.rows[tbody.rows.length - 1];
|
||||||
futureRow = tbody.rows[tbody.rows.length - 2];
|
nextRow = tbody.rows[nextRowIndex];
|
||||||
newRow = model.cloneNode(true);
|
newRow = $(model.cloneNode(true));
|
||||||
tbody.insertBefore(newRow, futureRow);
|
tbody.insertBefore(newRow, nextRow);
|
||||||
$(newRow).removeClassName("dataModel");
|
newRow.removeClassName("dataModel");
|
||||||
|
|
||||||
var attendeesDiv = $$('TABLE#freeBusy TD.freeBusyAttendees DIV').first();
|
var attendeesDiv = $$('TABLE#freeBusy TD.freeBusyAttendees DIV').first();
|
||||||
var dataDiv = $$('TABLE#freeBusy TD.freeBusyData DIV').first();
|
var dataDiv = $$('TABLE#freeBusy TD.freeBusyData DIV').first();
|
||||||
|
|
||||||
dataDiv.scrollTop = attendeesDiv.scrollTop;
|
dataDiv.scrollTop = attendeesDiv.scrollTop;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkAttendee() { log ("checkAttendee");
|
function checkAttendee(input) {
|
||||||
if (document.currentPopupMenu)
|
var row = $(input.parentNode.parentNode);
|
||||||
hideMenu(document.currentPopupMenu);
|
|
||||||
|
|
||||||
if (document.currentPopupMenu && !this.confirmedValue) {
|
|
||||||
// Hack for IE7; blur event is triggered on input field when
|
|
||||||
// selecting a menu item
|
|
||||||
var visible = $(document.currentPopupMenu).getStyle('visibility') != 'hidden';
|
|
||||||
if (visible)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.focussed = false;
|
|
||||||
var row = this.parentNode.parentNode;
|
|
||||||
var tbody = row.parentNode;
|
var tbody = row.parentNode;
|
||||||
if (tbody && this.value.trim().length == 0) {
|
if (tbody && input.value.trim().length == 0) {
|
||||||
var dataTable = $("freeBusyData").tBodies[0];
|
var dataTable = $("freeBusyData").tBodies[0];
|
||||||
var dataRow = dataTable.rows[row.sectionRowIndex];
|
var dataRow = dataTable.rows[row.sectionRowIndex];
|
||||||
tbody.removeChild(row);
|
tbody.removeChild(row);
|
||||||
dataTable.removeChild(dataRow);
|
dataTable.removeChild(dataRow);
|
||||||
}
|
}
|
||||||
else if (this.readAttribute("modified") == "1") {
|
else if (input.modified) {
|
||||||
if (!$(row).hasClassName("needs-action")) {
|
if (!row.hasClassName("needs-action")) {
|
||||||
$(row).addClassName("needs-action");
|
row.addClassName("needs-action");
|
||||||
$(row).removeClassName("declined");
|
row.removeClassName("declined");
|
||||||
$(row).removeClassName("accepted");
|
row.removeClassName("accepted");
|
||||||
}
|
}
|
||||||
if (!this.hasfreebusy) {
|
if (!input.hasfreebusy) {
|
||||||
if (this.uid && this.confirmedValue)
|
if (input.uid && input.confirmedValue) {
|
||||||
this.value = this.confirmedValue;
|
input.value = input.confirmedValue;
|
||||||
log ("4");
|
}
|
||||||
displayFreeBusyForNode(this);
|
displayFreeBusyForNode(input);
|
||||||
this.hasfreebusy = true;
|
input.hasfreebusy = true;
|
||||||
}
|
}
|
||||||
this.setAttribute("modified", "0");
|
input.modified = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInputBlur(event) {
|
||||||
|
if (document.currentPopupMenu && !this.confirmedValue) {
|
||||||
|
// Hack for IE7; blur event is triggered on input field when
|
||||||
|
// selecting a menu item
|
||||||
|
var visible = $(document.currentPopupMenu).getStyle('visibility') != 'hidden';
|
||||||
|
if (visible) {
|
||||||
|
log("XXX we return");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.currentPopupMenu)
|
||||||
|
hideMenu(document.currentPopupMenu);
|
||||||
|
|
||||||
|
if (this.isList) {
|
||||||
|
resolveListAttendees(this, false);
|
||||||
|
} else {
|
||||||
|
checkAttendee(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
attendeesEditor.currentField = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayFreeBusyForNode(input) {
|
function displayFreeBusyForNode(input) {
|
||||||
var rowIndex = input.parentNode.parentNode.sectionRowIndex;
|
var rowIndex = input.parentNode.parentNode.sectionRowIndex;
|
||||||
var nodes = $("freeBusyData").tBodies[0].rows[rowIndex].cells; log ("displayFreeBusyForNode index " + rowIndex + " (" + nodes.length + " cells)");
|
var nodes = $("freeBusyData").tBodies[0].rows[rowIndex].cells;
|
||||||
|
log ("displayFreeBusyForNode index " + rowIndex + " (" + nodes.length + " cells)");
|
||||||
if (input.uid) {
|
if (input.uid) {
|
||||||
if (document.contactFreeBusyAjaxRequest) { log ("busy -- delay " + rowIndex);
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
awaitingFreeBusyRequests.push(input); }
|
var node = $(nodes[i]);
|
||||||
else {
|
node.removeClassName("noFreeBusy");
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
while (node.firstChild) {
|
||||||
$(nodes[i]).removeClassName("noFreeBusy");
|
node.removeChild(node.firstChild);
|
||||||
$(nodes[i]).innerHTML = ('<span class="freeBusyZoneElement"></span>'
|
}
|
||||||
+ '<span class="freeBusyZoneElement"></span>'
|
for (var j = 0; j < 4; j++) {
|
||||||
+ '<span class="freeBusyZoneElement"></span>'
|
createElement("span", null, "freeBusyZoneElement",
|
||||||
+ '<span class="freeBusyZoneElement"></span>');
|
null, null, node);
|
||||||
}
|
}
|
||||||
// if (document.contactFreeBusyAjaxRequest) {
|
|
||||||
// // Abort any pending request
|
|
||||||
// document.contactFreeBusyAjaxRequest.aborted = true;
|
|
||||||
// document.contactFreeBusyAjaxRequest.abort();
|
|
||||||
// }
|
|
||||||
var sd = $('startTime_date').valueAsShortDateString();
|
|
||||||
var ed = $('endTime_date').valueAsShortDateString();
|
|
||||||
var urlstr = ( UserFolderURL + "../" + input.uid
|
|
||||||
+ "/freebusy.ifb/ajaxRead?"
|
|
||||||
+ "sday=" + sd + "&eday=" + ed + "&additional=" +
|
|
||||||
additionalDays ); log (urlstr);
|
|
||||||
document.contactFreeBusyAjaxRequest
|
|
||||||
= triggerAjaxRequest(urlstr,
|
|
||||||
updateFreeBusyDataCallback,
|
|
||||||
input);
|
|
||||||
}
|
}
|
||||||
|
var sd = $('startTime_date').valueAsShortDateString();
|
||||||
|
var ed = $('endTime_date').valueAsShortDateString();
|
||||||
|
var urlstr = (UserFolderURL + "../" + input.uid
|
||||||
|
+ "/freebusy.ifb/ajaxRead?"
|
||||||
|
+ "sday=" + sd + "&eday=" + ed + "&additional=" +
|
||||||
|
additionalDays);
|
||||||
|
triggerAjaxRequest(urlstr,
|
||||||
|
updateFreeBusyDataCallback,
|
||||||
|
input);
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
$(nodes[i]).addClassName("noFreeBusy");
|
var node = $(nodes[i]);
|
||||||
$(nodes[i]).update();
|
node.addClassName("noFreeBusy");
|
||||||
|
while (node.firstChild) {
|
||||||
|
node.removeChild(node.firstChild);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,15 +590,12 @@ function updateFreeBusyDataCallback(http) {
|
||||||
var slots = http.responseText.split(",");
|
var slots = http.responseText.split(",");
|
||||||
var rowIndex = input.parentNode.parentNode.sectionRowIndex;
|
var rowIndex = input.parentNode.parentNode.sectionRowIndex;
|
||||||
var nodes = $("freeBusyData").tBodies[0].rows[rowIndex].cells;
|
var nodes = $("freeBusyData").tBodies[0].rows[rowIndex].cells;
|
||||||
log ("received " + slots.length + " slots for " + rowIndex + " with " + nodes.length + " cells");
|
// log ("received " + slots.length + " slots for " + rowIndex + " with " + nodes.length + " cells");
|
||||||
for (var i = 0; i < slots.length; i++) {
|
for (var i = 0; i < slots.length; i++) {
|
||||||
if (slots[i] != '0')
|
if (slots[i] != '0')
|
||||||
setSlot(nodes, i, slots[i]);
|
setSlot(nodes, i, slots[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.contactFreeBusyAjaxRequest = null;
|
|
||||||
if (awaitingFreeBusyRequests.length > 0) { log ("1");
|
|
||||||
displayFreeBusyForNode(awaitingFreeBusyRequests.shift()); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,8 +604,8 @@ function resetAllFreeBusys() {
|
||||||
var inputs = table.getElementsByTagName("input");
|
var inputs = table.getElementsByTagName("input");
|
||||||
|
|
||||||
for (var i = 0; i < inputs.length - 1; i++) {
|
for (var i = 0; i < inputs.length - 1; i++) {
|
||||||
var currentInput = inputs[i]; log ("reset fb " + currentInput.uid);
|
var currentInput = inputs[i];
|
||||||
currentInput.hasfreebusy = false; log ("2");
|
currentInput.hasfreebusy = false;
|
||||||
displayFreeBusyForNode(currentInput);
|
displayFreeBusyForNode(currentInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +621,7 @@ function initializeWindowButtons() {
|
||||||
$("nextSlot").observe ("click", onNextSlotClick, false);
|
$("nextSlot").observe ("click", onNextSlotClick, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findSlot (direction) {
|
function findSlot(direction) {
|
||||||
var userList = UserLogin;
|
var userList = UserLogin;
|
||||||
var table = $("freeBusy");
|
var table = $("freeBusy");
|
||||||
var inputs = table.getElementsByTagName("input");
|
var inputs = table.getElementsByTagName("input");
|
||||||
|
@ -565,7 +733,7 @@ function onNextSlotClick(event) {
|
||||||
|
|
||||||
function onEditorOkClick(event) {
|
function onEditorOkClick(event) {
|
||||||
preventDefault(event);
|
preventDefault(event);
|
||||||
|
|
||||||
var attendees = window.opener.attendees;
|
var attendees = window.opener.attendees;
|
||||||
var newAttendees = new Hash();
|
var newAttendees = new Hash();
|
||||||
var table = $("freeBusy");
|
var table = $("freeBusy");
|
||||||
|
@ -578,16 +746,24 @@ function onEditorOkClick(event) {
|
||||||
if (inputs[i].uid)
|
if (inputs[i].uid)
|
||||||
uid = inputs[i].uid;
|
uid = inputs[i].uid;
|
||||||
if (!(name && name.length > 0))
|
if (!(name && name.length > 0))
|
||||||
if (inputs[i].uid)
|
if (uid.length > 0)
|
||||||
name = inputs[i].uid;
|
name = uid;
|
||||||
else
|
else
|
||||||
name = email;
|
name = email;
|
||||||
var attendee = attendees.get(email);
|
var attendee = attendees["email"];
|
||||||
if (!attendee)
|
if (!attendee) {
|
||||||
attendee = new Hash({'email': email,
|
attendee = {"email": email,
|
||||||
'name': name,
|
"name": name,
|
||||||
'uid': uid,
|
"role": "req-participant",
|
||||||
'partstat': 'needs-action'});
|
"partstat": "needs-action",
|
||||||
|
"uid": uid};
|
||||||
|
}
|
||||||
|
var partstat = row.getAttribute("partstat");
|
||||||
|
if (partstat)
|
||||||
|
attendee["partstat"] = partstat;
|
||||||
|
var role = row.getAttribute("role");
|
||||||
|
if (role)
|
||||||
|
attendee["role"] = role;
|
||||||
newAttendees.set(email, attendee);
|
newAttendees.set(email, attendee);
|
||||||
}
|
}
|
||||||
window.opener.refreshAttendees(newAttendees.toJSON());
|
window.opener.refreshAttendees(newAttendees.toJSON());
|
||||||
|
@ -733,38 +909,56 @@ function prepareAttendees() {
|
||||||
var modelData = tbodyData.rows[tbodyData.rows.length - 1];
|
var modelData = tbodyData.rows[tbodyData.rows.length - 1];
|
||||||
var newDataRow = tbodyData.rows[tbodyData.rows.length - 2];
|
var newDataRow = tbodyData.rows[tbodyData.rows.length - 2];
|
||||||
|
|
||||||
attendees.values().each(function(attendee) {
|
attendees.keys().each(function(atKey) {
|
||||||
attendee = $H(attendee);
|
var attendee = attendees.get(atKey);
|
||||||
var row = modelAttendee.cloneNode(true);
|
var row = $(modelAttendee.cloneNode(true));
|
||||||
tbodyAttendees.insertBefore(row, newAttendeeRow);
|
tbodyAttendees.insertBefore(row, newAttendeeRow);
|
||||||
$(row).removeClassName("attendeeModel");
|
row.removeClassName("attendeeModel");
|
||||||
$(row).addClassName(attendee.get('partstat'));
|
row.setAttribute("partstat", attendee["partstat"]);
|
||||||
var input = $(row).down("input");
|
row.setAttribute("role", attendee["role"]);
|
||||||
var value = attendee.get('name');
|
var uid = attendee["uid"];
|
||||||
if (value)
|
if (uid && uid == OwnerLogin) {
|
||||||
value += " ";
|
row.addClassName("organizer-row");
|
||||||
else
|
row.removeClassName("attendee-row");
|
||||||
value = "";
|
row.isOrganizer = true;
|
||||||
value += "<" + attendee.get('email') + ">";
|
} else {
|
||||||
input.value = value;
|
row.addClassName("attendee-row");
|
||||||
if (attendee.get('uid'))
|
row.removeClassName("organizer-row");
|
||||||
input.uid = attendee.get('uid');
|
row.isOrganizer = false;
|
||||||
input.setAttribute("name", "");
|
}
|
||||||
input.setAttribute("modified", "0");
|
var statusTD = row.down(".attendeeStatus");
|
||||||
input.observe("blur", checkAttendee);
|
if (statusTD) {
|
||||||
input.observe("keydown", onContactKeydown);
|
var boundOnStatusClick
|
||||||
|
= onAttendeeStatusClick.bindAsEventListener(row);
|
||||||
row = modelData.cloneNode(true);
|
statusTD.observe("click", boundOnStatusClick, false);
|
||||||
tbodyData.insertBefore(row, newDataRow);
|
}
|
||||||
$(row).removeClassName("dataModel");
|
|
||||||
log ("3");
|
var input = row.down("input");
|
||||||
displayFreeBusyForNode(input);
|
var value = attendee["name"];
|
||||||
});
|
if (value)
|
||||||
|
value += " ";
|
||||||
|
else
|
||||||
|
value = "";
|
||||||
|
value += "<" + attendee["email"] + ">";
|
||||||
|
input.value = value;
|
||||||
|
input.uid = attendee["uid"];
|
||||||
|
input.cname = attendee["cname"];
|
||||||
|
input.setAttribute("name", "");
|
||||||
|
input.modified = false;
|
||||||
|
input.observe("blur", onInputBlur);
|
||||||
|
input.observe("keydown", onContactKeydown.bindAsEventListener(input)
|
||||||
|
);
|
||||||
|
|
||||||
|
row = $(modelData.cloneNode(true));
|
||||||
|
tbodyData.insertBefore(row, newDataRow);
|
||||||
|
row.removeClassName("dataModel");
|
||||||
|
displayFreeBusyForNode(input);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate "Add attendee" button
|
// Activate "Add attendee" button
|
||||||
var links = tableAttendees.select("TR.futureAttendee TD A");
|
var links = tableAttendees.select("TR.futureAttendee TD A");
|
||||||
links.first().observe("click", newAttendee);
|
links.first().observe("click", onNewAttendeeClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWindowResize(event) {
|
function onWindowResize(event) {
|
||||||
|
@ -799,6 +993,8 @@ function onFreeBusyLoadHandler() {
|
||||||
'hour': $("endTime_time_hour"),
|
'hour': $("endTime_time_hour"),
|
||||||
'minute': $("endTime_time_minute")}};
|
'minute': $("endTime_time_minute")}};
|
||||||
|
|
||||||
|
OwnerLogin = window.opener.getOwnerLogin();
|
||||||
|
|
||||||
synchronizeWithParent("startTime", "startTime");
|
synchronizeWithParent("startTime", "startTime");
|
||||||
synchronizeWithParent("endTime", "endTime");
|
synchronizeWithParent("endTime", "endTime");
|
||||||
|
|
||||||
|
@ -858,7 +1054,7 @@ function initTimeWidgets(widgets) {
|
||||||
function onAdjustTime(event) {
|
function onAdjustTime(event) {
|
||||||
var endDate = window.getEndDate();
|
var endDate = window.getEndDate();
|
||||||
var startDate = window.getStartDate();
|
var startDate = window.getStartDate();
|
||||||
if ($(this).readAttribute("id").startsWith("start")) {
|
if (this.id.startsWith("start")) {
|
||||||
// Start date was changed
|
// Start date was changed
|
||||||
var delta = window.getShadowStartDate().valueOf() -
|
var delta = window.getShadowStartDate().valueOf() -
|
||||||
startDate.valueOf();
|
startDate.valueOf();
|
||||||
|
|
|
@ -6,6 +6,10 @@ var ComponentEditor = {
|
||||||
reminderWindow: null
|
reminderWindow: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getOwnerLogin() {
|
||||||
|
return ownerLogin;
|
||||||
|
}
|
||||||
|
|
||||||
function onPopupAttendeesWindow(event) {
|
function onPopupAttendeesWindow(event) {
|
||||||
if (event)
|
if (event)
|
||||||
preventDefault(event);
|
preventDefault(event);
|
||||||
|
@ -202,7 +206,7 @@ function onSummaryChange (e) {
|
||||||
|
|
||||||
function onReplyChange(event) {
|
function onReplyChange(event) {
|
||||||
var delegateEditor = $("delegateEditor");
|
var delegateEditor = $("delegateEditor");
|
||||||
if (this.value == 2) {
|
if (this.value == 4) {
|
||||||
// Delegated
|
// Delegated
|
||||||
delegateEditor.show();
|
delegateEditor.show();
|
||||||
$("delegatedTo").focus();
|
$("delegatedTo").focus();
|
||||||
|
@ -328,7 +332,11 @@ function onOkButtonClick (e) {
|
||||||
action = 'accept';
|
action = 'accept';
|
||||||
else if (value == 1)
|
else if (value == 1)
|
||||||
action = 'decline';
|
action = 'decline';
|
||||||
else if (value == 2) {
|
else if (value == 2)
|
||||||
|
action = 'needsaction';
|
||||||
|
else if (value == 3)
|
||||||
|
action = 'tentative';
|
||||||
|
else if (value == 4) {
|
||||||
var url = ApplicationBaseURL + activeCalendar + '/' + activeComponent;
|
var url = ApplicationBaseURL + activeCalendar + '/' + activeComponent;
|
||||||
document.modifyEventAjaxRequest = delegateInvitation(url, modifyEventCallback);
|
document.modifyEventAjaxRequest = delegateInvitation(url, modifyEventCallback);
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 510 B |
Before Width: | Height: | Size: 511 B |
BIN
UI/WebServerResources/attendee-partstats.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
UI/WebServerResources/attendee-roles.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 354 B |
Before Width: | Height: | Size: 540 B |
Before Width: | Height: | Size: 452 B |
|
@ -67,7 +67,7 @@ function createElement(tagName, id, classes,
|
||||||
if (parentNode)
|
if (parentNode)
|
||||||
parentNode.appendChild(newElement);
|
parentNode.appendChild(newElement);
|
||||||
|
|
||||||
return $(newElement);
|
return newElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function URLForFolderID(folderID) {
|
function URLForFolderID(folderID) {
|
||||||
|
|
|
@ -83,6 +83,10 @@ DIV#attendeesMenu LI.separator
|
||||||
DIV#attendeesView
|
DIV#attendeesView
|
||||||
{ left: 0.5em; }
|
{ left: 0.5em; }
|
||||||
|
|
||||||
|
TABLE#freeBusyAttendees TD.attendeeStatus,
|
||||||
|
TABLE#freeBusyAttendees TD.attendeeStatus DIV
|
||||||
|
{ width: 24px; }
|
||||||
|
|
||||||
TABLE
|
TABLE
|
||||||
{ empty-cells: show; }
|
{ empty-cells: show; }
|
||||||
|
|
||||||
|
@ -100,6 +104,18 @@ DIV#propertiesView LEGEND
|
||||||
|
|
||||||
/* UIxMailPartICalViewer */
|
/* UIxMailPartICalViewer */
|
||||||
|
|
||||||
|
#iCalAttendees SPAN
|
||||||
|
{ display: block;
|
||||||
|
height: 18px;
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px; }
|
||||||
|
|
||||||
|
#iCalAttendees DIV.status-icon
|
||||||
|
{ margin-top: 2px;
|
||||||
|
border: 0px;
|
||||||
|
padding: 0px; }
|
||||||
|
|
||||||
.clear
|
.clear
|
||||||
{ padding-top: 0; }
|
{ padding-top: 0; }
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 428 B |