mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-08 00:11:22 +00:00
See ChangeLog
Monotone-Parent: 2b83c62317d266d5f7a2e2046fc19f68f88a385f Monotone-Revision: 763ab7e667a159d6b727544a067a085d622ab598 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2010-06-25T19:58:30 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
57
ChangeLog
57
ChangeLog
@@ -1,3 +1,60 @@
|
||||
2010-06-25 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/MailerUI/UIxMailMainFrame.m (-inboxData): new method used to
|
||||
avoid an AJAX call when first loading the webmail module. It
|
||||
returns a dictionary with the UIDs of the inbox folder as well as
|
||||
the headers of the first few messages.
|
||||
|
||||
* UI/MailerUI/UIxMailListActions.m (-imap4SortOrdering): fixed an
|
||||
issue that would not save the sorting state when matching the
|
||||
default sort key but not the sort direction.
|
||||
(-getUIDsAndHeadersInFolder:): new method that returns all UIDs of
|
||||
a mail folder and the headers of the first corresponding messages.
|
||||
(-getHeadersForUIDs:inFolder:): was getHeadersAction. It now
|
||||
returns an array of arrays instead of an array of
|
||||
dictionaries. The first array contains the previous dictionary
|
||||
keys so we can easily reconstruct a dictionary in JavaScript.
|
||||
|
||||
* UI/MailerUI/UIxMailEditor.m (-setSourceUID:, -sourceUID,
|
||||
-setSourceFolder:, -sourceFolder): new methods to keep track of
|
||||
the source folder replying or forwarding a message.
|
||||
(-sendAction): now calls the JavaScript function refreshMessage
|
||||
instead of refreshCurrentMailbox.
|
||||
|
||||
* SoObjects/Mailer/SOGoDraftObject.m (-setSourceFolder:,
|
||||
-setSourceFolderWithMailObject:, -sourceFolder): new methods to
|
||||
keep track of the source folder replying or forwarding a message.
|
||||
(-fetchMailForEditing:): fixed the message UID value.
|
||||
|
||||
* UI/WebServerResources/SOGoMailDataSource.js (remove): new
|
||||
function that was integrated to invalidate. There are now
|
||||
splitted.
|
||||
(init): new function to initialize the data source with
|
||||
pre-fetched uids and headers.
|
||||
(getData): if the source is not yet loaded, the function will now
|
||||
be called by the method _loadCallback.
|
||||
(_getRemoteDataCallback): headers received from the server are no
|
||||
formatted as a hash but as an array with the first entry
|
||||
corresponding the previous hash keys.
|
||||
|
||||
* UI/WebServerResources/SOGoDataTable.js (initSource): was
|
||||
setSource which was redefined to received a data source as
|
||||
argument.
|
||||
(invalidate): new function to refresh a single row.
|
||||
|
||||
* UI/WebServerResources/MailerUI.js (openMailbox): added caching
|
||||
of data sources (IMAP folders). The previous selection is now
|
||||
restored when chaning folders.
|
||||
(loadMessageCallback): the window is no longer reloaded if the
|
||||
message doesn't exist; only the proper row is removed.
|
||||
(refreshMessage): new function called after sending a message.
|
||||
|
||||
2010-06-24 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/MailerUI/UIxMailEditor.m (-sendAction): trigger the new
|
||||
JavaScript function refreshMessage() instead of
|
||||
refreshCurrentFolder() so we only refresh one row.
|
||||
|
||||
2010-06-23 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoUserDefaults.m (-language): verify that the
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
NSString *text;
|
||||
NSString *sourceURL;
|
||||
NSString *sourceFlag;
|
||||
NSString *sourceFolder;
|
||||
}
|
||||
|
||||
/* contents */
|
||||
@@ -75,6 +76,8 @@
|
||||
/* for replies and forwards */
|
||||
- (void) setSourceURL: (NSString *) newSurceURL;
|
||||
- (void) setSourceFlag: (NSString *) newSourceFlag;
|
||||
- (void) setSourceFolder: (NSString *) newSourceFolder;
|
||||
- (NSString *) sourceFolder;
|
||||
|
||||
- (void) setIMAP4ID: (int) newIMAPID;
|
||||
- (int) IMAP4ID;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2007-2009 Inverse inc.
|
||||
Copyright (C) 2007-2010 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo.
|
||||
@@ -259,6 +259,35 @@ static NSString *userAgent = nil;
|
||||
ASSIGN (sourceFlag, newSourceFlag);
|
||||
}
|
||||
|
||||
- (void) setSourceFolder: (NSString *) newSourceFolder
|
||||
{
|
||||
ASSIGN (sourceFolder, newSourceFolder);
|
||||
}
|
||||
|
||||
- (void) setSourceFolderWithMailObject: (SOGoMailObject *) sourceMail
|
||||
{
|
||||
NSMutableArray *paths;
|
||||
id parent;
|
||||
|
||||
parent = [sourceMail container];
|
||||
paths = [NSMutableArray arrayWithCapacity: 1];
|
||||
while (parent && ![parent isKindOfClass: [SOGoMailAccount class]])
|
||||
{
|
||||
[paths insertObject: [parent nameInContainer] atIndex: 0];
|
||||
parent = [parent container];
|
||||
}
|
||||
if (parent)
|
||||
[paths insertObject: [NSString stringWithFormat: @"/%@", [parent nameInContainer]]
|
||||
atIndex: 0];
|
||||
|
||||
[self setSourceFolder: [paths componentsJoinedByString: @"/"]];
|
||||
}
|
||||
|
||||
- (NSString *) sourceFolder
|
||||
{
|
||||
return sourceFolder;
|
||||
}
|
||||
|
||||
- (NSException *) storeInfo
|
||||
{
|
||||
NSMutableDictionary *infos;
|
||||
@@ -273,12 +302,13 @@ static NSString *userAgent = nil;
|
||||
if (inReplyTo)
|
||||
[infos setObject: inReplyTo forKey: @"inReplyTo"];
|
||||
if (IMAP4ID > -1)
|
||||
[infos setObject: [NSNumber numberWithInt: IMAP4ID]
|
||||
forKey: @"IMAP4ID"];
|
||||
if (sourceURL && sourceFlag)
|
||||
[infos setObject: [NSString stringWithFormat: @"%i", IMAP4ID]
|
||||
forKey: @"IMAP4ID"];
|
||||
if (sourceURL && sourceFlag && sourceFolder)
|
||||
{
|
||||
[infos setObject: sourceURL forKey: @"sourceURL"];
|
||||
[infos setObject: sourceFlag forKey: @"sourceFlag"];
|
||||
[infos setObject: sourceFolder forKey: @"sourceFolder"];
|
||||
}
|
||||
|
||||
if ([infos writeToFile: [self infoPath] atomically:YES])
|
||||
@@ -324,6 +354,9 @@ static NSString *userAgent = nil;
|
||||
value = [infoDict objectForKey: @"sourceFlag"];
|
||||
if (value)
|
||||
[self setSourceFlag: value];
|
||||
value = [infoDict objectForKey: @"sourceFolder"];
|
||||
if (value)
|
||||
[self setSourceFolder: value];
|
||||
|
||||
value = [infoDict objectForKey: @"inReplyTo"];
|
||||
if (value)
|
||||
@@ -622,7 +655,8 @@ static NSString *userAgent = nil;
|
||||
|
||||
[self setText: [sourceMail contentForEditing]];
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
IMAP4ID = [[sourceMail nameInContainer] intValue];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
[self storeInfo];
|
||||
}
|
||||
@@ -650,6 +684,9 @@ static NSString *userAgent = nil;
|
||||
[self setHeaders: info];
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
[self setSourceFlag: @"Answered"];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
[self storeInfo];
|
||||
}
|
||||
|
||||
@@ -670,6 +707,8 @@ static NSString *userAgent = nil;
|
||||
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
[self setSourceFlag: @"$Forwarded"];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
/* attach message */
|
||||
ud = [[context activeUser] userDefaults];
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
NSArray *cc;
|
||||
NSArray *bcc;
|
||||
NSString *subject;
|
||||
NSString *sourceUID;
|
||||
NSString *sourceFolder;
|
||||
NSString *text;
|
||||
NSMutableArray *fromEMails;
|
||||
NSString *from;
|
||||
@@ -116,6 +118,8 @@ static NSArray *infoKeys = nil;
|
||||
[to release];
|
||||
[cc release];
|
||||
[bcc release];
|
||||
[sourceUID release];
|
||||
[sourceFolder release];
|
||||
[attachmentName release];
|
||||
[attachmentNames release];
|
||||
[attachedFiles release];
|
||||
@@ -245,6 +249,29 @@ static NSArray *infoKeys = nil;
|
||||
return text;
|
||||
}
|
||||
|
||||
- (void) setSourceUID: (int) newSourceUID
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"%i", newSourceUID];
|
||||
ASSIGN (sourceUID, s);
|
||||
}
|
||||
|
||||
- (NSString *) sourceUID
|
||||
{
|
||||
return sourceUID;
|
||||
}
|
||||
|
||||
- (void) setSourceFolder: (NSString *) newSourceFolder
|
||||
{
|
||||
ASSIGN (sourceFolder, newSourceFolder);
|
||||
}
|
||||
|
||||
- (NSString *) sourceFolder
|
||||
{
|
||||
return sourceFolder;
|
||||
}
|
||||
|
||||
- (void) setTo: (NSArray *) newTo
|
||||
{
|
||||
if ([newTo isKindOfClass: [NSNull class]])
|
||||
@@ -490,6 +517,11 @@ static NSArray *infoKeys = nil;
|
||||
return [[self attachmentNames] count] > 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (NSString *) uid
|
||||
{
|
||||
return [[self clientObject] nameInContainer];
|
||||
}
|
||||
|
||||
- (id) defaultAction
|
||||
{
|
||||
SOGoDraftObject *co;
|
||||
@@ -498,6 +530,8 @@ static NSArray *infoKeys = nil;
|
||||
[co fetchInfo];
|
||||
[self loadInfo: [co headers]];
|
||||
[self setText: [co text]];
|
||||
[self setSourceUID: [co IMAP4ID]];
|
||||
[self setSourceFolder: [co sourceFolder]];
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -537,6 +571,7 @@ static NSArray *infoKeys = nil;
|
||||
- (id <WOActionResults>) sendAction
|
||||
{
|
||||
id <WOActionResults> result;
|
||||
SOGoDraftObject *co;
|
||||
|
||||
// TODO: need to validate whether we have a To etc
|
||||
|
||||
@@ -548,7 +583,12 @@ static NSArray *infoKeys = nil;
|
||||
{
|
||||
result = (id <WOActionResults>) [[self clientObject] sendMail];
|
||||
if (!result)
|
||||
result = [self jsCloseWithRefreshMethod: @"refreshCurrentFolder()"];
|
||||
{
|
||||
co = [self clientObject];
|
||||
result = [self jsCloseWithRefreshMethod: [NSString stringWithFormat: @"refreshMessage(\"%@\", %i)",
|
||||
[co sourceFolder],
|
||||
[co IMAP4ID]]];
|
||||
}
|
||||
}
|
||||
else
|
||||
result = [self failedToSaveFormResponse];
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
- (EOQualifier *) searchQualifier;
|
||||
- (NSString *) msgLabels;
|
||||
|
||||
- (NSArray *) getSortedUIDsInFolder: (SOGoMailFolder *) mailFolder;
|
||||
- (NSArray *) getHeadersForUIDs: (NSArray *) uids
|
||||
inFolder: (SOGoMailFolder *) mailFolder;
|
||||
- (NSDictionary *) getUIDsAndHeadersInFolder: (SOGoMailFolder *) mailFolder;
|
||||
|
||||
- (id) getMailAction;
|
||||
- (id <WOActionResults>) getSortedUIDsAction;
|
||||
- (id <WOActionResults>) getHeadersAction;
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
|
||||
#import "UIxMailListActions.h"
|
||||
|
||||
// The maximum number of headers to prefetch when querying the UIDs list
|
||||
#define headersPrefetchMaxSize 100
|
||||
|
||||
@implementation UIxMailListActions
|
||||
|
||||
- (id) initWithRequest: (WORequest *) newRequest
|
||||
@@ -341,7 +344,7 @@
|
||||
- (NSString *) imap4SortOrdering
|
||||
{
|
||||
NSString *sort, *ascending;
|
||||
NSString *module; //*login
|
||||
NSString *module;
|
||||
NSMutableDictionary *moduleSettings;
|
||||
BOOL asc;
|
||||
SOGoUser *activeUser;
|
||||
@@ -352,14 +355,23 @@
|
||||
ascending = [[context request] formValueForKey: @"asc"];
|
||||
asc = [ascending boolValue];
|
||||
|
||||
if (![sort isEqualToString: [self defaultSortKey]])
|
||||
activeUser = [context activeUser];
|
||||
clientObject = [self clientObject];
|
||||
module = [[[clientObject container] container] nameInContainer];
|
||||
us = [activeUser userSettings];
|
||||
moduleSettings = [us objectForKey: module];
|
||||
|
||||
if ([sort isEqualToString: [self defaultSortKey]] && !asc)
|
||||
{
|
||||
if (moduleSettings)
|
||||
{
|
||||
[moduleSettings removeObjectForKey: @"SortingState"];
|
||||
[us synchronize];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save the sorting state in the user settings
|
||||
activeUser = [context activeUser];
|
||||
clientObject = [self clientObject];
|
||||
module = [[[clientObject container] container] nameInContainer];
|
||||
us = [activeUser userSettings];
|
||||
moduleSettings = [us objectForKey: module];
|
||||
if (!moduleSettings)
|
||||
{
|
||||
moduleSettings = [NSMutableDictionary dictionary];
|
||||
@@ -413,10 +425,9 @@
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
- (NSArray *) sortedUIDs
|
||||
- (NSArray *) getSortedUIDsInFolder: (SOGoMailFolder *) mailFolder
|
||||
{
|
||||
EOQualifier *qualifier, *fetchQualifier, *notDeleted;
|
||||
SOGoMailFolder *folder;
|
||||
|
||||
if (!sortedUIDs)
|
||||
{
|
||||
@@ -434,10 +445,9 @@
|
||||
else
|
||||
fetchQualifier = notDeleted;
|
||||
|
||||
folder = [self clientObject];
|
||||
sortedUIDs
|
||||
= [folder fetchUIDsMatchingQualifier: fetchQualifier
|
||||
sortOrdering: [self imap4SortOrdering]];
|
||||
= [mailFolder fetchUIDsMatchingQualifier: fetchQualifier
|
||||
sortOrdering: [self imap4SortOrdering]];
|
||||
[sortedUIDs retain];
|
||||
}
|
||||
|
||||
@@ -449,7 +459,7 @@
|
||||
NSArray *messageNbrs;
|
||||
int index;
|
||||
|
||||
messageNbrs = [self sortedUIDs];
|
||||
messageNbrs = [self getSortedUIDsInFolder: [self clientObject]];
|
||||
index
|
||||
= [messageNbrs indexOfObject: [NSNumber numberWithInt: messageNbr]];
|
||||
// if (index < 0)
|
||||
@@ -524,75 +534,55 @@
|
||||
return [self redirectToLocation:@"view"];
|
||||
}
|
||||
|
||||
- (NSDictionary *) getUIDsAndHeadersInFolder: (SOGoMailFolder *) mailFolder
|
||||
{
|
||||
NSArray *uids, *headers;
|
||||
NSDictionary *data;
|
||||
NSRange r;
|
||||
int count;
|
||||
|
||||
uids = [self getSortedUIDsInFolder: mailFolder]; // retrieves the form parameters "sort" and "asc"
|
||||
|
||||
// Also retrieve the first headers, up to 'headersPrefetchMaxSize'
|
||||
count = [uids count];
|
||||
if (count > headersPrefetchMaxSize) count = headersPrefetchMaxSize;
|
||||
r = NSMakeRange(0, count);
|
||||
headers = [self getHeadersForUIDs: [uids subarrayWithRange: r]
|
||||
inFolder: mailFolder];
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: uids, @"uids",
|
||||
headers, @"headers", nil];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) getSortedUIDsAction
|
||||
{
|
||||
NSArray *uids;
|
||||
NSRange r;
|
||||
WORequest *request;
|
||||
NSDictionary *data;
|
||||
SOGoMailFolder *folder;
|
||||
WOResponse *response;
|
||||
int firstUID, firstIndex, count;
|
||||
|
||||
request = [context request];
|
||||
uids = [self sortedUIDs]; // retrieves the form parameters "sort" and "asc"
|
||||
|
||||
if ([request formValueForKey: @"start"] != nil)
|
||||
{
|
||||
firstUID = [[request formValueForKey: @"start"] intValue];
|
||||
firstIndex = [self indexOfMessageUID: firstUID];
|
||||
if (firstIndex == NSNotFound)
|
||||
return [NSException exceptionWithHTTPStatus: 404
|
||||
reason: @"Message not found"];
|
||||
}
|
||||
else
|
||||
firstIndex = -1;
|
||||
|
||||
if ([request formValueForKey: @"count"] != nil)
|
||||
{
|
||||
count = [[request formValueForKey: @"count"] intValue];
|
||||
}
|
||||
else
|
||||
count = 0;
|
||||
|
||||
if (firstIndex > -1)
|
||||
{
|
||||
if (count <= 0 || (count + firstIndex) > [uids count])
|
||||
count = [uids count] - firstIndex;
|
||||
r = NSMakeRange(firstIndex, count);
|
||||
uids = [uids subarrayWithRange: r];
|
||||
}
|
||||
|
||||
response = [context response];
|
||||
folder = [self clientObject];
|
||||
data = [self getUIDsAndHeadersInFolder: folder];
|
||||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
[response appendContentString: [uids jsonRepresentation]];
|
||||
[response appendContentString: [data jsonRepresentation]];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) getHeadersAction
|
||||
- (NSArray *) getHeadersForUIDs: (NSArray *) uids
|
||||
inFolder: (SOGoMailFolder *) mailFolder
|
||||
{
|
||||
NSArray *uids, *to, *from;
|
||||
NSArray *to, *from;
|
||||
NSDictionary *msgs;
|
||||
NSMutableArray *headers;
|
||||
NSMutableDictionary *msg;
|
||||
NSMutableArray *headers, *msg;
|
||||
NSEnumerator *msgsList;
|
||||
NSString *msgIconStatus, *msgDate;
|
||||
SOGoMailFolder *mailFolder;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
UIxEnvelopeAddressFormatter *addressFormatter;
|
||||
|
||||
request = [context request];
|
||||
|
||||
if ([request formValueForKey: @"uids"] == nil)
|
||||
{
|
||||
return [NSException exceptionWithHTTPStatus: 404
|
||||
reason: @"No UID specified"];
|
||||
}
|
||||
|
||||
uids = [[request formValueForKey: @"uids"] componentsSeparatedByString: @","]; // Should we support ranges? ie "x-y"
|
||||
headers = [NSMutableArray arrayWithCapacity: [uids count]];
|
||||
mailFolder = [self clientObject];
|
||||
addressFormatter = [context mailEnvelopeAddressFormatter];
|
||||
|
||||
// Fetch headers
|
||||
@@ -601,78 +591,109 @@
|
||||
|
||||
msgsList = [[msgs objectForKey: @"fetch"] objectEnumerator];
|
||||
[self setMessage: [msgsList nextObject]];
|
||||
|
||||
msg = [NSMutableArray arrayWithObjects: @"To", @"Attachment", @"Flagged", @"Subject", @"From", @"Unread", @"Priority", @"Date", @"Size", @"rowClasses", @"labels", @"rowID", @"uid", nil];
|
||||
[headers addObject: msg];
|
||||
while (message)
|
||||
{
|
||||
msg = [NSMutableDictionary dictionaryWithCapacity: 11];
|
||||
msg = [NSMutableArray arrayWithCapacity: 12];
|
||||
|
||||
// Columns data
|
||||
|
||||
// To
|
||||
to = [[message objectForKey: @"envelope"] to];
|
||||
if ([to count] > 0)
|
||||
[msg setObject: [addressFormatter stringForArray: to]
|
||||
forKey: @"To"];
|
||||
|
||||
if ([self hasMessageAttachment])
|
||||
[msg setObject: [NSString stringWithFormat: @"<img src=\"%@\"/>", [self urlForResourceFilename: @"title_attachment_14x14.png"]]
|
||||
forKey: @"Attachment"];
|
||||
|
||||
if ([self isMessageFlagged])
|
||||
{
|
||||
[msg setObject: [NSString stringWithFormat: @"<img src=\"%@\" class=\"messageIsFlagged\">",
|
||||
[self urlForResourceFilename: @"flag.png"]]
|
||||
forKey: @"Flagged"];
|
||||
}
|
||||
[msg addObject: [addressFormatter stringForArray: to]];
|
||||
else
|
||||
{
|
||||
[msg setObject: [NSString stringWithFormat: @"<img src=\"%@\">",
|
||||
[self urlForResourceFilename: @"dot.png"]]
|
||||
forKey: @"Flagged"];
|
||||
}
|
||||
[msg addObject: @""];
|
||||
|
||||
[msg setObject: [NSString stringWithFormat: @"<span>%@</span>",
|
||||
[self messageSubject]]
|
||||
forKey: @"Subject"];
|
||||
// Attachment
|
||||
if ([self hasMessageAttachment])
|
||||
[msg addObject: [NSString stringWithFormat: @"<img src=\"%@\"/>", [self urlForResourceFilename: @"title_attachment_14x14.png"]]];
|
||||
else
|
||||
[msg addObject: @""];
|
||||
|
||||
// Flagged
|
||||
if ([self isMessageFlagged])
|
||||
[msg addObject: [NSString stringWithFormat: @"<img src=\"%@\" class=\"messageIsFlagged\">",
|
||||
[self urlForResourceFilename: @"flag.png"]]];
|
||||
else
|
||||
[msg addObject: [NSString stringWithFormat: @"<img src=\"%@\">",
|
||||
[self urlForResourceFilename: @"dot.png"]]];
|
||||
|
||||
// Subject
|
||||
[msg addObject: [NSString stringWithFormat: @"<span>%@</span>",
|
||||
[self messageSubject]]];
|
||||
|
||||
// From
|
||||
from = [[message objectForKey: @"envelope"] from];
|
||||
if ([from count] > 0)
|
||||
[msg setObject: [addressFormatter stringForArray: from] forKey: @"From"];
|
||||
[msg addObject: [addressFormatter stringForArray: from]];
|
||||
else
|
||||
[msg setObject: @"" forKey: @"From"];
|
||||
[msg addObject: @""];
|
||||
|
||||
|
||||
// Unread
|
||||
if ([self isMessageRead])
|
||||
msgIconStatus = @"dot.png";
|
||||
else
|
||||
msgIconStatus = @"icon_unread.gif";
|
||||
|
||||
[msg setObject: [self messageRowStyleClass] forKey: @"rowClasses"];
|
||||
[msg setObject: [NSString stringWithFormat: @"<img src=\"%@\" class=\"mailerReadIcon\" title=\"%@\" title-markread=\"%@\" title-markunread=\"%@\" id=\"%@\"/>",
|
||||
[msg addObject: [NSString stringWithFormat: @"<img src=\"%@\" class=\"mailerReadIcon\" title=\"%@\" title-markread=\"%@\" title-markunread=\"%@\" id=\"%@\"/>",
|
||||
[self urlForResourceFilename: msgIconStatus],
|
||||
[self labelForKey: @"Mark Unread"],
|
||||
[self labelForKey: @"Mark Read"],
|
||||
[self labelForKey: @"Mark Unread"],
|
||||
[self msgIconReadImgID]]
|
||||
forKey: @"Unread"];
|
||||
[self msgIconReadImgID]]];
|
||||
|
||||
[msg setObject: [self messagePriority] forKey: @"Priority"];
|
||||
// Priority
|
||||
[msg addObject: [self messagePriority]];
|
||||
|
||||
// Date
|
||||
msgDate = [self messageDate];
|
||||
if (msgDate == nil)
|
||||
msgDate = @"";
|
||||
[msg setObject: msgDate forKey: @"Date"];
|
||||
[msg addObject: msgDate];
|
||||
|
||||
[msg setObject: [self messageSize] forKey: @"Size"];
|
||||
// Size
|
||||
[msg addObject: [self messageSize]];
|
||||
|
||||
[msg setObject: [self msgLabels] forKey: @"labels"];
|
||||
// rowClasses
|
||||
[msg addObject: [self messageRowStyleClass]];
|
||||
|
||||
[msg setObject: [self msgRowID] forKey: @"rowID"];
|
||||
// labels
|
||||
[msg addObject: [self msgLabels]];
|
||||
|
||||
[msg setObject: [message objectForKey: @"uid"] forKey: @"uid"];
|
||||
// rowID
|
||||
[msg addObject: [self msgRowID]];
|
||||
|
||||
// uid
|
||||
[msg addObject: [message objectForKey: @"uid"]];
|
||||
|
||||
[headers addObject: msg];
|
||||
|
||||
[self setMessage: [msgsList nextObject]];
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) getHeadersAction
|
||||
{
|
||||
NSArray *uids, *headers;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
|
||||
request = [context request];
|
||||
if ([request formValueForKey: @"uids"] == nil)
|
||||
{
|
||||
return [NSException exceptionWithHTTPStatus: 404
|
||||
reason: @"No UID specified"];
|
||||
}
|
||||
|
||||
uids = [[request formValueForKey: @"uids"] componentsSeparatedByString: @","]; // Should we support ranges? ie "x-y"
|
||||
headers = [self getHeadersForUIDs: uids
|
||||
inFolder: [self clientObject]];
|
||||
response = [context response];
|
||||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
#import <NGCards/NGVCard.h>
|
||||
#import <NGCards/NGVCardReference.h>
|
||||
#import <NGCards/NGVList.h>
|
||||
@@ -42,6 +44,7 @@
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
#import <Mailer/SOGoMailFolder.h>
|
||||
#import <SOGo/NSDictionary+URL.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
@@ -54,6 +57,7 @@
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
|
||||
#import "UIxMailMainFrame.h"
|
||||
#import "UIxMailListActions.h"
|
||||
|
||||
// Avoid compilation warnings
|
||||
@interface SOGoUserFolder (private)
|
||||
@@ -173,6 +177,33 @@
|
||||
return [u hasSuffix:@"/"] ? @"view" : @"#";
|
||||
}
|
||||
|
||||
- (NSString *) inboxData
|
||||
{
|
||||
SOGoMailAccounts *accounts;
|
||||
SOGoMailAccount *account;
|
||||
SOGoMailFolder *inbox;
|
||||
|
||||
NSString *firstAccount;
|
||||
NSDictionary *data;
|
||||
SOGoUser *activeUser;
|
||||
UIxMailListActions *actions;
|
||||
|
||||
[self _setupContext];
|
||||
|
||||
actions = [[[UIxMailListActions new] initWithRequest: [context request]] autorelease];
|
||||
activeUser = [context activeUser];
|
||||
accounts = [self clientObject];
|
||||
|
||||
firstAccount = [[[accounts accountKeys] allKeys]
|
||||
objectAtIndex: 0];
|
||||
account = [accounts lookupName: firstAccount inContext: context acquire: NO];
|
||||
inbox = [account inboxFolderInContext: context];
|
||||
|
||||
data = [actions getUIDsAndHeadersInFolder: inbox];
|
||||
|
||||
return [data jsonRepresentation];
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) composeAction
|
||||
{
|
||||
id contact;
|
||||
@@ -333,7 +364,7 @@
|
||||
[self _setupContext];
|
||||
vertical = [moduleSettings objectForKey: @"DragHandleVertical"];
|
||||
|
||||
return ((vertical && [vertical intValue] > 0) ? (id)[vertical stringByAppendingFormat: @"px"] : nil);
|
||||
return ((vertical && [vertical intValue] > 0) ? (id)[vertical stringByAppendingString: @"px"] : nil);
|
||||
}
|
||||
|
||||
- (NSString *) horizontalDragHandleStyle
|
||||
@@ -343,7 +374,7 @@
|
||||
[self _setupContext];
|
||||
horizontal = [moduleSettings objectForKey: @"DragHandleHorizontal"];
|
||||
|
||||
return ((horizontal && [horizontal intValue] > 0) ? (id)[horizontal stringByAppendingFormat: @"px"] : nil);
|
||||
return ((horizontal && [horizontal intValue] > 0) ? (id)[horizontal stringByAppendingString: @"px"] : nil);
|
||||
}
|
||||
|
||||
- (NSString *) mailboxContentStyle
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
const:jsFiles="UIxMailToSelection.js,ckeditor/ckeditor.js,SOGoAutoCompletion.js">
|
||||
<script type="text/javascript">
|
||||
var mailIsReply = <var:string value="isMailReply"/>;
|
||||
var sourceUID = <var:string value="sourceUID"/>;
|
||||
var sourceFolder = '<var:string value="sourceFolder" const:escapeHTML="NO"/>';
|
||||
</script>
|
||||
<div class="popupMenu" id="contactsMenu">
|
||||
<ul><!-- space --></ul>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<script type="text/javascript">
|
||||
var textMailAccounts = '<var:string value="mailAccounts" const:escapeHTML="NO"/>';
|
||||
var textDefaultColumnsOrder = '<var:string value="defaultColumnsOrder" const:escapeHTML="NO"/>';
|
||||
var inboxData = <var:string value="inboxData" const:escapeHTML="NO"/>;
|
||||
</script>
|
||||
<style type="text/css">
|
||||
<var:if condition="horizontalDragHandleStyle">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: js2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/* JavaScript for SOGoMail */
|
||||
var accounts = {};
|
||||
@@ -21,7 +21,8 @@ var Mailer = {
|
||||
popups: new Array(),
|
||||
quotas: null,
|
||||
|
||||
dataTable: null
|
||||
dataTable: null,
|
||||
dataSources: new Hash()
|
||||
};
|
||||
|
||||
var usersRightsWindowHeight = 320;
|
||||
@@ -103,6 +104,8 @@ function onMenuSharing(event) {
|
||||
|
||||
/* mail list DOM changes */
|
||||
|
||||
/* Update the messages list when flagging/unflagging a message.
|
||||
* No AJAX is triggered here. */
|
||||
function flagMailInWindow (win, msguid, flagged) {
|
||||
var row = win.$("row_" + msguid);
|
||||
|
||||
@@ -120,6 +123,8 @@ function flagMailInWindow (win, msguid, flagged) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the messages list when setting the unread/read flag of a message.
|
||||
* No AJAX is triggered here. */
|
||||
function markMailInWindow(win, msguid, markread) {
|
||||
var row = win.$("row_" + msguid);
|
||||
var unseenCount = 0;
|
||||
@@ -130,8 +135,6 @@ function markMailInWindow(win, msguid, markread) {
|
||||
row.removeClassName("mailer_unreadmail");
|
||||
var img = win.$("readdiv_" + msguid);
|
||||
if (img) {
|
||||
img.removeClassName("mailerUnreadIcon");
|
||||
img.addClassName("mailerReadIcon");
|
||||
img.setAttribute("src", ResourcesURL + "/dot.png");
|
||||
var title = img.getAttribute("title-markunread");
|
||||
if (title)
|
||||
@@ -148,24 +151,25 @@ function markMailInWindow(win, msguid, markread) {
|
||||
row.addClassName("mailer_unreadmail");
|
||||
var img = win.$("readdiv_" + msguid);
|
||||
if (img) {
|
||||
img.removeClassName("mailerReadIcon");
|
||||
img.addClassName("mailerUnreadIcon");
|
||||
img.setAttribute("src", ResourcesURL + "/icon_unread.gif");
|
||||
var title = img.getAttribute("title-markread");
|
||||
if (title)
|
||||
img.setAttribute("title", title);
|
||||
}
|
||||
else {
|
||||
log ("No IMG found for " + msguid);
|
||||
}
|
||||
unseenCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unseenCount != 0) {
|
||||
// Update unseen count only if it's the inbox
|
||||
for (var i = 0; i < mailboxTree.aNodes.length; i++)
|
||||
if (mailboxTree.aNodes[i].datatype == "inbox") break;
|
||||
if (i != mailboxTree.aNodes.length && Mailer.currentMailbox == mailboxTree.aNodes[i].dataname)
|
||||
updateStatusFolders(unseenCount, true);
|
||||
if (unseenCount != 0) {
|
||||
// Update unseen count only if it's the inbox
|
||||
for (var i = 0; i < mailboxTree.aNodes.length; i++)
|
||||
if (mailboxTree.aNodes[i].datatype == "inbox") break;
|
||||
if (i != mailboxTree.aNodes.length && Mailer.currentMailbox == mailboxTree.aNodes[i].dataname)
|
||||
updateStatusFolders(unseenCount, true);
|
||||
}
|
||||
}
|
||||
|
||||
return (unseenCount != 0);
|
||||
@@ -205,11 +209,13 @@ function openMessageWindowsForSelection(action, firstOnly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Triggered when clicking on the read/unread dot of a message row */
|
||||
function mailListMarkMessage(event) {
|
||||
var msguid = this.id.split('_')[1];
|
||||
var row = $(this).up('TR');
|
||||
var action;
|
||||
var markread;
|
||||
if ($(this).hasClassName('mailerUnreadIcon')) {
|
||||
if (row.hasClassName("mailer_unreadmail")) {
|
||||
action = 'markMessageRead';
|
||||
markread = true;
|
||||
}
|
||||
@@ -217,10 +223,13 @@ function mailListMarkMessage(event) {
|
||||
action = 'markMessageUnread';
|
||||
markread = false;
|
||||
}
|
||||
|
||||
markMailInWindow(window, msguid, markread);
|
||||
|
||||
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/"
|
||||
+ msguid + "/" + action;
|
||||
|
||||
var data = { "window": window, "msguid": msguid, "markread": markread };
|
||||
var data = { "msguid": msguid };
|
||||
triggerAjaxRequest(url, mailListMarkMessageCallback, data);
|
||||
|
||||
preventDefault(event);
|
||||
@@ -228,15 +237,15 @@ function mailListMarkMessage(event) {
|
||||
}
|
||||
|
||||
function mailListMarkMessageCallback(http) {
|
||||
var data = http.callbackData;
|
||||
if (isHttpStatus204(http.status)
|
||||
|| http.status == 304) { // In some cases, Safari returns a 304 even
|
||||
// though SOGo returns a 204!
|
||||
var data = http.callbackData;
|
||||
markMailInWindow(data["window"], data["msguid"], data["markread"]);
|
||||
Mailer.dataTable.invalidate(data["msguid"], true);
|
||||
}
|
||||
else {
|
||||
alert("Message Mark Failed (" + http.status + "): " + http.statusText);
|
||||
window.location.reload();
|
||||
log("Message Mark Failed (" + http.status + "): " + http.statusText);
|
||||
Mailer.dataTable.invalidate(data["msguid"], false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +260,12 @@ function mailListFlagMessageToggle (e) {
|
||||
action = "markMessageUnflagged";
|
||||
flagged = false;
|
||||
}
|
||||
|
||||
|
||||
flagMailInWindow(window, msguid, flagged);
|
||||
|
||||
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/"
|
||||
+ msguid + "/" + action;
|
||||
var data = { "window": window, "msguid": msguid, "flagged": flagged };
|
||||
var data = { "msguid": msguid };
|
||||
|
||||
triggerAjaxRequest(url, mailListFlagMessageToggleCallback, data);
|
||||
}
|
||||
@@ -262,34 +273,14 @@ function mailListFlagMessageToggle (e) {
|
||||
function mailListFlagMessageToggleCallback (http) {
|
||||
if (isHttpStatus204(http.status)) {
|
||||
var data = http.callbackData;
|
||||
flagMailInWindow(data["window"], data["msguid"], data["flagged"]);
|
||||
Mailer.dataTable.invalidate(data["msguid"], true);
|
||||
}
|
||||
else {
|
||||
alert("Message Mark Failed (" + http.status + "): " + http.statusText);
|
||||
window.location.reload();
|
||||
log("Message Mark Failed (" + http.status + "): " + http.statusText);
|
||||
Mailer.dataTable.invalidate(data["msguid"], true);
|
||||
}
|
||||
}
|
||||
|
||||
/* maillist row highlight */
|
||||
|
||||
var oldMaillistHighlight = null; // to remember deleted/selected style
|
||||
|
||||
function ml_highlight(sender) {
|
||||
oldMaillistHighlight = sender.className;
|
||||
if (oldMaillistHighlight == "tableview_highlight")
|
||||
oldMaillistHighlight = null;
|
||||
sender.className = "tableview_highlight";
|
||||
}
|
||||
|
||||
function ml_lowlight(sender) {
|
||||
if (oldMaillistHighlight) {
|
||||
sender.className = oldMaillistHighlight;
|
||||
oldMaillistHighlight = null;
|
||||
}
|
||||
else
|
||||
sender.className = "tableview";
|
||||
}
|
||||
|
||||
function onUnload(event) {
|
||||
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/expunge";
|
||||
|
||||
@@ -659,22 +650,36 @@ function openMailbox(mailbox, reload, updateStatus) {
|
||||
|
||||
// TODO : refresh mailbox without removing all rows.
|
||||
var messageList = $("messageListBody").down('TBODY');
|
||||
var dataSource = new SOGoMailDataSource(Mailer.dataTable, url);
|
||||
Mailer.dataTable.setSource('SOGoMailDataSource', url, urlParams);
|
||||
var key = mailbox;
|
||||
if (urlParams.keys().length > 0) {
|
||||
var p = urlParams.keys().collect(function(key) { return key + "=" + urlParams.get(key); }).join("&");
|
||||
key += "?" + p;
|
||||
}
|
||||
|
||||
var dataSource = Mailer.dataSources.get(key);
|
||||
if (!dataSource || reload) {
|
||||
dataSource = new SOGoMailDataSource(Mailer.dataTable, url);
|
||||
if (inboxData[key]) {
|
||||
dataSource.init(inboxData[key][0], inboxData[key][1]);
|
||||
inboxData = []; // invalidate this initial lookup
|
||||
}
|
||||
else
|
||||
dataSource.load(urlParams);
|
||||
Mailer.dataSources.set(key, dataSource);
|
||||
}
|
||||
Mailer.dataTable.setSource(dataSource);
|
||||
messageList.deselectAll();
|
||||
Mailer.dataTable.render();
|
||||
configureDraggables();
|
||||
Mailer.currentMailbox = mailbox;
|
||||
|
||||
/*
|
||||
// TODO : restore previously selected message.
|
||||
// Restore previous selection
|
||||
var currentMessage = Mailer.currentMessages[mailbox];
|
||||
if (currentMessage) {
|
||||
Mailer.dataTable.render(currentMessage);
|
||||
if (!reload)
|
||||
if (!reload) {
|
||||
loadMessage(currentMessage);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (updateStatus != false)
|
||||
getStatusFolders();
|
||||
@@ -685,16 +690,22 @@ function openMailbox(mailbox, reload, updateStatus) {
|
||||
* Called from SOGoDataTable.render()
|
||||
*/
|
||||
function messageListCallback(row, data, isNew) {
|
||||
var currentMessage = Mailer.currentMessages[Mailer.currentMailbox];
|
||||
|
||||
row.id = data['rowID'];
|
||||
row.writeAttribute('labels', (data['labels']?data['labels']:""));
|
||||
row.className = data['rowClasses'];
|
||||
|
||||
// Restore previous selection
|
||||
if (data['uid'] == currentMessage)
|
||||
row.addClassName('_selected');
|
||||
|
||||
if (isNew) {
|
||||
row.observe("mousedown", onRowClick);
|
||||
row.observe("selectstart", listRowMouseDownHandler);
|
||||
row.observe("contextmenu", onMessageContextMenu);
|
||||
}
|
||||
|
||||
row.className = data['rowClasses'];
|
||||
row.id = data['rowID'];
|
||||
row.writeAttribute('labels', (data['labels']?data['labels']:""));
|
||||
|
||||
var columnsOrder = UserDefaults["SOGoMailListViewColumnsOrder"];
|
||||
var cells;
|
||||
if (Prototype.Browser.IE)
|
||||
@@ -781,8 +792,16 @@ function updateMessageListCounter(count, isDelta) {
|
||||
cell.update(_("No message"));
|
||||
}
|
||||
|
||||
/* Function is called when the event datatable:rendered is fired from SOGoDataTable. */
|
||||
function onMessageListRender(event) {
|
||||
// Event is fired from SOGoDataTable.
|
||||
// Restore previous selection
|
||||
var currentMessage = Mailer.currentMessages[Mailer.currentMailbox];
|
||||
if (currentMessage) {
|
||||
var rows = this.select("TR#row_" + currentMessage);
|
||||
if (rows.length == 1)
|
||||
rows[0].selectElement();
|
||||
}
|
||||
// Update message counter in folder name
|
||||
updateMessageListCounter(event.memo, false);
|
||||
}
|
||||
|
||||
@@ -926,22 +945,25 @@ function onMessageSelectionChange() {
|
||||
$('messageContent').update();
|
||||
}
|
||||
|
||||
function loadMessage(idx) {
|
||||
function loadMessage(msguid) {
|
||||
if (document.messageAjaxRequest) {
|
||||
document.messageAjaxRequest.aborted = true;
|
||||
document.messageAjaxRequest.abort();
|
||||
}
|
||||
|
||||
var div = $('messageContent');
|
||||
var cachedMessage = getCachedMessage(idx);
|
||||
var row = $("row_" + idx);
|
||||
var seenStateChanged = row && row.hasClassName('mailer_unreadmail');
|
||||
var cachedMessage = getCachedMessage(msguid);
|
||||
var row = $("row_" + msguid);
|
||||
var seenStateHasChanged = row && row.hasClassName('mailer_unreadmail');
|
||||
if (cachedMessage == null) {
|
||||
var url = (ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/"
|
||||
+ idx + "/view?noframe=1");
|
||||
+ msguid + "/view?noframe=1");
|
||||
div.update();
|
||||
document.messageAjaxRequest = triggerAjaxRequest(url, messageCallback, idx);
|
||||
markMailInWindow(window, idx, true);
|
||||
document.messageAjaxRequest = triggerAjaxRequest(url,
|
||||
loadMessageCallback,
|
||||
{ 'msguid': msguid, 'seenStateHasChanged': seenStateHasChanged });
|
||||
// Warning: We assume the user can set the read/unread flag of the message.
|
||||
markMailInWindow(window, msguid, true);
|
||||
}
|
||||
else {
|
||||
div.update(cachedMessage['text']);
|
||||
@@ -949,9 +971,9 @@ function loadMessage(idx) {
|
||||
document.messageAjaxRequest = null;
|
||||
configureLinksInMessage();
|
||||
resizeMailContent();
|
||||
if (seenStateChanged) {
|
||||
if (seenStateHasChanged) {
|
||||
// Mark message as read on server
|
||||
var img = row.select("IMG.mailerUnreadIcon").first();
|
||||
var img = row.select("IMG.mailerReadIcon").first();
|
||||
var fcnMarkRead = mailListMarkMessage.bind(img);
|
||||
fcnMarkRead();
|
||||
}
|
||||
@@ -1313,7 +1335,7 @@ function onAttachmentClick (event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function messageCallback(http) {
|
||||
function loadMessageCallback(http) {
|
||||
var div = $('messageContent');
|
||||
|
||||
if (http.status == 200) {
|
||||
@@ -1326,7 +1348,11 @@ function messageCallback(http) {
|
||||
|
||||
if (http.callbackData) {
|
||||
var cachedMessage = new Array();
|
||||
cachedMessage['idx'] = Mailer.currentMailbox + '/' + http.callbackData;
|
||||
var msguid = http.callbackData.msguid;
|
||||
// Warning: If the user can't set the read/unread flag, it won't
|
||||
// be reflected in the view unless we force the refresh.
|
||||
Mailer.dataTable.invalidate(msguid, true);
|
||||
cachedMessage['idx'] = Mailer.currentMailbox + '/' + msguid;
|
||||
cachedMessage['time'] = (new Date()).getTime();
|
||||
cachedMessage['text'] = http.responseText;
|
||||
if (cachedMessage['text'].length < 30000)
|
||||
@@ -1335,7 +1361,7 @@ function messageCallback(http) {
|
||||
}
|
||||
else if (http.status == 404) {
|
||||
alert (_("The message you have selected doesn't exist anymore."));
|
||||
window.location.reload();
|
||||
Mailer.dataTable.remove(http.callbackData.msguid);
|
||||
}
|
||||
else
|
||||
log("messageCallback: problem during ajax request: " + http.status);
|
||||
@@ -1518,6 +1544,13 @@ function refreshCurrentFolder() {
|
||||
openMailbox(Mailer.currentMailbox, true);
|
||||
}
|
||||
|
||||
/* Called after sending an email */
|
||||
function refreshMessage(mailbox, messageUID) {
|
||||
if (mailbox == Mailer.currentMailbox) {
|
||||
Mailer.dataTable.invalidate(messageUID);
|
||||
}
|
||||
}
|
||||
|
||||
function configureMessageListEvents(headerTable, dataTable) {
|
||||
if (headerTable)
|
||||
// Sortable columns
|
||||
@@ -1629,6 +1662,7 @@ function initMailer(event) {
|
||||
|
||||
if (!$(document.body).hasClassName("popup")) {
|
||||
//initDnd();
|
||||
|
||||
Mailer.dataTable = $("mailboxList");
|
||||
Mailer.dataTable.addInterface(SOGoDataTableInterface);
|
||||
Mailer.dataTable.setRowRenderCallback(messageListCallback);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: js2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/*
|
||||
* Data table interface to be added to a DIV (this!)
|
||||
@@ -58,7 +58,13 @@ var SOGoDataTableInterface = {
|
||||
this.rowRenderCallback = callbackFunction;
|
||||
},
|
||||
|
||||
setSource: function(dataSourceClass, url, params) {
|
||||
setSource: function(ds) {
|
||||
this.dataSource = ds;
|
||||
this._emptyTable();
|
||||
this.scrollTop = 0;
|
||||
},
|
||||
|
||||
initSource: function(dataSourceClass, url, params) {
|
||||
// log ("DataTable.setSource() " + url);
|
||||
if (this.dataSource) this.dataSource.destroy();
|
||||
this._emptyTable();
|
||||
@@ -87,7 +93,7 @@ var SOGoDataTableInterface = {
|
||||
return firstRowIndex;
|
||||
},
|
||||
|
||||
render: function(uid) {
|
||||
render: function() {
|
||||
var index = this.firstVisibleRowIndex();
|
||||
var count = this.visibleRowCount();
|
||||
|
||||
@@ -95,10 +101,10 @@ var SOGoDataTableInterface = {
|
||||
var start = index - (this.overflow/2);
|
||||
if (start < 0) start = 0;
|
||||
var end = index + count + this.overflow - (index - start);
|
||||
// log ("DataTable.getData() from " + index + " to " + (index + count) + " boosted from " + start + " to " + end);
|
||||
// log ("DataTable.getData() from " + index + " to " + (index + count) + " boosted from " + start + " to " + end);
|
||||
|
||||
// Don't overflow above the maximum number of entries from the data source
|
||||
if (this.dataSource.uids && this.dataSource.uids.length < end) end = this.dataSource.uids.length;
|
||||
//if (this.dataSource.uids && this.dataSource.uids.length < end) end = this.dataSource.uids.length;
|
||||
|
||||
index = start;
|
||||
count = end - start;
|
||||
@@ -216,6 +222,7 @@ var SOGoDataTableInterface = {
|
||||
}
|
||||
}
|
||||
|
||||
// Update references to selected rows
|
||||
this.body.refreshSelectionByIds();
|
||||
log ("DataTable._render() top gap/bottom gap/total rows = " + this.rowTop.getStyle('height') + "/" + this.rowBottom.getStyle('height') + "/" + this.body.select("tr").length + " (height = " + this.down("table").getHeight() + "px)");
|
||||
|
||||
@@ -229,12 +236,32 @@ var SOGoDataTableInterface = {
|
||||
Event.fire(this, "datatable:rendered", max);
|
||||
},
|
||||
|
||||
invalidate: function(uid, withoutRefresh) {
|
||||
// Refetch the data for uid. Only refresh the data table if
|
||||
// necessary.
|
||||
var index = this.dataSource.invalidate(uid);
|
||||
this.currentRenderID = index + "-" + 1;
|
||||
this.dataSource.getData(this.currentRenderID,
|
||||
index,
|
||||
1,
|
||||
(withoutRefresh?false:this._invalidate.bind(this)),
|
||||
0);
|
||||
},
|
||||
|
||||
_invalidate: function(renderID, start, max, data) {
|
||||
if (renderID == this.currentRenderID) {
|
||||
var rows = this.body.select("TR#" + data[0]['rowID']);
|
||||
if (rows.length > 0)
|
||||
this.rowRenderCallback(rows[0], data[0], false);
|
||||
}
|
||||
},
|
||||
|
||||
remove: function(uid) {
|
||||
var rows = this.body.select("TR#row_" + uid);
|
||||
if (rows.length == 1) {
|
||||
var row = rows.first();
|
||||
row.parentNode.removeChild(row);
|
||||
var index = this.dataSource.invalidate(uid);
|
||||
var index = this.dataSource.remove(uid);
|
||||
// log ("DataTable.remove(" + uid + ")");
|
||||
if (this.renderedIndex < index &&
|
||||
(this.renderedIndex + this.renderedCount) > index) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: js2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
SOGoMailDataSource = Class.create({
|
||||
|
||||
@@ -15,7 +15,7 @@ SOGoMailDataSource = Class.create({
|
||||
this.ajaxGetData = false;
|
||||
|
||||
// Constants
|
||||
this.overflow = 60;
|
||||
this.overflow = 50; // must be higher or equal to the overflow of the data table class
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@@ -28,7 +28,13 @@ SOGoMailDataSource = Class.create({
|
||||
invalidate: function(uid) {
|
||||
this.cache.unset(uid);
|
||||
var index = this.uids.indexOf(parseInt(uid));
|
||||
log ("MailDataSource.invalidate(" + uid + ") at index " + index);
|
||||
// log ("MailDataSource.invalidate(" + uid + ") at index " + index);
|
||||
|
||||
return index;
|
||||
},
|
||||
|
||||
remove: function(uid) {
|
||||
var index = this.invalidate(uid);
|
||||
if (index >= 0) {
|
||||
this.uids.splice(index, 1);
|
||||
}
|
||||
@@ -36,6 +42,21 @@ SOGoMailDataSource = Class.create({
|
||||
return index;
|
||||
},
|
||||
|
||||
init: function(uids, headers) {
|
||||
this.uids = uids;
|
||||
|
||||
var keys = headers[0];
|
||||
for (var i = 1; i < headers.length; i++) {
|
||||
var header = [];
|
||||
for (var j = 0; j < keys.length; j++)
|
||||
header[keys[j]] = headers[i][j];
|
||||
this.cache.set(header["uid"], header);
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
// log ("MailDataSource.init() " + this.uids.length + " UIDs, " + this.cache.keys().length + " headers");
|
||||
},
|
||||
|
||||
load: function(urlParams) {
|
||||
var params;
|
||||
this.loaded = false;
|
||||
@@ -45,7 +66,7 @@ SOGoMailDataSource = Class.create({
|
||||
else
|
||||
params = "";
|
||||
|
||||
log ("MailDataSource.load() " + params);
|
||||
// log ("MailDataSource.load() " + params);
|
||||
triggerAjaxRequest(this.url + "/uids",
|
||||
this._loadCallback.bind(this),
|
||||
null,
|
||||
@@ -56,9 +77,13 @@ SOGoMailDataSource = Class.create({
|
||||
_loadCallback: function(http) {
|
||||
if (http.status == 200) {
|
||||
if (http.responseText.length > 0) {
|
||||
this.uids = $A(http.responseText.evalJSON(true));
|
||||
log ("MailDataSource._loadCallback() " + this.uids.length + " uids");
|
||||
var data = http.responseText.evalJSON(true);
|
||||
this.init(data.uids, data.headers);
|
||||
this.loaded = true;
|
||||
if (this.delayedGetData) {
|
||||
this.delayedGetData();
|
||||
this.delayedGetData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -68,10 +93,9 @@ SOGoMailDataSource = Class.create({
|
||||
|
||||
getData: function(id, index, count, callbackFunction, delay) {
|
||||
if (this.loaded == false) {
|
||||
// UIDs are not yet loaded -- delay the call to the current function
|
||||
// UIDs are not yet loaded -- delay the call until loading the data is completed.
|
||||
// log ("MailDataSource.getData() delaying data fetching while waiting for UIDs");
|
||||
if (this.delayedGetData) window.clearTimeout(this.delayedGetData);
|
||||
this.delayedGetData = this.getData.bind(this, id, index, count, callbackFunction, delay).delay(0.3);
|
||||
this.delayedGetData = this.getData.bind(this, id, index, count, callbackFunction, delay);
|
||||
return;
|
||||
}
|
||||
if (this.delayed_getData) window.clearTimeout(this.delayed_getData);
|
||||
@@ -88,16 +112,24 @@ SOGoMailDataSource = Class.create({
|
||||
var i, j;
|
||||
var missingUids = new Array();
|
||||
|
||||
// Compute last index depending on number of UIDs
|
||||
start = index - (this.overflow/2);
|
||||
if (start < 0) start = 0;
|
||||
end = index + count + this.overflow - (index - start);
|
||||
if (end > this.uids.length) {
|
||||
start -= end - this.uids.length;
|
||||
end = this.uids.length;
|
||||
if (count > 1) {
|
||||
// Compute last index depending on number of UIDs
|
||||
start = index - (this.overflow/2);
|
||||
if (start < 0) start = 0;
|
||||
end = index + count + this.overflow - (index - start);
|
||||
if (end > this.uids.length) {
|
||||
start -= end - this.uids.length;
|
||||
end = this.uids.length;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
}
|
||||
log ("MailDataSource._getData() from " + index + " to " + (index + count) + " boosted from " + start + " to " + end);
|
||||
else {
|
||||
// Count is 1; don't fetch more data since the caller is
|
||||
// SOGoDataTable.invalide() and asks for only one data row.
|
||||
start = index;
|
||||
end = index + count;
|
||||
}
|
||||
// log ("MailDataSource._getData() from " + index + " to " + (index + count) + " boosted from " + start + " to " + end);
|
||||
|
||||
for (i = 0, j = start; j < end; j++) {
|
||||
if (!this.cache.get(this.uids[j])) {
|
||||
@@ -115,7 +147,7 @@ SOGoMailDataSource = Class.create({
|
||||
id: id },
|
||||
params).delay(0.5);
|
||||
}
|
||||
else
|
||||
else if (callbackFunction)
|
||||
this._returnData(callbackFunction, id, start, end);
|
||||
},
|
||||
|
||||
@@ -125,7 +157,7 @@ SOGoMailDataSource = Class.create({
|
||||
this.ajaxGetData.abort();
|
||||
// log ("MailDataSource._getData() aborted previous AJAX request");
|
||||
}
|
||||
// log ("MailDataSource._getData() fetching headers of " + urlParams);
|
||||
// log ("MailDataSource._getData() fetching headers of " + urlParams);
|
||||
this.ajaxGetData = triggerAjaxRequest(this.url + "/headers",
|
||||
this._getRemoteDataCallback.bind(this),
|
||||
callbackData,
|
||||
@@ -139,16 +171,20 @@ SOGoMailDataSource = Class.create({
|
||||
// We receives an array of hashes
|
||||
var headers = $A(http.responseText.evalJSON(true));
|
||||
var data = http.callbackData;
|
||||
|
||||
for (var i = 0; i < headers.length; i++) {
|
||||
this.cache.set(headers[i]["uid"], headers[i]);
|
||||
var keys = headers[0];
|
||||
for (var i = 1; i < headers.length; i++) {
|
||||
var header = [];
|
||||
for (var j = 0; j < keys.length; j++)
|
||||
header[keys[j]] = headers[i][j];
|
||||
this.cache.set(header["uid"], header);
|
||||
}
|
||||
|
||||
this._returnData(data["callbackFunction"], data["id"], data["start"], data["end"]);
|
||||
if (data["callbackFunction"])
|
||||
this._returnData(data["callbackFunction"], data["id"], data["start"], data["end"]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("SOGoMailDataSource._getRemoteDataCallback Error " + http.status + ": " + http.responseText);
|
||||
log("SOGoMailDataSource._getRemoteDataCallback Error " + http.status + ": " + http.responseText);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user