+2007-12-06 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/Appointments/SOGoCalendarComponent.m
+ ([SOGoCalendarComponent -contentAsString]): securize the returned content.
+ ([SOGoCalendarComponent -aclsForUser:uid]): check whether the user
+ is an organizer or a participant as well.
+
+ * SoObjects/Appointments/SOGoAppointmentObject.m
+ ([SOGoAppointmentObject -changeParticipationStatus:_status]): the
+ user we should change the status of is not the active user but the
+ owner of the object. This is for delegation.
+
+ * SoObjects/Appointments/SOGoAppointmentFolder.m
+ ([SOGoAppointmentFolder -fetchContentObjectNames]): fetch the
+ elements through the fetchFields:from:to:title:component: method
+ method, so that the result is already filtered depending on the
+ acl.
+
+ * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor
+ -toolbar]): if the current user is a delegate, take the permission
+ "ModifyComponent" into account. Also, do not let him/her modify an
+ event for which he/she is the organizer.
+
+ * SoObjects/Contacts/SOGoContactLDAPFolder.m
+ ([SOGoContactLDAPFolder -davResourceType]): declared as a carddav
+ addressbook collection.
+
+ * SoObjects/Contacts/SOGoContactGCSFolder.m ([SOGoContactGCSFolder
+ -davResourceType]): declared as a carddav addressbook collection.
+
+ * SoObjects/SOGo/SOGoObject.m ([SOGoObject -davLastModified]):
+ override SoObject's implementation. Otherwise a localized date is returned.
+
+ * UI/Common/UIxPageFrame.m ([UIxPageFrame -isCalendar])
+ ([UIxPageFrame -isContacts], [UIxPageFrame -isMail]): getters to
+ determine which module is the current one.
+
+2007-12-06 Francis Lachapelle <flachapelle@inverse.ca>
+
+ * UI/Scheduler/NSArray+Scheduler.m ([NSArray -compareEventsTitleAscending:otherEvent])
+ ([NSArray -compareEventsLocationAscending:otherEvent])
+ ([NSArray -compareEventsEndDateAscending:otherEvent])
+ ([NSArray -reversedArray]): new methods that sort an array of
+ events depending of various parameters.
+
+ * UI/Scheduler/UIxCalListingActions.m ([UIxCalListingActions
+ -eventsListAction]): added support for sorting events.
+
+2007-12-06 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * UI/MailerUI/UIxMailEditor.m ([UIxMailEditor -saveAction])
+ ([UIxMailEditor -sendAction]): make sure that the attachments
+ having the same filename are correctly sequenced (ex: base.ext,
+ base-1.ext, base-2.ext).
+
+ * SoObjects/Mailer/SOGoMailBodyPart.m ([SOGoMailBodyPart
+ -fetchBLOB]): added support for quoted-printable decoding. Also,
+ we return nil if the type is not supported.
+
2007-12-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Scheduler/UIxTaskEditor.m ([UIxTaskEditor -newAction]):
2007-12-05 Francis Lachapelle <flachapelle@inverse.ca>
- * SoObjects/Mailer/SOGoDraftObject.m: The condition for replyToAll
+ * SoObjects/Mailer/SOGoDraftObject.m: the condition for replyToAll
has to be done later to avoid duplicated to and cc addresses.
2007-12-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject+SoDAV.h>
+#import <NGObjWeb/SoSecurityManager.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOMessage.h>
#import <NGObjWeb/WORequest.h>
return filterData;
}
-#warning filters is leaked here
- (NSArray *) _parseCalendarFilters: (id <DOMElement>) parentNode
{
NSEnumerator *children;
// return objectNames;
// }
+- (NSArray *) fetchContentObjectNames
+{
+ static NSArray *cNameField = nil;
+
+ if (!cNameField)
+ cNameField = [[NSArray alloc] initWithObjects: @"c_name", nil];
+
+ return [[self fetchFields: cNameField from: nil to: nil
+ title: nil component: nil] objectsForKey: @"c_name"];
+}
+
/* folder type */
- (NSString *) folderType
iCalEvent *event;
iCalPerson *attendee;
NSException *ex;
+ SOGoUser *ownerUser;
ex = nil;
event = [self component: NO secure: NO];
if (event)
{
- attendee = [event findParticipant: [context activeUser]];
+ ownerUser = [SOGoUser userWithLogin: owner roles: nil];
+ attendee = [event findParticipant: ownerUser];
if (attendee)
ex = [self _handleAttendee: attendee statusChange: _status
inEvent: event];
#import <NGObjWeb/SoSecurityManager.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext+SoObjects.h>
+#import <NGObjWeb/WORequest+So.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NGHashMap.h>
#import <NGCards/iCalCalendar.h>
return iCalString;
}
+- (NSString *) contentAsString
+{
+ NSString *secureContent;
+
+ if ([[context request] isSoWebDAVRequest])
+ secureContent = [self secureContentAsString];
+ else
+ secureContent = [super contentAsString];
+
+ return secureContent;
+}
+
- (iCalCalendar *) calendar: (BOOL) create secure: (BOOL) secure
{
NSString *componentTag;
NSArray *superAcls;
iCalRepeatableEntityObject *component;
NSString *accessRole, *ownerRole;
+ SOGoUser *aclUser;
roles = [NSMutableArray array];
superAcls = [super aclsForUser: uid];
{
if (component)
{
+ aclUser = [SOGoUser userWithLogin: uid roles: nil];
+ if ([component userIsOrganizer: aclUser])
+ [roles addObject: SOGoCalendarRole_Organizer];
+ else if ([component userIsParticipant: aclUser])
+ [roles addObject: SOGoCalendarRole_Participant];
accessRole = [container roleForComponentsWithAccessClass:
[component symbolicAccessClass]
forUser: uid];
};
SOGoCalendarComponent = {
superclass = "SOGoContentObject";
-/* defaultAccess = "SeeComponent"; */
defaultRoles = {
"ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer" );
"ViewDAndT" = ( "Organizer", "Participant", "ComponentDAndTViewer" );
"ModifyComponent" = ( "Owner", "Organizer" );
- "RespondToComponent" = ( "Participant" );
-/* "SeeComponent" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); */
+ "RespondToComponent" = ( "Participant", "ComponentModifier", "ComponentResponder" );
+ "Access Object" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" );
+ "Access Contents Information" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" );
+ "WebDAV Access" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" );
};
};
SOGoAppointmentObject = {
return @"vcard-collection";
}
+- (NSArray *) davResourceType
+{
+ NSMutableArray *resourceType;
+ NSArray *cardDavCollection;
+
+ cardDavCollection
+ = [NSArray arrayWithObjects: @"addressbook",
+ @"urn:ietf:params:xml:ns:carddav", nil];
+
+ resourceType = [NSMutableArray arrayWithArray: [super davResourceType]];
+ [resourceType addObject: cardDavCollection];
+
+ return resourceType;
+}
+
/* sorting */
- (NSComparisonResult) compare: (id) otherFolder
{
return @"vcard-collection";
}
+- (NSArray *) davResourceType
+{
+ NSMutableArray *resourceType;
+ NSArray *cardDavCollection;
+
+ cardDavCollection
+ = [NSArray arrayWithObjects: @"addressbook",
+ @"urn:ietf:params:xml:ns:carddav", nil];
+
+ resourceType = [NSMutableArray arrayWithArray: [super davResourceType]];
+ [resourceType addObject: cardDavCollection];
+
+ return resourceType;
+}
+
- (id) lookupName: (NSString *) objectName
inContext: (WOContext *) lookupContext
acquire: (BOOL) acquire
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NGBase64Coding.h>
+#import <NGExtensions/NGQuotedPrintableCoding.h>
#import <NGImap4/NGImap4Connection.h>
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
if (enc)
{
- enc = [enc uppercaseString];
+ enc = [enc lowercaseString];
- if ([enc isEqualToString:@"BASE64"])
+ if ([enc isEqualToString: @"base64"])
data = [data dataByDecodingBase64];
- else if ([enc isEqualToString:@"7BIT"])
+ else if ([enc isEqualToString: @"quoted-printable"])
+ data = [data dataByDecodingQuotedPrintableTransferEncoding];
+ else if ([enc isEqualToString: @"7bit"]
+ || [enc isEqualToString: @"8bit"])
; /* keep data as is */ // TODO: do we need to change encodings?
else
- [self errorWithFormat:@"unsupported encoding: %@", enc];
+ {
+ data = nil;
+ [self errorWithFormat: @"unsupported encoding: %@", enc];
+ }
}
-
+
return data;
}
/* dav */
- (NSArray *) davNamespaces;
+- (NSArray *) davResourceType;
/* outlook */
- (NSString *) outlookFolderClass;
#import "SOGoDAVRendererTypes.h"
#import "NSArray+Utilities.h"
+#import "NSCalendarDate+SOGo.h"
#import "NSDictionary+Utilities.h"
#import "NSString+Utilities.h"
return @"text/plain";
}
+- (NSString *) davLastModified
+{
+ return [[NSCalendarDate date] rfc822DateString];
+}
+
- (WOResponse *) _webDAVResponse: (WOContext *) localContext
{
WOResponse *response;
return ([[self productCSSURL] length] > 0);
}
+- (BOOL) _moduleIs: (NSString *) moduleName
+{
+ NSString *frameworkName;
+
+ frameworkName = [[context page] frameworkName];
+
+ return [frameworkName isEqualToString: moduleName];
+}
+
+- (BOOL) isCalendar
+{
+ return [self _moduleIs: @"SchedulerUI"];
+}
+
+- (BOOL) isContacts
+{
+ return [self _moduleIs: @"ContactsUI"];
+}
+
+- (BOOL) isMail
+{
+ return [self _moduleIs: @"MailerUI"];
+}
+
- (void) setToolbar: (NSString *) newToolbar
{
ASSIGN (toolbar, newToolbar);
/* these are for the inline attachment list */
NSString *attachmentName;
NSArray *attachmentNames;
+ NSMutableArray *attachedFiles;
}
@end
[bcc release];
[attachmentName release];
[attachmentNames release];
+ [attachedFiles release];
[super dealloc];
}
}
/* actions */
+- (NSString *) _fixedFilename: (NSString *) filename
+{
+ NSString *newFilename, *baseFilename, *extension;
+ unsigned int variation;
+
+ if (!attachedFiles)
+ attachedFiles = [NSMutableArray new];
+
+ newFilename = filename;
+
+ baseFilename = [filename stringByDeletingPathExtension];
+ extension = [filename pathExtension];
+ variation = 0;
+ while ([attachedFiles containsObject: newFilename])
+ {
+ variation++;
+ newFilename = [NSString stringWithFormat: @"%@-%d.%@", baseFilename,
+ variation, extension];
+ }
+ [attachedFiles addObject: newFilename];
+
+ return newFilename;
+}
- (NSDictionary *) _scanAttachmentFilenamesInRequest: (id) httpBody
{
unsigned int count, max;
NGMimeBodyPart *part;
NGMimeContentDispositionHeaderField *header;
- NSString *mimeType;
+ NSString *mimeType, *filename;
parts = [httpBody parts];
max = [parts count];
[part headerForKey: @"content-disposition"];
mimeType = [(NGMimeType *)
[part headerForKey: @"content-type"] stringValue];
+ filename = [self _fixedFilename: [header filename]];
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
- [header filename], @"filename",
+ filename, @"filename",
mimeType, @"mimetype", nil];
[filenames setObject: attachment forKey: [header name]];
}
{
NSArray *a;
- if (attachmentNames != nil)
- return attachmentNames;
-
- a = [[self clientObject] fetchAttachmentNames];
- a = [a sortedArrayUsingSelector: @selector (compare:)];
- attachmentNames = [a copy];
+ if (attachmentNames)
+ {
+ a = [[self clientObject] fetchAttachmentNames];
+ a = [a sortedArrayUsingSelector: @selector (compare:)];
+ attachmentNames = [a copy];
+ }
return attachmentNames;
}
@interface NSArray (SOGoEventComparison)
-- (NSComparisonResult) compareEventsAscending: (NSArray *) otherEvent;
+- (NSComparisonResult) compareEventsStartDateAscending: (NSArray *) otherEvent;
+- (NSComparisonResult) compareEventsEndDateAscending: (NSArray *) otherEvent;
+- (NSComparisonResult) compareEventsTitleAscending: (NSArray *) otherEvent;
+- (NSComparisonResult) compareEventsLocationAscending: (NSArray *) otherEvent;
- (NSComparisonResult) compareTasksAscending: (NSArray *) otherTask;
+- (NSArray *) reversedArray;
@end
return result;
}
-- (NSComparisonResult) compareEventsAscending: (NSArray *) otherEvent
+- (NSComparisonResult) compareEventsStartDateAscending: (NSArray *) otherEvent
{
NSComparisonResult result;
unsigned int selfTime, otherTime;
return result;
}
+- (NSComparisonResult) compareEventsEndDateAscending: (NSArray *) otherEvent
+{
+ NSComparisonResult result;
+ unsigned int selfTime, otherTime;
+
+ selfTime = [[self objectAtIndex: 5] intValue];
+ otherTime = [[otherEvent objectAtIndex: 5] intValue];
+ if (selfTime > otherTime)
+ result = NSOrderedDescending;
+ else if (selfTime < otherTime)
+ result = NSOrderedAscending;
+ else
+ result = NSOrderedSame;
+
+ return result;
+}
+
+- (NSComparisonResult) compareEventsTitleAscending: (NSArray *) otherEvent
+{
+ NSString *selfTitle, *otherTitle;
+
+ selfTitle = [self objectAtIndex: 3];
+ otherTitle = [otherEvent objectAtIndex: 3];
+
+ return [selfTitle caseInsensitiveCompare: otherTitle];
+}
+
+- (NSComparisonResult) compareEventsLocationAscending: (NSArray *) otherEvent
+{
+ NSString *selfTitle, *otherTitle;
+
+ selfTitle = [self objectAtIndex: 6];
+ otherTitle = [otherEvent objectAtIndex: 6];
+
+ return [selfTitle caseInsensitiveCompare: otherTitle];
+}
+
- (NSComparisonResult) compareTasksAscending: (NSArray *) otherTask
{
NSComparisonResult result;
return result;
}
+- (NSArray *) reversedArray
+{
+ return [[self reverseObjectEnumerator] allObjects];
+}
+
@end
NSMutableArray *newEvents, *newEvent;
unsigned int interval;
BOOL isAllDay;
+ NSString *sort, *ascending;
[self _setupContext];
[newEvent addObject: [self _formattedDateForSeconds: interval
forAllDay: isAllDay]];
[newEvents addObject: newEvent];
-
+
oldEvent = [events nextObject];
}
- [newEvents sortUsingSelector: @selector (compareEventsAscending:)];
+
+ sort = [[context request] formValueForKey: @"sort"];
+ if ([sort isEqualToString: @"title"])
+ [newEvents sortUsingSelector: @selector (compareEventsTitleAscending:)];
+ else if ([sort isEqualToString: @"end"])
+ [newEvents sortUsingSelector: @selector (compareEventsEndDateAscending:)];
+ else if ([sort isEqualToString: @"location"])
+ [newEvents sortUsingSelector: @selector (compareEventsLocationAscending:)];
+ else
+ [newEvents sortUsingSelector: @selector (compareEventsStartDateAscending:)];
+
+ ascending = [[context request] formValueForKey: @"asc"];
+ if (![ascending boolValue])
+ newEvents = [newEvents reversedArray];
return [self _responseWithData: newEvents];
}
SoSecurityManager *sm;
NSString *toolbarFilename, *adminToolbar;
iCalPersonPartStat participationStatus;
+ SOGoUser *currentUser;
if ([clientObject isKindOfClass: [SOGoAppointmentObject class]])
adminToolbar = @"SOGoAppointmentObject.toolbar";
sm = [SoSecurityManager sharedSecurityManager];
if ([[component attendees] count])
{
- if ([component userIsOrganizer: ownerUser]
- && ![sm validatePermission: SOGoCalendarPerm_ModifyComponent
- onObject: clientObject
- inContext: context])
- toolbarFilename = adminToolbar;
- else if ([component userIsParticipant: ownerUser]
- && ![sm validatePermission: SOGoCalendarPerm_RespondToComponent
- onObject: clientObject
- inContext: context])
- {
- participationStatus
- = [[component findParticipant: ownerUser] participationStatus];
- /* Lightning does not manage participation status within tasks */
- if (participationStatus == iCalPersonPartStatAccepted)
- toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
- else if (participationStatus == iCalPersonPartStatDeclined)
- toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
+ currentUser = [context activeUser];
+ if ([component userIsOrganizer: currentUser])
+ toolbarFilename = @"SOGoComponentClose.toolbar";
+ else
+ {
+ if ([component userIsOrganizer: ownerUser]
+ && ![sm validatePermission: SOGoCalendarPerm_ModifyComponent
+ onObject: clientObject
+ inContext: context])
+ toolbarFilename = adminToolbar;
+ else if ([component userIsParticipant: ownerUser]
+ && !([sm validatePermission: SOGoCalendarPerm_RespondToComponent
+ onObject: clientObject
+ inContext: context]
+ && [sm validatePermission: SOGoCalendarPerm_ModifyComponent
+ onObject: clientObject
+ inContext: context]))
+ {
+ participationStatus
+ = [[component findParticipant: ownerUser] participationStatus];
+ /* Lightning does not manage participation status within tasks */
+ if (participationStatus == iCalPersonPartStatAccepted)
+ toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
+ else if (participationStatus == iCalPersonPartStatDeclined)
+ toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
+ else
+ toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
+ }
else
- toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
+ toolbarFilename = @"SOGoComponentClose.toolbar";
}
- else
- toolbarFilename = @"SOGoComponentClose.toolbar";
}
else
{
</ul>
</div>
- <form name="searchform" var:href="view" var:_sort="sortKey"
- onsubmit="return onSearchFormSubmit();" method="GET">
<!-- var:if condition="isPopup" const:negate="YES" -->
<!-- <var:if condition="hideFolderTree" const:negate="YES" -->
<div class="contactFoldersList" id="contactFoldersList">
<!-- var:if condition="isPopup">
var:component-content />
/var:if> -->
- </form>
<var:string value="errorAlertJavaScript" const:escapeHTML="NO" />
</var:if>
<table id="eventsList" cellspacing="0">
<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>
+ <td id="titleHeader" class="headerCell headerTitle sortableTableHeader"><var:string label:value="Title"/></td>
+ <td id="startHeader" class="headerCell headerDateTime sortableTableHeader"><var:string label:value="Start"/></td>
+ <td id="endHeader" class="headerCell headerDateTime sortableTableHeader"><var:string label:value="End"/></td>
+ <td id="locationHeader" class="headerCell headerLocation sortableTableHeader"><var:string label:value="Location"/></td>
</tr>
</thead>
<tbody></tbody>
<a id="logoff" var:href="logoffPath"
><var:string label:value="Disconnect" /></a>
<var:if condition="userHasCalendarAccess">
- <a id="calendarBannerLink"
- var:href="relativeCalendarPath"
- ><var:string label:value="Calendar" /></a> |
+ <var:if condition="isCalendar">
+ <span class="active"><var:string label:value="Calendar"
+ /></span>
+ </var:if>
+ <var:if condition="isCalendar" const:negate="YES">
+ <a id="calendarBannerLink"
+ var:href="relativeCalendarPath"
+ ><var:string label:value="Calendar" /></a>
+ </var:if>
+ |
</var:if>
- <a id="contactsBannerLink"
- var:href="relativeContactsPath"
- ><var:string label:value="Address Book" /></a> |
+ <var:if condition="isContacts">
+ <span class="active"><var:string label:value="Address Book"
+ /></span>
+ </var:if>
+ <var:if condition="isContacts" const:negate="YES">
+ <a id="contactsBannerLink"
+ var:href="relativeContactsPath"
+ ><var:string label:value="Address Book" /></a>
+ </var:if>
+ |
<var:if condition="userHasMailAccess">
- <a id="mailBannerLink" var:href="relativeMailPath"
- ><var:string label:value="Mail" /></a> |
+ <var:if condition="isMail">
+ <span class="active"><var:string label:value="Mail"
+ /></span>
+ </var:if>
+ <var:if condition="isMail" const:negate="YES">
+ <a id="mailBannerLink" var:href="relativeMailPath"
+ ><var:string label:value="Mail" /></a>
+ </var:if>
+ |
</var:if>
<a id="preferencesBannerLink"
var:href="relativePreferencesPath"
}
function appendAddressBook(name, folder) {
- if (folder)
+ var owner;
+
+ if (folder) {
+ owner = getSubscribedFolderOwner(folder);
folder = accessToSubscribedFolder(folder);
+ }
else
folder = "/" + name;
+
+ if (!owner)
+ owner = UserLogin;
+
if ($(folder))
window.alert(clabels["You have already subscribed to that folder!"]);
else {
+ var contactFolders = $("contactFolders");
+ var items = contactFolders.childNodesWithTag("li");
var li = document.createElement("li");
- $("contactFolders").appendChild(li);
+
+ // Add the calendar to the proper place
+ var i = getListIndexForFolder(items, owner, name);
+ if (i != items.length) // User is subscribed to other calendars of the same owner
+ contactFolders.insertBefore(li, items[i]);
+ else
+ contactFolders.appendChild(li);
+
li.setAttribute("id", folder);
+ li.setAttribute("owner", owner);
li.appendChild(document.createTextNode(name));
setEventsOnContactFolder(li);
}
if (selected.length > 0) {
var folderOwner = selected[0].getAttribute("owner");
+ var modifyOption = $(this).down("ul").childElements().first();
var sharingOption = $(this).down("ul").childElements().last();
- // Disable the "Sharing" option when address book is not owned by user
- if (folderOwner == UserLogin || IsSuperUser)
+ // Disable the "Sharing" and "Modify" options when address book
+ // is not owned by user
+ if (folderOwner == UserLogin || IsSuperUser) {
+ modifyOption.removeClassName("disabled");
sharingOption.removeClassName("disabled");
- else
+ }
+ else {
+ modifyOption.addClassName("disabled");
sharingOption.addClassName("disabled");
+ }
}
}
/* JavaScript for SOGoCalendar */
-var sortOrder = '';
-var sortKey = '';
var listFilter = 'view_today';
var listOfSelection = null;
document.eventsListAjaxRequest = null;
var table = $("eventsList");
- var params = parseQueryParameters(http.callbackData);
- sortKey = params["sort"];
- sortOrder = params["desc"];
lastClickedRow = -1; // from generic.js
if (http.responseText.length > 0) {
Event.observe(td, "mousedown", listRowMouseDownHandler, true);
td.appendChild(document.createTextNode(data[i][6]));
}
+
+ if (sorting["attribute"] && sorting["attribute"].length > 0) {
+ 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"])
+ sortImage.src = ResourcesURL + "/title_sortdown_12x12.png";
+ else
+ sortImage.src = ResourcesURL + "/title_sortup_12x12.png";
+ }
+ }
}
}
else
}
function onHeaderClick(event) {
- //log("onHeaderClick: " + this.link);
- //_loadEventHref(this.link);
+ var headerId = this.getAttribute("id");
+ var newSortAttribute;
+ if (headerId == "titleHeader")
+ newSortAttribute = "title";
+ else if (headerId == "startHeader")
+ newSortAttribute = "start";
+ else if (headerId == "endHeader")
+ newSortAttribute = "end";
+ else if (headerId == "locationHeader")
+ newSortAttribute = "location";
+ else
+ newSortAttribute = "start";
+
+ if (sorting["attribute"] == newSortAttribute)
+ sorting["ascending"] = !sorting["ascending"];
+ else {
+ sorting["attribute"] = newSortAttribute;
+ sorting["ascending"] = true;
+ }
+ refreshEvents();
- preventDefault(event);
+ Event.stop(event);
}
function refreshCurrentFolder() {
titleSearch = "&search=" + value;
else
titleSearch = "";
-
- return _loadEventHref("eventslist?desc=" + sortOrder
- + "&sort=" + sortKey
+
+ return _loadEventHref("eventslist?asc=" + sorting["ascending"]
+ + "&sort=" + sorting["attribute"]
+ "&day=" + currentDay
+ titleSearch
+ "&filterpopup=" + listFilter);
window.alert(clabels["You have already subscribed to that folder!"]);
else {
var calendarList = $("calendarList");
- var lis = calendarList.childNodesWithTag("li");
+ var items = calendarList.childNodesWithTag("li");
var li = document.createElement("li");
// Add the calendar to the proper place
- var previousOwner = null;
- for (var i = 0; i < lis.length; i++) {
- var currentFolderName = lis[i].lastChild.nodeValue.strip();
- var currentOwner = lis[i].readAttribute('owner');
- if (currentOwner == owner) {
- previousOwner = currentOwner;
- if (currentFolderName > folderName)
- break;
- }
- else if (previousOwner ||
- (currentOwner != UserLogin && currentOwner > owner))
- break;
- }
- if (i != lis.length) // User is subscribed to other calendars of the same owner
- calendarList.insertBefore(li, lis[i]);
+ var i = getListIndexForFolder(items, owner, folderName);
+ if (i != items.length) // User is subscribed to other calendars of the same owner
+ calendarList.insertBefore(li, items[i]);
else
calendarList.appendChild(li);
// Generate new color
if (calendarColorIndex == null)
- calendarColorIndex = lis.length;
+ calendarColorIndex = items.length;
calendarColorIndex++;
var colorTable = [1, 1, 1];
var color;
list = $("eventsList");
list.multiselect = true;
- //configureSortableTableHeaders(list);
+ configureSortableTableHeaders(list);
TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
Event.observe(list, "mousedown",
onEventsSelectionChange.bindAsEventListener(list));
}
function initCalendars() {
+ sorting["attribute"] = "start";
+ sorting["ascending"] = true;
+
if (!document.body.hasClassName("popup")) {
initDateSelectorEvents();
initCalendarSelector();
return false;
}
-function rememberAddress(email) {
- var list, span, idx;
-
- list = $('addr_addresses');
- span = document.createElement('span');
- span.id = email;
- idx = document.createTextNode(currentIndex);
- span.appendChild(idx);
- list.appendChild(span);
-}
-
function checkAddresses() {
alert("addressCount: " + this.getAddressCount() + " currentIndex: " + currentIndex + " lastIndex: " + lastIndex);
}
-function addAddress(type, email, uid, sn, cn, dn) {
- var shouldAddRow, s, e;
-
- shouldAddRow = true;
- if (cn)
- s = this.sanitizedCn(cn) + ' <' + email + '>';
- else
- s = email;
-
- if(this.hasAddress(email))
- return;
-
- e = $('addr_0');
- if(e.value == '') {
- e.value = s;
- shouldAddRow = false;
- }
- if(shouldAddRow) {
- this.fancyAddRow(false, s);
- }
- this.rememberAddress(email);
-}
-
-function fancyAddRow(shouldEdit, text) {
+function fancyAddRow(shouldEdit, text, type) {
var addr, addressList, lastChild, proto, row, select, input;
addr = $('addr_' + lastIndex);
var rowNodes = row.childNodesWithTag("td");
select = $(rowNodes[0]).childNodesWithTag("select")[0];
select.name = 'popup_' + currentIndex;
- select.value = proto.down("select").value;
+ select.value = (type? type : proto.down("select").value);
input = $(rowNodes[1]).childNodesWithTag("input")[0];
input.name = 'addr_' + currentIndex;
input.id = 'addr_' + currentIndex;
function addressFieldLostFocus(sender) {
lastIndex = this.getIndexFromIdentifier(sender.id);
+ var addresses = sender.value.split(',');
+ if (addresses.length > 0) {
+ sender.value = addresses[0].strip();
+ for (var i = 1; i < addresses.length; i++) {
+ var addr = addresses[i].strip();
+ if (addr.length > 0)
+ fancyAddRow(false, addr, $(sender).up("tr").down("select").value);
+ }
+ }
+
return false;
}
addr = $('addr_' + lastIndex);
if (!addr) return;
if (addr.value.strip() != '') return;
- addr = this.findAddressWithIndex(lastIndex);
- if(addr) {
- var addresses = $('addr_addresses');
- addresses.removeChild(addr);
- }
senderRow = $("row_" + lastIndex);
addressList.removeChild(senderRow);
}
-function findAddressWithIndex(idx) {
- var list, i, count, addr, idx
- list = $('addr_addresses').childNodes;
- count = list.length;
- for(i = 0; i < count; i++) {
- addr = list[i];
- if(addr.innerHTML == idx)
- return addr;
- }
- return null;
-}
-
function getIndexFromIdentifier(id) {
return id.split('_')[1];
}
z-index: 100;
color: #aaa; }
-DIV.linkbanner A
-{ top: 0px;
- left: 0px;
+DIV.linkbanner A,
+DIV.linkbanner SPAN
+{ cursor: default;
color: #ddd;
text-decoration: none;
- padding: .2em .5em; }
+ top: 0px;
+ left: 0px;
+ padding: 2px 5px; }
+
+DIV.linkbanner SPAN
+{ color: #afafff; }
DIV.linkbanner A:hover
{ color: #dd5; }
if (event.keyCode == 13) {
onSearchFormSubmit();
- event.preventDefault();
+ preventDefault(event);
}
else
this.timer = setTimeout("onSearchFormSubmit()", 1000);
return owner;
}
+function getListIndexForFolder(items, owner, folderName) {
+ var i;
+ var previousOwner = null;
+
+ for (var i = 0; i < items.length; i++) {
+ var currentFolderName = items[i].lastChild.nodeValue.strip();
+ var currentOwner = items[i].readAttribute('owner');
+ if (currentOwner == owner) {
+ previousOwner = currentOwner;
+ if (currentFolderName > folderName)
+ break;
+ }
+ else if (previousOwner ||
+ (currentOwner != UserLogin && currentOwner > owner))
+ break;
+ else if (currentOwner == "nobody")
+ break;
+ }
+
+ return i;
+}
+
function listRowMouseDownHandler(event) {
preventDefault(event);
//Event.stop(event);