]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1185 d1b88da0-ebda-0310...
authorfrancis <francis@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 11 Oct 2007 16:33:27 +0000 (16:33 +0000)
committerfrancis <francis@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 11 Oct 2007 16:33:27 +0000 (16:33 +0000)
62 files changed:
ChangeLog
GNUmakefile
Main/SOGo.m
NEWS
SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
SOPE/NGCards/iCalRecurrenceCalculator.m
SoObjects/Appointments/SOGoAppointmentFolder.m
SoObjects/Appointments/SOGoAptMailNotification.m
SoObjects/Contacts/SOGoContactGCSFolder.m
SoObjects/Mailer/SOGoDraftObject.m
SoObjects/SOGo/LDAPSource.h
SoObjects/SOGo/LDAPSource.m
SoObjects/SOGo/LDAPUserManager.h
SoObjects/SOGo/LDAPUserManager.m
SoObjects/SOGo/NSString+Utilities.m
SoObjects/SOGo/SOGoUser.m
UI/Common/English.lproj/Localizable.strings
UI/Common/French.lproj/Localizable.strings
UI/Common/UIxFolderActions.m
UI/Common/UIxPageFrame.m
UI/MailPartViewers/UIxMailPartTextViewer.m
UI/MailerUI/English.lproj/Localizable.strings
UI/MailerUI/French.lproj/Localizable.strings
UI/MailerUI/German.lproj/Localizable.strings
UI/MailerUI/UIxMailEditor.m
UI/MainUI/English.lproj/Localizable.strings
UI/MainUI/French.lproj/Localizable.strings
UI/MainUI/SOGoUserHomePage.m
UI/SOGoUI/UIxComponent.m
UI/Scheduler/English.lproj/Localizable.strings
UI/Scheduler/French.lproj/Localizable.strings
UI/Scheduler/UIxAppointmentEditor.h
UI/Scheduler/UIxAppointmentEditor.m
UI/Scheduler/UIxCalListingActions.m
UI/Scheduler/UIxCalMonthOverview.h
UI/Scheduler/UIxComponentEditor.m
UI/Templates/ContactsUI/UIxContactsListView.wox
UI/Templates/MailerUI/UIxMailListView.wox
UI/Templates/MainUI/SOGoRootPage.wox
UI/Templates/SchedulerUI/UIxCalMainView.wox
UI/Templates/SchedulerUI/UIxCalendarSelector.wox
UI/Templates/SchedulerUI/UIxComponentEditor.wox
UI/Templates/UIxPageFrame.wox
UI/WebServerResources/ContactsUI.css
UI/WebServerResources/ContactsUI.js
UI/WebServerResources/HTMLElement.js
UI/WebServerResources/HTMLTableElement.js
UI/WebServerResources/MailerUI.css
UI/WebServerResources/MailerUI.js
UI/WebServerResources/SOGoRootPage.css
UI/WebServerResources/SchedulerUI.css
UI/WebServerResources/SchedulerUI.js
UI/WebServerResources/UIxAclEditor.css
UI/WebServerResources/UIxAclEditor.js
UI/WebServerResources/UIxCalUserRightsEditor.js
UI/WebServerResources/UIxContactsUserFolders.js
UI/WebServerResources/UIxContactsUserRightsEditor.js
UI/WebServerResources/UIxMailEditor.css
UI/WebServerResources/UIxMailEditor.js
UI/WebServerResources/UIxMailUserRightsEditor.js
UI/WebServerResources/generic.css
UI/WebServerResources/generic.js

index ac0d9909c6d19e28fe22aae69dbe9e33d109e152..1c09f87eb08667f5af11f5b84caceb16344bfe8b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,74 @@
+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.
index fa15ad0d9da0bca9a50d0406cdb090538b166a0b..2877399d7dcb9a75d48e4aab3f051ed51f918ec3 100644 (file)
@@ -5,6 +5,7 @@ include $(GNUSTEP_MAKEFILES)/common.make
 
 SUBPROJECTS = \
        SOPE/NGCards \
+       SOPE/sope-gdl1/GDLContentStore \
        OGoContentStore \
        SoObjects       \
        Main            \
index 3bc17f5905a7ab1696ca36b9393abbfa520be2e6..15b568dd5784cffab01853d5ae18a23b10af78d1 100644 (file)
@@ -254,9 +254,6 @@ static BOOL debugObjectAllocation = NO;
   if ([_key length] < 1)
     return NO;
   
-  if (isdigit([_key characterAtIndex:0]))
-    return NO;
-
   return YES;
 }
 
diff --git a/NEWS b/NEWS
index 8947cccfd1e185557e6e82e561f0973416b23689..a61bbec9c1e78b7c3c23c93b2d56b329dab354fe 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@
 - 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;
@@ -10,8 +11,9 @@
 - 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
index 2516534a9d5a80d9f85fbe595582966efdfd7d7c..e8a236312392b3290e3e28175b3c5d2ef81b3ad3 100644 (file)
@@ -262,10 +262,9 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
   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;
@@ -314,7 +313,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
       continue;
     
     /* first check whether we are in the interval */
-    
+
     if ((monthIdxInRecurrence % interval) != 0)
       continue;
 
index a56eaef387e35edf4ab49fdd0ea6348e18a8f0bd..4923639cbaf6e9b424fe3267bd085154debcbac5 100644 (file)
@@ -100,9 +100,10 @@ static Class yearlyCalcClass  = Nil;
     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];
   }
@@ -158,6 +159,7 @@ static Class yearlyCalcClass  = Nil;
     unsigned            k;
 
     exDate = [exDates objectAtIndex:i];
+    
     for (k = 0; k < rCount; k++) {
       unsigned rIdx;
       
index a517d18df56ec7ce56fdd57505cf653ddf481cf4..a2306fba6bf1223ac82306d7f5fb9b6c8186cd1c 100644 (file)
@@ -221,6 +221,7 @@ static NSNumber   *sharedYes = nil;
   return filterData;
 }
 
+#warning filters is leaked here
 - (NSArray *) _parseCalendarFilters: (id <DOMElement>) parentNode
 {
   NSEnumerator *children;
@@ -258,6 +259,7 @@ static NSNumber   *sharedYes = nil;
   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"]
@@ -568,13 +570,16 @@ static NSNumber   *sharedYes = nil;
   
   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;
 }
@@ -633,20 +638,24 @@ static NSNumber   *sharedYes = nil;
   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];
+      }
   }
 }
 
@@ -845,21 +854,20 @@ static NSNumber   *sharedYes = nil;
       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]];
 
@@ -926,7 +934,7 @@ static NSNumber   *sharedYes = nil;
                              @"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
index 5c6b2c4f0334a1bb5f653a85794d82f80e78ef31..912c3a0e22f32a0eb1f484bb98a833194f7fdf87 100644 (file)
@@ -90,7 +90,7 @@ static NSTimeZone     *EST = nil;
   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];
 }
index b8856acd973a8bc0ce89ec396594e43364b17e91..1a58723ddb2417c42d9667f8fd4138719e39994f 100644 (file)
@@ -30,6 +30,9 @@
 #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;
index 173e62d091dc442329f5eb76fd3c4e36db45859b..3aa25f15e15cf75179b2574d17253d6b1e4e52c0 100644 (file)
@@ -578,7 +578,7 @@ static BOOL        showTextAttachmentsInline  = NO;
 
 - (BOOL) isValidAttachmentName: (NSString *) _name
 {
-  static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", @" ", nil };
+  static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", nil };
   unsigned i;
   NSRange  r;
 
@@ -611,7 +611,8 @@ static BOOL        showTextAttachmentsInline  = NO;
                    withMetadata: (NSDictionary *) metadata
 {
   NSString *p, *name, *mimeType;
-  
+  NSRange r;
+
   if (![_attach isNotNull]) {
     return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
                        reason: @"Missing attachment content!"];
@@ -621,7 +622,13 @@ static BOOL        showTextAttachmentsInline  = NO;
     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];
   
index 3e8a3c7b4906ab8edbfc0ba588c38e570649104f..201e16b8a5719b0e84ab739cf90054eecd15ce90 100644 (file)
@@ -31,6 +31,7 @@
 
 @interface LDAPSource : NSObject
 {
+  NSString *sourceID;
   NSString *bindDN;
   NSString *hostname;
   unsigned int port;
@@ -67,6 +68,7 @@
 - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID;
 - (NSArray *) allEntryIDs;
 - (NSArray *) fetchContactsMatching: (NSString *) filter;
+- (NSString *) sourceID;
 
 @end
 
index c2350e446793a451b4ea500f56a2908c3ef35e88..28475ad186212dda342b46c661c00ebf1c54c852 100644 (file)
@@ -30,6 +30,7 @@
 #import <NGLdap/NGLdapEntry.h>
 
 #import "LDAPSource.h"
+#import "LDAPUserManager.h"
 
 static NSArray *commonSearchFields;
 static int timeLimit;
@@ -114,8 +115,9 @@ static int sizeLimit;
                                    @"locality",
                                    @"birthyear",
                                    @"serialNumber",
-                                   @"calFBURL",
+                                   @"calFBURL", @"proxyAddresses",
                                    nil];
+       
       [commonSearchFields retain];
     }
 }
@@ -138,6 +140,7 @@ static int sizeLimit;
       hostname = nil;
       port = 389;
       password = nil;
+      sourceID = nil;
 
       baseDN = nil;
       IDField = @"cn"; /* the first part of a user DN */
@@ -163,6 +166,7 @@ static int sizeLimit;
   [UIDField release];
   [bindFields release];
   [ldapConnection release];
+  [sourceID release];
   [super dealloc];
 }
 
@@ -170,6 +174,8 @@ static int sizeLimit;
 {
   self = [self init];
 
+  ASSIGN(sourceID, [udSource objectForKey: @"id"]);
+
   [self setBindDN: [udSource objectForKey: @"bindDN"]
        hostname: [udSource objectForKey: @"hostname"]
        port: [udSource objectForKey: @"port"]
@@ -340,6 +346,8 @@ static int sizeLimit;
 
 - (NSArray *) _searchAttributes
 {
+  NSArray *attrs;
+
   if (!searchAttributes)
     {
       searchAttributes = [NSMutableArray new];
@@ -350,6 +358,12 @@ static int sizeLimit;
       [searchAttributes addObjectsFromArray: commonSearchFields];
     }
 
+  // We also include our MailFieldNames in the search
+  if ((attrs = [[[LDAPUserManager sharedUserManager] metadataForSourceID: sourceID] objectForKey: @"MailFieldNames"]))
+    {
+      [searchAttributes addObjectsFromArray: attrs];
+    }
+
   return searchAttributes;
 }
 
@@ -493,4 +507,9 @@ static int sizeLimit;
   return contactEntry;
 }
 
+- (NSString *) sourceID
+{
+  return sourceID;
+}
+
 @end
index 6a3c6510b8e0f53d74b50cad4bb9a048230151b5..5ab95c9237aa758d89d8ce122ba8343468338906 100644 (file)
@@ -44,6 +44,7 @@
 + (id) sharedUserManager;
 
 - (NSArray *) sourceIDs;
+- (NSDictionary *) metadataForSourceID: (NSString *) sourceID;
 - (NSArray *) authenticationSourceIDs;
 - (NSArray *) addressBookSourceIDs;
 
index 01ab01a36151300785022951aa664103efa81764..76e181088746c3b01379a473dd1e8e10fcfd54a8 100644 (file)
@@ -75,6 +75,9 @@ static NSString *defaultMailDomain = nil;
   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];
 }
 
@@ -151,6 +154,11 @@ static NSString *defaultMailDomain = nil;
   return sourceIDs;
 }
 
+- (NSDictionary *) metadataForSourceID: (NSString *) sourceID
+{
+  return [sourcesMetadata objectForKey: sourceID];
+}
+
 - (NSArray *) authenticationSourceIDs
 {
   return [self _sourcesOfType: @"canAuthenticate"];
@@ -295,7 +303,8 @@ static NSString *defaultMailDomain = nil;
   NSEnumerator *ldapSources;
   LDAPSource *currentSource;
   NSString *cn, *email, *c_uid;
-
+  NSArray *attrs;
+  
   emails = [NSMutableArray array];
   cn = nil;
   c_uid = nil;
@@ -311,15 +320,18 @@ static NSString *defaultMailDomain = 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];
     }
@@ -332,7 +344,13 @@ static NSString *defaultMailDomain = nil;
   [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
index e5d67de73886b1ddad2a9e0d2c55a8d98da94772..1192ccd70d20e3b517da61896445c4085e6603d6 100644 (file)
@@ -1,6 +1,6 @@
 /* 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>
  *
@@ -155,7 +155,7 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil;
   if (!urlAfterEndingChars)
     {
       urlAfterEndingChars = [NSMutableCharacterSet new];
-      [urlAfterEndingChars addCharactersInString: @"\t \r\n"];
+      [urlAfterEndingChars addCharactersInString: @"[]\t \r\n"];
     }
 
   start = refRange.location;
@@ -165,7 +165,7 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil;
     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)
@@ -193,13 +193,15 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil;
   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
@@ -208,8 +210,9 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil;
                = 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
index 9dedfae46808e707f0e13b8471de759809625c40..0197ca9399eb66691049ddddfd9836124c09e3db 100644 (file)
@@ -365,22 +365,31 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
 
   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];
@@ -499,7 +508,7 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
   
   [(WOContext *)_ctx setObject: ((folder)
                                 ? folder
-                                : [NSNull null])
+                                : (id)[NSNull null])
                forKey: @"ActiveUserHomeFolder"];
   return folder;
 }
index 6d453e1314b5a7d775909cd580b7f320c5c42ddc..dec4c8c7e2b35c5e87525af6211eb7c90cf7b4bf 100644 (file)
@@ -10,7 +10,7 @@
 "Address Book" = "Address Book";
 "Mail" = "Mail";
 "Preferences" = "Preferences";
-"Logoff" = "Logoff";
+"Sign Out" = "Sign Out";
 "Right Administration" = "Right Administration";
 "Log Console (dev.)" = "Log Console (dev.)";
 
@@ -27,7 +27,7 @@
 
 "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";
index 7cd854ba0177afa0858d9eea46fd13d4bfbc42d6..5e1e6ce0cb566c830c8dc909e87beec545a6e828 100644 (file)
@@ -8,7 +8,7 @@
 "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.)";
 
index 943fbafe4f8aa31c66ff6e6c32b72d40e56a8449..1c2d59b05e561fea66eb1dfefc2422bb5dd8cffe 100644 (file)
@@ -31,6 +31,7 @@
 #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
index 193781ed9744b896e25d5a834a2bffb380a6702a..a5e6989a83c7e362a86af1c612e2cc2fff9f0203 100644 (file)
          ([[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"])
           );
 }
 
index 450c14217673352a06b833c05d8f129fb2a2d82b..22d41a38665b0fe4d5b649f11609d91b2969f1cd 100644 (file)
@@ -44,8 +44,6 @@
   content = [NSMutableString string];
   superContent = [[super flatContentAsString] stringByEscapingHTMLString];
   [content appendString: [superContent stringByDetectingURLs]];
-  [content replaceString: @"\r\n" withString: @"<br />"];
-  [content replaceString: @"\n" withString: @"<br />"];
 
   return content;
 }
index b058b07a19fe528df61042af8e45203c63068bc7..b8d4e8b9a444edeffc964c425018d51e5442d8a9 100644 (file)
 
 "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.";
index cf34cac37e4cdad0ad5ae5a7aabbd27b4248f0bd..3fed423bceea5bb1a050aeb16022833d717d3446 100644 (file)
 
 "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.";
index 9f5b86c3ab4f7fef3e9ff9a66b81b05935f86df0..ad9ec372c5dee79e9cf1cc5afe547203bcd5f33a 100644 (file)
 
 "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.";
index d09189a6a3ad9983832c1baa217042bb47725e99..a2eb9ee00cf94c8b412ee6e4cc60d5ef6d7c33ec 100644 (file)
@@ -442,7 +442,7 @@ static NSArray *infoKeys = nil;
        {
          result = [[self clientObject] sendMail];
          if (!result)
-           result = [self jsCloseWithRefreshMethod: nil];
+           result = [self jsCloseWithRefreshMethod: @"refreshFolderByType(\"sent\")"];
        }
       else
        result = [self failedToSaveFormResponse];
index 932c421941350fc3a3eaa7a1f6e052d94169b172..9cc6c319a96b87c0053d810e762a61bf160f76a5 100644 (file)
@@ -6,3 +6,5 @@
 "Password:" = "Password:";
 
 "Connect" = "Connect";
+
+"Wrong username or password." = "Wrong username or password.";
\ No newline at end of file
index dbdc05ac207ad9f654910d680abb64b201a988cc..2cd2ec0693b72eaacc977f26272f2f3af94e299c 100644 (file)
@@ -6,3 +6,5 @@
 "Password:" = "Mot de passe :";
 
 "Connect" = "Connexion";
+
+"Wrong username or password." = "Mauvais nom d'utilisateur ou mot de passe.";
\ No newline at end of file
index 032a615fa9ce88a40102e00d213ea0a96c4e9066..22c6a295cfea5431509e0d81268f870ce858a91f 100644 (file)
@@ -64,8 +64,6 @@ static NSString *defaultModule = nil;
                    @"'Calendar', 'Contacts' or Mail)", defaultModule];
              defaultModule = @"Calendar";
            }
-         else
-           defaultModule = @"Calendar";
        }
       else
        defaultModule = @"Calendar";
index 643dca5631ed92f0ca6532938f45b397b874198f..273d3e20b9ffd48936b5fd88ef4743a66727ec21 100644 (file)
@@ -423,6 +423,9 @@ static BOOL uixDebugEnabled = NO;
 
 - (NSString *) shortUserNameForDisplay
 {
+  if ([context activeUser] == nil)
+    return @"wrongusernamepassword";
+
   return [[context activeUser] login];
 }
 
index fde04128b507dfc6aa0aee09dd35b6dcadc4bbbe..69afbd28c34cf98ac7c99e69d69b46091b64d6fe 100644 (file)
@@ -410,5 +410,5 @@ validate_endbeforestart    = "Enddate is before startdate!";
 "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";
index ce11072569150013e7ed42262ca58b6133b1e27a..3adda5cff614631cefabbdc11f49a4d64b6c8849 100644 (file)
@@ -409,5 +409,5 @@ validate_endbeforestart    = "La date de fin est avant la date de début !";
 "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";
index e90745500b329a58bc0f59bcac237f46d5693fb6..c3ead685618170fd679d15bc0710fe83ee619e18 100644 (file)
@@ -35,6 +35,7 @@
   NSCalendarDate *aptStartDate;
   NSCalendarDate *aptEndDate;
   NSString *item;
+  NSString *repeat;
 }
 
 /* template values */
index a88b3f3829bfdbba85f901ded60eb519456ad2ec..4f4fb0bb36c0787f7ac66936f7497822b56d686b 100644 (file)
@@ -20,6 +20,8 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#warning WE LEAK IVARS LIKE CRAZY HERE
+
 #include <math.h>
 
 #import <NGObjWeb/SoObject.h>
@@ -29,6 +31,7 @@
 
 #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
index b036060f904ffdee469c434c108ad15ced569931..56a608294164a02ee1b8cff2e41c9c8baf525c4a 100644 (file)
 {
   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
index f265d43d07fd14e582caf4348b14564e5765159c..511d0819fca0ef12e3e122f98451ac7c932d396d 100644 (file)
@@ -18,7 +18,7 @@
   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"
index 9046b32297b5668e005676f070507e2dfa9effc0..a972885d656924f12209bcc0c0653f81f83baf70 100644 (file)
 
 - (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];
 }
 
index 950cfade25442e880cfad80e74eae9676f0c0106..d98db7d2557246e5e14dd4ced6f6b55236378626 100644 (file)
     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"
@@ -46,4 +47,4 @@
         </var:foreach>
       </tbody>
     </table>
-  </var:component>
+  </var:component>
\ No newline at end of file
index f77b319867ce0155984c92080699218f4a4e8c57..09dbd6b6fadb0bbd250bfa6c5f18c60994986c2e 100644 (file)
@@ -1,6 +1,6 @@
 <?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"
@@ -13,9 +13,9 @@
        ><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"
@@ -23,7 +23,7 @@
          ></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
       >
index af0bc6bc46a16c7bd0f8292e6f7b6a7f2e478bc6..78353a75b2b6e87e430ad0391263f9b5015c805d 100644 (file)
@@ -11,7 +11,9 @@
   <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/>
index 4c5039a3dffae6dbb7439f4c876724b7273124a7..19ac4c815066d0a6198f8e9e2b992304a3051f14 100644 (file)
     <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>
index ae36b74f952cb095d6cda495dcadde33776a29c2..6340a725703722e9229fc5e851556a4ca6497a7a 100644 (file)
@@ -27,7 +27,7 @@
            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">
index 14e763516563679aa241cd6ee4708e4da13fc314..afa92bf3c3cae544b70edb601c6739961f5029f3 100644 (file)
             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>
index ada40f363869cd5264317c487a6b6894682810ac..627c099479589ef185148577837439f2217fcd72 100644 (file)
@@ -46,6 +46,7 @@
        <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"
@@ -88,7 +90,7 @@
          </var:if
            ><var:component className="UIxToolbar" var:toolbar="toolbar"
            />
-       </var:if>
+       </var:if></var:if>
        
        <div class="pageContent"
          ><var:component-content
index ccf2bc5dbcbe32fbd581980ab2d06a115165363b..97d1d7f269d4ecdf4e4ab214328e550fef2ab9e6 100644 (file)
@@ -39,7 +39,7 @@ DIV#contactsListContent
   left: 0px;
   right: 0px;
   height: 16em;
-  overflow: scroll;
+  overflow: auto;
   overflow-x: hidden; }
 
 .aptview_text
@@ -169,17 +169,15 @@ DIV#folderTreeContent TABLE TD
   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
 {
@@ -247,18 +245,6 @@ DIV.contactColumn H4
 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
 { 
index 2b58fa4cc29d1cb6b996bd4563e48cba4e945d73..15921f4e161187f7f3c698d5cccea07855f78356 100644 (file)
@@ -2,7 +2,6 @@
 
 var cachedContacts = new Array();
 var currentContactFolder = null;
-var savedColumnsWidth = null;
 
 var usersRightsWindowHeight = 200;
 var usersRightsWindowWidth = 450;
@@ -47,8 +46,8 @@ function openContactsFolder(contactsFolder, reload, idx) {
         var contactsList = $("contactsList");
         if (contactsList)
            selection = contactsList.getSelectedRowsId();
-        else
-           window.alert("no contactsList");
+//        else
+//           window.alert("no contactsList");
      }
      else
        selection = null;
@@ -74,33 +73,30 @@ function openContactsFolderAtIndex(element) {
     = 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")
@@ -117,6 +113,11 @@ function contactsListCallback(http) {
          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"])
@@ -418,10 +419,9 @@ function onHeaderClick(event) {
       sorting["ascending"] = true;
    }
 
-   savedColumnsWidth = this.up('table').getColumnsWidth();
    refreshCurrentFolder();
 
-   preventDefault(event);
+   Event.stop(event);
 }
 
 function newContact(sender) {
@@ -437,7 +437,7 @@ function onFolderSelectionChange() {
   
    if (nodes[0].hasClassName("denied")) {
       var div = $("contactsListContent");
-      div.innerHTML = "";
+      div.update();
    }
    else {
       search = {};
@@ -630,7 +630,6 @@ function lookupDeniedFolders() {
   for (var i = 0; i < list.length; i++) {
      var folderID = list[i].getAttribute("id");
      var url = URLForFolderID(folderID) + "/canAccessContent";
-     
      triggerAjaxRequest(url, deniedFoldersLookupCallback, folderID);
   }
 }
@@ -746,6 +745,13 @@ function initContacts(event) {
      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);
index f93d1fb8b10634174809e49b3754ade9d65126a3..c3c3bd35b889065a8a0a7d93bb179e9783c95215 100644 (file)
@@ -156,6 +156,31 @@ Element.addMethods({
     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');
index e029cd8ba7f92a350f8ff2641df740474eaecb28..44917545707b366979aa1ba6a98128dd60ec5dd4 100644 (file)
@@ -34,28 +34,6 @@ Element.addMethods({
          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
index c1ac5c7dd600e579126e9ff4519fab70c7d2023a..1b6a5204276d6e7f20176a8848a66b495b04039e 100644 (file)
@@ -52,7 +52,7 @@ DIV#mailboxContent
   left: 0px;
   right: 0px;
   height: 15.5em;
-  overflow: scroll;
+  overflow: auto;
   overflow-x: hidden; }
 
 DIV#messageContent
@@ -367,7 +367,7 @@ DIV.mailer_plaincontent
 {
   position: relative;
   font-family: monospace, fixed;
-  white-space: normal;
+  white-space: pre;
   font-size: inherit;
   margin: 0px;
   padding: 0px;
@@ -475,14 +475,20 @@ TABLE#addr_table
 }
 
 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,
@@ -500,8 +506,7 @@ TABLE#messageList TD.messageAddressColumn
   overflow: hidden; }
 
 TD#dateHeader,
-TABLE#messageList TD.tbtv_date_headercell,
-TABLE#messageList TD.messageDateColumn
+TABLE#messageList TD.tbtv_date_headercell
 { /*width: 25%;*/
   overflow: hidden; }
 
@@ -516,18 +521,6 @@ TABLE#messageList TR._deleted TD
   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
 {
index 074a94f944c3167deca28fc5eff81d87ca9d44cf..265552f4ad3dca8d70345fe0fdd0ccfa91057d48 100644 (file)
@@ -141,6 +141,8 @@ function openMessageWindowsForSelection(action, firstOnly) {
                            ApplicationBaseURL + currentMailbox
                            + "/" + rows[i].substr(4)
                            + "/" + action);
+    } else {
+      window.alert(labels["Please select a message."]);
     }
   }
 
@@ -232,6 +234,7 @@ function uixDeleteSelectedMessages(sender) {
     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++;
@@ -246,9 +249,8 @@ function uixDeleteSelectedMessages(sender) {
       }
     }
     http = null;
-
+    
     /* remove from page */
-
     /* line-through would be nicer, but hiding is OK too */
     var row = $(rowIds[i]);
     row.parentNode.removeChild(row);
@@ -335,14 +337,18 @@ function onMailboxTreeItemClick(event) {
   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() {
@@ -378,10 +384,11 @@ function composeNewMessage() {
 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];
@@ -415,7 +422,6 @@ function openMailbox(mailbox, reload, idx) {
                                      + rightDragHandle.offsetHeight
                                      + 'px') });
     }
-
     document.messageListAjaxRequest
       = triggerAjaxRequest(url, messageListCallback,
                           currentMessage);
@@ -429,39 +435,53 @@ function openMailbox(mailbox, reload, idx) {
 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"])
@@ -471,8 +491,11 @@ function messageListCallback(http) {
       }
     }
   }
-  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) {
@@ -864,9 +887,8 @@ function onHeaderClick(event) {
     sorting["attribute"] = newSortAttribute;
     sorting["ascending"] = true;
   }
-
   refreshCurrentFolder();
-
+  
   Event.stop(event);
 }
 
@@ -874,8 +896,9 @@ function refreshCurrentFolder() {
   openMailbox(currentMailbox, true);
 }
 
-function pouetpouet(event) {
-  window.alert("pouet pouet");
+function refreshFolderByType(type) {
+  if (currentMailboxType == type)
+    refreshCurrentFolder();
 }
 
 var mailboxSpanAcceptType = function(type) {
@@ -956,35 +979,34 @@ var messageListData = 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;
@@ -1303,12 +1325,13 @@ function onMenuExpungeFolder(event) {
 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)
@@ -1317,7 +1340,7 @@ function onMenuEmptyTrash(event) {
 
 function folderOperationCallback(http) {
   if (http.readyState == 4
-      && http.status == 204)
+      && isHttpStatus204(http.status))
     initMailboxTree();
   else
     window.alert(labels["Operation failed"]);
@@ -1325,7 +1348,7 @@ function folderOperationCallback(http) {
 
 function folderRefreshCallback(http) {
   if (http.readyState == 4
-      && http.status == 204) {
+      && isHttpStatus204(http.status)) {
     var oldMailbox = http.callbackData;
     if (oldMailbox == currentMailbox)
       refreshCurrentFolder();
index 9654ce87dad0cd539dbd7ee08ef699a06a42a876..0018554ea9e8deab3dc484e2ba52ecd69b758cc2 100644 (file)
@@ -46,6 +46,10 @@ DIV#loginButton IMG#progressIndicator
   margin-top: 5px;
   margin-left: 5px; }
 
+P.error
+{ color: #f00;
+  text-align: center; }
+
 P.browser
 { background-color: #fff;
   border-top: 1px solid #888;
index 8bea4af88d31783cc125aa0a4b1b92a1ca54a5f0..970062ce038b3d86e8a29821430d15083b901dbd 100644 (file)
@@ -61,6 +61,7 @@ UL#tasksList, UL#calendarList
   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;
@@ -69,7 +70,8 @@ UL#tasksList, UL#calendarList
   overflow-x: hidden; }
 
 UL#calendarList
-{ clear: both;
+{ clear: left;
+  width: 100%;
   height: 10.5em;
   margin: 0px; }
 
@@ -107,7 +109,8 @@ UL#tasksList LI[class~="_selected"].duetoday
 { 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; }
 
@@ -266,13 +269,19 @@ TABLE#dateSelectorTable
   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,
index 8a4d6aa42c8045cb1693013bef875cfe69386af1..af65b80e6b9fa2e66b76b1f4eb8e27df7faf56a8 100644 (file)
@@ -165,15 +165,21 @@ function modifyEvent(sender, modification) {
 
 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) {
@@ -307,16 +313,16 @@ function eventsListCallback(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]);
@@ -371,7 +377,7 @@ function tasksListCallback(http) {
       //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]);
@@ -771,7 +777,7 @@ function calendarDisplayCallback(http) {
   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"])
@@ -897,8 +903,8 @@ function _loadEventHref(href) {
     = 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;
 }
@@ -927,8 +933,8 @@ function _loadTasksHref(href) {
 }
 
 function onHeaderClick(event) {
-//   log("onHeaderClick: " + this.link);
-  _loadEventHref(this.link);
+  //log("onHeaderClick: " + this.link);
+  //_loadEventHref(this.link);
 
   preventDefault(event);
 }
@@ -958,7 +964,7 @@ function onListFilterChange() {
   return refreshEvents();
 }
 
-function onEventClick(event) {
+function onEventClick(event) { log ("onEventClick");
   var day = this.day;
   var hour = this.hour;
 
@@ -1035,7 +1041,7 @@ function onSearchFormSubmit() {
 
 function onCalendarSelectEvent() {
   var list = $("eventsList");
-  list.deselectAll();
+  list.tBodies[0].deselectAll();
 
   if (selectedCalendarCell)
      for (var i = 0; i < selectedCalendarCell.length; i++)
@@ -1132,17 +1138,15 @@ function updateTaskStatus(event) {
   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;
@@ -1157,6 +1161,12 @@ function updateTaskStatus(event) {
 
 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++) {
@@ -1182,7 +1192,7 @@ function updateCalendarStatus(event) {
   if (event) {
      var folderID = this.parentNode.getAttribute("id");
      var urlstr = URLForFolderID(folderID);
-     if (this.checked)
+     if (newStatus)
        urlstr += "/activateFolder";
      else
        urlstr += "/deactivateFolder";
@@ -1202,18 +1212,18 @@ function updateCalendarStatus(event) {
 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) {
@@ -1343,12 +1353,15 @@ function initCalendarSelector() {
   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");
@@ -1415,30 +1428,31 @@ function appendCalendar(folderName, folder) {
 
     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);
     
@@ -1461,7 +1475,7 @@ function appendCalendar(folderName, folder) {
 }
 
 function onFolderSubscribeCB(folderData) {
-   var folder = $(folderData["folder"]);
+  var folder = $(folderData["folder"]);
    if (!folder)
      appendCalendar(folderData["folderName"], folderData["folder"]);
 }
@@ -1544,6 +1558,8 @@ function configureLists() {
 
    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;
index 4358f979edd91db0ccdaf08bc9e39ca840b33106..2161352da4b98108e8866ec3da7fde7f716395c2 100644 (file)
@@ -17,28 +17,31 @@ DIV.acls LABEL
 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;
index 2bef5e1d3b796f25490e1e22b6cc7aa3c3ca37ad..4bce6213628ba61ee10f67a0bc81c8dff1ef0f82 100644 (file)
@@ -142,4 +142,4 @@ function onAclLoadHandler() {
    this.userRightsWidth = window.opener.getUsersRightsWindowWidth();
 }
 
-Event.observe(window, "load", onAclLoadHandler);
+addEvent(window, 'load', onAclLoadHandler);
index 71fe311f7d2559b3a7ab2b90f036f0853f6e84d6..174cf154c56d35cbfdef0274a3dc105697595335 100644 (file)
@@ -3,7 +3,7 @@ function onCancelClick(event) {
 }
 
 function initACLButtons() {
-   $("cancelButton").addEventListener("click", onCancelClick, false);
+  Event.observe($("cancelButton"), "click", onCancelClick);
 }
 
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
index bfcbd245cf8856cfcc6ef157b1495089e5fbe8ef..1734da55a20543f6afe2efb16023f534917c5464 100644 (file)
@@ -22,7 +22,7 @@ function addLineToTree(tree, parent, line) {
        || nodes.length > 1) {
       var parentNode = nodes[0];
       var userInfos = parentNode.split(":");
-      var email = userInfos[1] + " &lt;" + userInfos[2] + ">";
+      var email = userInfos[1] + " &lt;" + userInfos[2] + "&gt;";
       tree.add(parent, 0, email, 0, '#', userInfos[0], 'person',
               '', '',
               ResourcesURL + '/abcard.gif',
@@ -35,7 +35,11 @@ function addLineToTree(tree, parent, line) {
         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;
index 71fe311f7d2559b3a7ab2b90f036f0853f6e84d6..ee8e8fccb663f91fad97a24fc82f4d91a662221a 100644 (file)
@@ -3,7 +3,8 @@ function onCancelClick(event) {
 }
 
 function initACLButtons() {
-   $("cancelButton").addEventListener("click", onCancelClick, false);
+  var button = $("cancelButton");
+   Event.observe(button, "click", onCancelClick);
 }
 
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
index 94b5f0a8ffe1502fc9bc130db3113d6612d23f56..26f7793b454c863eecf4f336c73141819195543b 100644 (file)
@@ -75,7 +75,8 @@ input.currentAttachment
   right: 1em; }
 
 input.attachment
-{ display: none; }
+{ position: absolute;
+  left: -1000px; }
 
 div#compose_attachments_list
 { background-color: #ffffff;
index bddc2b238b56104869b62e8698e565724d9609a5..d4374c8e1c8478f6d52f9721d894d1d85dede5e3 100644 (file)
@@ -9,7 +9,6 @@ function onContactAdd() {
     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;
@@ -159,6 +158,13 @@ function clickedEditorAttach(sender) {
   }  
 
   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,
@@ -172,16 +178,7 @@ function clickedEditorAttach(sender) {
 }
 
 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) {
@@ -217,6 +214,7 @@ function clickedEditorSave(sender) {
   document.pageform.action = "save";
   document.pageform.submit();
 
+  refreshMailbox();
   return false;
 }
 
@@ -336,11 +334,12 @@ function onMailEditorClose(event) {
     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);
index 71fe311f7d2559b3a7ab2b90f036f0853f6e84d6..6ef7e2fd65f35a45fee8f12f3fac01f998b834aa 100644 (file)
@@ -6,4 +6,4 @@ function initACLButtons() {
    $("cancelButton").addEventListener("click", onCancelClick, false);
 }
 
-window.addEventListener("load", initACLButtons, false);
+addEvent(window, "load", initACLButtons);
index 861e7d2fc8f744a51f72a136400f9bf4e7fe490a..b38d529e28b555f3ca8d8508b74ba9c8f2020734 100644 (file)
@@ -415,8 +415,7 @@ TD.tbtv_navcell
   -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;
@@ -425,16 +424,16 @@ TD.tbtv_headercell:active
   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;
@@ -444,7 +443,7 @@ td.tbtv_headercell a:hover
 
 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;
@@ -567,7 +566,7 @@ INPUT.button,
 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;
@@ -701,6 +700,20 @@ INPUT.checkBox
   -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
index 9a7c60538391a03b15e13d27a4ca81df83ed43d9..9fa35dedb528e6afcfd199dae2e896ab4252b903 100644 (file)
@@ -32,6 +32,8 @@ var menus = new Array();
 var search = {};
 var sorting = {};
 
+var lastClickedRow = null;
+
 var weekStartIsMonday = true;
 
 // logArea = null;
@@ -222,7 +224,7 @@ function openContactWindow(url, wId) {
   return w;
 }
 
-function openMailComposeWindow(url, wId) { log (url);
+function openMailComposeWindow(url, wId) {
   if (!wId)
     wId = "" + (new Date().getTime());
   var w = window.open(url, wId,
@@ -310,7 +312,10 @@ function triggerAjaxRequest(url, callback, userdata) {
 }
 
 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";
@@ -340,6 +345,10 @@ function checkAjaxRequestsState() {
   }
 }
 
+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;
@@ -480,7 +489,7 @@ function isNodeSelected(node) {
 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');
@@ -493,43 +502,63 @@ function acceptMultiSelect(node) {
 
 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;
 }
 
@@ -1046,7 +1075,8 @@ function accessToSubscribedFolder(serverFolder) {
 }
 
 function listRowMouseDownHandler(event) {
-   preventDefault(event);
+  preventDefault(event);
+  //Event.stop(event); 
 }
 
 /* tabs */
@@ -1301,7 +1331,6 @@ function onLoadHandler(event) {
   initMenus();
   initTabs();
   configureDragHandles();
-  configureSortableTableHeaders();
   configureLinkBanner();
   translateLabels();
   var progressImage = $("progressIndicator");
@@ -1326,14 +1355,11 @@ function onBodyClickContextMenu(event) {
    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))
    }
 }