See ChangeLog
Monotone-Parent: ede90c4ec21ca642e49b4287679877bd02717ed6 Monotone-Revision: ae2c5342363a3fa87101fa6840e1c1e1f7a819c0 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2011-06-01T21:10:25 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
624172fe92
commit
53a01edee4
36
ChangeLog
36
ChangeLog
|
@ -1,9 +1,45 @@
|
|||
2011-06-01 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoUserDefaults.m (-setMailSortByThreads)
|
||||
(-mailSortByThreads): new accessors for the "SOGoMailSortByThreads"
|
||||
user defaults.
|
||||
|
||||
* UI/PreferencesUI/UIxPreferences.m (-setSortByThreads)
|
||||
(sortByThreads): idem.
|
||||
|
||||
* SoObjects/Mailer/SOGoMailFolder.m
|
||||
(-fetchUIDsMatchingQualifier:sortOrdering:threaded:): new method
|
||||
to fetch a threaded-view of the folder.
|
||||
|
||||
* SoObjects/SOGo/NSArray+Utilities.m (-flattenedArray): added
|
||||
recurrence to flatten interleaved arrays.
|
||||
|
||||
* SoObjects/Mailer/SOGoMailAccount.m (-updateFilters): write
|
||||
multiple 'redirect' directives when forwarding to multiple email
|
||||
addresses.
|
||||
|
||||
* UI/MailerUI/UIxMailListActions.m (-threadedUIDs): new method
|
||||
that returns a flatten representation of messages threads.
|
||||
|
||||
* UI/MailerUI/UIxMailMainFrame.m (-columnsMetaData): added CSS
|
||||
classnames for the thread column.
|
||||
(-columnsDisplayOrder): add or remove the thread column depending
|
||||
on the user's defaults.
|
||||
|
||||
* UI/MailerUI/UIxMailListActions.m (-getUIDsAndHeadersInFolder)
|
||||
(-getSortedUIDsAction): added support for threads.
|
||||
|
||||
* UI/WebServerResources/ContactsUI.js (onContactContextMenu):
|
||||
select row at pointer position when not already selected.
|
||||
|
||||
* UI/WebServerResources/MailerUI.js: added support for the
|
||||
threaded view.
|
||||
(onMessageContextMenu): select row at pointer position when not
|
||||
already selected.
|
||||
|
||||
* UI/WebServerResources/SOGoMailDataSource.js: added support for
|
||||
the threaded view.
|
||||
|
||||
2011-05-31 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/WebServerResources/SchedulerUI.js (initCalendarSelector): use
|
||||
|
|
10
NEWS
10
NEWS
|
@ -1,3 +1,13 @@
|
|||
1.3-2011MMDD (1.3.8)
|
||||
---------------------
|
||||
New Features
|
||||
- initial support for threaded-view in the webmail interface
|
||||
|
||||
Enhancements
|
||||
- improved list selection and contextual menu behavior in all web modules
|
||||
|
||||
Bug Fixes
|
||||
|
||||
1.3-20110503 (1.3.7)
|
||||
---------------------
|
||||
New Features
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2009-2010 Inverse inc.
|
||||
Copyright (C) 2009-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
@ -60,7 +60,8 @@
|
|||
inContext: (id) context;
|
||||
- (WOResponse *) archiveAllMessagesInContext: (id) localContext;
|
||||
|
||||
- (NSArray *) fetchUIDsMatchingQualifier: (id)_q sortOrdering: (id) _so;
|
||||
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so;
|
||||
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so threaded: (BOOL) _threaded;
|
||||
- (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts;
|
||||
|
||||
- (WOResponse *) copyUIDs: (NSArray *) uids
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2009-2010 Inverse inc.
|
||||
Copyright (C) 2009-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
@ -315,8 +315,8 @@ static NSString *defaultUserID = @"anyone";
|
|||
}
|
||||
}
|
||||
else
|
||||
error = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"Did not find Trash folder!"];
|
||||
error = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"Did not find Trash folder!"];
|
||||
}
|
||||
|
||||
if (b)
|
||||
|
@ -544,9 +544,27 @@ static NSString *defaultUserID = @"anyone";
|
|||
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q
|
||||
sortOrdering: (id) _so
|
||||
{
|
||||
/* seems to return an NSArray of NSNumber's */
|
||||
return [[self imap4Connection] fetchUIDsInURL: [self imap4URL]
|
||||
qualifier: _q sortOrdering: _so];
|
||||
return [self fetchUIDsMatchingQualifier: _q
|
||||
sortOrdering: _so
|
||||
threaded: NO];
|
||||
}
|
||||
|
||||
- (NSArray *) fetchUIDsMatchingQualifier: (id) _q
|
||||
sortOrdering: (id) _so
|
||||
threaded: (BOOL) _threaded
|
||||
{
|
||||
if (_threaded)
|
||||
{
|
||||
return [[self imap4Connection] fetchThreadedUIDsInURL: [self imap4URL]
|
||||
qualifier: _q
|
||||
sortOrdering: _so];
|
||||
}
|
||||
else
|
||||
{
|
||||
return [[self imap4Connection] fetchUIDsInURL: [self imap4URL]
|
||||
qualifier: _q
|
||||
sortOrdering: _so];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *) fetchUIDs: (NSArray *) _uids
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* NSArray+Utilities.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2009 Inverse inc.
|
||||
* Copyright (C) 2006-2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -129,7 +129,10 @@
|
|||
flattenedArray = [NSMutableArray array];
|
||||
objects = [self objectEnumerator];
|
||||
while ((currentObject = [objects nextObject]))
|
||||
[flattenedArray addObjectsFromArray: currentObject];
|
||||
if ([currentObject isKindOfClass: [NSArray class]])
|
||||
[flattenedArray addObjectsFromArray: [(NSArray *)currentObject flattenedArray]];
|
||||
else
|
||||
[flattenedArray addObject: currentObject];
|
||||
|
||||
return flattenedArray;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
SOGoMailSignaturePlacement = "below";
|
||||
SOGoMailPollingIntervals = ( 1, 2, 5, 10, 20, 30, 60 );
|
||||
SOGoMailComposeMessageType = "text";
|
||||
SOGoMailListViewColumnsOrder = ( "Flagged", "Attachment", "Subject",
|
||||
SOGoMailListViewColumnsOrder = ( "Thread", "Flagged", "Attachment", "Subject",
|
||||
"From", "Unread", "Date", "Priority",
|
||||
"Size" );
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SOGoUserDefaults.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
* Copyright (C) 2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -85,6 +85,9 @@ extern NSString *SOGoWeekStartFirstFullWeek;
|
|||
- (void) setMailShowSubscribedFoldersOnly: (BOOL) newValue;
|
||||
- (BOOL) mailShowSubscribedFoldersOnly;
|
||||
|
||||
- (void) setMailSortByThreads: (BOOL) newValue;
|
||||
- (BOOL) mailSortByThreads;
|
||||
|
||||
- (void) setDraftsFolderName: (NSString *) newValue;
|
||||
- (NSString *) draftsFolderName;
|
||||
|
||||
|
|
|
@ -372,6 +372,16 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
|||
return [self boolForKey: @"SOGoMailShowSubscribedFoldersOnly"];
|
||||
}
|
||||
|
||||
- (void) setMailSortByThreads: (BOOL) newValue
|
||||
{
|
||||
[self setBool: newValue forKey: @"SOGoMailSortByThreads"];
|
||||
}
|
||||
|
||||
- (BOOL) mailSortByThreads
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailSortByThreads"];
|
||||
}
|
||||
|
||||
- (void) setDraftsFolderName: (NSString *) newValue
|
||||
{
|
||||
[self setObject: newValue forKey: @"SOGoDraftsFolderName"];
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
id message;
|
||||
SOGoDateFormatter *dateFormatter;
|
||||
NSTimeZone *userTimeZone;
|
||||
BOOL sortByThread;
|
||||
int folderType;
|
||||
int specificMessageNumber;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
user = [[self context] activeUser];
|
||||
ASSIGN (dateFormatter, [user dateFormatterInContext: context]);
|
||||
ASSIGN (userTimeZone, [[user userDefaults] timeZone]);
|
||||
sortByThread = [[user userDefaults] mailSortByThreads];
|
||||
folderType = 0;
|
||||
specificMessageNumber = 0;
|
||||
}
|
||||
|
@ -458,13 +459,115 @@
|
|||
|
||||
sortedUIDs
|
||||
= [mailFolder fetchUIDsMatchingQualifier: fetchQualifier
|
||||
sortOrdering: [self imap4SortOrdering]];
|
||||
sortOrdering: [self imap4SortOrdering]
|
||||
threaded: sortByThread];
|
||||
|
||||
[sortedUIDs retain];
|
||||
}
|
||||
|
||||
return sortedUIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flatten representation of the messages threads as triples of
|
||||
* metadata, including the message UID, thread level and root position.
|
||||
* @param _sortedUIDs the interleaved arrays representation of the messages UIDs
|
||||
* @return an flatten array representation of the messages UIDs
|
||||
*/
|
||||
- (NSArray *) threadedUIDs: (NSArray *) _sortedUIDs
|
||||
{
|
||||
NSMutableArray *threads;
|
||||
NSMutableArray *currentThreads;
|
||||
NSEnumerator *rootThreads;
|
||||
id thread;
|
||||
int count;
|
||||
int i;
|
||||
BOOL first;
|
||||
BOOL expected;
|
||||
int previousLevel;
|
||||
|
||||
count = 0;
|
||||
i = 0;
|
||||
previousLevel = 0;
|
||||
expected = YES;
|
||||
threads = [NSMutableArray arrayWithObject: [NSArray arrayWithObjects: @"uid", @"level", @"first", nil]];
|
||||
rootThreads = [_sortedUIDs objectEnumerator];
|
||||
thread = [rootThreads nextObject];
|
||||
|
||||
// Make sure rootThreads starts with an NSArray
|
||||
if (![thread respondsToSelector: @selector(objectEnumerator)])
|
||||
return nil;
|
||||
|
||||
first = [thread count] > 1;
|
||||
thread = [thread objectEnumerator];
|
||||
|
||||
currentThreads = [NSMutableArray array];
|
||||
|
||||
while (thread)
|
||||
{
|
||||
unsigned int ecount = 0;
|
||||
id t;
|
||||
|
||||
if ([thread isKindOfClass: [NSEnumerator class]])
|
||||
{
|
||||
t = [thread nextObject];
|
||||
}
|
||||
else
|
||||
t = thread; // never happen?
|
||||
while (t && ![t isKindOfClass: [NSArray class]])
|
||||
{
|
||||
BOOL currentFirst;
|
||||
int currentLevel;
|
||||
NSArray *currentThread;
|
||||
|
||||
currentFirst = (first && ecount == 0) || (i == 0 && count > 0) || (count > 0 && previousLevel < 0);
|
||||
currentLevel = (first && ecount == 0)? 0 : (count > 0? count : -1);
|
||||
currentThread = [NSArray arrayWithObjects: t,
|
||||
[NSNumber numberWithInt: currentLevel],
|
||||
[NSNumber numberWithInt: currentFirst], nil];
|
||||
[threads addObject: currentThread];
|
||||
i++;
|
||||
count++;
|
||||
ecount++;
|
||||
expected = NO;
|
||||
previousLevel = currentLevel;
|
||||
t = [thread nextObject];
|
||||
}
|
||||
if (t)
|
||||
{
|
||||
// If t is defined, it has to be an NSArray
|
||||
if (expected)
|
||||
{
|
||||
count++;
|
||||
expected = NO;
|
||||
}
|
||||
thread = [thread allObjects];
|
||||
if ([thread count] > 0)
|
||||
[currentThreads addObject: [thread objectEnumerator]];
|
||||
thread = [t objectEnumerator];
|
||||
}
|
||||
else if ([currentThreads count] > 0)
|
||||
{
|
||||
thread = [currentThreads objectAtIndex: 0];
|
||||
[currentThreads removeObjectAtIndex: 0];
|
||||
count -= ecount;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread = [[rootThreads nextObject] objectEnumerator]; // assume all objects of rootThreads are NSArrays
|
||||
count = 0;
|
||||
expected = YES;
|
||||
}
|
||||
|
||||
// Prepare next iteration
|
||||
thread = [thread allObjects];
|
||||
first = !first && (thread != nil) && [thread count] > 1;
|
||||
thread = [thread objectEnumerator];
|
||||
}
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
- (int) indexOfMessageUID: (int) messageNbr
|
||||
{
|
||||
NSArray *messageNbrs;
|
||||
|
@ -521,11 +624,9 @@
|
|||
}
|
||||
*/
|
||||
|
||||
/* actions */
|
||||
|
||||
- (NSDictionary *) getUIDsAndHeadersInFolder: (SOGoMailFolder *) mailFolder
|
||||
{
|
||||
NSArray *uids, *headers;
|
||||
NSArray *uids, *threadedUids, *headers;
|
||||
NSDictionary *data;
|
||||
NSRange r;
|
||||
int count;
|
||||
|
@ -536,18 +637,31 @@
|
|||
count = [uids count];
|
||||
if (count > headersPrefetchMaxSize) count = headersPrefetchMaxSize;
|
||||
r = NSMakeRange(0, count);
|
||||
headers = [self getHeadersForUIDs: [uids subarrayWithRange: r]
|
||||
headers = [self getHeadersForUIDs: [[uids flattenedArray] subarrayWithRange: r]
|
||||
inFolder: mailFolder];
|
||||
|
||||
if (sortByThread)
|
||||
{
|
||||
threadedUids = [self threadedUIDs: uids];
|
||||
if (threadedUids != nil)
|
||||
uids = threadedUids;
|
||||
else
|
||||
sortByThread = NO;
|
||||
}
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: uids, @"uids",
|
||||
headers, @"headers", nil];
|
||||
headers, @"headers",
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded", nil];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Module actions */
|
||||
|
||||
- (id <WOActionResults>) getSortedUIDsAction
|
||||
{
|
||||
id data;
|
||||
NSDictionary *data;
|
||||
NSArray *uids, *threadedUids;
|
||||
NSString *noHeaders;
|
||||
SOGoMailFolder *folder;
|
||||
WORequest *request;
|
||||
|
@ -563,10 +677,22 @@
|
|||
[folder expungeLastMarkedFolder];
|
||||
noHeaders = [request formValueForKey: @"no_headers"];
|
||||
if ([noHeaders length])
|
||||
data = [self getSortedUIDsInFolder: folder];
|
||||
{
|
||||
uids = [self getSortedUIDsInFolder: folder];
|
||||
if (sortByThread)
|
||||
{
|
||||
threadedUids = [self threadedUIDs: uids];
|
||||
if (threadedUids != nil)
|
||||
uids = threadedUids;
|
||||
else
|
||||
sortByThread = NO;
|
||||
}
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys: uids, @"uids",
|
||||
[NSNumber numberWithBool: sortByThread], @"threaded", nil];
|
||||
}
|
||||
else
|
||||
data = [self getUIDsAndHeadersInFolder: folder];
|
||||
|
||||
|
||||
[response appendContentString: [data jsonRepresentation]];
|
||||
|
||||
return response;
|
||||
|
|
|
@ -471,13 +471,20 @@
|
|||
columnsMetaData = [NSMutableDictionary dictionaryWithCapacity: 8];
|
||||
|
||||
tmpKeys = [NSArray arrayWithObjects: @"headerClass", @"headerId", @"value",
|
||||
nil];
|
||||
nil];
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageSubjectColumn tbtv_headercell sortableTableHeader resizable",
|
||||
@"subjectHeader", @"Subject", nil];
|
||||
@"subjectHeader", @"Subject", nil];
|
||||
[columnsMetaData setObject: [NSDictionary dictionaryWithObjects: tmpColumns
|
||||
forKeys: tmpKeys]
|
||||
forKey: @"Subject"];
|
||||
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageThreadColumn tbtv_headercell",
|
||||
@"invisibleHeader", @"Thread", nil];
|
||||
[columnsMetaData setObject: [NSDictionary dictionaryWithObjects: tmpColumns
|
||||
forKeys: tmpKeys]
|
||||
forKey: @"Thread"];
|
||||
|
||||
tmpColumns
|
||||
= [NSArray arrayWithObjects: @"messageFlagColumn tbtv_headercell",
|
||||
|
@ -566,6 +573,16 @@
|
|||
|
||||
finalOrder = [columnsOrder mutableCopy];
|
||||
[finalOrder autorelease];
|
||||
|
||||
if (![ud mailSortByThreads])
|
||||
[finalOrder removeObject: @"Thread"];
|
||||
else
|
||||
{
|
||||
i = [finalOrder indexOfObject: @"Thread"];
|
||||
if (i == NSNotFound)
|
||||
[finalOrder insertObject: @"Thread" atIndex: 0];
|
||||
}
|
||||
|
||||
if ([self showToAddress])
|
||||
{
|
||||
i = [finalOrder indexOfObject: @"From"];
|
||||
|
|
|
@ -547,6 +547,16 @@
|
|||
return [userDefaults mailShowSubscribedFoldersOnly];
|
||||
}
|
||||
|
||||
- (void) setSortByThreads: (BOOL) sortByThreads
|
||||
{
|
||||
[userDefaults setMailSortByThreads: sortByThreads];
|
||||
}
|
||||
|
||||
- (BOOL) sortByThreads
|
||||
{
|
||||
return [userDefaults mailSortByThreads];
|
||||
}
|
||||
|
||||
- (NSArray *) messageCheckList
|
||||
{
|
||||
NSArray *intervalsList;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoMailListViewColumnsOrder"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoMailSortByThreads,SOGoMailListViewColumnsOrder"
|
||||
const:userSettingsKeys="Mail"
|
||||
const:jsFiles="dtree.js,MailerUIdTree.js,SOGoAutoCompletion.js,SOGoResizableTable.js,SOGoMailDataSource.js,SOGoDataTable.js">
|
||||
<script type="text/javascript">
|
||||
|
@ -222,6 +222,9 @@
|
|||
<tr class="tableview"
|
||||
><var:foreach list="columnsDisplayOrder" item="currentColumn">
|
||||
<th var:class="currentColumn.headerClass" var:id="currentColumn.headerId">
|
||||
<var:if condition="currentColumn.value" const:value="Thread">
|
||||
<entity name="nbsp"/>
|
||||
</var:if>
|
||||
<var:if condition="currentColumn.value" const:value="Flagged">
|
||||
<entity name="nbsp"/>
|
||||
</var:if>
|
||||
|
@ -232,10 +235,12 @@
|
|||
<var:if condition="currentColumn.value" const:value="Unread">
|
||||
<img rsrc:src="title_read_14x14.png" label:title="$currentColumn.value" />
|
||||
</var:if>
|
||||
<var:if condition="currentColumn.value" const:value="Flagged" const:negate="YES">
|
||||
<var:if condition="currentColumn.value" const:value="Attachment" const:negate="YES">
|
||||
<var:if condition="currentColumn.value" const:value="Unread" const:negate="YES">
|
||||
<var:string var:value="columnTitle" />
|
||||
<var:if condition="currentColumn.value" const:value="Thread" const:negate="YES">
|
||||
<var:if condition="currentColumn.value" const:value="Flagged" const:negate="YES">
|
||||
<var:if condition="currentColumn.value" const:value="Attachment" const:negate="YES">
|
||||
<var:if condition="currentColumn.value" const:value="Unread" const:negate="YES">
|
||||
<var:string var:value="columnTitle" />
|
||||
</var:if>
|
||||
</var:if>
|
||||
</var:if>
|
||||
</var:if>
|
||||
|
@ -255,6 +260,10 @@
|
|||
<tbody>
|
||||
<tr const:style="display: none;"
|
||||
><var:foreach list="columnsDisplayOrder" item="currentColumn"
|
||||
><var:if condition="currentColumn.value" const:value="Thread"
|
||||
><td class="messageThreadColumn"
|
||||
><!-- thread --></td
|
||||
></var:if
|
||||
><var:if condition="currentColumn.value" const:value="Flagged"
|
||||
><td class="messageFlagColumn"
|
||||
><!-- flagged --></td
|
||||
|
|
|
@ -176,6 +176,11 @@
|
|||
const:id="subscribedFoldersOnly"
|
||||
var:checked="showSubscribedFoldersOnly" />
|
||||
<var:string label:value="Show subscribed mailboxes only"/></label><br/>
|
||||
<label><input type="checkbox"
|
||||
const:name="sortByThreads"
|
||||
const:id="sortByThreads"
|
||||
var:checked="sortByThreads" />
|
||||
<var:string label:value="Sort messages by threads"/></label><br/>
|
||||
<label><var:string label:value="Check for new mail:"/>
|
||||
<var:popup list="messageCheckList" item="item"
|
||||
const:id="messageCheck"
|
||||
|
|
|
@ -40,7 +40,9 @@ DIV#contactsListContent
|
|||
height: 15.5em;
|
||||
border-left: 1px solid #9B9B9B;
|
||||
overflow: auto;
|
||||
overflow-x: hidden; }
|
||||
overflow-x: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none; }
|
||||
|
||||
.aptview_text
|
||||
{
|
||||
|
|
|
@ -215,11 +215,20 @@ function contactsListCallback(http) {
|
|||
}
|
||||
|
||||
function onContactContextMenu(event) {
|
||||
var target = Event.element(event);
|
||||
var contact = target.up('TR');
|
||||
var contactsList = $("contactsList");
|
||||
var contacts = contactsList.getSelectedRows();
|
||||
|
||||
if (contacts.indexOf(contact) < 0) {
|
||||
onRowClick(event, target);
|
||||
contacts = contactsList.getSelectedRows();
|
||||
}
|
||||
|
||||
var menu = $("contactMenu");
|
||||
menu.observe("hideMenu", onContactContextMenuHide);
|
||||
if (contactsList)
|
||||
popupMenu(event, "contactMenu", contactsList.getSelectedRows());
|
||||
popupMenu(event, "contactMenu", contacts);
|
||||
}
|
||||
|
||||
function onContactContextMenuHide(event) {
|
||||
|
@ -1285,7 +1294,7 @@ function initContacts(event) {
|
|||
// Initialize event delegation on contacts table
|
||||
table.multiselect = true;
|
||||
var tbody = $(table.tBodies[0]);
|
||||
tbody.on("mousedown", onContactSelectionChange);
|
||||
tbody.on("click", onContactSelectionChange);
|
||||
tbody.on("dblclick", onContactRowDblClick);
|
||||
tbody.on("selectstart", listRowMouseDownHandler);
|
||||
tbody.on("contextmenu", onContactContextMenu);
|
||||
|
@ -1470,12 +1479,19 @@ function startDragging (itm, e) {
|
|||
var handle = $("dragDropVisual");
|
||||
var contacts = $('contactsList').getSelectedRowsId();
|
||||
var count = contacts.length;
|
||||
var row = target.up('TR');
|
||||
|
||||
handle.show();
|
||||
handle.update (count);
|
||||
if (e.shiftKey || currentFolderIsRemote ()) {
|
||||
handle.addClassName ("copy");
|
||||
if (count == 0 || contacts.indexOf(row.id) < 0) {
|
||||
onRowClick(e, target);
|
||||
contacts = $("contactsList").getSelectedRowsId();
|
||||
count = contacts.length;
|
||||
}
|
||||
|
||||
handle.update (count);
|
||||
if (e.shiftKey || currentFolderIsRemote()) {
|
||||
handle.addClassName("copy");
|
||||
}
|
||||
handle.show();
|
||||
}
|
||||
|
||||
function whileDragging (itm, e) {
|
||||
|
|
|
@ -256,6 +256,7 @@ TR#messageCountHeader TH
|
|||
TABLE.messageList TD
|
||||
{ border-right: 1px solid transparent; }
|
||||
|
||||
TABLE.messageList .messageThreadColumn,
|
||||
TABLE.messageList .messageFlagColumn,
|
||||
TABLE.messageList .messageAttachmentColumn,
|
||||
TABLE.messageList .messageUnreadColumn
|
||||
|
@ -270,6 +271,45 @@ TABLE.messageList .messageSubjectColumn
|
|||
TABLE.messageList .messageSubjectColumn SPAN
|
||||
{ padding-left: 20px; }
|
||||
|
||||
TABLE.messageList TR.openedThread TD,
|
||||
TABLE.messageList TR.closedThread TD,
|
||||
TABLE.messageList TR.thread .messageThreadColumn
|
||||
{ background-color: #DDD; }
|
||||
|
||||
TABLE.messageList TR.thread TD
|
||||
{ background-color: #EEE; }
|
||||
|
||||
TABLE.messageList TR.thread1 .messageSubjectColumn
|
||||
{ background-position: 20px 0px !important;
|
||||
padding-left: 20px; }
|
||||
TABLE.messageList TR.thread2 .messageSubjectColumn
|
||||
{ background-position: 40px 0px !important;
|
||||
padding-left: 40px; }
|
||||
TABLE.messageList TR.thread3 .messageSubjectColumn
|
||||
{ background-position: 60px 0px !important;
|
||||
padding-left: 60px; }
|
||||
TABLE.messageList TR.thread4 .messageSubjectColumn
|
||||
{ background-position: 80px 0px !important;
|
||||
padding-left: 80px; }
|
||||
TABLE.messageList TR.thread5 .messageSubjectColumn
|
||||
{ background-position: 100px 0px !important;
|
||||
padding-left: 100px; }
|
||||
TABLE.messageList TR.thread6 .messageSubjectColumn
|
||||
{ background-position: 120px 0px !important;
|
||||
padding-left: 120px; }
|
||||
TABLE.messageList TR.thread7 .messageSubjectColumn
|
||||
{ background-position: 140px 0px !important;
|
||||
padding-left: 140px; }
|
||||
TABLE.messageList TR.thread8 .messageSubjectColumn
|
||||
{ background-position: 160px 0px !important;
|
||||
padding-left: 160px; }
|
||||
TABLE.messageList TR.thread9 .messageSubjectColumn
|
||||
{ background-position: 180px 0px !important;
|
||||
padding-left: 180px; }
|
||||
TABLE.messageList TR.thread10 .messageSubjectColumn
|
||||
{ background-position: 200px 0px !important;
|
||||
padding-left: 200px; }
|
||||
|
||||
TABLE.messageList .messageAddressColumn
|
||||
{ max-width: 18%;
|
||||
width: 18%; }
|
||||
|
|
|
@ -17,7 +17,10 @@ var Mailer = {
|
|||
quotas: null,
|
||||
|
||||
dataTable: null,
|
||||
dataSources: new Hash()
|
||||
dataSources: new Hash(),
|
||||
|
||||
columnsOrder: null,
|
||||
sortByThread: false
|
||||
};
|
||||
|
||||
var usersRightsWindowHeight = 320;
|
||||
|
@ -169,8 +172,10 @@ function markMailInWindow(win, msguid, markread) {
|
|||
return (unseenCount != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by UIxMailView with window.opener.
|
||||
*/
|
||||
function markMailReadInWindow(win, msguid) {
|
||||
/* this is called by UIxMailView with window.opener */
|
||||
return markMailInWindow(win, msguid, true);
|
||||
}
|
||||
|
||||
|
@ -203,6 +208,31 @@ function openMessageWindowsForSelection(action, firstOnly) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
function mailListToggleMessageThread(row, cell) {
|
||||
var show = row.hasClassName('closedThread');
|
||||
$(cell).down('img').remove();
|
||||
if (show) {
|
||||
row.removeClassName('closedThread');
|
||||
row.addClassName('openedThread');
|
||||
var img = createElement("img", null, null, { src: ResourcesURL + '/arrow-down.png' });
|
||||
cell.insertBefore(img, cell.firstChild);
|
||||
}
|
||||
else {
|
||||
row.removeClassName('openedThread');
|
||||
row.addClassName('closedThread');
|
||||
var img = createElement("img", null, null, { src: ResourcesURL + '/arrow-right.png' });
|
||||
cell.insertBefore(img, cell.firstChild);
|
||||
}
|
||||
while ((row = row.next()) && row.hasClassName('thread')) {
|
||||
if (show)
|
||||
row.show();
|
||||
else
|
||||
row.hide();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* Triggered when clicking on the read/unread dot of a message row or
|
||||
* through the contextual menu. */
|
||||
function mailListToggleMessagesRead(row) {
|
||||
|
@ -399,6 +429,7 @@ function deleteSelectedMessages(sender) {
|
|||
var uids = new Array(); // message IDs
|
||||
var paths = new Array(); // row IDs
|
||||
var unseenCount = 0;
|
||||
var refreshFolder = false;
|
||||
|
||||
if (rowIds && rowIds.length > 0) {
|
||||
messageList.deselectAll();
|
||||
|
@ -432,15 +463,26 @@ function deleteSelectedMessages(sender) {
|
|||
var row = $("row_" + uid);
|
||||
var nextRow = false;
|
||||
if (row) {
|
||||
//row.addClassName("deleted"); // when we'll offer "mark as deleted"
|
||||
nextRow = row.next("tr");
|
||||
if (!nextRow.id.startsWith('row_'))
|
||||
nextRow = row.previous("tr");
|
||||
// row.addClassName("deleted"); // when we'll offer "mark as deleted"
|
||||
else if (row.hasClassName('openedThread') || row.hasClassName('closedThread')) {
|
||||
// Thread root deleted -- must refresh folder
|
||||
refreshFolder = true;
|
||||
// New row will be the new thread root -- mark it as first mail of the thread
|
||||
var nextUid = nextRow.id.substr(4);
|
||||
var nextIndex = Mailer.dataTable.dataSource.indexOf(nextUid);
|
||||
Mailer.dataTable.dataSource.uids[nextIndex][2] = 1; // mark it as "first"
|
||||
Mailer.dataTable.invalidate(nextUid, true);
|
||||
}
|
||||
if (nextRow.id.startsWith('row_')) {
|
||||
Mailer.currentMessages[Mailer.currentMailbox] = nextRow.id.substr(4);
|
||||
nextRow.selectElement();
|
||||
if (loadMessage(Mailer.currentMessages[Mailer.currentMailbox]))
|
||||
if (loadMessage(Mailer.currentMessages[Mailer.currentMailbox]) && !refreshFolder)
|
||||
// Seen state has changed
|
||||
Mailer.dataTable.invalidate(Mailer.currentMessages[Mailer.currentMailbox], true);
|
||||
refreshFolder = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -452,7 +494,6 @@ function deleteSelectedMessages(sender) {
|
|||
lastClickedRow = nextRow.rowIndex;
|
||||
lastClickedRowId = nextRow.id;
|
||||
}
|
||||
Mailer.dataTable.refresh();
|
||||
deleteCachedMailboxByType("trash");
|
||||
}
|
||||
else {
|
||||
|
@ -468,7 +509,7 @@ function deleteSelectedMessages(sender) {
|
|||
}
|
||||
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/batchDelete";
|
||||
var parameters = "uid=" + uids.join(",");
|
||||
var data = { "id": uids, "mailbox": Mailer.currentMailbox, "path": paths, "refreshUnseenCount": (unseenCount > 0) };
|
||||
var data = { "id": uids, "mailbox": Mailer.currentMailbox, "path": paths, "refreshUnseenCount": (unseenCount > 0), "refreshFolder": refreshFolder };
|
||||
triggerAjaxRequest(url, deleteSelectedMessagesCallback, data, parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
}
|
||||
|
@ -485,6 +526,8 @@ function deleteSelectedMessagesCallback(http) {
|
|||
// TODO : the unseen count should be returned when calling the batchDelete remote action,
|
||||
// in order to avoid this extra AJAX call.
|
||||
getUnseenCountForFolder(data["mailbox"]);
|
||||
if (data["refreshFolder"])
|
||||
Mailer.dataTable.refresh();
|
||||
}
|
||||
else if (!http.callbackData["withoutTrash"]) {
|
||||
showConfirmDialog(_("Warning"),
|
||||
|
@ -514,16 +557,11 @@ function onMenuDeleteMessage(event) {
|
|||
preventDefault(event);
|
||||
}
|
||||
|
||||
function deleteMessage(url, id, mailbox, messageId) {
|
||||
var data = { "id": new Array(id), "mailbox": mailbox, "path": new Array(messageId) };
|
||||
var parameters = "uid=" + id;
|
||||
deleteMessageRequestCount++;
|
||||
triggerAjaxRequest(url, deleteSelectedMessagesCallback, data, parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
}
|
||||
|
||||
/**
|
||||
* The following two functions are called from UIxMailPopupView
|
||||
* with window.opener.
|
||||
*/
|
||||
function deleteMessageWithDelay(url, id, mailbox, messageId) {
|
||||
/* this is called by UIxMailPopupView with window.opener */
|
||||
var row = $("row_" + id);
|
||||
if (row) row.hide();
|
||||
setTimeout("deleteMessage('" +
|
||||
|
@ -534,6 +572,14 @@ function deleteMessageWithDelay(url, id, mailbox, messageId) {
|
|||
50);
|
||||
}
|
||||
|
||||
function deleteMessage(url, id, mailbox, messageId) {
|
||||
var data = { "id": new Array(id), "mailbox": mailbox, "path": new Array(messageId) };
|
||||
var parameters = "uid=" + id;
|
||||
deleteMessageRequestCount++;
|
||||
triggerAjaxRequest(url, deleteSelectedMessagesCallback, data, parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
}
|
||||
|
||||
function onPrintCurrentMessage(event) {
|
||||
var messageList = $("messageListBody").down("TBODY");
|
||||
var rows = messageList.getSelectedNodesId();
|
||||
|
@ -588,9 +634,9 @@ function toggleAddressColumn(search, replace) {
|
|||
if (header) {
|
||||
header.id = replace + "Header";
|
||||
header.update(_(replace.capitalize()));
|
||||
var i = UserDefaults["SOGoMailListViewColumnsOrder"].indexOf(search.capitalize());
|
||||
var i = Mailer.columnsOrder.indexOf(search.capitalize());
|
||||
if (i >= 0)
|
||||
UserDefaults["SOGoMailListViewColumnsOrder"][i] = replace.capitalize();
|
||||
Mailer.columnsOrder[i] = replace.capitalize();
|
||||
}
|
||||
if (sorting["attribute"] == search)
|
||||
sorting["attribute"] = replace;
|
||||
|
@ -767,7 +813,7 @@ function openMailbox(mailbox, reload) {
|
|||
if (inboxData) {
|
||||
// Use UIDs and headers from the WOX template; this only
|
||||
// happens once and only with the inbox
|
||||
dataSource.init(inboxData['uids'], inboxData['headers']);
|
||||
dataSource.init(inboxData['uids'], inboxData['threaded'], inboxData['headers']);
|
||||
inboxData = null; // invalidate this initial lookup
|
||||
}
|
||||
else
|
||||
|
@ -813,12 +859,20 @@ function messageListCallback(row, data, isNew) {
|
|||
row.id = data['rowID'];
|
||||
row.writeAttribute('labels', (data['labels']?data['labels']:""));
|
||||
row.className = data['rowClasses'];
|
||||
row.show(); // make sure the row is visible
|
||||
|
||||
// Restore previous selection
|
||||
if (data['uid'] == currentMessage)
|
||||
row.addClassName('_selected');
|
||||
|
||||
var columnsOrder = UserDefaults["SOGoMailListViewColumnsOrder"];
|
||||
if (data['Thread'])
|
||||
row.addClassName('openedThread');
|
||||
else if (data['ThreadLevel'] > 0) {
|
||||
if (data['ThreadLevel'] > 10) data['ThreadLevel'] = 10;
|
||||
row.addClassName('thread');
|
||||
row.addClassName('thread' + data['ThreadLevel']);
|
||||
}
|
||||
|
||||
var cells;
|
||||
if (Prototype.Browser.IE)
|
||||
cells = row.childNodes;
|
||||
|
@ -827,7 +881,7 @@ function messageListCallback(row, data, isNew) {
|
|||
|
||||
for (var j = 0; j < cells.length; j++) {
|
||||
var cell = $(cells[j]);
|
||||
var cellType = columnsOrder[j];
|
||||
var cellType = Mailer.columnsOrder[j];
|
||||
|
||||
if (data[cellType]) cell.innerHTML = data[cellType];
|
||||
else cell.innerHTML = ' ';
|
||||
|
@ -957,21 +1011,26 @@ function onMessageListRender(event) {
|
|||
}
|
||||
|
||||
function onMessageContextMenu(event) {
|
||||
var row = getTarget(event);
|
||||
var target = Event.element(event);
|
||||
var menu = $('messageListMenu');
|
||||
var topNode = $('messageListBody');
|
||||
var selectedNodes = topNode.getSelectedRows();
|
||||
if (row.tagName != 'TR')
|
||||
row = row.parentNode;
|
||||
if (row.tagName != 'TR')
|
||||
row = row.parentNode;
|
||||
var selectedNodes = topNode.getSelectedRowsId();
|
||||
var row = target.up('TR');
|
||||
|
||||
if (selectedNodes.indexOf(row.id) < 0) {
|
||||
if (target.tagName != 'TD')
|
||||
target = target.up('TD');
|
||||
onRowClick(event, target);
|
||||
selectedNodes = topNode.getSelectedRowsId();
|
||||
}
|
||||
|
||||
menu.observe("hideMenu", onMessageContextMenuHide);
|
||||
|
||||
if (selectedNodes.length > 1)
|
||||
popupMenu(event, "messagesListMenu", selectedNodes);
|
||||
else
|
||||
else if (selectedNodes.length == 1)
|
||||
popupMenu(event, "messageListMenu", row);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onMessageContextMenuHide(event) {
|
||||
|
@ -1110,7 +1169,10 @@ function onMessageSelectionChange(event) {
|
|||
if (t.tagName == 'IMG') {
|
||||
t = t.parentNode;
|
||||
if (t.tagName == 'TD') {
|
||||
if (t.className == 'messageUnreadColumn') {
|
||||
if (t.className == 'messageThreadColumn') {
|
||||
//mailListToggleMessageThread(t.parentNode, t); Disable thread collapsing
|
||||
}
|
||||
else if (t.className == 'messageUnreadColumn') {
|
||||
mailListToggleMessagesRead(t.parentNode);
|
||||
return true;
|
||||
}
|
||||
|
@ -1781,15 +1843,17 @@ function refreshMessage(mailbox, messageUID) {
|
|||
}
|
||||
}
|
||||
|
||||
function configureMessageListEvents(headerTable, dataTable) {
|
||||
function configureMessageListEvents() {
|
||||
var headerTable = $("messageListHeader");
|
||||
var dataTable = $("messageListBody");
|
||||
|
||||
if (headerTable)
|
||||
// Sortable columns
|
||||
configureSortableTableHeaders(headerTable);
|
||||
|
||||
if (dataTable) {
|
||||
dataTable.multiselect = true;
|
||||
// Each body row can load a message
|
||||
dataTable.observe("mouseup", onMessageSelectionChange);
|
||||
dataTable.observe("click", onMessageSelectionChange);
|
||||
dataTable.observe("dblclick", onMessageDoubleClick);
|
||||
dataTable.observe("selectstart", listRowMouseDownHandler);
|
||||
dataTable.observe("contextmenu", onMessageContextMenu);
|
||||
|
@ -1844,6 +1908,11 @@ function openInbox(node) {
|
|||
|
||||
function initMailer(event) {
|
||||
if (!$(document.body).hasClassName("popup")) {
|
||||
Mailer.columnsOrder = UserDefaults["SOGoMailListViewColumnsOrder"];
|
||||
Mailer.sortByThread = UserDefaults["SOGoMailSortByThreads"] != null && parseInt(UserDefaults["SOGoMailSortByThreads"]) > 0;
|
||||
if (!Mailer.sortByThread && Mailer.columnsOrder[0] == "Thread")
|
||||
Mailer.columnsOrder.shift(); // drop the thread column
|
||||
|
||||
// Restore sorting from user settings
|
||||
if (UserSettings && UserSettings["Mail"] && UserSettings["Mail"]["SortingState"]) {
|
||||
sorting["attribute"] = UserSettings["Mail"]["SortingState"][0];
|
||||
|
@ -1866,7 +1935,7 @@ function initMailer(event) {
|
|||
messageListHeader.restore($H(UserSettings["Mail"]["ColumnsState"]));
|
||||
}
|
||||
|
||||
configureMessageListEvents($("messageListHeader"), $("messageListBody"));
|
||||
configureMessageListEvents();
|
||||
|
||||
initMailboxTree();
|
||||
initMessageCheckTimer();
|
||||
|
@ -2589,15 +2658,16 @@ function onLabelMenuPrepareVisibility() {
|
|||
function onMarkMenuPrepareVisibility() {
|
||||
var messageList = $("messageListBody");
|
||||
if (messageList) {
|
||||
var nodes = messageList.down("TBODY").getSelectedNodes();
|
||||
var nodes = messageList.down("TBODY").getSelectedNodesId();
|
||||
|
||||
var isRead = false;
|
||||
var isFlagged = false;
|
||||
|
||||
if (nodes.length > 0) {
|
||||
var row = nodes[0];
|
||||
var firstTd = row.childElements().first();
|
||||
var img = firstTd.childElements().first();
|
||||
var row = null;
|
||||
for (var i = 0; row == null && i < nodes.length; i++)
|
||||
row = $(nodes[i]);
|
||||
var img = row.down('img');
|
||||
isFlagged = img.hasClassName ("messageIsFlagged");
|
||||
isRead = !row.hasClassName("mailer_unreadmail");
|
||||
}
|
||||
|
@ -2685,7 +2755,7 @@ function getMenus() {
|
|||
"-", "moveMailboxMenu",
|
||||
"copyMailboxMenu", "label-menu",
|
||||
"mark-menu", "-",
|
||||
saveAs, null,
|
||||
saveAs, null, null,
|
||||
onMenuDeleteMessage ],
|
||||
imageMenu: [ saveImage ],
|
||||
attachmentMenu: [ saveAttachment ],
|
||||
|
@ -2857,16 +2927,15 @@ function startDragging (itm, e) {
|
|||
if (target.up('TBODY') == undefined)
|
||||
return;
|
||||
|
||||
if (target.tagName != 'TD')
|
||||
target = target.up('TD');
|
||||
var row = target.up('TR');
|
||||
|
||||
var handle = $("dragDropVisual");
|
||||
var selectedIds = $("messageListBody").getSelectedRowsId();
|
||||
var count = selectedIds.length;
|
||||
var rowId = row.id;
|
||||
|
||||
if (count == 0 || selectedIds.indexOf(rowId) < 0) {
|
||||
if (target.tagName != 'TD')
|
||||
target = target.up('TD');
|
||||
onRowClick(e, target);
|
||||
selectedIds = $("messageListBody").getSelectedRowsId();
|
||||
count = selectedIds.length;
|
||||
|
|
|
@ -57,9 +57,9 @@ var SOGoDataTableInterface = {
|
|||
s = startIndex;
|
||||
e = endIndex;
|
||||
}
|
||||
|
||||
|
||||
while (s <= e) {
|
||||
uid = "row_" + div.dataSource.uids[s];
|
||||
uid = "row_" + div.dataSource.uidAtIndex(s);
|
||||
if (this.selectedIds.indexOf(uid) < 0)
|
||||
this.selectedIds.push(uid);
|
||||
s++;
|
||||
|
@ -71,7 +71,7 @@ var SOGoDataTableInterface = {
|
|||
var div = this.up('div');
|
||||
this.selectedIds = new Array();
|
||||
for (var i = 0; i < div.dataSource.uids.length; i++)
|
||||
this.selectedIds.push("row_" + div.dataSource.uids[i]);
|
||||
this.selectedIds.push("row_" + div.dataSource.uidAtIndex(i));
|
||||
this.refreshSelectionByIds();
|
||||
},
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ SOGoMailDataSource = Class.create({
|
|||
this.url = url;
|
||||
|
||||
this.uids = new Array();
|
||||
this.threaded = false;
|
||||
this.cache = new Hash();
|
||||
|
||||
this.loaded = false;
|
||||
|
@ -27,7 +28,7 @@ SOGoMailDataSource = Class.create({
|
|||
|
||||
invalidate: function(uid) {
|
||||
this.cache.unset(uid);
|
||||
var index = this.uids.indexOf(parseInt(uid));
|
||||
var index = this.indexOf(uid);
|
||||
// log ("MailDataSource.invalidate(" + uid + ") at index " + index);
|
||||
|
||||
return index;
|
||||
|
@ -41,10 +42,16 @@ SOGoMailDataSource = Class.create({
|
|||
|
||||
return index;
|
||||
},
|
||||
|
||||
init: function(uids, headers) {
|
||||
|
||||
init: function(uids, threaded, headers) {
|
||||
this.uids = uids;
|
||||
|
||||
if (typeof threaded != "undefined") {
|
||||
this.threaded = threaded;
|
||||
if (threaded)
|
||||
this.uids.shift(); // drop key fields
|
||||
}
|
||||
// log ("MailDataSource.init() " + this.uids.length + " uids loaded");
|
||||
|
||||
if (headers) {
|
||||
var keys = headers[0];
|
||||
for (var i = 1; i < headers.length; i++) {
|
||||
|
@ -53,6 +60,7 @@ SOGoMailDataSource = Class.create({
|
|||
header[keys[j]] = headers[i][j];
|
||||
this.cache.set(header["uid"], header);
|
||||
}
|
||||
// log ("MailDataSource.init() " + this.cache.keys().length + " headers loaded");
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
|
@ -81,7 +89,7 @@ SOGoMailDataSource = Class.create({
|
|||
if (http.responseText.length > 0) {
|
||||
var data = http.responseText.evalJSON(true);
|
||||
if (data.uids)
|
||||
this.init(data.uids, data.headers);
|
||||
this.init(data.uids, data.threaded, data.headers);
|
||||
else
|
||||
this.init(data);
|
||||
if (this.delayedGetData) {
|
||||
|
@ -136,8 +144,9 @@ SOGoMailDataSource = Class.create({
|
|||
// 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])) {
|
||||
missingUids[i] = this.uids[j];
|
||||
var uid = this.threaded? this.uids[j][0] : this.uids[j];
|
||||
if (!this.cache.get(uid)) {
|
||||
missingUids[i] = uid;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -196,12 +205,45 @@ SOGoMailDataSource = Class.create({
|
|||
var i, j;
|
||||
var data = new Array();
|
||||
for (i = start, j = 0; i < end; i++, j++) {
|
||||
data[j] = this.cache.get(this.uids[i]);
|
||||
if (this.threaded) {
|
||||
data[j] = this.cache.get(this.uids[i][0]);
|
||||
|
||||
// Add thread-related data
|
||||
if (parseInt(this.uids[i][2]) > 0)
|
||||
data[j]['Thread'] = ' '; //'<img class="messageThread" src="' + ResourcesURL + '/arrow-down.png">';
|
||||
else
|
||||
delete data[j]['Thread'];
|
||||
if (parseInt(this.uids[i][1]) > -1)
|
||||
data[j]['ThreadLevel'] = this.uids[i][1];
|
||||
else
|
||||
delete data[j]['ThreadLevel'];
|
||||
}
|
||||
else {
|
||||
data[j] = this.cache.get(this.uids[i]);
|
||||
}
|
||||
}
|
||||
callbackFunction(id, start, this.uids.length, data);
|
||||
},
|
||||
|
||||
indexOf: function(uid) {
|
||||
return this.uids.indexOf(parseInt(uid));
|
||||
var index = -1;
|
||||
if (this.threaded) {
|
||||
for (var i = 0; i < this.uids.length; i++)
|
||||
if (this.uids[i][0] == uid) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
index = this.uids.indexOf(parseInt(uid));
|
||||
|
||||
return index;
|
||||
},
|
||||
|
||||
uidAtIndex: function(index) {
|
||||
if (this.threaded)
|
||||
return this.uids[index][0];
|
||||
else
|
||||
return this.uids[index];
|
||||
}
|
||||
});
|
||||
|
|
|
@ -93,7 +93,7 @@ div#headerArea div.addressList
|
|||
div#attachmentsArea
|
||||
{ display: none;
|
||||
float: right;
|
||||
width: 120px;
|
||||
width: 200px;
|
||||
padding: 2px 5px 0;
|
||||
margin: auto;
|
||||
border-left: 1px solid #888; }
|
||||
|
@ -144,7 +144,9 @@ UL#attachments
|
|||
list-style-type: none;
|
||||
list-style-image: none;
|
||||
overflow: auto;
|
||||
overflow-x: hidden; }
|
||||
overflow-x: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none; }
|
||||
|
||||
UL#attachments LI
|
||||
{ white-space: nowrap;
|
||||
|
|
|
@ -361,6 +361,7 @@ function initMailEditor() {
|
|||
|
||||
var list = $("attachments");
|
||||
if (!list) return;
|
||||
list.multiselect = true;
|
||||
list.on("click", onRowClick);
|
||||
list.attachMenu("attachmentsMenu");
|
||||
var elements = $(list).childNodesWithTag("li");
|
||||
|
|
|
@ -89,7 +89,7 @@ DIV.listWrapper
|
|||
DIV#filtersListWrapper
|
||||
{ bottom: 30px;
|
||||
right: 2em;
|
||||
top: 164px;
|
||||
top: 174px;
|
||||
left: 2em; }
|
||||
|
||||
TABLE#filtersList
|
||||
|
|
|
@ -605,14 +605,6 @@ function onRowClick(event, target) {
|
|||
// Single line selection
|
||||
$(node.parentNode).deselectAll();
|
||||
$(node).selectElement();
|
||||
|
||||
if (initialSelection != $(node.parentNode).getSelectedNodesId()) {
|
||||
// Selection has changed; fire mousedown event
|
||||
var parentNode = node.parentNode;
|
||||
if (parentNode.tagName == 'TBODY')
|
||||
parentNode = parentNode.parentNode;
|
||||
parentNode.fire("mousedown");
|
||||
}
|
||||
}
|
||||
if (rowIndex != null) {
|
||||
lastClickedRow = rowIndex;
|
||||
|
@ -735,8 +727,6 @@ function hideMenu(menuNode) {
|
|||
menuNode.parentMenu.submenu = null;
|
||||
menuNode.parentMenu = null;
|
||||
}
|
||||
|
||||
$(menuNode).fire("mousedown");
|
||||
}
|
||||
|
||||
function onMenuEntryClick(event) {
|
||||
|
|
|
@ -50,7 +50,15 @@ TABLE.messageList TD
|
|||
{ white-space: pre; }
|
||||
|
||||
TABLE.messageList TR._selected TD
|
||||
{ border-right: 1px solid #9ABCD8; }
|
||||
{ border-right: 1px solid #9ABCD8 !important; }
|
||||
|
||||
TABLE.messageList TR.openedThread TD,
|
||||
TABLE.messageList TR.closedThread TD,
|
||||
TABLE.messageList TR.thread .messageThreadColumn
|
||||
{ border-right: 1px solid #DDD; }
|
||||
|
||||
TABLE.messageList TR.thread TD
|
||||
{ border-right: 1px solid #EEE; }
|
||||
|
||||
/* ContactsUI */
|
||||
|
||||
|
|
Loading…
Reference in New Issue