Merge pull request #45 from alexcloutier/feature/PreventInvitations
New user preference to prevent invitations
This commit is contained in:
commit
f3ded6ce2a
|
@ -1,3 +1,4 @@
|
||||||
|
"This or these persons cannot be invited:" = "This or these persons cannot be invited:";
|
||||||
"Personal Calendar" = "Personal Calendar";
|
"Personal Calendar" = "Personal Calendar";
|
||||||
vevent_class0 = "(Public event)";
|
vevent_class0 = "(Public event)";
|
||||||
vevent_class1 = "(Private event)";
|
vevent_class1 = "(Private event)";
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#import <Foundation/NSEnumerator.h>
|
#import <Foundation/NSEnumerator.h>
|
||||||
#import <Foundation/NSTimeZone.h>
|
#import <Foundation/NSTimeZone.h>
|
||||||
#import <Foundation/NSValue.h>
|
#import <Foundation/NSValue.h>
|
||||||
|
#import <Foundation/NSPredicate.h>
|
||||||
|
|
||||||
#import <NGObjWeb/NSException+HTTP.h>
|
#import <NGObjWeb/NSException+HTTP.h>
|
||||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
#import <SOGo/SOGoPermissions.h>
|
#import <SOGo/SOGoPermissions.h>
|
||||||
#import <SOGo/SOGoGroup.h>
|
#import <SOGo/SOGoGroup.h>
|
||||||
#import <SOGo/SOGoUser.h>
|
#import <SOGo/SOGoUser.h>
|
||||||
|
#import <SOGo/SOGoUserSettings.h>
|
||||||
#import <SOGo/SOGoDomainDefaults.h>
|
#import <SOGo/SOGoDomainDefaults.h>
|
||||||
#import <SOGo/SOGoWebDAVValue.h>
|
#import <SOGo/SOGoWebDAVValue.h>
|
||||||
#import <SOGo/WORequest+SOGo.h>
|
#import <SOGo/WORequest+SOGo.h>
|
||||||
|
@ -126,7 +128,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (iCalRepeatableEntityObject *) lookupOccurrence: (NSString *) recID
|
- (iCalRepeatableEntityObject *) lookupOccurrence: (NSString *) recID
|
||||||
|
|
||||||
{
|
{
|
||||||
return [[self calendar: NO secure: NO] eventWithRecurrenceID: recID];
|
return [[self calendar: NO secure: NO] eventWithRecurrenceID: recID];
|
||||||
}
|
}
|
||||||
|
@ -343,9 +344,7 @@
|
||||||
[event removeFromAttendees: delegate];
|
[event removeFromAttendees: delegate];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[self errorWithFormat:
|
[self errorWithFormat:@"broken chain: delegate with email '%@' was not found", mailTo];
|
||||||
@"broken chain: delegate with email '%@' was not found",
|
|
||||||
mailTo];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +411,73 @@
|
||||||
withType: @"calendar:invitation-update"];
|
withType: @"calendar:invitation-update"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method scans the list of attendees.
|
||||||
|
- (NSException *) _handleAttendeeAvailability: (NSArray *) theAttendees
|
||||||
|
forEvent: (iCalEvent *) theEvent
|
||||||
|
{
|
||||||
|
iCalPerson *currentAttendee;
|
||||||
|
NSMutableArray *attendees, *unavailableAttendees, *whiteList;
|
||||||
|
NSEnumerator *enumerator;
|
||||||
|
NSPredicate *predicate;
|
||||||
|
NSString *currentUID, *ownerUID;
|
||||||
|
NSMutableString *reason;
|
||||||
|
NSDictionary *values;
|
||||||
|
NSMutableDictionary *value, *moduleSettings;
|
||||||
|
SOGoUser *user;
|
||||||
|
SOGoUserSettings *us;
|
||||||
|
int count = 0, i = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Build list of the attendees uids without ressources
|
||||||
|
attendees = [NSMutableArray arrayWithCapacity: [theAttendees count]];
|
||||||
|
unavailableAttendees = [[NSMutableArray alloc] init];
|
||||||
|
enumerator = [theAttendees objectEnumerator];
|
||||||
|
ownerUID = [[[self context] activeUser] login];
|
||||||
|
|
||||||
|
while ((currentAttendee = [enumerator nextObject]))
|
||||||
|
{
|
||||||
|
currentUID = [currentAttendee uid];
|
||||||
|
if (currentUID)
|
||||||
|
{
|
||||||
|
user = [SOGoUser userWithLogin: currentUID];
|
||||||
|
us = [user userSettings];
|
||||||
|
moduleSettings = [us objectForKey:@"Calendar"];
|
||||||
|
// Check if the user prevented his account from beeing invited to events
|
||||||
|
if (![user isResource] && [[moduleSettings objectForKey:@"PreventInvitations"] boolValue])
|
||||||
|
{
|
||||||
|
// Check if the user have a whiteList
|
||||||
|
whiteList = [NSMutableArray arrayWithObject:[moduleSettings objectForKey:@"PreventInvitationsWhitelist"]];
|
||||||
|
predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", ownerUID];
|
||||||
|
[whiteList filterUsingPredicate:predicate];
|
||||||
|
// If the filter have a hit, do not add the currentUID to the unavailableAttendees array
|
||||||
|
if ([whiteList count] == 0)
|
||||||
|
{
|
||||||
|
values = [NSDictionary dictionaryWithObject:[user cn] forKey:@"Cn"];
|
||||||
|
[unavailableAttendees addObject:values];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count = [unavailableAttendees count];
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
reason = [NSMutableString stringWithString:[self labelForKey: @"This or these persons cannot be invited:"]];
|
||||||
|
// Add all the unavailable users in the warning message
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
value = [unavailableAttendees objectAtIndex:i];
|
||||||
|
[reason appendString:[value keysWithFormat: @"\n %{Cn}"]];
|
||||||
|
if (i < count-2)
|
||||||
|
[reason appendString:@", "];
|
||||||
|
}
|
||||||
|
[unavailableAttendees release];
|
||||||
|
return [NSException exceptionWithHTTPStatus:409 reason: reason];
|
||||||
|
}
|
||||||
|
[unavailableAttendees release];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This methods scans the list of attendees. If they are
|
// This methods scans the list of attendees. If they are
|
||||||
// considered as resource, it checks for conflicting
|
// considered as resource, it checks for conflicting
|
||||||
|
@ -618,6 +684,8 @@
|
||||||
// We check for conflicts
|
// We check for conflicts
|
||||||
if ((e = [self _handleResourcesConflicts: attendees forEvent: newEvent]))
|
if ((e = [self _handleResourcesConflicts: attendees forEvent: newEvent]))
|
||||||
return e;
|
return e;
|
||||||
|
if ((e = [self _handleAttendeeAvailability: attendees forEvent: newEvent]))
|
||||||
|
return e;
|
||||||
|
|
||||||
enumerator = [attendees objectEnumerator];
|
enumerator = [attendees objectEnumerator];
|
||||||
while ((currentAttendee = [enumerator nextObject]))
|
while ((currentAttendee = [enumerator nextObject]))
|
||||||
|
@ -661,7 +729,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
[e addToAttendees: [theAttendees objectAtIndex: j]];
|
[e addToAttendees: [theAttendees objectAtIndex: j]];
|
||||||
else
|
else
|
||||||
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
|
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,8 +776,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
withType: @"calendar:cancellation"];
|
withType: @"calendar:cancellation"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ex = [self _handleResourcesConflicts: [newEvent attendees]
|
if ((ex = [self _handleResourcesConflicts: [newEvent attendees] forEvent: newEvent]))
|
||||||
forEvent: newEvent]))
|
return ex;
|
||||||
|
if ((ex = [self _handleAttendeeAvailability: [newEvent attendees] forEvent: newEvent]))
|
||||||
return ex;
|
return ex;
|
||||||
|
|
||||||
addedAttendees = [changes insertedAttendees];
|
addedAttendees = [changes insertedAttendees];
|
||||||
|
@ -858,8 +926,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// within the repeating vEvent.
|
// within the repeating vEvent.
|
||||||
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
||||||
oldEvent = (iCalEvent*)[self lookupOccurrence: recurrenceTime];
|
oldEvent = (iCalEvent*)[self lookupOccurrence: recurrenceTime];
|
||||||
if (oldEvent == nil)
|
if (oldEvent == nil) // If no occurence found, create one
|
||||||
// If no occurence found, create one
|
|
||||||
oldEvent = (iCalEvent *)[self newOccurenceWithID: recurrenceTime];
|
oldEvent = (iCalEvent *)[self newOccurenceWithID: recurrenceTime];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,8 +1069,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
{
|
{
|
||||||
NSString *currentEmail, *quotedEmail;
|
NSString *currentEmail, *quotedEmail;
|
||||||
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
||||||
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"",
|
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail];
|
||||||
currentEmail];
|
|
||||||
[otherAttendee setValue: 0 ofAttribute: @"SENT-BY"
|
[otherAttendee setValue: 0 ofAttribute: @"SENT-BY"
|
||||||
to: quotedEmail];
|
to: quotedEmail];
|
||||||
}
|
}
|
||||||
|
@ -1088,8 +1154,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addDelegate || removeDelegate
|
if (addDelegate || removeDelegate
|
||||||
|| [currentStatus caseInsensitiveCompare: newStatus]
|
|| [currentStatus caseInsensitiveCompare: newStatus] != NSOrderedSame)
|
||||||
!= NSOrderedSame)
|
|
||||||
{
|
{
|
||||||
NSMutableArray *delegates;
|
NSMutableArray *delegates;
|
||||||
NSString *delegatedUID;
|
NSString *delegatedUID;
|
||||||
|
@ -1104,8 +1169,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
{
|
{
|
||||||
NSString *currentEmail, *quotedEmail;
|
NSString *currentEmail, *quotedEmail;
|
||||||
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
||||||
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"",
|
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail];
|
||||||
currentEmail];
|
|
||||||
[attendee setValue: 0 ofAttribute: @"SENT-BY"
|
[attendee setValue: 0 ofAttribute: @"SENT-BY"
|
||||||
to: quotedEmail];
|
to: quotedEmail];
|
||||||
}
|
}
|
||||||
|
@ -1215,9 +1279,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
{
|
{
|
||||||
att = [attendees objectAtIndex: i];
|
att = [attendees objectAtIndex: i];
|
||||||
uid = [att uid];
|
uid = [att uid];
|
||||||
if (uid
|
if (uid && att != attendee && ![uid isEqualToString: delegatedUID])
|
||||||
&& att != attendee
|
|
||||||
&& ![uid isEqualToString: delegatedUID])
|
|
||||||
[self _updateAttendee: attendee
|
[self _updateAttendee: attendee
|
||||||
withDelegate: delegate
|
withDelegate: delegate
|
||||||
ownerUser: theOwnerUser
|
ownerUser: theOwnerUser
|
||||||
|
@ -1238,13 +1300,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
NSDictionary *code;
|
NSDictionary *code;
|
||||||
|
|
||||||
element = [NSMutableArray array];
|
element = [NSMutableArray array];
|
||||||
[element addObject: davElementWithContent (@"recipient", XMLNS_CALDAV,
|
[element addObject: davElementWithContent (@"recipient", XMLNS_CALDAV, recipient)];
|
||||||
recipient)];
|
[element addObject: davElementWithContent (@"request-status", XMLNS_CALDAV, @"2.0;Success")];
|
||||||
[element addObject: davElementWithContent (@"request-status",
|
code = davElementWithContent (@"response", XMLNS_CALDAV, element);
|
||||||
XMLNS_CALDAV,
|
|
||||||
@"2.0;Success")];
|
|
||||||
code = davElementWithContent (@"response", XMLNS_CALDAV,
|
|
||||||
element);
|
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -1371,8 +1429,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
attendee = [event userAsAttendee: ownerUser];
|
attendee = [event userAsAttendee: ownerUser];
|
||||||
if (attendee)
|
if (attendee)
|
||||||
{
|
{
|
||||||
if (delegate
|
if (delegate && ![[delegate email] isEqualToString: [attendee delegatedTo]])
|
||||||
&& ![[delegate email] isEqualToString: [attendee delegatedTo]])
|
|
||||||
{
|
{
|
||||||
delegatedUid = [delegate uid];
|
delegatedUid = [delegate uid];
|
||||||
if (delegatedUid)
|
if (delegatedUid)
|
||||||
|
@ -1405,8 +1462,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// the database. We do this ONLY when using SOGo from the
|
// the database. We do this ONLY when using SOGo from the
|
||||||
// Web interface or over ActiveSync.
|
// Web interface or over ActiveSync.
|
||||||
// Over DAV, it'll be handled directly in PUTAction:
|
// Over DAV, it'll be handled directly in PUTAction:
|
||||||
if (![context request]
|
if (![context request] || [[context request] handledByDefaultHandler]
|
||||||
|| [[context request] handledByDefaultHandler]
|
|
||||||
|| [[[context request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
|
|| [[[context request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
|
||||||
ex = [self saveContentString: [[event parent] versitString]];
|
ex = [self saveContentString: [[event parent] versitString]];
|
||||||
}
|
}
|
||||||
|
@ -1616,10 +1672,8 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
{
|
{
|
||||||
event = [allEvents objectAtIndex: i];
|
event = [allEvents objectAtIndex: i];
|
||||||
if ([event isAllDay] && [event isOpaque])
|
if ([event isAllDay] && [event isOpaque])
|
||||||
{
|
|
||||||
[event setTransparency: @"TRANSPARENT"];
|
[event setTransparency: @"TRANSPARENT"];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1744,12 +1798,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
NSArray *roles;
|
NSArray *roles;
|
||||||
SOGoUser *ownerUser;
|
SOGoUser *ownerUser;
|
||||||
|
|
||||||
if (calendar == fullCalendar
|
if (calendar == fullCalendar || calendar == safeCalendar
|
||||||
|| calendar == safeCalendar
|
|
||||||
|| calendar == originalCalendar)
|
|| calendar == originalCalendar)
|
||||||
[NSException raise: NSInvalidArgumentException
|
[NSException raise: NSInvalidArgumentException format: @"the 'calendar' argument must be a distinct instance" @" from the original object"];
|
||||||
format: @"the 'calendar' argument must be a distinct instance"
|
|
||||||
@" from the original object"];
|
|
||||||
|
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
|
|
||||||
|
@ -1760,17 +1811,14 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// responding to one of our invitation. In this case, _setupResponseCalendarInRequest
|
// responding to one of our invitation. In this case, _setupResponseCalendarInRequest
|
||||||
// will only take the new attendee status and actually discard any other modifications.
|
// will only take the new attendee status and actually discard any other modifications.
|
||||||
//
|
//
|
||||||
if ([roles containsObject: @"ComponentResponder"]
|
if ([roles containsObject: @"ComponentResponder"] && ![roles containsObject: @"ComponentModifier"])
|
||||||
&& ![roles containsObject: @"ComponentModifier"])
|
|
||||||
calendar = [self _setupResponseInRequestCalendar: calendar];
|
calendar = [self _setupResponseInRequestCalendar: calendar];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (![[rq headersForKey: @"X-SOGo"]
|
if (![[rq headersForKey: @"X-SOGo"] containsObject: @"NoGroupsDecomposition"])
|
||||||
containsObject: @"NoGroupsDecomposition"])
|
|
||||||
[self _decomposeGroupsInRequestCalendar: calendar];
|
[self _decomposeGroupsInRequestCalendar: calendar];
|
||||||
|
|
||||||
if ([[ownerUser domainDefaults] iPhoneForceAllDayTransparency]
|
if ([[ownerUser domainDefaults] iPhoneForceAllDayTransparency] && [rq isIPhone])
|
||||||
&& [rq isIPhone])
|
|
||||||
{
|
{
|
||||||
[self _adjustTransparencyInRequestCalendar: calendar];
|
[self _adjustTransparencyInRequestCalendar: calendar];
|
||||||
}
|
}
|
||||||
|
@ -1834,11 +1882,11 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
//
|
//
|
||||||
else if (scheduling && [event userIsAttendee: ownerUser])
|
else if (scheduling && [event userIsAttendee: ownerUser])
|
||||||
{
|
{
|
||||||
[self sendResponseToOrganizer: event
|
[self sendIMIPReplyForEvent: event
|
||||||
from: ownerUser];
|
from: ownerUser
|
||||||
|
to: [event organizer]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[self sendReceiptEmailForObject: event
|
[self sendReceiptEmailForObject: event
|
||||||
addedAttendees: attendees
|
addedAttendees: attendees
|
||||||
deletedAttendees: nil
|
deletedAttendees: nil
|
||||||
|
@ -1960,8 +2008,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// recurrence-id and not in the master event. We must fix this, otherwise
|
// recurrence-id and not in the master event. We must fix this, otherwise
|
||||||
// SOGo will break.
|
// SOGo will break.
|
||||||
if (!recurrenceId && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid])
|
if (!recurrenceId && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid])
|
||||||
[[[[newEvent parent] events] objectAtIndex: 0]
|
[[[[newEvent parent] events] objectAtIndex: 0] setOrganizer: [newEvent organizer]];
|
||||||
setOrganizer: [newEvent organizer]];
|
|
||||||
|
|
||||||
if (newEvent == oldEvent)
|
if (newEvent == oldEvent)
|
||||||
newEvent = nil;
|
newEvent = nil;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Foundation/NSCalendarDate.h>
|
#import <Foundation/NSCalendarDate.h>
|
||||||
|
#import <Foundation/NSDictionary.h>
|
||||||
#import <Foundation/NSPropertyList.h>
|
#import <Foundation/NSPropertyList.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#import <Foundation/NSTimeZone.h>
|
#import <Foundation/NSTimeZone.h>
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#import <SOGo/NSString+Utilities.h>
|
#import <SOGo/NSString+Utilities.h>
|
||||||
#import <SOGo/SOGoUser.h>
|
#import <SOGo/SOGoUser.h>
|
||||||
#import <SOGo/SOGoUserDefaults.h>
|
#import <SOGo/SOGoUserDefaults.h>
|
||||||
|
#import <SOGo/SOGoUserSettings.h>
|
||||||
#import <SOGo/SOGoDomainDefaults.h>
|
#import <SOGo/SOGoDomainDefaults.h>
|
||||||
#import <SOGo/SOGoSieveManager.h>
|
#import <SOGo/SOGoSieveManager.h>
|
||||||
#import <SOGo/SOGoSystemDefaults.h>
|
#import <SOGo/SOGoSystemDefaults.h>
|
||||||
|
@ -638,6 +640,47 @@ static NSArray *reminderValues = nil;
|
||||||
return [userDefaults busyOffHours];
|
return [userDefaults busyOffHours];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) whiteList
|
||||||
|
{
|
||||||
|
SOGoUserSettings *us;
|
||||||
|
NSMutableDictionary *moduleSettings;
|
||||||
|
NSArray *whiteList;
|
||||||
|
|
||||||
|
us = [user userSettings];
|
||||||
|
moduleSettings = [us objectForKey: @"Calendar"];
|
||||||
|
whiteList = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
|
||||||
|
return whiteList;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setWhiteList: (NSArray *) whiteList
|
||||||
|
{
|
||||||
|
SOGoUserSettings *us;
|
||||||
|
NSMutableDictionary *moduleSettings;
|
||||||
|
us = [user userSettings];
|
||||||
|
moduleSettings = [us objectForKey: @"Calendar"];
|
||||||
|
[moduleSettings setObject: whiteList forKey: @"PreventInvitationsWhitelist"];
|
||||||
|
[us synchronize];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setPreventInvitations: (BOOL) preventInvitations
|
||||||
|
{
|
||||||
|
SOGoUserSettings *us;
|
||||||
|
NSMutableDictionary *moduleSettings;
|
||||||
|
us = [user userSettings];
|
||||||
|
moduleSettings = [us objectForKey: @"Calendar"];
|
||||||
|
[moduleSettings setObject: [NSNumber numberWithBool: preventInvitations] forKey: @"PreventInvitations"];
|
||||||
|
[us synchronize];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) preventInvitations
|
||||||
|
{
|
||||||
|
SOGoUserSettings *us;
|
||||||
|
NSMutableDictionary *moduleSettings;
|
||||||
|
us = [user userSettings];
|
||||||
|
moduleSettings = [us objectForKey: @"Calendar"];
|
||||||
|
return [[moduleSettings objectForKey: @"PreventInvitations"] boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray *) firstWeekList
|
- (NSArray *) firstWeekList
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObjects:
|
return [NSArray arrayWithObjects:
|
||||||
|
|
|
@ -11,11 +11,14 @@
|
||||||
title="title"
|
title="title"
|
||||||
const:popup="YES"
|
const:popup="YES"
|
||||||
const:cssFiles="datepicker.css"
|
const:cssFiles="datepicker.css"
|
||||||
const:jsFiles="RowEditionController.js,PasswordPolicy.js,ckeditor/ckeditor.js,datepicker.js"
|
const:jsFiles="RowEditionController.js,PasswordPolicy.js,ckeditor/ckeditor.js,datepicker.js, SOGoAutoCompletion.js"
|
||||||
>
|
>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var localeCode = '<var:string value="localeCode"/>';
|
var localeCode = '<var:string value="localeCode"/>';
|
||||||
</script>
|
</script>
|
||||||
|
<div class="popupMenu" id="contactsMenu">
|
||||||
|
<ul></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="colorPickerDialog" style="display: none;" class="dialog right bottom">
|
<div id="colorPickerDialog" style="display: none;" class="dialog right bottom">
|
||||||
<div>
|
<div>
|
||||||
|
@ -214,41 +217,85 @@
|
||||||
const:id="reminderList"
|
const:id="reminderList"
|
||||||
string="itemReminderText" var:selection="reminder"/></dd>
|
string="itemReminderText" var:selection="reminder"/></dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<div class="tabsContainer" id="calendarOptionsTabs">
|
||||||
<label><var:string label:value="Categories"/></label>
|
<ul>
|
||||||
<div id="calendarCategoriesListWrapper" class="listWrapper"
|
<li target="calendarCategoriesView">
|
||||||
><table class="categoriesList" cellspacing="0">
|
<span><var:string label:value="Categories"/></span></li>
|
||||||
|
<li target="calendarAppointmentsInvitationsView">
|
||||||
|
<span><var:string label:value="Appointments invitations"/></span></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tabs">
|
||||||
|
<div id="calendarCategoriesView" class="tab">
|
||||||
|
<div id="calendarCategoriesListWrapper" class="listWrapper">
|
||||||
|
<table class="categoriesList" cellspacing="0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="tableview"
|
<tr class="tableview">
|
||||||
><th const:class="tbtv_headercell" const:id="nameTableHeader"
|
<th const:class="tbtv_headercell" const:id="nameTableHeader">
|
||||||
><var:string label:value="Name"/></th
|
<var:string label:value="Name"/></th>
|
||||||
><th const:class="tbtv_headercell" const:id="colorTableHeader"
|
<th const:class="tbtv_headercell" const:id="colorTableHeader">
|
||||||
><var:string label:value="Color"/></th
|
<var:string label:value="Color"/></th>
|
||||||
></tr
|
</tr>
|
||||||
></thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<var:foreach list="calendarCategoryList" item="category">
|
<var:foreach list="calendarCategoryList" item="category">
|
||||||
<tr const:class="categoryListRow"
|
<tr const:class="categoryListRow">
|
||||||
><td const:class="categoryListCell"
|
<td const:class="categoryListCell">
|
||||||
><var:string var:value="category"/></td
|
<var:string var:value="category"/></td>
|
||||||
><td const:class="categoryListCell"
|
<td const:class="categoryListCell">
|
||||||
><div const:class="colorBox" var:data-color="categoryColor"><entity name="nbsp"/></div></td
|
<div const:class="colorBox" var:data-color="categoryColor"><entity name="nbsp"/></div></td>
|
||||||
></tr>
|
</tr>
|
||||||
</var:foreach>
|
</var:foreach>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div><!-- #calendarCategoriesListWrapper -->
|
||||||
<div class="bottomToolbar">
|
<div class="bottomToolbar">
|
||||||
<a const:id="calendarCategoryAdd" class="bottomButton" href="#">
|
<a const:id="calendarCategoryAdd" class="bottomButton" href="#">
|
||||||
<span><img rsrc:src="add-icon.png" label:title="Add" />
|
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
|
||||||
</span></a>
|
|
||||||
<a const:id="calendarCategoryDelete" class="bottomButton" href="#">
|
<a const:id="calendarCategoryDelete" class="bottomButton" href="#">
|
||||||
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
|
<span><img rsrc:src="remove-icon.png" label:title="Delete" /> </span></a>
|
||||||
</span></a>
|
</div><!-- .bottomToolbar -->
|
||||||
</div>
|
|
||||||
<input type="hidden" const:id="calendarCategoriesValue"
|
<input type="hidden" const:id="calendarCategoriesValue"
|
||||||
const:name="calendarCategoriesValue" var:value="calendarCategoriesValue"/>
|
const:name="calendarCategoriesValue" var:value="calendarCategoriesValue"/>
|
||||||
</div>
|
</div><!-- #calendarCategoriesView -->
|
||||||
|
|
||||||
|
<div id="calendarAppointmentsInvitationsView" class="tab">
|
||||||
|
<div><input type="checkbox"
|
||||||
|
const:name="preventInvitations"
|
||||||
|
const:id="preventInvitations"
|
||||||
|
var:checked="preventInvitations" />
|
||||||
|
<var:string label:value="Prevent from being invited to appointments"/></div>
|
||||||
|
<hr />
|
||||||
|
<var:string label:value="White list for appointments invitations:"/>
|
||||||
|
<div id="appointmentsWhiteListWrapper" class="listWrapper">
|
||||||
|
<table id="tableViewWhiteList" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr class="tableview">
|
||||||
|
<th const:class="tbtv_headercell" const:id="whiteListTableHeader">
|
||||||
|
<var:string label:value="Contacts names"/></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<var:foreach list="appointmentsWhiteList" item="contact">
|
||||||
|
<tr const:class="whiteListRow">
|
||||||
|
<td const:class="whiteListCell">
|
||||||
|
<var:string var:value="contact"/></td>
|
||||||
|
</tr>
|
||||||
|
</var:foreach>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div><!-- #appointmentsWhiteListWrapper -->
|
||||||
|
<div class="bottomToolbar">
|
||||||
|
<a const:id="appointmentsWhiteListAdd" class="bottomButton" href="#">
|
||||||
|
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
|
||||||
|
<a const:id="appointmentsWhiteListDelete" class="bottomButton" href="#">
|
||||||
|
<span><img rsrc:src="remove-icon.png" label:title="Delete" /></span></a>
|
||||||
|
</div><!-- .bottomToolbar -->
|
||||||
|
<input type="hidden" const:id="whiteList"
|
||||||
|
const:name="whiteList" var:value="whiteList"/>
|
||||||
|
</div><!-- #calendarAppointmentsInvitationsView -->
|
||||||
|
</div><!-- .tabs -->
|
||||||
|
</div><!-- #calendarOptionsTabs -->
|
||||||
|
</div><!-- #calendarOptionsView -->
|
||||||
</var:if>
|
</var:if>
|
||||||
<div id="contactsOptionsView" class="tab">
|
<div id="contactsOptionsView" class="tab">
|
||||||
<label><var:string label:value="Categories"/></label>
|
<label><var:string label:value="Categories"/></label>
|
||||||
|
|
|
@ -11,28 +11,29 @@ var SOGoAutoCompletionInterface = {
|
||||||
|
|
||||||
// Attributes that could be changed from the object
|
// Attributes that could be changed from the object
|
||||||
// inheriting the inteface
|
// inheriting the inteface
|
||||||
uidField: "c_name",
|
uidField: "c_name",
|
||||||
addressBook: null,
|
addressBook: null,
|
||||||
excludeGroups: false,
|
SOGoUsersSearch: false,
|
||||||
excludeLists: false,
|
excludeGroups: false,
|
||||||
|
excludeLists: false,
|
||||||
|
|
||||||
// Internal attributes
|
// Internal attributes
|
||||||
animationParent: null,
|
animationParent: null,
|
||||||
selectedIndex: -1,
|
selectedIndex: -1,
|
||||||
delay: 0.750,
|
delay: 0.750,
|
||||||
delayedSearch: false,
|
delayedSearch: false,
|
||||||
menu: null,
|
menu: null,
|
||||||
|
|
||||||
bind: function () {
|
bind: function () {
|
||||||
this.menu = $('contactsMenu');
|
this.menu = $('contactsMenu');
|
||||||
this.writeAttribute("autocomplete", "off");
|
this.writeAttribute("autocomplete", "off");
|
||||||
this.writeAttribute("container", null);
|
this.writeAttribute("container", null);
|
||||||
this.confirmedValue = null;
|
this.confirmedValue = null;
|
||||||
this.observe("keydown", this.onKeydown.bindAsEventListener(this));
|
this.observe("keydown", this.onKeydown.bindAsEventListener(this));
|
||||||
this.observe("blur", this.onBlur.bindAsEventListener(this));
|
this.observe("blur", this.onBlur.bindAsEventListener(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeydown: function (event) {
|
onKeydown: function (event) {
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
this.focussed = true;
|
this.focussed = true;
|
||||||
return;
|
return;
|
||||||
|
@ -102,9 +103,9 @@ var SOGoAutoCompletionInterface = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlur: function (event) {
|
onBlur: function (event) {
|
||||||
if (this.delayedSearch)
|
if (this.delayedSearch)
|
||||||
window.clearTimeout(this.delayedSearch);
|
window.clearTimeout(this.delayedSearch);
|
||||||
if (this.confirmedValue) {
|
if (this.confirmedValue) {
|
||||||
|
@ -116,9 +117,9 @@ var SOGoAutoCompletionInterface = {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.writeAttribute("uid", null);
|
this.writeAttribute("uid", null);
|
||||||
},
|
},
|
||||||
|
|
||||||
performSearch: function (input) {
|
performSearch: function (input) {
|
||||||
// Perform address completion
|
// Perform address completion
|
||||||
if (document.contactLookupAjaxRequest) {
|
if (document.contactLookupAjaxRequest) {
|
||||||
// Abort any pending request
|
// Abort any pending request
|
||||||
|
@ -126,6 +127,12 @@ var SOGoAutoCompletionInterface = {
|
||||||
document.contactLookupAjaxRequest.abort();
|
document.contactLookupAjaxRequest.abort();
|
||||||
}
|
}
|
||||||
if (input.value.trim().length > minimumSearchLength) {
|
if (input.value.trim().length > minimumSearchLength) {
|
||||||
|
if (input.SOGoUsersSearch) {
|
||||||
|
var urlstr = UserFolderURL + "usersSearch?search=" + encodeURIComponent(input.value);
|
||||||
|
document.contactLookupAjaxRequest =
|
||||||
|
triggerAjaxRequest(urlstr, input.performUsersSearchCallback.bind(input), input);
|
||||||
|
}
|
||||||
|
else {
|
||||||
var urlstr = UserFolderURL + "Contacts/";
|
var urlstr = UserFolderURL + "Contacts/";
|
||||||
if (input.addressBook)
|
if (input.addressBook)
|
||||||
urlstr += input.addressBook + "/contact";
|
urlstr += input.addressBook + "/contact";
|
||||||
|
@ -141,13 +148,14 @@ var SOGoAutoCompletionInterface = {
|
||||||
document.contactLookupAjaxRequest =
|
document.contactLookupAjaxRequest =
|
||||||
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
|
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (document.currentPopupMenu)
|
if (document.currentPopupMenu)
|
||||||
hideMenu(document.currentPopupMenu);
|
hideMenu(document.currentPopupMenu);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
performSearchCallback: function (http) {
|
performSearchCallback: function (http) {
|
||||||
if (http.readyState == 4) {
|
if (http.readyState == 4) {
|
||||||
var list = this.menu.down("ul");
|
var list = this.menu.down("ul");
|
||||||
|
|
||||||
|
@ -257,9 +265,108 @@ var SOGoAutoCompletionInterface = {
|
||||||
hideMenu(document.currentPopupMenu);
|
hideMenu(document.currentPopupMenu);
|
||||||
document.contactLookupAjaxRequest = null;
|
document.contactLookupAjaxRequest = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onAddressResultClick: function(event) {
|
performUsersSearchCallback: function (http) {
|
||||||
|
if (http.readyState == 4) {
|
||||||
|
var list = this.menu.down("ul");
|
||||||
|
var input = http.callbackData;
|
||||||
|
if (http.status == 200) {
|
||||||
|
var response = http.responseText.evalJSON();
|
||||||
|
|
||||||
|
if (response.length > 1) {
|
||||||
|
list.select("li").each(function(item) {
|
||||||
|
item.stopObserving("mousedown");
|
||||||
|
item.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate popup menu
|
||||||
|
for (var i = 0; i < response.length; i++) {
|
||||||
|
var c_name = response[i][1];
|
||||||
|
var completeEmail = c_name;
|
||||||
|
var c_mail = response[i][2];
|
||||||
|
var uid = response[i][3];
|
||||||
|
if (c_mail)
|
||||||
|
completeEmail += " <" + c_mail + ">";
|
||||||
|
var node = new Element('li', { 'address': completeEmail,
|
||||||
|
'uid': uid });
|
||||||
|
var matchPosition = completeEmail.toLowerCase().indexOf(input.getValue().toLowerCase());
|
||||||
|
if (matchPosition > -1) {
|
||||||
|
var matchBefore = completeEmail.substring(0, matchPosition);
|
||||||
|
var matchText = completeEmail.substring(matchPosition, matchPosition + input.getValue().length);
|
||||||
|
var matchAfter = completeEmail.substring(matchPosition + input.getValue().length);
|
||||||
|
node.appendChild(document.createTextNode(matchBefore));
|
||||||
|
node.appendChild(new Element('strong').update(matchText));
|
||||||
|
node.appendChild(document.createTextNode(matchAfter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node.appendChild(document.createTextNode(completeEmail));
|
||||||
|
}
|
||||||
|
list.appendChild(node);
|
||||||
|
$(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show popup menu
|
||||||
|
var offsetScroll = Element.cumulativeScrollOffset(input);
|
||||||
|
var offset = Element.positionedOffset(input);
|
||||||
|
if ($(document.body).hasClassName("popup") && typeof initPopupMailer == 'undefined')
|
||||||
|
// Hack for some situations where the offset must be computed differently
|
||||||
|
offset = Element.cumulativeOffset(input);
|
||||||
|
var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
|
||||||
|
var height = 'auto';
|
||||||
|
var heightDiff = window.height() - offset[1];
|
||||||
|
var nodeHeight = node.getHeight();
|
||||||
|
|
||||||
|
if ((response.length * nodeHeight) > heightDiff)
|
||||||
|
// Limit the size of the popup to the window height, minus 12 pixels
|
||||||
|
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
|
||||||
|
|
||||||
|
this.menu.setStyle({ top: top + "px",
|
||||||
|
left: offset[0] + "px",
|
||||||
|
height: height,
|
||||||
|
maxWidth: (window.width() - offset[0] - 12) + "px",
|
||||||
|
visibility: "visible" });
|
||||||
|
this.menu.scrollTop = 0;
|
||||||
|
|
||||||
|
document.currentPopupMenu = this.menu;
|
||||||
|
$(document.body).stopObserving("click");
|
||||||
|
$(document.body).observe("click", onBodyClickMenuHandler);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (document.currentPopupMenu)
|
||||||
|
hideMenu(document.currentPopupMenu);
|
||||||
|
|
||||||
|
if (response.length == 1) {
|
||||||
|
// Single result
|
||||||
|
var c_name = response[0][1];
|
||||||
|
var completeEmail = c_name;
|
||||||
|
var c_mail = response[0][2];
|
||||||
|
var c_uid = response[0][0];
|
||||||
|
input.writeAttribute("uid", c_uid);
|
||||||
|
if (c_mail)
|
||||||
|
completeEmail += " <" + c_mail + ">";
|
||||||
|
if (c_uid.substring(0, input.getValue().length).toUpperCase() == input.getValue().toUpperCase())
|
||||||
|
input.value = completeEmail;
|
||||||
|
else
|
||||||
|
// The result matches email address, not user name
|
||||||
|
input.value += ' >> ' + completeEmail;
|
||||||
|
input.confirmedValue = completeEmail;
|
||||||
|
|
||||||
|
var end = input.getValue().length;
|
||||||
|
$(input).selectText(start, end);
|
||||||
|
|
||||||
|
this.selectedIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (document.currentPopupMenu)
|
||||||
|
hideMenu(document.currentPopupMenu);
|
||||||
|
document.contactLookupAjaxRequest = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onAddressResultClick: function(event) {
|
||||||
var e = Event.element(event);
|
var e = Event.element(event);
|
||||||
if (e.tagName != 'LI')
|
if (e.tagName != 'LI')
|
||||||
e = e.up('LI');
|
e = e.up('LI');
|
||||||
|
@ -274,5 +381,5 @@ var SOGoAutoCompletionInterface = {
|
||||||
this.fire("autocompletion:changed", Event.KEY_RETURN);
|
this.fire("autocompletion:changed", Event.KEY_RETURN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,12 @@ DIV.bottomToolbar
|
||||||
right: 2em;
|
right: 2em;
|
||||||
bottom: 8px; }
|
bottom: 8px; }
|
||||||
|
|
||||||
|
#WhiteListAdd, #WhiteListDelete
|
||||||
|
{
|
||||||
|
border-bottom: 1px solid #9B9B9B;
|
||||||
|
border-right: 1px solid #9B9B9B;
|
||||||
|
}
|
||||||
|
|
||||||
#mailAccountsToolbar
|
#mailAccountsToolbar
|
||||||
{ left: 5px;
|
{ left: 5px;
|
||||||
bottom: 9px;
|
bottom: 9px;
|
||||||
|
@ -47,17 +53,35 @@ DIV.listWrapper
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
border-left: 1px solid #9b9b9b;
|
border-left: 1px solid #9b9b9b;
|
||||||
|
border-right: 1px solid #9b9b9b;
|
||||||
background: #ccddec;}
|
background: #ccddec;}
|
||||||
|
|
||||||
.listWrapper TABLE TD
|
.listWrapper TABLE TD
|
||||||
{ height: 22px; }
|
{ height: 22px; }
|
||||||
|
|
||||||
#calendarCategoriesListWrapper
|
#calendarCategoriesListWrapper
|
||||||
{ top: 232px;
|
{ top:1em;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
right: 2em;
|
right: 2em;
|
||||||
left: 2em; }
|
left: 2em; }
|
||||||
|
|
||||||
|
#appointmentsWhiteListWrapper
|
||||||
|
{ top:4.5em;
|
||||||
|
bottom: 30px;
|
||||||
|
right: 2em;
|
||||||
|
left: 2em; }
|
||||||
|
|
||||||
|
#tableViewWhiteList
|
||||||
|
{ width:100%; }
|
||||||
|
|
||||||
|
DIV#calendarOptionsTabs
|
||||||
|
{ position: absolute;
|
||||||
|
top: 225px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
#contactsCategoriesListWrapper
|
#contactsCategoriesListWrapper
|
||||||
{ overflow: auto;
|
{ overflow: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -9,6 +9,9 @@ function savePreferences(sender) {
|
||||||
if (sigList)
|
if (sigList)
|
||||||
sigList.disabled = false;
|
sigList.disabled = false;
|
||||||
|
|
||||||
|
if ($("appointmentsWhiteListWrapper"))
|
||||||
|
serializeAppointmentsWhiteList();
|
||||||
|
|
||||||
if ($("calendarCategoriesListWrapper"))
|
if ($("calendarCategoriesListWrapper"))
|
||||||
serializeCalendarCategories();
|
serializeCalendarCategories();
|
||||||
|
|
||||||
|
@ -212,6 +215,13 @@ function initPreferences() {
|
||||||
mailController.attachToTabsContainer(tabsContainer);
|
mailController.attachToTabsContainer(tabsContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inner tabs on the calendar module tab
|
||||||
|
tabsContainer = $('calendarOptionsTabs');
|
||||||
|
if (tabsContainer) {
|
||||||
|
var mailController = new SOGoTabsController();
|
||||||
|
mailController.attachToTabsContainer(tabsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
_setupEvents();
|
_setupEvents();
|
||||||
|
|
||||||
// Optional function called when initializing the preferences
|
// Optional function called when initializing the preferences
|
||||||
|
@ -223,6 +233,50 @@ function initPreferences() {
|
||||||
$('colorPickerDialog').on('click', 'span', onColorPickerChoice);
|
$('colorPickerDialog').on('click', 'span', onColorPickerChoice);
|
||||||
$(document.body).on("click", onBodyClickHandler);
|
$(document.body).on("click", onBodyClickHandler);
|
||||||
|
|
||||||
|
// Calendar whiteList
|
||||||
|
var whiteList = $("appointmentsWhiteListWrapper");
|
||||||
|
if(whiteList) {
|
||||||
|
var whiteListValue = $("whiteList").getValue();
|
||||||
|
if (whiteListValue != "") {
|
||||||
|
whiteListValue = whiteListValue.split(",");
|
||||||
|
var tablebody = $("appointmentsWhiteListWrapper").childNodesWithTag("table")[0].tBodies[0];
|
||||||
|
for (i = 0; i < whiteListValue.length; i++)
|
||||||
|
{
|
||||||
|
var elements = whiteListValue[i].split("=");
|
||||||
|
var row = new Element("tr");
|
||||||
|
var td = new Element("td").update("");
|
||||||
|
var textField = new Element("input");
|
||||||
|
var span = new Element("span");
|
||||||
|
|
||||||
|
row.addClassName("whiteListRow");
|
||||||
|
row.observe("mousedown", onRowClick);
|
||||||
|
td.addClassName ("whiteListCell");
|
||||||
|
td.observe("mousedown", endAllEditables);
|
||||||
|
td.observe("dblclick", onNameEdit);
|
||||||
|
textField.addInterface(SOGoAutoCompletionInterface);
|
||||||
|
textField.SOGoUsersSearch = true;
|
||||||
|
textField.observe("autocompletion:changed", endEditable);
|
||||||
|
textField.addClassName("textField");
|
||||||
|
textField.value = elements[1];
|
||||||
|
textField.setAttribute("uid", elements[0]);
|
||||||
|
textField.hide();
|
||||||
|
span.innerText = elements[1];
|
||||||
|
|
||||||
|
td.appendChild(textField);
|
||||||
|
td.appendChild(span);
|
||||||
|
row.appendChild (td);
|
||||||
|
tablebody.appendChild(row);
|
||||||
|
$(tablebody).deselectAll();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var table = whiteList.childNodesWithTag("table")[0];
|
||||||
|
table.multiselect = true;
|
||||||
|
$("appointmentsWhiteListAdd").observe("click", onAppointmentsWhiteListAdd);
|
||||||
|
$("appointmentsWhiteListDelete").observe("click", onAppointmentsWhiteListDelete);
|
||||||
|
}
|
||||||
|
|
||||||
// Calender categories
|
// Calender categories
|
||||||
var wrapper = $("calendarCategoriesListWrapper");
|
var wrapper = $("calendarCategoriesListWrapper");
|
||||||
if (wrapper) {
|
if (wrapper) {
|
||||||
|
@ -282,8 +336,7 @@ function initPreferences() {
|
||||||
|
|
||||||
button = $("enableVacationEndDate");
|
button = $("enableVacationEndDate");
|
||||||
if (button) {
|
if (button) {
|
||||||
jQuery("#vacationEndDate_date").closest(".date").datepicker(
|
jQuery("#vacationEndDate_date").closest(".date").datepicker({ autoclose: true, position: 'above', weekStart: $('weekStartDay').getValue() });
|
||||||
{ autoclose: true, position: 'above', weekStart: $('weekStartDay').getValue() });
|
|
||||||
button.on("click", function(event) {
|
button.on("click", function(event) {
|
||||||
if (this.checked)
|
if (this.checked)
|
||||||
$("vacationEndDate_date").enable();
|
$("vacationEndDate_date").enable();
|
||||||
|
@ -977,6 +1030,119 @@ function onCalendarColorEdit(e) {
|
||||||
onCCE(e, "calendarCategoriesListWrapper");
|
onCCE(e, "calendarCategoriesListWrapper");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeEditable (element) {
|
||||||
|
element.addClassName("editing");
|
||||||
|
element.removeClassName("whiteListCell");
|
||||||
|
|
||||||
|
var span = element.down("SPAN");
|
||||||
|
span.update();
|
||||||
|
|
||||||
|
var textField = element.down("INPUT");
|
||||||
|
textField.show();
|
||||||
|
textField.focus();
|
||||||
|
textField.select();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function endAllEditables (e) {
|
||||||
|
var r = $$("TABLE#tableViewWhiteList TBODY TR TD");
|
||||||
|
for (var i = 0; i < r.length; i++) {
|
||||||
|
var element = $(r[i]);
|
||||||
|
if (r[i] != this && element.hasClassName("editing"))
|
||||||
|
endEditable(null, element.down("INPUT"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNameEdit (e) {
|
||||||
|
endAllEditables();
|
||||||
|
if (!this.hasClassName("editing")) {
|
||||||
|
makeEditable (this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function endEditable(event, textField) {
|
||||||
|
if (!textField)
|
||||||
|
textField = this;
|
||||||
|
|
||||||
|
var uid = textField.readAttribute("uid");
|
||||||
|
var cell = textField.up("TD");
|
||||||
|
var textSpan = cell.down("SPAN");
|
||||||
|
|
||||||
|
cell.removeClassName("editing");
|
||||||
|
cell.addClassName("whiteListCell");
|
||||||
|
textField.hide();
|
||||||
|
|
||||||
|
var tmp = textField.value;
|
||||||
|
tmp = tmp.replace (/</, "<");
|
||||||
|
tmp = tmp.replace (/>/, ">");
|
||||||
|
if (!uid)
|
||||||
|
cell.up("TR").addClassName("notfound");
|
||||||
|
if (tmp)
|
||||||
|
textSpan.update(tmp);
|
||||||
|
else
|
||||||
|
cell.up("TR").remove();
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
Event.stop(event);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAppointmentsWhiteListAdd(e) {
|
||||||
|
var tablebody = $("appointmentsWhiteListWrapper").childNodesWithTag("table")[0].tBodies[0];
|
||||||
|
var row = new Element("tr");
|
||||||
|
var td = new Element("td").update("");
|
||||||
|
var textField = new Element("input");
|
||||||
|
var span = new Element("span");
|
||||||
|
|
||||||
|
row.addClassName("whiteListRow");
|
||||||
|
row.observe("mousedown", onRowClick);
|
||||||
|
td.addClassName ("whiteListCell");
|
||||||
|
td.observe("mousedown", endAllEditables);
|
||||||
|
td.observe("dblclick", onNameEdit);
|
||||||
|
textField.addInterface(SOGoAutoCompletionInterface);
|
||||||
|
textField.SOGoUsersSearch = true;
|
||||||
|
textField.observe("autocompletion:changed", endEditable);
|
||||||
|
textField.addClassName("textField");
|
||||||
|
|
||||||
|
td.appendChild(textField);
|
||||||
|
td.appendChild(span);
|
||||||
|
row.appendChild (td);
|
||||||
|
tablebody.appendChild(row);
|
||||||
|
$(tablebody).deselectAll();
|
||||||
|
row.selectElement();
|
||||||
|
|
||||||
|
makeEditable(td);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAppointmentsWhiteListDelete(e) {
|
||||||
|
var list = $('appointmentsWhiteListWrapper').down("TABLE").down("TBODY");
|
||||||
|
var rows = list.getSelectedNodes();
|
||||||
|
var count = rows.length;
|
||||||
|
|
||||||
|
for (var i=0; i < count; i++) {
|
||||||
|
rows[i].editionController = null;
|
||||||
|
rows[i].remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeAppointmentsWhiteList() {
|
||||||
|
var r = $$("#appointmentsWhiteListWrapper TBODY TR");
|
||||||
|
|
||||||
|
var values = [];
|
||||||
|
for (var i = 0; i < r.length; i++) {
|
||||||
|
var tds = r[i].childElements().first().down("INPUT");
|
||||||
|
var uid = tds.getAttribute("uid");
|
||||||
|
var value = tds.getValue();
|
||||||
|
var user = uid + "=" + value;
|
||||||
|
if (uid != null)
|
||||||
|
values.push(user);
|
||||||
|
}
|
||||||
|
$("whiteList").value = values;
|
||||||
|
}
|
||||||
|
|
||||||
function onCalendarCategoryAdd(e) {
|
function onCalendarCategoryAdd(e) {
|
||||||
var row = new Element("tr");
|
var row = new Element("tr");
|
||||||
var nametd = new Element("td").update("");
|
var nametd = new Element("td").update("");
|
||||||
|
@ -1016,7 +1182,7 @@ function serializeCalendarCategories() {
|
||||||
var values = [];
|
var values = [];
|
||||||
for (var i = 0; i < r.length; i++) {
|
for (var i = 0; i < r.length; i++) {
|
||||||
var tds = r[i].childElements();
|
var tds = r[i].childElements();
|
||||||
var name = $(tds.first()).innerHTML;
|
var name = $(tds.first()).innerHTML.trim();
|
||||||
var color = $(tds.last().childElements().first()).readAttribute('data-color');
|
var color = $(tds.last().childElements().first()).readAttribute('data-color');
|
||||||
values.push("\"" + name + "\": \"" + color + "\"");
|
values.push("\"" + name + "\": \"" + color + "\"");
|
||||||
}
|
}
|
||||||
|
@ -1144,7 +1310,7 @@ function onContactsCategoryAdd(e) {
|
||||||
var list = $('contactsCategoriesListWrapper').down("TABLE").down("TBODY");
|
var list = $('contactsCategoriesListWrapper').down("TABLE").down("TBODY");
|
||||||
list.appendChild(row);
|
list.appendChild(row);
|
||||||
|
|
||||||
resetContactsTableActions ();
|
resetContactsTableActions();
|
||||||
nametd.editionController.startEditing();
|
nametd.editionController.startEditing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1179,7 +1345,6 @@ function onAddOutgoingAddressesCheck(checkBox) {
|
||||||
checkBox = $("addOutgoingAddresses");
|
checkBox = $("addOutgoingAddresses");
|
||||||
}
|
}
|
||||||
$("addressBookList").disabled = !checkBox.checked;
|
$("addressBookList").disabled = !checkBox.checked;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReplyPlacementListChange() {
|
function onReplyPlacementListChange() {
|
||||||
|
|
|
@ -374,7 +374,7 @@ TH.tbtv_navcell
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
background-color: #E7E7E7;
|
background-color: #E7E7E7;
|
||||||
height: 20px; }
|
height: 20px;}
|
||||||
|
|
||||||
TD.sortableTableHeader:active,
|
TD.sortableTableHeader:active,
|
||||||
TH.sortableTableHeader:active
|
TH.sortableTableHeader:active
|
||||||
|
@ -410,7 +410,8 @@ TH.tbtv_headercell IMG.tbtv_sortcell
|
||||||
text-align: right;
|
text-align: right;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px; }
|
height: 12px;
|
||||||
|
top:0;}
|
||||||
|
|
||||||
.tableview
|
.tableview
|
||||||
{ cursor: default;
|
{ cursor: default;
|
||||||
|
|
Loading…
Reference in a new issue