+2007-10-10 Ludovic Marcotte <ludovic@inverse.ca>
+
+ * UI/Scheduler/UIxComponentEditor.m
+ Implemented event/task priority support.
+
+ * SoObjects/Contacts/SOGoContactGCSFolder.m
+ Added CardDAV support.
+
+ * SoObjects/SOGo/LDAPUserManager.m and SOGoUser.m
+ Implemented From: based on LDAP results based on
+ the MailFieldNames attribute (an array) specified
+ in every LDAP-based authentication sources.
+
+ * UI/MailPartViewers/UIxMailPartTextViewer.m and
+ UI/WebServerResources/MailerUI.css
+ We avoid replacing "\r\n" and "\n" with <br /> and
+ rather use CSS capabilities for proper formatting.
+ This is _WAY_ faster on very large mails.
+
+2007-10-10 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * UI/Scheduler/UIxComponentEditor.m
+ ([UIxComponentEditor -componentCalendar]): returns the calendar
+ object of the current event.
+
+2007-10-05 Ludovic Marcotte <ludovic@inverse.ca>
+
+ * UI/WebServerResources/MailerUI.js
+ We check if at least one message is selected
+ before performing a Reply/Reply All/Forward
+
+ * SoObjects/Appointments/SOGoAppointmentFolder.m
+ and others - implemented support for recurring
+ events (with some known limitations right now,
+ all soon to be fixed).
+
+2007-10-04 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * Main/SOGo.m ([SOGo -isUserName:_keyinContext:_ctx]): removed
+ the constraint that a username can't start with a digit.
+
+2007-10-02 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * Moved SOPE/sope-gdl1/GDLContentStore from the default trunk
+ repository to Inverse's branch.
+
+2007-09-28 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * SoObjects/Mailer/SOGoDraftObject.m
+ ([SOGoDraftObject -isValidAttachmentName:_name]): removed
+ constraint on space in file name.
+ ([SOGoDraftObject -saveAttachment:_attachwithMetadata:metadata]):
+ now removes from file name all characters preceding a backslash.
+ This happens with IE7 because the complete attachment file path
+ is sent.
+
+2007-09-25 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * SoObjects/Appointments/SOGoAptMailNotification.m
+ ([SOGoAptMailNotification -appointmentURL]): set personal as the
+ default calendar where to add the event.
+
+ * UI/MainUI/SOGoUserHomePage.m ([SOGoUserHomePage +initialize]):
+ activate the SOGoUIxDefaultModule user defaults.
+
+2007-09-21 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * UI/SOGoUI/UIxComponent.m
+ ([UIxComponent -shortUserNameForDisplay]): returns the string
+ "wrongusernamepassword" when authentication failed.
+
2007-09-17 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/MailPartViewers/UIxMailPartICalViewer.m
2006-09-13 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Contacts/UIxContactView.m: added many wrapper methods to
- display blocks of data à la Thunderbird Addressbook. If data is
+ display blocks of data à la Thunderbird Addressbook. If data is
available, those wrappers (around the NGVCard methods) will
enclose the results in a proper HTML output with the correct label
(if present), otherwise it will return an empty string.
SUBPROJECTS = \
SOPE/NGCards \
+ SOPE/sope-gdl1/GDLContentStore \
OGoContentStore \
SoObjects \
Main \
if ([_key length] < 1)
return NO;
- if (isdigit([_key characterAtIndex:0]))
- return NO;
-
return YES;
}
- implemented cookie-based identification in the web interface;
- fixed a bug where a false positive happening whenever a wrong user login was
given during an indirect bind;
+- remove the constraint that a username can't begin with a digit;
- deleting a message no longer expunges its parent folder;
- implemented support for multiple calendars;
- it is now possible to rename folders;
- added tooltips for toolbar buttons (English and French);
- added checkmarks in live search options popup menus;
- added browser detection with recommanded alternatives;
-- initial support for resizable columns in tables;
-- improved IE7 and Safari support: attendees selector;
+- support for resizable columns in tables;
+- improved support for multiple selection in tables and lists;
+- improved IE7 and Safari support: attendees selector, email file attachments;
- countless bugfixes;
0.9.0-20070824
interval = [self->rrule repeatInterval];
until = [self lastInstanceStartDate]; // TODO: maybe replace
byMonthDay = [self->rrule byMonthDay];
-
- /* check whether the range to be processed is beyond the 'until' date */
-
+
+ /* check whether the range to be processed is beyond the 'until' date */
if (until != nil) {
if ([until compare:rStart] == NSOrderedAscending) /* until before start */
return nil;
continue;
/* first check whether we are in the interval */
-
+
if ((monthIdxInRecurrence % interval) != 0)
continue;
rule = [_rRules objectAtIndex:i];
if (![rule isKindOfClass:iCalRecurrenceRuleClass])
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
-
+
calc = [self recurrenceCalculatorForRecurrenceRule:rule
withFirstInstanceCalendarDateRange:_fir];
+
rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
[ranges addObjectsFromArray:rs];
}
unsigned k;
exDate = [exDates objectAtIndex:i];
+
for (k = 0; k < rCount; k++) {
unsigned rIdx;
return filterData;
}
+#warning filters is leaked here
- (NSArray *) _parseCalendarFilters: (id <DOMElement>) parentNode
{
NSEnumerator *children;
max = [filters count];
for (count = 0; count < max; count++)
{
+#warning huh? why not objectAtIndex: count?
currentFilter = [filters objectAtIndex: 0];
apts = [self fetchCoreInfosFrom: [currentFilter objectForKey: @"start"]
to: [currentFilter objectForKey: @"end"]
md = [[_record mutableCopy] autorelease];
- /* cycle is in _r */
+ /* cycle is in _r. We also have to override the c_startdate/c_enddate with the date values of
+ the reccurence since we use those when displaying events in SOGo Web */
tmp = [_r startDate];
[tmp setTimeZone: timeZone];
[md setObject:tmp forKey:@"startDate"];
+ [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_startdate"];
tmp = [_r endDate];
[tmp setTimeZone: timeZone];
[md setObject:tmp forKey:@"endDate"];
+ [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_enddate"];
return md;
}
rules = [cycleinfo objectForKey:@"rules"];
exRules = [cycleinfo objectForKey:@"exRules"];
exDates = [cycleinfo objectForKey:@"exDates"];
-
+
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange:_r
firstInstanceCalendarDateRange:fir
recurrenceRules:rules
exceptionRules:exRules
exceptionDates:exDates];
count = [ranges count];
+
for (i = 0; i < count; i++) {
NGCalendarDateRange *rRange;
id fixedRow;
rRange = [ranges objectAtIndex:i];
fixedRow = [self fixupCycleRecord:row cycleRange:rRange];
- if (fixedRow != nil) [_ma addObject:fixedRow];
+ if (fixedRow != nil)
+ {
+ [_ma addObject:fixedRow];
+ }
}
}
ma = [NSMutableArray arrayWithArray: records];
}
- /* fetch recurrent apts now */
- sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@%@",
- dateSqlString, componentSqlString, privacySqlString];
- qualifier = [EOQualifier qualifierWithQualifierFormat: sql];
+ /* fetch recurrent apts now. we do NOT consider the date range when doing that
+ as the c_startdate/c_enddate of a recurring event is always set to the first
+ recurrence - others are generated on the fly */
+ sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@", componentSqlString, privacySqlString];
- [fields addObject: @"c_cycleinfo"];
+ qualifier = [EOQualifier qualifierWithQualifierFormat: sql];
records = [_folder fetchFields: fields matchingQualifier: qualifier];
+
if (records)
{
- if (logger)
- [self debugWithFormat: @"fetched %i cyclic records: %@",
- [records count], records];
- if (r)
+ if (r) {
records = [self fixupCyclicRecords: records fetchRange: r];
+ }
if (!ma)
ma = [NSMutableArray arrayWithCapacity: [records count]];
@"c_status", @"c_classification",
@"c_isallday", @"c_isopaque",
@"c_participants", @"c_partmails",
- @"c_partstates", @"c_sequence", @"c_priority",
+ @"c_partstates", @"c_sequence", @"c_priority", @"c_cycleinfo",
nil];
return [self fetchFields: infos from: _startDate to: _endDate
NSString *aptUID;
aptUID = [[self newApt] uid];
- return [NSString stringWithFormat:@"%@/Calendar/%@/edit?mail-invitation=yes",
+ return [NSString stringWithFormat:@"%@/Calendar/personal/%@/edit?mail-invitation=yes",
[self homePageURL],
aptUID];
}
#import <EOControl/EOQualifier.h>
#import <EOControl/EOSortOrdering.h>
#import <GDLContentStore/GCSFolder.h>
+#import <DOM/DOMProtocols.h>
+#import <SaxObjC/SaxObjC.h>
+#import <SaxObjC/XMLNamespaces.h>
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
#import "SOGoContactGCSEntry.h"
if (filter && [filter length] > 0)
{
+#warning why we do not use %%%@%% everywhere?
qs = [NSString stringWithFormat:
@"(c_sn isCaseInsensitiveLike: '%@%%') OR "
@"(c_givenname isCaseInsensitiveLike: '%@%%') OR "
return newRecords;
}
+- (BOOL) _isValidFilter: (NSString *) theString
+{
+ if ([theString caseInsensitiveCompare: @"sn"] == NSOrderedSame)
+ return YES;
+
+ if ([theString caseInsensitiveCompare: @"givenname"] == NSOrderedSame)
+ return YES;
+
+ if ([theString caseInsensitiveCompare: @"mail"] == NSOrderedSame)
+ return YES;
+
+ if ([theString caseInsensitiveCompare: @"telephonenumber"] == NSOrderedSame)
+ return YES;
+
+ return NO;
+}
+
+- (NSDictionary *) _parseContactFilter: (id <DOMElement>) filterElement
+{
+ NSMutableDictionary *filterData;
+ id <DOMNode> parentNode;
+ id <DOMNodeList> ranges;
+ NSString *componentName;
+
+ parentNode = [filterElement parentNode];
+
+ if ([[parentNode tagName] isEqualToString: @"filter"] &&
+ [self _isValidFilter: [filterElement attribute: @"name"]])
+ {
+ ranges = [filterElement getElementsByTagName: @"text-match"];
+
+ if ([ranges count] && [[[ranges objectAtIndex: 0] childNodes] count])
+ {
+ filterData = [NSMutableDictionary new];
+ [filterData autorelease];
+ [filterData setObject: [[[[ranges objectAtIndex: 0] childNodes] lastObject] data]
+ forKey: [filterElement attribute: @"name"]];
+ }
+ }
+ else
+ filterData = nil;
+
+ return filterData;
+}
+
+#warning filters is leaked here
+- (NSArray *) _parseContactFilters: (id <DOMElement>) parentNode
+{
+ NSEnumerator *children;
+ id<DOMElement> node;
+ NSMutableArray *filters;
+ NSDictionary *filter;
+
+ filters = [NSMutableArray new];
+
+ children = [[parentNode getElementsByTagName: @"prop-filter"]
+ objectEnumerator];
+
+ node = [children nextObject];
+
+ while (node)
+ {
+ filter = [self _parseContactFilter: node];
+ if (filter)
+ [filters addObject: filter];
+ node = [children nextObject];
+ }
+
+ return filters;
+}
+
+- (void) _appendComponentsMatchingFilters: (NSArray *) filters
+ toResponse: (WOResponse *) response
+{
+ unsigned int count, max;
+ NSDictionary *currentFilter, *contact;
+ NSEnumerator *contacts;
+ NSString *baseURL;
+
+ baseURL = [self baseURLInContext: context];
+
+ max = [filters count];
+ for (count = 0; count < max; count++)
+ {
+ currentFilter = [filters objectAtIndex: count];
+ contacts = [[self lookupContactsWithFilter: [[currentFilter allValues] lastObject]
+ sortBy: @"c_givenname"
+ ordering: NSOrderedDescending]
+ objectEnumerator];
+
+ while ((contact = [contacts nextObject]))
+ {
+ [self appendObject: contact
+ withBaseURL: baseURL
+ toREPORTResponse: response];
+ }
+ }
+}
+
+- (void) appendObject: (NSDictionary *) object
+ withBaseURL: (NSString *) baseURL
+ toREPORTResponse: (WOResponse *) r
+{
+ SOGoContactGCSEntry *component;
+ Class componentClass;
+ NSString *name, *etagLine, *contactString;
+
+ name = [object objectForKey: @"c_name"];
+ componentClass = [SOGoContactGCSEntry class];
+
+ component = [componentClass objectWithName: name inContainer: self];
+
+ [r appendContentString: @" <D:response>\r\n"];
+ [r appendContentString: @" <D:href>"];
+ [r appendContentString: baseURL];
+ if (![baseURL hasSuffix: @"/"])
+ [r appendContentString: @"/"];
+ [r appendContentString: name];
+ [r appendContentString: @"</D:href>\r\n"];
+
+ [r appendContentString: @" <D:propstat>\r\n"];
+ [r appendContentString: @" <D:prop>\r\n"];
+ etagLine = [NSString stringWithFormat: @" <D:getetag>%@</D:getetag>\r\n",
+ [component davEntityTag]];
+ [r appendContentString: etagLine];
+ [r appendContentString: @" </D:prop>\r\n"];
+ [r appendContentString: @" <D:status>HTTP/1.1 200 OK</D:status>\r\n"];
+ [r appendContentString: @" </D:propstat>\r\n"];
+ [r appendContentString: @" <C:addressbook-data>"];
+ contactString = [[component contentAsString] stringByEscapingXMLString];
+ [r appendContentString: contactString];
+ [r appendContentString: @"</C:addressbook-data>\r\n"];
+ [r appendContentString: @" </D:response>\r\n"];
+}
+
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
sortBy: (NSString *) sortKey
ordering: (NSComparisonResult) sortOrdering
EOQualifier *qualifier;
EOSortOrdering *ordering;
-// NSLog (@"fetching records matching '%@', sorted by '%@' in order %d",
-// filter, sortKey, sortOrdering);
-
fields = folderListingFields;
qualifier = [self _qualifierForFilter: filter];
dbRecords = [[self ocsFolder] fetchFields: fields
matchingQualifier: qualifier];
+
if ([dbRecords count] > 0)
{
records = [self _flattenedRecords: dbRecords];
// else
// [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
- //[self debugWithFormat:@"fetched %i records.", [records count]];
+ [self debugWithFormat:@"fetched %i records.", [records count]];
return records;
}
return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
}
+- (id) davAddressbookQuery: (id) queryContext
+{
+ WOResponse *r;
+ NSArray *filters;
+ id <DOMDocument> document;
+
+ r = [context response];
+ [r setStatus: 207];
+ [r setContentEncoding: NSUTF8StringEncoding];
+ [r setHeader: @"text/xml; charset=\"utf-8\"" forKey: @"content-type"];
+ [r setHeader: @"no-cache" forKey: @"pragma"];
+ [r setHeader: @"no-cache" forKey: @"cache-control"];
+ [r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"];
+ [r appendContentString: @"<D:multistatus xmlns:D=\"DAV:\""
+ @" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\r\n"];
+
+ document = [[context request] contentAsDOMDocument];
+ filters = [self _parseContactFilters: [document documentElement]];
+
+ [self _appendComponentsMatchingFilters: filters
+ toResponse: r];
+ [r appendContentString:@"</D:multistatus>\r\n"];
+
+ return r;
+}
+
- (NSArray *) davComplianceClassesInContext: (id)_ctx
{
NSMutableArray *classes;
- (BOOL) isValidAttachmentName: (NSString *) _name
{
- static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", @" ", nil };
+ static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", nil };
unsigned i;
NSRange r;
withMetadata: (NSDictionary *) metadata
{
NSString *p, *name, *mimeType;
-
+ NSRange r;
+
if (![_attach isNotNull]) {
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
reason: @"Missing attachment content!"];
return [NSException exceptionWithHTTPStatus:500 /* Server Error */
reason: @"Could not create folder for draft!"];
}
+
name = [metadata objectForKey: @"filename"];
+ r = [name rangeOfString: @"\\"
+ options: NSBackwardsSearch];
+ if (r.length > 0)
+ name = [name substringFromIndex: r.location + 1];
+
if (![self isValidAttachmentName: name])
return [self invalidAttachmentNameError: name];
@interface LDAPSource : NSObject
{
+ NSString *sourceID;
NSString *bindDN;
NSString *hostname;
unsigned int port;
- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID;
- (NSArray *) allEntryIDs;
- (NSArray *) fetchContactsMatching: (NSString *) filter;
+- (NSString *) sourceID;
@end
#import <NGLdap/NGLdapEntry.h>
#import "LDAPSource.h"
+#import "LDAPUserManager.h"
static NSArray *commonSearchFields;
static int timeLimit;
@"locality",
@"birthyear",
@"serialNumber",
- @"calFBURL",
+ @"calFBURL", @"proxyAddresses",
nil];
+
[commonSearchFields retain];
}
}
hostname = nil;
port = 389;
password = nil;
+ sourceID = nil;
baseDN = nil;
IDField = @"cn"; /* the first part of a user DN */
[UIDField release];
[bindFields release];
[ldapConnection release];
+ [sourceID release];
[super dealloc];
}
{
self = [self init];
+ ASSIGN(sourceID, [udSource objectForKey: @"id"]);
+
[self setBindDN: [udSource objectForKey: @"bindDN"]
hostname: [udSource objectForKey: @"hostname"]
port: [udSource objectForKey: @"port"]
- (NSArray *) _searchAttributes
{
+ NSArray *attrs;
+
if (!searchAttributes)
{
searchAttributes = [NSMutableArray new];
[searchAttributes addObjectsFromArray: commonSearchFields];
}
+ // We also include our MailFieldNames in the search
+ if ((attrs = [[[LDAPUserManager sharedUserManager] metadataForSourceID: sourceID] objectForKey: @"MailFieldNames"]))
+ {
+ [searchAttributes addObjectsFromArray: attrs];
+ }
+
return searchAttributes;
}
return contactEntry;
}
+- (NSString *) sourceID
+{
+ return sourceID;
+}
+
@end
+ (id) sharedUserManager;
- (NSArray *) sourceIDs;
+- (NSDictionary *) metadataForSourceID: (NSString *) sourceID;
- (NSArray *) authenticationSourceIDs;
- (NSArray *) addressBookSourceIDs;
value = [udSource objectForKey: @"displayName"];
if (value)
[metadata setObject: value forKey: @"displayName"];
+ value = [udSource objectForKey: @"MailFieldNames"];
+ if (value)
+ [metadata setObject: value forKey: @"MailFieldNames"];
[sourcesMetadata setObject: metadata forKey: sourceID];
}
return sourceIDs;
}
+- (NSDictionary *) metadataForSourceID: (NSString *) sourceID
+{
+ return [sourcesMetadata objectForKey: sourceID];
+}
+
- (NSArray *) authenticationSourceIDs
{
return [self _sourcesOfType: @"canAuthenticate"];
NSEnumerator *ldapSources;
LDAPSource *currentSource;
NSString *cn, *email, *c_uid;
-
+ NSArray *attrs;
+
emails = [NSMutableArray array];
cn = nil;
c_uid = nil;
cn = [userEntry objectForKey: @"c_cn"];
if (!c_uid)
c_uid = [userEntry objectForKey: @"c_uid"];
- email = [userEntry objectForKey: @"mail"];
- if (email && ![emails containsObject: email])
- [emails addObject: email];
- email = [userEntry objectForKey: @"mozillaSecondEmail"];
- if (email && ![emails containsObject: email])
- [emails addObject: email];
- email = [userEntry objectForKey: @"xmozillasecondemail"];
- if (email && ![emails containsObject: email])
- [emails addObject: email];
+
+ if ((attrs = [[sourcesMetadata objectForKey: [currentSource sourceID]] objectForKey: @"MailFieldNames"]))
+ {
+ int i;
+
+ for (i = 0; i < [attrs count]; i++)
+ {
+ email = [userEntry objectForKey: [attrs objectAtIndex: i]];
+ if (email && ![emails containsObject: email])
+ [emails addObject: email];
+ }
+ }
}
currentSource = [ldapSources nextObject];
}
[currentUser setObject: emails forKey: @"emails"];
[currentUser setObject: cn forKey: @"cn"];
[currentUser setObject: c_uid forKey: @"c_uid"];
- [self _fillContactMailRecords: currentUser];
+
+ // If our LDAP queries gave us nothing, we add at least one default
+ // email address based on the default domain.
+ if ([emails count] == 0)
+ {
+ [self _fillContactMailRecords: currentUser];
+ }
}
- (void) _retainUser: (NSDictionary *) newUser
/* NSString+Utilities.m - this file is part of SOGo
*
- * Copyright (C) 2006 Inverse group conseil
+ * Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
if (!urlAfterEndingChars)
{
urlAfterEndingChars = [NSMutableCharacterSet new];
- [urlAfterEndingChars addCharactersInString: @"\t \r\n"];
+ [urlAfterEndingChars addCharactersInString: @"[]\t \r\n"];
}
start = refRange.location;
start--;
start++;
length = [self length] - start;
- workRange = NSMakeRange (start, length);
+ workRange = NSMakeRange(start, length);
workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
options: NSLiteralSearch range: workRange];
if (workRange.location != NSNotFound)
while (httpRange.location != NSNotFound)
{
if ([ranges hasRangeIntersection: httpRange])
- rest.location = NSMaxRange (httpRange);
+ rest.location = NSMaxRange(httpRange);
else
{
currentURL = [selfCopy _rangeOfURLInRange: httpRange];
urlText = [selfCopy substringFromRange: currentURL];
if ([urlText length] > matchLength)
{
+ if ([urlText hasPrefix: prefix]) prefix = @"";
+
newUrlText = [NSString stringWithFormat: @"<a href=\"%@%@\">%@</a>",
prefix, urlText, urlText];
[selfCopy replaceCharactersInRange: currentURL
= NSMakeRange (currentURL.location, [newUrlText length]);
[ranges addRange: currentURL];
}
- rest.location = NSMaxRange (currentURL);
+ rest.location = NSMaxRange(currentURL);
}
+
length = [selfCopy length];
rest.length = length - rest.location;
httpRange = [selfCopy rangeOfString: match
if (!mailAccounts)
{
+ NSArray *mails;
+ int i;
+
mailAccount = [NSMutableDictionary dictionary];
name = [NSString stringWithFormat: @"%@@%@", login, fallbackIMAP4Server];
[mailAccount setObject: login forKey: @"userName"];
[mailAccount setObject: fallbackIMAP4Server forKey: @"serverName"];
[mailAccount setObject: name forKey: @"name"];
- identity = [NSMutableDictionary dictionary];
- fullName = [self cn];
- if (![fullName length])
- fullName = login;
- [identity setObject: fullName forKey: @"fullName"];
- [identity setObject: [self systemEmail] forKey: @"email"];
- [identity setObject: [NSNumber numberWithBool: YES] forKey: @"isDefault"];
-
identities = [NSMutableArray array];
- [identities addObject: identity];
+ mails = [self allEmails];
+
+ for (i = 0; i < [mails count]; i++)
+ {
+ identity = [NSMutableDictionary dictionary];
+ fullName = [self cn];
+ if (![fullName length])
+ fullName = login;
+ [identity setObject: fullName forKey: @"fullName"];
+ [identity setObject: [mails objectAtIndex: i] forKey: @"email"];
+
+ if (i == 0) [identity setObject: [NSNumber numberWithBool: YES] forKey: @"isDefault"];
+ [identities addObject: identity];
+ }
+
[mailAccount setObject: identities forKey: @"identities"];
mailAccounts = [NSMutableArray new];
[(WOContext *)_ctx setObject: ((folder)
? folder
- : [NSNull null])
+ : (id)[NSNull null])
forKey: @"ActiveUserHomeFolder"];
return folder;
}
"Address Book" = "Address Book";
"Mail" = "Mail";
"Preferences" = "Preferences";
-"Logoff" = "Logoff";
+"Sign Out" = "Sign Out";
"Right Administration" = "Right Administration";
"Log Console (dev.)" = "Log Console (dev.)";
"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object.";
-"browserNotCompatible" = "We've detected that your browser version is currently not supported on this site. Our recommendation is to use Firefox. Link to download the most current version of this browser is provided bellow:";
+"browserNotCompatible" = "We've detected that your browser version is currently not supported on this site. Our recommendation is to use Firefox. Click on the link bellow to download the most current version of this browser.";
"alternativeBrowsers" = "Alternatively, you can also use the following compatible browsers";
"alternativeBrowserSafari" = "Alternatively, you can also use Safari.";
"Download" = "Download";
"Address Book" = "Carnet d'adresses";
"Mail" = "Courrier";
"Preferences" = "Préférences";
-"Logoff" = "Quitter";
+"Sign Out" = "Quitter";
"Right Administration" = "Partage";
"Log Console (dev.)" = "Journal (dév.)";
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/SoSecurityManager.h>
+#import <NGObjWeb/SoClassSecurityInfo.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
#import <SoObjects/SOGo/NSArray+Utilities.h>
- (WOResponse *) canAccessContentAction
{
- return [self responseWith204];
+#warning IMPROVEMENTS REQUIRED!
+ NSArray *acls;
+// NSEnumerator *userAcls;
+// NSString *currentAcl;
+
+ [self _setupContext];
+
+// NSLog(@"canAccessContentAction %@, owner %@", subscriptionPointer, owner);
+
+ if ([login isEqualToString: owner] || [owner isEqualToString: @"nobody"]) {
+ return [self responseWith204];
+ }
+ else {
+ acls = [clientObject aclsForUser: login];
+// userAcls = [acls objectEnumerator];
+// currentAcl = [userAcls nextObject];
+// while (currentAcl) {
+// NSLog(@"ACL login %@, owner %@, folder %@: %@",
+// login, owner, baseFolder, currentAcl);
+// currentAcl = [userAcls nextObject];
+// }
+ if (([[clientObject folderType] isEqualToString: @"Contact"] && [acls containsObject: SOGoRole_ObjectReader]) ||
+ ([[clientObject folderType] isEqualToString: @"Appointment"] && [acls containsObject: SOGoRole_AuthorizedSubscriber])) {
+ return [self responseWith204];
+ }
+ }
+
+ return [self responseWithStatus: 403];
}
- (WOResponse *) _realFolderActivation: (BOOL) makeActive
([[cc userAgentType] isEqualToString: @"IE"] && [cc majorVersion] >= 7) ||
([[cc userAgentType] isEqualToString: @"Mozilla"] && [cc majorVersion] >= 5) ||
([[cc userAgentType] isEqualToString: @"Safari"] && [cc majorVersion] >= 4)
+ // ([[cc userAgentType] isEqualToString: @"Konqueror"])
);
}
content = [NSMutableString string];
superContent = [[super flatContentAsString] stringByEscapingHTMLString];
[content appendString: [superContent stringByDetectingURLs]];
- [content replaceString: @"\r\n" withString: @"<br />"];
- [content replaceString: @"\n" withString: @"<br />"];
return content;
}
"quotasFormat" = "Quotas: %{0} used on %{1} Kb; %{2}%";
+"Please select a message." = "Please select a message.";
"Please select a message to print." = "Please select a message to print.";
"Please select only one message to print." = "Please select only one message to print.";
"quotasFormat" = "Quotas: %{0} Ko utilisés sur %{1}; %{2}%";
+"Please select a message." = "Veuillez sélectionner un message.";
"Please select a message to print." = "Veuillez sélectionner un message à imprimer.";
"Please select only one message to print." = "Veuillez ne sélectionner qu'un seul message à imprimer.";
"quotasFormat" = "Quota: %{0} von %{1} KB verwendet; %{2}%";
+"Please select a message." = "Sie müssen eine Nachricht auswählen.";
"Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen.";
"Please select only one message to print." = "Bitte wählen Sie nur eine Nachricht zum Drucken aus.";
{
result = [[self clientObject] sendMail];
if (!result)
- result = [self jsCloseWithRefreshMethod: nil];
+ result = [self jsCloseWithRefreshMethod: @"refreshFolderByType(\"sent\")"];
}
else
result = [self failedToSaveFormResponse];
"Password:" = "Password:";
"Connect" = "Connect";
+
+"Wrong username or password." = "Wrong username or password.";
\ No newline at end of file
"Password:" = "Mot de passe :";
"Connect" = "Connexion";
+
+"Wrong username or password." = "Mauvais nom d'utilisateur ou mot de passe.";
\ No newline at end of file
@"'Calendar', 'Contacts' or Mail)", defaultModule];
defaultModule = @"Calendar";
}
- else
- defaultModule = @"Calendar";
}
else
defaultModule = @"Calendar";
- (NSString *) shortUserNameForDisplay
{
+ if ([context activeUser] == nil)
+ return @"wrongusernamepassword";
+
return [[context activeUser] login];
}
"Location" = "Location";
"(Private Event)" = "(Private Event)";
-"closeThisWindowMessage" = "Thank you! You may now close this window.";
+"closeThisWindowMessage" = "Thank you! You may now close this window or view your ";
"Multicolumn Day View" = "Multicolumn Day View";
"Location" = "Lieu";
"(Private Event)" = "(Événement privé)";
-"closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre.";
+"closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre ou consulter votre ";
"Multicolumn Day View" = "Multicolonne";
NSCalendarDate *aptStartDate;
NSCalendarDate *aptEndDate;
NSString *item;
+ NSString *repeat;
}
/* template values */
* Boston, MA 02111-1307, USA.
*/
+#warning WE LEAK IVARS LIKE CRAZY HERE
+
#include <math.h>
#import <NGObjWeb/SoObject.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalPerson.h>
+#import <NGCards/iCalRecurrenceRule.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/SOGoContentObject.h>
aptEndDate = nil;
item = nil;
event = nil;
+ repeat = nil;
isAllDay = NO;
}
return self;
}
+- (void) dealloc
+{
+ RELEASE(repeat);
+ [super dealloc];
+}
+
/* template values */
- (iCalEvent *) event
{
else
text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
+ NSLog(@"itemRepeatText: %@", text);
+
return text;
}
- (NSString *) repeat
{
- return @"";
+ return repeat;
}
- (void) setRepeat: (NSString *) newRepeat
{
+ ASSIGN(repeat, newRepeat);
}
- (NSString *) reminder
ASSIGN (aptStartDate, startDate);
ASSIGN (aptEndDate, endDate);
-
- /* here comes the code for initializing repeat, reminder and isAllDay... */
+ // We initialize our repeat ivars
+ if ([event hasRecurrenceRules])
+ {
+ iCalRecurrenceRule *rule;
+
+ repeat = @"CUSTOM";
+
+ rule = [[event recurrenceRules] lastObject];
+
+ if ([rule frequency] == iCalRecurrenceFrequenceWeekly)
+ {
+ if ([rule repeatInterval] == 1) repeat = @"WEEKLY";
+ else if ([rule repeatInterval] == 2) repeat = @"BI-WEEKLY";
+ }
+ else if ([rule frequency] == iCalRecurrenceFrequenceDaily)
+ {
+ if ([rule byDayMask] == (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)) repeat = @"EVERY WEEKDAY";
+ else if (![rule byDayMask]) repeat = @"DAILY";
+ }
+ else if ([rule frequency] == iCalRecurrenceFrequenceMonthly && [rule repeatInterval] == 1) repeat = @"MONTHLY";
+ else if ([rule frequency] == iCalRecurrenceFrequenceYearly && [rule repeatInterval] == 1) repeat = @"YEARLY";
+ }
+ else
+ {
+ DESTROY(repeat);
+ }
return self;
}
NSString *iCalString;
clientObject = [self clientObject];
+ NSLog(@"saveAction, clientObject = %@", clientObject);
+
iCalString = [[clientObject calendar: NO] versitString];
+
+ NSLog(@"saveAction, iCalString = %@", iCalString);
[clientObject saveContentString: iCalString];
return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"];
}
if ([clientObject isNew])
[event setTransparency: @"OPAQUE"];
+
+ // We remove any repeat rules
+ if (!repeat && [event hasRecurrenceRules])
+ {
+ [event removeAllRecurrenceRules];
+ }
+ else if (!([repeat caseInsensitiveCompare: @"-"] == NSOrderedSame || [repeat caseInsensitiveCompare: @"CUSTOM"] == NSOrderedSame))
+ {
+ iCalRecurrenceRule *rule;
+
+ rule = [[iCalRecurrenceRule alloc] init];
+
+ if ([repeat caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame)
+ {
+ [rule setFrequency: iCalRecurrenceFrequenceWeekly];
+ [rule setInterval: @"2"];
+ }
+ else if ([repeat caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame)
+ {
+ [rule setByDayMask: (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)];
+ [rule setFrequency: iCalRecurrenceFrequenceDaily];
+ [rule setInterval: @"1"];
+ }
+ else
+ {
+ [rule setFrequency: (iCalRecurrenceFrequency)[rule valueForFrequency: repeat]];
+ [rule setInterval: @"1"];
+ }
+ [event setRecurrenceRules: [NSArray arrayWithObject: rule]];
+ RELEASE(rule);
+ }
}
// TODO: add tentatively
{
NSEnumerator *folders, *currentInfos;
SOGoAppointmentFolder *currentFolder;
- NSMutableDictionary *infos, *currentInfo, *newInfo;
- NSString *owner, *uid;
+ NSMutableDictionary *newInfo;
+ NSMutableArray *infos;
NSNull *marker;
SOGoAppointmentFolders *clientObject;
marker = [NSNull null];
- infos = [NSMutableDictionary dictionary];
- clientObject = [self clientObject];
+ clientObject = [self clientObject];
folders = [[clientObject subFolders] objectEnumerator];
currentFolder = [folders nextObject];
+
+ infos = [NSMutableArray array];
while (currentFolder)
{
if ([currentFolder isActive])
{
- owner = [currentFolder ownerInContext: context];
currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
to: endDate
component: component] objectEnumerator];
- newInfo = [currentInfos nextObject];
- while (newInfo)
+
+ while ((newInfo = [currentInfos nextObject]))
{
- uid = [newInfo objectForKey: @"c_uid"];
- currentInfo = [infos objectForKey: uid];
- if (!currentInfo
- || [owner isEqualToString: userLogin])
- {
- [self _updatePrivacyInComponent: newInfo
- fromFolder: currentFolder];
- [newInfo setObject: [currentFolder nameInContainer]
- forKey: @"c_folder"];
- // [newInfo setObject: owner forKey: @"c_owner"];
- [infos setObject: [newInfo objectsForKeys: fields
- notFoundMarker: marker]
- forKey: uid];
- }
- newInfo = [currentInfos nextObject];
+ [self _updatePrivacyInComponent: newInfo
+ fromFolder: currentFolder];
+ [newInfo setObject: [currentFolder nameInContainer]
+ forKey: @"c_folder"];
+
+ [infos addObject: [newInfo objectsForKeys: fields
+ notFoundMarker: marker]];
}
}
currentFolder = [folders nextObject];
}
- return [infos allValues];
+ return infos;
}
- (WOResponse *) _responseWithData: (NSArray *) data
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
-// $Id$
+// $Id: UIxCalMonthOverview.h 181 2004-08-11 15:13:25Z helge $
#import "UIxCalMonthViewOld.h"
- (NSString *) componentCalendar
{
- return @"/";
+ SOGoAppointmentFolder *calendar;
+
+ calendar = [[self clientObject] container];
+
+ return calendar;
}
/* priorities */
- (NSArray *) priorities
{
/* 0 == undefined
- 5 == normal
+ 9 == low
+ 5 == medium
1 == high
*/
static NSArray *priorities = nil;
if (!priorities)
{
- priorities = [NSArray arrayWithObjects: @"0", @"5", @"1", nil];
+ priorities = [NSArray arrayWithObjects: @"9", @"5", @"1", nil];
[priorities retain];
}
[component setUid: [clientObject nameInContainer]];
[component setCreated: now];
[component setTimeStampAsDate: now];
- [component setPriority: @"0"];
}
+ [component setPriority: priority];
[component setLastModified: now];
}
selectorComponentClass="selectorComponentClass"
title="name">
<table id="contactsList" multiselect="yes">
- <tbody>
+ <thead>
<tr class="tableview">
<!-- localize -->
- <td class="tbtv_headercell" id="nameHeader"
+ <td class="tbtv_headercell sortableTableHeader" id="nameHeader"
><var:string label:value="Name"
/></td
- ><td class="tbtv_headercell" id="mailHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="mailHeader"
><var:string label:value="Email"/></td
- ><td class="tbtv_headercell" id="screenNameHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="screenNameHeader"
><var:string label:value="Screen Name" /></td
- ><td class="tbtv_headercell" id="orgHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="orgHeader"
><var:string label:value="Organization" /></td
- ><td class="tbtv_headercell" id="phoneHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="phoneHeader"
><var:string label:value="Work Phone" /></td
></tr>
-
+ </thead>
+ <tbody>
<var:foreach list="contactInfos" item="currentContact">
<tr class="tableview"
var:id="currentCName"
</var:foreach>
</tbody>
</table>
- </var:component>
+ </var:component>
\ No newline at end of file
<?xml version='1.0' standalone='yes'?>
<!DOCTYPE table>
-<table multiselect="yes" id="messageList"
+<table id="messageList"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
><td class="tbtv_headercell messageFlagColumn">
<img rsrc:src="title_attachment_14x14.png" width="14"
height="14"/></td
- ><td class="tbtv_headercell" id="subjectHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="subjectHeader"
><var:string label:value="Subject"/></td
- ><td class="tbtv_headercell" id="fromHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="fromHeader"
><var:if condition="showToAddress" const:negate="YES"
><var:string label:value="From"/></var:if
><var:if condition="showToAddress"
></td
><td class="tbtv_headercell" id="messageFlagHeader"
><img rsrc:src="title_read_14x14.png"/></td
- ><td class="tbtv_headercell" id="dateHeader"
+ ><td class="tbtv_headercell sortableTableHeader" id="dateHeader"
><var:string label:value="Date"/></td
></tr>
<tr class="tableview"
var:idx="prevFirstMessageNumber"
><var:string label:value="previous"/></a> |
</var:if>
- <var:string value="firstMessageNumber" />
- <var:string label:value="msgnumber_to" />
- <var:string value="lastMessageNumber" />
- <var:string label:value="msgnumber_of" />
- <var:string value="sortedUIDs.count" />
- <var:if condition="hasNext"
- >| <a href="#"
- var:idx="nextFirstMessageNumber"
- ><var:string label:value="next" /></a>
- </var:if
+ <var:if condition="lastMessageNumber" const:negate="YES">
+ 0 <var:string label:value="message"/>
+ </var:if>
+ <var:if condition="lastMessageNumber" const:negate="0">
+ <var:string value="firstMessageNumber" />
+ <var:string label:value="msgnumber_to" />
+ <var:string value="lastMessageNumber" />
+ <var:string label:value="msgnumber_of" />
+ <var:string value="sortedUIDs.count" />
+ <var:if condition="hasNext"
+ >| <a href="#"
+ var:idx="nextFirstMessageNumber"
+ ><var:string label:value="next" /></a>
+ </var:if>
+ </var:if
></td
></tr
>
<form id="connectForm" var:href="connectURL">
<div id="loginScreen">
<img id="splash" rsrc:src="lori-login.jpg"/><br/><br/>
- <label><var:string label:value="Login:"/><br/>
+ <var:if condition="shortUserNameForDisplay" const:value="wrongusernamepassword"
+ ><p class="error"><var:string label:value="Wrong username or password."/></p>
+ </var:if><label><var:string label:value="Login:"/><br/>
<input class="textField" id="userName" name="userName"
type="text" var:value="userName" /></label><br/>
<label><var:string label:value="Password:"/><br/>
<var:component className="UIxCalFilterPanel" />
<div id="eventsListView">
<table id="eventsList">
- <tr>
- <td class="headerCell headerTitle"><span class="sortableTableHeader"><var:string label:value="Title"/></span></td>
- <td class="headerCell headerDateTime"><span class="sortableTableHeader"><var:string label:value="Start"/></span></td>
- <td class="headerCell headerDateTime"><span class="sortableTableHeader"><var:string label:value="End"/></span></td>
- <td class="headerCell headerLocation"><span class="sortableTableHeader"><var:string label:value="Location"/></span></td>
- </tr>
+ <thead>
+ <tr>
+ <td class="headerCell headerTitle sortableTableHeader"><var:string label:value="Title"/></td>
+ <td class="headerCell headerDateTime sortableTableHeader"><var:string label:value="Start"/></td>
+ <td class="headerCell headerDateTime sortableTableHeader"><var:string label:value="End"/></td>
+ <td class="headerCell headerLocation sortableTableHeader"><var:string label:value="Location"/></td>
+ </tr>
+ </thead>
+ <tbody></tbody>
</table>
</div>
<div id="rightDragHandle" class="dragHandle"><!-- space --></div>
label:title="Remove the selected Calendar"
/></span></a>
</span>
- <ul id="calendarList" multiselect="yes">
+ <ul id="calendarList">
<var:foreach list="calendars" item="currentCalendar"
><li class="denied" var:id="currentCalendar.id"
var:owner="currentCalendar.owner">
string="item.displayName"
selection="componentCalendar"
/></span></span>
+ <span class="checkBoxList"><var:string label:value="Priority:" />
+ <span class="content"><var:popup list="priorities" item="item"
+ label:noSelectionString="prio_0"
+ string="itemPriorityText" selection="priority"/>
+ </span></span>
<label id="attendeesLabel" style="display: none;"><var:string label:value="Attendees:"
/><span class="content"
><a href="#" id="attendeesHref"><!-- space --></a></span></label>
<script type="text/javascript" rsrc:src="events.js"><!-- space required --></script>
<script type="text/javascript" rsrc:src="prototype.js"><!-- space required --></script>
<script type="text/javascript" rsrc:src="tablekit.js"><!-- space required --></script>
+ <script type="text/javascript" rsrc:src="tablekit-trueresize.js"><!-- space required --></script>
<script type="text/javascript" rsrc:src="JavascriptAPIExtensions.js"><!-- space required --></script>
<script type="text/javascript" rsrc:src="HTMLElement.js"><!-- space required --></script>
<script type="text/javascript" rsrc:src="HTMLInputElement.js"><!-- space required --></script>
const:identifier="labels" />
<var:js-stringtable
const:identifier="clabels" />
-
<var:if condition="shortUserNameForDisplay" const:value="anonymous"
const:negate="YES"
- ><var:if condition="isPopup" const:negate="YES"
+ ><var:if condition="shortUserNameForDisplay" const:value="wrongusernamepassword"
+ const:negate="YES"
+ ><var:if condition="isPopup" const:negate="YES"
><var:if condition="context.isUIxDebugEnabled"
><div id="logConsole"><!-- space --></div></var:if>
<div id="linkBanner" class="linkbanner">
<a id="logoff" var:href="logoffPath"
- ><var:string label:value="Logoff" /></a>
+ ><var:string label:value="Sign Out" /></a>
<a var:href="relativeCalendarPath"
><var:string label:value="Calendar" /></a> |
<a var:href="relativeContactsPath"
</var:if
><var:component className="UIxToolbar" var:toolbar="toolbar"
/>
- </var:if>
+ </var:if></var:if>
<div class="pageContent"
><var:component-content
left: 0px;
right: 0px;
height: 16em;
- overflow: scroll;
+ overflow: auto;
overflow-x: hidden; }
.aptview_text
padding: 0px; }
TABLE#contactsList
-{ display: block;
- position: relative;
- width: 100%; }
+{ width: 100%; }
-TABLE#contactsList TD
-{ white-space: normal; /* pre, normal, nowrap */
- /*width: 20%;*/ }
+TABLE#contactsList TD,
+TABLE#contactsList TH
+{ overflow: hidden;
+ white-space: nowrap; } /* pre, normal, nowrap */
-TD#nameHeader,
-TD#mailHeader
-{ /*width: 30%;*/ }
+TABLE#contactsList TH
+{ white-space: pre; }
TABLE#contactsList TD IMG
{
INPUT#searchValue:focus
{ color: #000; }
-TABLE#contactsList TD.resize-handle-active
-{ cursor: e-resize; }
-
-DIV.resize-handle
-{ cursor: e-resize;
- width: 2px;
- border-right: 1px solid #fff;
- position: absolute;
- top: 0;
- left: 0;
- max-height: 2em; }
-
/* drag handles */
DIV#dragHandle
{
var cachedContacts = new Array();
var currentContactFolder = null;
-var savedColumnsWidth = null;
var usersRightsWindowHeight = 200;
var usersRightsWindowWidth = 450;
var contactsList = $("contactsList");
if (contactsList)
selection = contactsList.getSelectedRowsId();
- else
- window.alert("no contactsList");
+// else
+// window.alert("no contactsList");
}
else
selection = null;
= triggerAjaxRequest(url, contactsListCallback);
}
-function configureContactsListHeaders(cells) {
- for (var i = 0; i < cells.length; i++) {
- var currentCell = $(cells[i]);
- Event.observe(currentCell, "click",
- onHeaderClick.bindAsEventListener(currentCell));
- //Event.observe(currentCell, "mousedown", listRowMouseDownHandler);
- }
-}
-
function contactsListCallback(http) {
- var div = $("contactsListContent");
-
if (http.readyState == 4
&& http.status == 200) {
document.contactsListAjaxRequest = null;
- div.update(http.responseText);
var table = $("contactsList");
if (table) {
- TableKit.Resizable.init(table);
- if (savedColumnsWidth != null) {
- // Restore columns width
- table.setColumnsWidth(savedColumnsWidth);
- }
- configureContactsListHeaders(table.tBodies[0].rows[0].cells);
+ // Update table
+ var data = http.responseText;
+ var html = data.replace(/^(.*\n)*.*(<table(.*\n)*)$/, "$2");
+ var tbody = table.tBodies[0];
+ var tmp = document.createElement('div');
+ $(tmp).update(html);
+ table.replaceChild(tmp.firstChild.tBodies[0], tbody);
}
-
+ else {
+ // Add table (doesn't happen .. yet)
+ var div = $("contactsListContent");
+ div.update(http.responseText);
+ table = $("contactsList");
+ configureSortableTableHeaders(table);
+ TableKit.Resizable.init(table, {'trueResize' : true, 'keepWidth' : true});
+ }
+
if (sorting["attribute"] && sorting["attribute"].length > 0) {
var sortHeader;
if (sorting["attribute"] == "displayName")
sortHeader = null;
if (sortHeader) {
+ var sortImages = $(table.tHead).getElementsByClassName("sortImage");
+ $(sortImages).each(function(item) {
+ item.remove();
+ });
+
var sortImage = createElement("img", "messageSortImage", "sortImage");
sortHeader.insertBefore(sortImage, sortHeader.firstChild);
if (sorting["ascending"])
sorting["ascending"] = true;
}
- savedColumnsWidth = this.up('table').getColumnsWidth();
refreshCurrentFolder();
- preventDefault(event);
+ Event.stop(event);
}
function newContact(sender) {
if (nodes[0].hasClassName("denied")) {
var div = $("contactsListContent");
- div.innerHTML = "";
+ div.update();
}
else {
search = {};
for (var i = 0; i < list.length; i++) {
var folderID = list[i].getAttribute("id");
var url = URLForFolderID(folderID) + "/canAccessContent";
-
triggerAjaxRequest(url, deniedFoldersLookupCallback, folderID);
}
}
configureSelectionButtons();
configureContactFolders();
// initDnd();
+
+ var table = $("contactsList");
+ if (table) {
+ // Initialize contacts table
+ configureSortableTableHeaders(table);
+ TableKit.Resizable.init(table, {'trueResize' : true, 'keepWidth' : true});
+ }
}
addEvent(window, 'load', initContacts);
element.addClassName('_selected');
},
+ selectRange: function(element, startIndex, endIndex) {
+ element = $(element);
+ var s;
+ var e;
+ var rows;
+
+ if (startIndex > endIndex) {
+ s = endIndex;
+ e = startIndex;
+ }
+ else {
+ s = startIndex;
+ e = endIndex;
+ }
+ if (element.tagName == 'UL')
+ rows = element.getElementsByTagName('LI');
+ else
+ rows = element.getElementsByTagName('TR');
+ while (s <= e) {
+ if (rows[s].nodeType == 1)
+ $(rows[s]).select();
+ s++;
+ }
+ },
+
deselect: function(element) {
element = $(element);
element.removeClassName('_selected');
node.select();
}
}
- },
-
- getColumnsWidth: function(element) {
- element = $(element);
- var widths = new Array();
- if (element.tagName == 'TABLE') {
- var cells = TableKit.getHeaderCells(element);
- for (var i = 0; i < cells.length; i++) {
- widths[i] = $(cells[i]).getWidth();
- }
- }
- return widths;
- },
-
- setColumnsWidth: function(element, widths) {
- element = $(element);
- if (element.tagName == 'TABLE') {
- for (var i = 0; i < widths.length; i++) {
- TableKit.Resizable.resize(element, i, widths[i]);
- }
- }
}
-
}); // Element.addMethods
left: 0px;
right: 0px;
height: 15.5em;
- overflow: scroll;
+ overflow: auto;
overflow-x: hidden; }
DIV#messageContent
{
position: relative;
font-family: monospace, fixed;
- white-space: normal;
+ white-space: pre;
font-size: inherit;
margin: 0px;
padding: 0px;
}
TABLE#messageList
-{ /*width: 100%;*/ }
+{ width: 100%; }
+
+TABLE#messageList TD,
+TABLE#messageList TH
+{ height: 1.2em;
+ overflow: hidden;
+ white-space: nowrap; }
-TABLE#messageList TD
-{ height: 1.2em; }
+TABLE#messageList TH
+{ white-space: pre; }
TD#messageFlagHeader,
TABLE#messageList TD.messageFlagColumn
-{ width: 1em;
+{ width: 22px;
text-align: center; }
TD#subjectHeader,
overflow: hidden; }
TD#dateHeader,
-TABLE#messageList TD.tbtv_date_headercell,
-TABLE#messageList TD.messageDateColumn
+TABLE#messageList TD.tbtv_date_headercell
{ /*width: 25%;*/
overflow: hidden; }
text-decoration: line-through;
}
-TABLE#messageList TD.resize-handle-active
-{ cursor: e-resize; }
-
-DIV.resize-handle
-{ cursor: e-resize;
- width: 2px;
- border-right: 1px solid #fff;
- position: absolute;
- top: 0;
- left: 0;
- max-height: 2em; }
-
/* drag handles */
DIV#verticalDragHandle
{
ApplicationBaseURL + currentMailbox
+ "/" + rows[i].substr(4)
+ "/" + action);
+ } else {
+ window.alert(labels["Please select a message."]);
}
}
url = ApplicationBaseURL + messageId + "/trash";
http = createHTTPClient();
http.open("POST", url, false /* not async */);
+ http.url = url;
http.send("");
if (!isHttpStatus204(http.status)) { /* request failed */
failCount++;
}
}
http = null;
-
+
/* remove from page */
-
/* line-through would be nicer, but hiding is OK too */
var row = $(rowIds[i]);
row.parentNode.removeChild(row);
if (currentMailboxType == "account" || currentMailboxType == "additional") {
currentMailbox = mailbox;
$("messageContent").update();
- var body = $("messageList").tBodies[0];
+ var table = $("messageList");
+ var head = table.tHead;
+ var body = table.tBodies[0];
for (var i = body.rows.length; i > 0; i--)
body.deleteRow(i-1);
+ if (head.rows[1])
+ head.rows[1].firstChild.update();
}
else
openMailbox(mailbox);
- preventDefault(event);
+ Event.stop(event);
}
function onMailboxMenuMove() {
function openMailbox(mailbox, reload, idx) {
if (mailbox != currentMailbox || reload) {
currentMailbox = mailbox;
- var url = ApplicationBaseURL + mailbox + "/view?noframe=1";
+ var url = ApplicationBaseURL + encodeURI(mailbox) + "/view?noframe=1";
var messageContent = $("messageContent");
messageContent.update();
-
+ lastClickedRow = null; // from generic.js
+
var currentMessage;
if (!idx) {
currentMessage = currentMessages[mailbox];
+ rightDragHandle.offsetHeight
+ 'px') });
}
-
document.messageListAjaxRequest
= triggerAjaxRequest(url, messageListCallback,
currentMessage);
function openMailboxAtIndex(event) {
openMailbox(currentMailbox, true, this.getAttribute("idx"));
- preventDefault(event);
+ Event.stop(event);
}
function messageListCallback(http) {
- var div = $('mailboxContent');
-
+ var table = $('messageList');
+
if (http.readyState == 4
&& http.status == 200) {
document.messageListAjaxRequest = null;
- div.update(http.responseText);
- TableKit.Resizable.init($('messageList'));
+ if (table) {
+ // Update table
+ var thead = table.tHead;
+ var tbody = table.tBodies[0];
+ var tmp = document.createElement('div');
+ $(tmp).update(http.responseText);
+ thead.rows[1].parentNode.replaceChild(tmp.firstChild.tHead.rows[1], thead.rows[1]);
+ table.replaceChild(tmp.firstChild.tBodies[0], tbody);
+ }
+ else {
+ // Add table
+ var div = $('mailboxContent');
+ div.update(http.responseText);
+ table = $('messageList');
+ configureMessageListEvents(table);
+ TableKit.Resizable.init(table, {'trueResize' : true, 'keepWidth' : true});
+ }
+ configureMessageListBodyEvents(table);
var selected = http.callbackData;
if (selected) {
var row = $("row_" + selected);
if (row)
row.select();
+ else
+ $("messageContent").update();
}
- configureMessageListEvents();
if (sorting["attribute"] && sorting["attribute"].length > 0) {
- var sortHeader;
- if (sorting["attribute"] == "subject")
- sortHeader = $("subjectHeader");
- else if (sorting["attribute"] == "from")
- sortHeader = $("fromHeader");
- else if (sorting["attribute"] == "date")
- sortHeader = $("dateHeader");
- else
- sortHeader = null;
-
+ var sortHeader = $(sorting["attribute"] + "Header");
+
if (sortHeader) {
+ var sortImages = $(table.tHead).getElementsByClassName("sortImage");
+ $(sortImages).each(function(item) {
+ item.remove();
+ });
+
var sortImage = createElement("img", "messageSortImage", "sortImage");
sortHeader.insertBefore(sortImage, sortHeader.firstChild);
if (sorting["ascending"])
}
}
}
- else
- log("messageListCallback: problem during ajax request (readyState = " + http.readyState + ", status = " + http.status + ")");
+ else {
+ var data = http.responseText;
+ var msg = data.replace(/^(.*\n)*.*<p>((.*\n)*.*)<\/p>(.*\n)*.*$/, "$2");
+ log("messageListCallback: problem during ajax request (readyState = " + http.readyState + ", status = " + http.status + ", response = " + msg + ")");
+ }
}
function quotasCallback(http) {
sorting["attribute"] = newSortAttribute;
sorting["ascending"] = true;
}
-
refreshCurrentFolder();
-
+
Event.stop(event);
}
openMailbox(currentMailbox, true);
}
-function pouetpouet(event) {
- window.alert("pouet pouet");
+function refreshFolderByType(type) {
+ if (currentMailboxType == type)
+ refreshCurrentFolder();
}
var mailboxSpanAcceptType = function(type) {
/* a model for a futur refactoring of the sortable table headers mechanism */
-function configureMessageListHeaders(cells) {
- for (var i = 0; i < cells.length; i++) {
- var currentCell = $(cells[i]);
- Event.observe(currentCell, "click",
- onHeaderClick.bindAsEventListener(currentCell));
- //Event.observe(currentCell, "mousedown", listRowMouseDownHandler);
+
+function configureMessageListEvents(table) {
+ if (table) {
+ table.multiselect = true;
+ // Each body row can load a message
+ Event.observe(table, "mousedown",
+ onMessageSelectionChange.bindAsEventListener(table));
+ // Sortable columns
+ configureSortableTableHeaders(table);
}
}
-function configureMessageListEvents() {
- var messageList = $("messageList");
- if (messageList) {
- Event.observe(messageList, "mousedown",
- onMessageSelectionChange.bindAsEventListener(messageList));
-
- configureMessageListHeaders(messageList.tHead.rows[0].cells);
-
- var cell = messageList.tHead.rows[1].cells[0];
+function configureMessageListBodyEvents(table) {
+ if (table) {
+ // Page navigation
+ var cell = table.tHead.rows[1].cells[0];
if ($(cell).hasClassName("tbtv_navcell")) {
var anchors = $(cell).childNodesWithTag("a");
for (var i = 0; i < anchors.length; i++)
Event.observe(anchors[i], "click", openMailboxAtIndex.bindAsEventListener(anchors[i]));
}
- rows = messageList.tBodies[0].rows;
+ rows = table.tBodies[0].rows;
for (var i = 0; i < rows.length; i++) {
Event.observe(rows[i], "mousedown", onRowClick);
+ Event.observe(rows[i], "selectstart", listRowMouseDownHandler);
Event.observe(rows[i], "contextmenu", onMessageContextMenu.bindAsEventListener(rows[i]));
-
+
rows[i].dndTypes = function() { return new Array("mailRow"); };
rows[i].dndGhost = messageListGhost;
rows[i].dndDataForType = messageListData;
function onMenuEmptyTrash(event) {
var folderID = document.menuTarget.getAttribute("dataname");
var urlstr = URLForFolderID(folderID) + "/emptyTrash";
- triggerAjaxRequest(urlstr, folderRefreshCallback, folderID);
+ triggerAjaxRequest(urlstr, folderOperationCallback, folderID);
if (folderID == currentMailbox) {
var div = $('messageContent');
for (var i = div.childNodes.length - 1; i > -1; i--)
div.removeChild(div.childNodes[i]);
+ refreshCurrentFolder();
}
var msgID = currentMessages[folderID];
if (msgID)
function folderOperationCallback(http) {
if (http.readyState == 4
- && http.status == 204)
+ && isHttpStatus204(http.status))
initMailboxTree();
else
window.alert(labels["Operation failed"]);
function folderRefreshCallback(http) {
if (http.readyState == 4
- && http.status == 204) {
+ && isHttpStatus204(http.status)) {
var oldMailbox = http.callbackData;
if (oldMailbox == currentMailbox)
refreshCurrentFolder();
margin-top: 5px;
margin-left: 5px; }
+P.error
+{ color: #f00;
+ text-align: center; }
+
P.browser
{ background-color: #fff;
border-top: 1px solid #888;
border-top: 2px solid #222;
border-left: 2px solid #222;
background-color: #fff;
+ -khtml-user-select: none;
-moz-border-top-colors: #9c9a94 #000 transparent;
-moz-border-left-colors: #9c9a94 #000 transparent;
list-style-type: none;
overflow-x: hidden; }
UL#calendarList
-{ clear: both;
+{ clear: left;
+ width: 100%;
height: 10.5em;
margin: 0px; }
{ color: #fff !important;
background-color: #00f !important; }
-UL#tasksList LI[class~="_selected"].duelater
+UL#tasksList LI[class~="_selected"].duelater,
+UL#tasksList LI[class~="_selected"].completed
{ color: #fff !important;
background-color: #999 !important; }
border: 1px solid #deebf7; }
TABLE#eventsList
-{ display: block;
- position: relative;
- width: 100%; }
+{ width: 100%; }
+
+TABLE#eventsList TD.headerTitle,
+TABLE#eventsList TD.headerDateTime
+{ width: 30%; }
+
+TABLE#eventsList TD,
+TABLE#eventsList TH
+{ overflow: hidden;
+ white-space: nowrap; } /* pre, normal, nowrap */
-TABLE#eventsList td.headerTitle,
-TABLE#eventsList td.headerLocation
-{ width: 35%; }
+TABLE#eventsList TH
+{ white-space: pre; }
._unfocused#dateSelector TD._selected,
UL._unfocused > LI._selected,
function closeInvitationWindow() {
var closeDiv = document.createElement("div");
+ document.body.appendChild(closeDiv);
closeDiv.addClassName("javascriptPopupBackground");
+
var closePseudoWin = document.createElement("div");
+ document.body.appendChild(closePseudoWin);
closePseudoWin.addClassName("javascriptMessagePseudoTopWindow");
closePseudoWin.style.top = "0px;";
closePseudoWin.style.left = "0px;";
closePseudoWin.style.right = "0px;";
closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
- document.body.appendChild(closeDiv);
- document.body.appendChild(closePseudoWin);
+
+ var calLink = document.createElement("a");
+ closePseudoWin.appendChild(calLink);
+ calLink.href = ApplicationBaseURL;
+ calLink.appendChild(document.createTextNode(labels["Calendar"].toLowerCase()));
}
function modifyEventCallback(http) {
var div = $("eventsListView");
document.eventsListAjaxRequest = null;
- var table = $("eventsList").tBodies[0];
+ var table = $("eventsList");
var params = parseQueryParameters(http.callbackData);
sortKey = params["sort"];
sortOrder = params["desc"];
- configureSortableTableHeaders();
+ lastClickedRow = null; // from generic.js
var data = http.responseText.evalJSON(true);
for (var i = 0; i < data.length; i++) {
var row = document.createElement("tr");
- table.appendChild(row);
+ table.tBodies[0].appendChild(row);
$(row).addClassName("eventRow");
row.setAttribute("id", escape(data[i][0]));
row.cname = escape(data[i][0]);
//log(i + " = " + data[i][3]);
var listItem = document.createElement("li");
list.appendChild(listItem);
- Event.observe(listItem, "mousedown", listRowMouseDownHandler); // causes problem with Safari
+ Event.observe(listItem, "mousedown", listRowMouseDownHandler);
Event.observe(listItem, "click", onRowClick);
Event.observe(listItem, "dblclick", editDoubleClickedEvent.bindAsEventListener(listItem));
listItem.setAttribute("id", data[i][0]);
if (http.readyState == 4
&& http.status == 200) {
document.dayDisplayAjaxRequest = null;
- div.innerHTML = http.responseText;
+ div.update(http.responseText);
if (http.callbackData["view"])
currentView = http.callbackData["view"];
if (http.callbackData["day"])
= triggerAjaxRequest(url, eventsListCallback, href);
var table = $("eventsList").tBodies[0];
- while (table.rows.length > 1)
- table.removeChild(table.rows[1]);
+ while (table.rows.length > 0)
+ table.removeChild(table.rows[0]);
return false;
}
}
function onHeaderClick(event) {
-// log("onHeaderClick: " + this.link);
- _loadEventHref(this.link);
+ //log("onHeaderClick: " + this.link);
+ //_loadEventHref(this.link);
preventDefault(event);
}
return refreshEvents();
}
-function onEventClick(event) {
+function onEventClick(event) { log ("onEventClick");
var day = this.day;
var hour = this.hour;
function onCalendarSelectEvent() {
var list = $("eventsList");
- list.deselectAll();
+ list.tBodies[0].deselectAll();
if (selectedCalendarCell)
for (var i = 0; i < selectedCalendarCell.length; i++)
var taskId = this.parentNode.getAttribute("id");
var newStatus = (this.checked ? 1 : 0);
var http = createHTTPClient();
-
- if (isSafari())
+
+ if (isSafari() && !isSafari3()) {
newStatus = (newStatus ? 0 : 1);
- //log("update task status: " + taskId + " to " + this.checked);
- event.cancelBubble = true;
+ }
url = (ApplicationBaseURL + "/" + this.parentNode.calendar
+ "/" + taskId + "/changeStatus?status=" + newStatus);
if (http) {
-// log ("url: " + url);
// TODO: add parameter to signal that we are only interested in OK
http.open("POST", url, false /* not async */);
http.url = url;
function updateCalendarStatus(event) {
var list = new Array();
+ var newStatus = (this.checked ? 1 : 0);
+
+ if (isSafari() && !isSafari3()) {
+ newStatus = (newStatus ? 0 : 1);
+ this.checked = newStatus;
+ }
var nodes = $("calendarList").childNodesWithTag("li");
for (var i = 0; i < nodes.length; i++) {
if (event) {
var folderID = this.parentNode.getAttribute("id");
var urlstr = URLForFolderID(folderID);
- if (this.checked)
+ if (newStatus)
urlstr += "/activateFolder";
else
urlstr += "/deactivateFolder";
function calendarStatusCallback(http) {
if (http.readyState == 4) {
if (isHttpStatus204(http.status)) {
- refreshEvents();
- refreshTasks();
- changeCalendarDisplay();
- }
- else {
- var folder = $(http.callbackData);
- var input = folder.childNodesWithTag("input")[0];
- input.checked = (!input.checked);
- }
- }
- else
- log("calendarStatusCallback Ajax error");
+ refreshEvents();
+ refreshTasks();
+ changeCalendarDisplay();
+ }
+ else {
+ var folder = $(http.callbackData);
+ var input = folder.childNodesWithTag("input")[0];
+ input.checked = (!input.checked);
+ }
+ }
+ else
+ log("calendarStatusCallback Ajax error");
}
function calendarEntryCallback(http) {
updateCalendarStatus();
selector.changeNotification = updateCalendarsList;
- var list = $("calendarList").childNodesWithTag("li");
- for (var i = 0; i < list.length; i++) {
- var input = list[i].childNodesWithTag("input")[0];
- Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input)); // not registered in IE?
- //Event.observe(list[i], "mousedown", listRowMouseDownHandler, true); // problem with Safari
- Event.observe(list[i], "click", onRowClick);
+ var list = $("calendarList");
+ list.multiselect = true;
+ var items = list.childNodesWithTag("li");
+ for (var i = 0; i < items.length; i++) {
+ var input = items[i].childNodesWithTag("input")[0];
+ Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
+ Event.observe(items[i], "mousedown", listRowMouseDownHandler);
+ Event.observe(items[i], "selectstart", listRowMouseDownHandler);
+ Event.observe(items[i], "click", onRowClick);
}
var links = $("calendarSelectorButtons").childNodesWithTag("a");
var li = document.createElement("li");
calendarList.appendChild(li);
+ li.setAttribute("id", folder);
var checkBox = document.createElement("input");
checkBox.setAttribute("type", "checkbox");
li.appendChild(checkBox);
li.appendChild(document.createTextNode(" "));
+ $(checkBox).addClassName("checkBox");
var colorBox = document.createElement("div");
li.appendChild(colorBox);
- li.appendChild(document.createTextNode(" " + folderName));
+ li.appendChild(document.createTextNode(" " + folderName)); log (folderName);
colorBox.appendChild(document.createTextNode("OO"));
- li.setAttribute("id", folder);
- Event.observe(li, "mousedown", listRowMouseDownHandler);
- Event.observe(li, "click", onRowClick);
- $(checkBox).addClassName("checkBox");
-
- Event.observe(checkBox, "click",
- updateCalendarStatus.bindAsEventListener(checkBox));
-
$(colorBox).addClassName("colorBox");
if (color)
$(colorBox).setStyle({color: color,
backgroundColor: color});
+ // Register events (doesn't work with Safari)
+ Event.observe(li, "mousedown", listRowMouseDownHandler);
+ Event.observe(li, "selectstart", listRowMouseDownHandler);
+ Event.observe(li, "click", onRowClick);
+ Event.observe(checkBox, "click",
+ updateCalendarStatus.bindAsEventListener(checkBox));
+
var url = URLForFolderID(folder) + "/canAccessContent";
triggerAjaxRequest(url, calendarEntryCallback, folder);
}
function onFolderSubscribeCB(folderData) {
- var folder = $(folderData["folder"]);
+ var folder = $(folderData["folder"]);
if (!folder)
appendCalendar(folderData["folderName"], folderData["folder"]);
}
list = $("eventsList");
list.multiselect = true;
+ //configureSortableTableHeaders(list);
+ TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
Event.observe(list, "mousedown",
onEventsSelectionChange.bindAsEventListener(list));
var div = list.parentNode;
DIV#userSelectorHeader
{ margin: 1em; }
+DIV#userSelector SPAN
+{ display: block; }
+
INPUT#defaultRolesBtn
-{ position: absolute;
- top: 5em;
+{ no_position: absolute;
+ margin-left: 1em;
+ margin-top: 1em;
left: 1em; }
DIV#userRoles
{ position: absolute;
- padding: 0px;
- margin: 0px;
left: 1em;
- top: 7em;
+ top: 8em;
right: 1em;
bottom: 0px; }
UL#userList
{ position: absolute;
- top: 1.5em;
+ top: 2.5em;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
cursor: default;
+ margin: 0px;
padding: 0px;
white-space: nowrap;
overflow: auto;
this.userRightsWidth = window.opener.getUsersRightsWindowWidth();
}
-Event.observe(window, "load", onAclLoadHandler);
+addEvent(window, 'load', onAclLoadHandler);
}
function initACLButtons() {
- $("cancelButton").addEventListener("click", onCancelClick, false);
+ Event.observe($("cancelButton"), "click", onCancelClick);
}
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
|| nodes.length > 1) {
var parentNode = nodes[0];
var userInfos = parentNode.split(":");
- var email = userInfos[1] + " <" + userInfos[2] + ">";
+ var email = userInfos[1] + " <" + userInfos[2] + ">";
tree.add(parent, 0, email, 0, '#', userInfos[0], 'person',
'', '',
ResourcesURL + '/abcard.gif',
else
icon += 'calendar-folder-16x16.png';
var folderId = userInfos[0] + ":" + folderInfos[1];
- tree.add(parent + i, parent, folderInfos[0], 0, '#', folderId,
+ var name = folderInfos[0]; // name has the format "Folername (Firstname Lastname <email>)"
+ var pos = name.indexOf(' (')
+ if (pos !== -1)
+ name = name.substring(0, pos); // strip the part with fullname and email
+ tree.add(parent + i, parent, name, 0, '#', folderId,
folderInfos[2] + '-folder', '', '', icon, icon);
}
offset = nodes.length - 1;
}
function initACLButtons() {
- $("cancelButton").addEventListener("click", onCancelClick, false);
+ var button = $("cancelButton");
+ Event.observe(button, "click", onCancelClick);
}
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
right: 1em; }
input.attachment
-{ display: none; }
+{ position: absolute;
+ left: -1000px; }
div#compose_attachments_list
{ background-color: #ffffff;
urlstr += '/';
urlstr += ("../../" + UserLogin + "/Contacts/"
+ contactSelectorAction + selectorURL);
-// log (urlstr);
var w = window.open(urlstr, "Addressbook",
"width=640,height=400,resizable=1,scrollbars=0");
w.selector = selector;
}
var inputs = area.getElementsByTagName("input");
+
+ // Verify if there's already a visible file input field
+ for (var i = 0; i < inputs.length; i++)
+ if ($(inputs[i]).hasClassName("currentAttachment"))
+ return false;
+
+ // Add new file input field
var attachmentName = "attachment" + inputs.length;
var newAttachment = createElement("input", attachmentName,
"currentAttachment", null,
}
function onAddAttachment() {
- var area = $("attachmentsArea");
- var inputs = area.getElementsByTagName("input");
- var attachmentName = "attachment" + inputs.length;
- var newAttachment = createElement("input", attachmentName,
- "currentAttachment", null,
- { type: "file",
- name: attachmentName },
- area);
- Event.observe(newAttachment, "change",
- onAttachmentChange.bindAsEventListener(newAttachment));
+ return clickedEditorAttach(null);
}
function onAttachmentChange(event) {
document.pageform.action = "save";
document.pageform.submit();
+ refreshMailbox();
return false;
}
var parts = url.split("/");
parts[parts.length-1] = "delete";
url = parts.join("/");
-
http = createHTTPClient();
http.open("POST", url, false /* not async */);
http.send("");
}
+
+ Event.stopObserving(window, "beforeunload", onMailEditorClose);
}
addEvent(window, 'load', initMailEditor);
$("cancelButton").addEventListener("click", onCancelClick, false);
}
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
-moz-border-bottom-colors: #000 #9c9a94 transparent;
-moz-border-right-colors: #000 #9c9a94 transparent; }
-TD.headerCell:active,
-TD.tbtv_headercell:active
+TD.sortableTableHeader:active
{ background-color: #dcdad5;
padding-top: 2px;
border-top: 1px solid #9c9a94;
border-bottom: 1px solid #9c9a94; }
TD.headerCell SPAN,
-td.tbtv_headercell SPAN
+TD.tbtv_headercell SPAN
{ float: left; }
-td.tbtv_headercell a
+TD.tbtv_headercell A
{ cursor: default;
margin: 0px auto;
display: block;
color: black; }
-td.tbtv_headercell a:hover
+TD.tbtv_headercell A:hover
{ margin: 0px auto;
display: block;
color: black;
IMG.sortImage,
TD.headerCell IMG.tbtv_sortcell,
-td.tbtv_headercell img.tbtv_sortcell
+TD.tbtv_headercell IMG.tbtv_sortcell
{ float: right;
text-align: right;
border: 0px;
A.button,
A[class~="_disabled"].button:active
{ cursor: default;
- padding: 1px .5em;
+ padding: 1px 0.5em;
background-color: #d4d0c8;
border-top: 2px solid #fff;
border-left: 2px solid #fff;
-moz-border-bottom-colors: #000 #fff;
-moz-border-right-colors: #000 #fff; }
+/* tablekit resizable columns */
+
+TABLE TD.resize-handle-active
+{ cursor: e-resize; }
+
+DIV.resize-handle
+{ cursor: e-resize;
+ width: 2px;
+ border-right: 1px solid #fff;
+ position: absolute;
+ top: 0;
+ left: 0;
+ max-height: 2em; }
+
@media print
{
BODY
var search = {};
var sorting = {};
+var lastClickedRow = null;
+
var weekStartIsMonday = true;
// logArea = null;
return w;
}
-function openMailComposeWindow(url, wId) { log (url);
+function openMailComposeWindow(url, wId) {
if (!wId)
wId = "" + (new Date().getTime());
var w = window.open(url, wId,
}
function startAnimation(parent, nextNode) {
- var anim = document.createElement("img");
+ var anim = $("progressIndicator");
+ if (anim) return anim;
+
+ anim = document.createElement("img");
anim = $(anim);
anim.id = "progressIndicator";
anim.src = ResourcesURL + "/busy.gif";
}
}
+function isSafari3() {
+ return (navigator.appVersion.indexOf("Version") > -1);
+}
+
function isSafari() {
//var agt = navigator.userAgent.toLowerCase();
//var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
function acceptMultiSelect(node) {
var response = false;
var attribute = node.getAttribute('multiselect');
- if (attribute) {
+ if (attribute && attribute.length > 0) {
log("node '" + node.getAttribute("id")
+ "' is still using old-stylemultiselect!");
response = (attribute.toLowerCase() == 'yes');
function onRowClick(event) {
var node = getTarget(event);
+ var rowIndex = null;
+
+ if (node.tagName == 'TD') {
+ node = node.parentNode; // select TR
+ rowIndex = node.rowIndex - $(node).up('table').down('thead').getElementsByTagName('tr').length;
+ }
+ else if (node.tagName == 'LI') {
+ // Find index of clicked row
+ var list = node.parentNode;
+ var items = list.childNodesWithTag("li");
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == node) {
+ rowIndex = i;
+ break;
+ }
+ }
+ }
- if (node.tagName == 'TD')
- node = node.parentNode;
- var startSelection = $(node.parentNode).getSelectedNodes();
- if (event.shiftKey == 1
+ var initialSelection = $(node.parentNode).getSelectedNodes();
+ if ((event.shiftKey == 1 || event.ctrlKey == 1)
+ && lastClickedRow
&& (acceptMultiSelect(node.parentNode)
|| acceptMultiSelect(node.parentNode.parentNode))) {
- if (isNodeSelected(node) == true) {
+ if (event.shiftKey)
+ $(node.parentNode).selectRange(lastClickedRow, rowIndex);
+ else if (isNodeSelected(node) == true) {
$(node).deselect();
} else {
$(node).select();
}
+ // At this point, should empty content of 3-pane view
} else {
+ // Single line selection
$(node.parentNode).deselectAll();
$(node).select();
- }
-
- if (startSelection != $(node.parentNode).getSelectedNodes()) {
- var parentNode = node.parentNode;
- if (parentNode.tagName == 'TBODY')
- parentNode = parentNode.parentNode;
- //log("onRowClick: parentNode = " + parentNode.tagName);
- // parentNode is UL or TABLE
- if (document.createEvent) {
- var onSelectionChangeEvent;
- if (isSafari())
- onSelectionChangeEvent = document.createEvent("UIEvents");
- else
- onSelectionChangeEvent = document.createEvent("Events");
- onSelectionChangeEvent.initEvent("mousedown", true, true);
- parentNode.dispatchEvent(onSelectionChangeEvent);
- }
- else if (document.createEventObject) {
- parentNode.fireEvent("onmousedown");
+
+ if (initialSelection != $(node.parentNode).getSelectedNodes()) {
+ // Selection has changed; fire mousedown event
+ var parentNode = node.parentNode;
+ if (parentNode.tagName == 'TBODY')
+ parentNode = parentNode.parentNode;
+ if (document.createEvent) {
+ var onSelectionChangeEvent;
+ if (isSafari())
+ onSelectionChangeEvent = document.createEvent("UIEvents");
+ else
+ onSelectionChangeEvent = document.createEvent("Events");
+ onSelectionChangeEvent.initEvent("mousedown", true, true);
+ parentNode.dispatchEvent(onSelectionChangeEvent);
+ }
+ else if (document.createEventObject) {
+ parentNode.fireEvent("onmousedown");
+ }
}
}
-
+ lastClickedRow = rowIndex;
+
return true;
}
}
function listRowMouseDownHandler(event) {
- preventDefault(event);
+ preventDefault(event);
+ //Event.stop(event);
}
/* tabs */
initMenus();
initTabs();
configureDragHandles();
- configureSortableTableHeaders();
configureLinkBanner();
translateLabels();
var progressImage = $("progressIndicator");
preventDefault(event);
}
-function configureSortableTableHeaders() {
- var headers = document.getElementsByClassName("sortableTableHeader");
+function configureSortableTableHeaders(table) {
+ var headers = $(table).getElementsByClassName("sortableTableHeader");
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
- var anchor = $(header).childNodesWithTag("a")[0];
- if (anchor)
- Event.observe(anchor, "click",
- onHeaderClick.bindAsEventListener(anchor));
+ Event.observe(header, "click", onHeaderClick.bindAsEventListener(header))
}
}