mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-11 16:28:51 +00:00
Merge pull request #50 from alexcloutier/feature/SearchInbox
New feature to search multiple mailboxes
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"Print" = "Print";
|
||||
"Stop" = "Stop";
|
||||
"Write" = "Write";
|
||||
"Search" = "Search";
|
||||
|
||||
"Send" = "Send";
|
||||
"Contacts" = "Contacts";
|
||||
@@ -41,6 +42,7 @@
|
||||
"Attachment" = "Attachment";
|
||||
"Unread" = "Unread";
|
||||
"Flagged" = "Flagged";
|
||||
"Search inbox" = "Search inbox";
|
||||
|
||||
/* Main Frame */
|
||||
|
||||
@@ -94,8 +96,9 @@
|
||||
"To" = "To";
|
||||
"Cc" = "Cc";
|
||||
"Bcc" = "Bcc";
|
||||
"Reply-To" = "Reply-To";
|
||||
"Reply-To" = "Reply-To";
|
||||
"Add address" = "Add address";
|
||||
"Body" = "Body";
|
||||
|
||||
"Open" = "Open";
|
||||
"Select All" = "Select All";
|
||||
@@ -237,6 +240,18 @@
|
||||
"As Not Junk" = "As Not Junk";
|
||||
"Run Junk Mail Controls" = "Run Junk Mail Controls";
|
||||
|
||||
"Search messages in" = "Search messages in";
|
||||
"Search" = "Search";
|
||||
"Search subfolders" = "Search subfolders";
|
||||
"Match any of the following" = "Match any of the following";
|
||||
"Match all of the following" = "Match all of the following";
|
||||
"contains" = "contains";
|
||||
"does not contain" = "does not contain";
|
||||
"No matches found" = "No matches found";
|
||||
"results found" = "results found";
|
||||
"result found" = "result found";
|
||||
"Please specify at least one filter" = "Please specify at least one filter";
|
||||
|
||||
/* Folder operations */
|
||||
"Name :" = "Name :";
|
||||
"Enter the new name of your folder :"
|
||||
|
||||
@@ -23,6 +23,7 @@ MailerUI_OBJC_FILES += \
|
||||
UIxMailPopupView.m \
|
||||
UIxMailMoveToPopUp.m \
|
||||
UIxMailFilterPanel.m \
|
||||
UIxMailSearch.m \
|
||||
\
|
||||
UIxMailAccountActions.m \
|
||||
UIxMailFolderActions.m \
|
||||
|
||||
@@ -63,5 +63,12 @@
|
||||
image = "tb-mail-print-flat-24x24.png";
|
||||
label = "Print";
|
||||
tooltip = "Print this message"; },
|
||||
|
||||
{ link = "#";
|
||||
onclick = "return onSearchMail(event);";
|
||||
cssClass = "";
|
||||
image = "search-messages.png";
|
||||
label = "Search";
|
||||
tooltip = "Search inbox"; }
|
||||
)
|
||||
)
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#import <Mailer/SOGoSentFolder.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoDateFormatter.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
@@ -322,27 +323,21 @@
|
||||
return @"ARRIVAL";
|
||||
}
|
||||
|
||||
- (NSString *) imap4SortKey
|
||||
{
|
||||
NSString *sort;
|
||||
|
||||
sort = [[context request] formValueForKey: @"sort"];
|
||||
|
||||
return [sort uppercaseString];
|
||||
}
|
||||
|
||||
- (NSString *) imap4SortOrdering
|
||||
{
|
||||
NSString *sort, *ascending;
|
||||
NSString *module;
|
||||
WORequest *request;
|
||||
NSString *sort, *module;
|
||||
NSMutableDictionary *moduleSettings;
|
||||
BOOL asc;
|
||||
NSDictionary *urlParams, *sortingAttributes;
|
||||
SOGoUser *activeUser;
|
||||
SOGoUserSettings *us;
|
||||
BOOL asc;
|
||||
|
||||
sort = [self imap4SortKey];
|
||||
ascending = [[context request] formValueForKey: @"asc"];
|
||||
asc = [ascending boolValue];
|
||||
request = [context request];
|
||||
urlParams = [[request contentAsString] objectFromJSONString];
|
||||
sortingAttributes = [urlParams objectForKey:@"sortingAttributes"];
|
||||
sort = [[sortingAttributes objectForKey:@"sort"] uppercaseString];
|
||||
asc = [[sortingAttributes objectForKey:@"asc"] boolValue];
|
||||
|
||||
activeUser = [context activeUser];
|
||||
module = @"Mail";
|
||||
@@ -393,37 +388,47 @@
|
||||
|
||||
- (EOQualifier *) searchQualifier
|
||||
{
|
||||
NSString *criteria, *value;
|
||||
EOQualifier *qualifier;
|
||||
WORequest *request;
|
||||
|
||||
request = [context request];
|
||||
criteria = [request formValueForKey: @"search"];
|
||||
value = [request formValueForKey: @"value"];
|
||||
qualifier = nil;
|
||||
if ([value length])
|
||||
{
|
||||
if ([criteria isEqualToString: @"subject"])
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(subject doesContain: %@)", value];
|
||||
else if ([criteria isEqualToString: @"sender"])
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(from doesContain: %@)", value];
|
||||
else if ([criteria isEqualToString: @"subject_or_sender"])
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"((subject doesContain: %@)"
|
||||
@" OR (from doesContain: %@))",
|
||||
value, value];
|
||||
else if ([criteria isEqualToString: @"to_or_cc"])
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"((to doesContain: %@)"
|
||||
@" OR (cc doesContain: %@))",
|
||||
value, value];
|
||||
else if ([criteria isEqualToString: @"entire_message"])
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(body doesContain: %@)", value];
|
||||
}
|
||||
EOQualifier *qualifier, *searchQualifier;
|
||||
WORequest *request;
|
||||
NSDictionary *sortingAttributes, *content;
|
||||
NSArray *filters;
|
||||
NSString *searchBy, *searchArgument, *searchInput, *searchString, *match;
|
||||
NSMutableArray *searchArray;
|
||||
int nbFilters = 0, i;
|
||||
|
||||
request = [context request];
|
||||
content = [[request contentAsString] objectFromJSONString];
|
||||
qualifier = nil;
|
||||
searchString = nil;
|
||||
|
||||
if ([content objectForKey:@"filters"])
|
||||
{
|
||||
filters = [content objectForKey:@"filters"];
|
||||
sortingAttributes = [content objectForKey:@"sortingAttributes"];
|
||||
nbFilters = [filters count];
|
||||
match = [NSString stringWithString:[sortingAttributes objectForKey:@"match"]]; // AND, OR
|
||||
|
||||
searchArray = [NSMutableArray arrayWithCapacity:nbFilters];
|
||||
for (i = 0; i < nbFilters; i++)
|
||||
{
|
||||
searchBy = [NSString stringWithString:[[filters objectAtIndex:i] objectForKey:@"searchBy"]];
|
||||
searchArgument = [NSString stringWithString:[[filters objectAtIndex:i] objectForKey:@"searchArgument"]];
|
||||
searchInput = [NSString stringWithString:[[filters objectAtIndex:i] objectForKey:@"searchInput"]];
|
||||
|
||||
if ([[[filters objectAtIndex:i] objectForKey:@"negative"] boolValue])
|
||||
searchString = [NSString stringWithFormat:@"(not (%@ %@: '%@'))", searchBy, searchArgument, searchInput];
|
||||
else
|
||||
searchString = [NSString stringWithFormat:@"(%@ %@: '%@')", searchBy, searchArgument, searchInput];
|
||||
|
||||
searchQualifier = [EOQualifier qualifierWithQualifierFormat:searchString];
|
||||
[searchArray addObject:searchQualifier];
|
||||
}
|
||||
if ([match isEqualToString:@"OR"])
|
||||
qualifier = [[EOOrQualifier alloc] initWithQualifierArray: searchArray];
|
||||
else
|
||||
qualifier = [[EOAndQualifier alloc] initWithQualifierArray: searchArray];
|
||||
}
|
||||
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
@@ -433,25 +438,20 @@
|
||||
|
||||
if (!sortedUIDs)
|
||||
{
|
||||
notDeleted = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(not (flags = %@))",
|
||||
@"deleted"];
|
||||
notDeleted = [EOQualifier qualifierWithQualifierFormat: @"(not (flags = %@))", @"deleted"];
|
||||
qualifier = [self searchQualifier];
|
||||
if (qualifier)
|
||||
{
|
||||
fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers:
|
||||
notDeleted, qualifier,
|
||||
nil];
|
||||
[fetchQualifier autorelease];
|
||||
}
|
||||
{
|
||||
fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers: notDeleted, qualifier, nil];
|
||||
[fetchQualifier autorelease];
|
||||
}
|
||||
else
|
||||
fetchQualifier = notDeleted;
|
||||
|
||||
sortedUIDs
|
||||
= [mailFolder fetchUIDsMatchingQualifier: fetchQualifier
|
||||
sortOrdering: [self imap4SortOrdering]
|
||||
threaded: sortByThread];
|
||||
|
||||
fetchQualifier = notDeleted;
|
||||
|
||||
sortedUIDs = [mailFolder fetchUIDsMatchingQualifier: fetchQualifier
|
||||
sortOrdering: [self imap4SortOrdering]
|
||||
threaded: sortByThread];
|
||||
|
||||
[sortedUIDs retain];
|
||||
}
|
||||
|
||||
@@ -459,7 +459,8 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flatten representation of the messages threads as triples of
|
||||
* Returns a
|
||||
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
|
||||
@@ -632,11 +633,14 @@
|
||||
|
||||
// Retrieve messages UIDs using form parameters "sort" and "asc"
|
||||
uids = [self getSortedUIDsInFolder: folder];
|
||||
|
||||
// Get rid of the extra parenthesis
|
||||
// uids = [[[[uids stringValue] stringByReplacingOccurrencesOfString:@"(" withString:@""] stringByReplacingOccurrencesOfString:@")" withString:@""] componentsSeparatedByString:@","];
|
||||
|
||||
if (includeHeaders)
|
||||
{
|
||||
// Also retrieve the first headers, up to 'headersPrefetchMaxSize'
|
||||
count = [uids count];
|
||||
count = [[uids flattenedArray] count];
|
||||
if (count > headersPrefetchMaxSize) count = headersPrefetchMaxSize;
|
||||
r = NSMakeRange(0, count);
|
||||
headers = [self getHeadersForUIDs: [[uids flattenedArray] subarrayWithRange: r]
|
||||
@@ -671,7 +675,7 @@
|
||||
|
||||
- (id <WOActionResults>) getUIDsAction
|
||||
{
|
||||
NSDictionary *data;
|
||||
NSDictionary *data, *requestContent;
|
||||
NSString *noHeaders;
|
||||
SOGoMailFolder *folder;
|
||||
WORequest *request;
|
||||
@@ -679,11 +683,14 @@
|
||||
|
||||
request = [context request];
|
||||
response = [context response];
|
||||
requestContent = [[request contentAsString] objectFromJSONString];
|
||||
|
||||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
forKey: @"content-type"];
|
||||
|
||||
folder = [self clientObject];
|
||||
|
||||
noHeaders = [request formValueForKey: @"no_headers"];
|
||||
noHeaders = [[requestContent objectForKey: @"sortingAttributes"] objectForKey:@"no_headers"];
|
||||
data = [self getUIDsInFolder: folder
|
||||
withHeaders: ([noHeaders length] == 0)];
|
||||
|
||||
|
||||
@@ -119,6 +119,17 @@
|
||||
return [names jsonRepresentation];
|
||||
}
|
||||
|
||||
- (NSString *) userNames
|
||||
{
|
||||
NSArray *accounts, *userNames;
|
||||
|
||||
accounts = [[self clientObject] mailAccounts];
|
||||
userNames = [accounts objectsForKey: @"userName" notFoundMarker: nil];
|
||||
|
||||
return [userNames jsonRepresentation];
|
||||
|
||||
}
|
||||
|
||||
- (NSString *) pageFormURL
|
||||
{
|
||||
NSString *u;
|
||||
|
||||
29
UI/MailerUI/UIxMailSearch.h
Normal file
29
UI/MailerUI/UIxMailSearch.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* UIxMailSearch.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2014 Inverse inc.
|
||||
*
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <SOGoUI/UIxComponent.h>
|
||||
|
||||
@interface UIxMailSearch : UIxComponent
|
||||
{
|
||||
id item;
|
||||
|
||||
}
|
||||
@end
|
||||
91
UI/MailerUI/UIxMailSearch.m
Normal file
91
UI/MailerUI/UIxMailSearch.m
Normal file
@@ -0,0 +1,91 @@
|
||||
/* UIxMailSearch.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
|
||||
#import <UIxMailSearch.h>
|
||||
|
||||
@implementation UIxMailSearch
|
||||
|
||||
- (id) init
|
||||
{
|
||||
item = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[item release];
|
||||
}
|
||||
|
||||
- (void) setItem: (NSString *) newItem
|
||||
{
|
||||
ASSIGN(item, newItem);
|
||||
}
|
||||
|
||||
- (NSString *) item
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
- (NSArray *) mailAccountsList
|
||||
{
|
||||
SOGoMailAccount *mAccount;
|
||||
SOGoMailAccounts *mAccounts;
|
||||
NSString *userName, *option, *aString;
|
||||
NSArray *accountFolders;
|
||||
NSMutableArray *mailboxes;
|
||||
NSDictionary *accountName;
|
||||
int nbMailboxes, nbMailAccounts, i, j;
|
||||
|
||||
// Number of accounts linked with the current user
|
||||
mAccounts = [self clientObject];
|
||||
nbMailAccounts = [[mAccounts mailAccounts] count];
|
||||
|
||||
mailboxes = [NSMutableArray array];
|
||||
for (i = 0; i < nbMailAccounts; i++)
|
||||
{
|
||||
accountName = [[[mAccounts mailAccounts] objectAtIndex:i] objectForKey:@"name"]; // Keys on this account = (name, port, encryption, mailboxes, serverName, identities, userName)
|
||||
userName = [[[mAccounts mailAccounts] objectAtIndex:i] objectForKey:@"userName"];
|
||||
|
||||
aString = [NSString stringWithFormat:@"%i", i];
|
||||
mAccount = [mAccounts lookupName:aString inContext: context acquire: NO];
|
||||
accountFolders = [mAccount allFoldersMetadata];
|
||||
|
||||
// Number of mailboxes inside the current account
|
||||
nbMailboxes = [accountFolders count];
|
||||
[mailboxes addObject:accountName];
|
||||
for (j = 0; j < nbMailboxes; j++)
|
||||
{
|
||||
option = [NSString stringWithFormat:@"%@%@", userName, [[accountFolders objectAtIndex:j] objectForKey:@"displayName"]];
|
||||
[mailboxes addObject:option];
|
||||
}
|
||||
}
|
||||
return mailboxes;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -327,6 +327,10 @@
|
||||
pageName = "UIxMailMainFrame";
|
||||
actionName = "saveColumnsState";
|
||||
};
|
||||
search = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailSearch";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
title="title"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoMailSortByThreads,SOGoMailListViewColumnsOrder,SOGoMailDisplayRemoteInlineImages"
|
||||
const:userSettingsKeys="Mail"
|
||||
const:jsFiles="dtree.js,MailerUIdTree.js,SOGoAutoCompletion.js,SOGoResizableTable.js,SOGoMailDataSource.js,SOGoDataTable.js,jquery-ui.js">
|
||||
const:jsFiles="dtree.js,MailerUIdTree.js,SOGoAutoCompletion.js,SOGoResizableTable.js,SOGoMailDataSource.js,SOGoDataTable.js,jquery-ui.js, UIxMailSearch.js"
|
||||
const:cssFiles="UIxMailSearch.css">
|
||||
<script type="text/javascript">
|
||||
var mailAccounts = <var:string value="mailAccounts" const:escapeHTML="NO"/>;
|
||||
var userNames = <var:string value="userNames" const:escapeHTML="NO" />;
|
||||
var inboxData = <var:string value="inboxData" const:escapeHTML="NO"/>;
|
||||
var unseenCountFolders = <var:string value="unseenCountFolders" const:escapeHTML="NO"/>;
|
||||
</script>
|
||||
|
||||
89
UI/Templates/MailerUI/UIxMailSearch.wox
Normal file
89
UI/Templates/MailerUI/UIxMailSearch.wox
Normal file
@@ -0,0 +1,89 @@
|
||||
<?xml version='1.0' standalone='yes'?>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:uix="OGo:uix"
|
||||
xmlns:rsrc="OGo:url"
|
||||
xmlns:label="OGo:label"
|
||||
const:jsFiles="tablekit.js, tablekit-sogo.js, tablekit-trueresize.js">
|
||||
|
||||
<ul id="searchByList" class="hidden">
|
||||
<li><var:string label:value="Subject"/></li>
|
||||
<li><var:string label:value="From"/></li>
|
||||
<li><var:string label:value="To"/></li>
|
||||
<li><var:string label:value="Cc"/></li>
|
||||
<li><var:string label:value="Body"/></li>
|
||||
</ul>
|
||||
<ul id="stringArgumentsList" class="hidden">
|
||||
<li><var:string label:value="contains"/></li>
|
||||
<li><var:string label:value="does not contain"/></li>
|
||||
</ul>
|
||||
|
||||
<table id="searchMailHeader">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="mailAccountsCell">
|
||||
<label><var:string label:value="Search messages in:" /></label>
|
||||
<var:popup const:id="mailAccountsList" list="mailAccountsList" item="item" />
|
||||
</td>
|
||||
<td id="headerButtons">
|
||||
<a class="button" name="search" id="searchButton" onclick="onSearchClick()">
|
||||
<span><var:string label:value="Search"/></span></a>
|
||||
<a class="button" name="cancel" id="cancelButton" onclick="onCancelClick()">
|
||||
<span><var:string label:value="Cancel" /></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div>
|
||||
<input type="checkbox" id="searchSubfolders" checked="true" onChange="onSearchSubfoldersCheck(this);" />
|
||||
<var:string label:value="Search subfolders" /></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div>
|
||||
<input type="radio" name="matchfilters" id="matchAllFilters" value="all" onChange="onMatchFilters(this);" selection="all" />
|
||||
<var:string label:value="Match all of the following" />
|
||||
<input type="radio" name="matchfilters" id="matchAnyFilters" value="any" onChange="onMatchFilters(this);" />
|
||||
<var:string label:value="Match any of the following" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="searchFiltersList">
|
||||
<table><!-- filters --></table>
|
||||
</div>
|
||||
<div id="resultsTable">
|
||||
<table id="searchMailFooter" class="sortable messageList" cellspacing="0">
|
||||
<thead>
|
||||
<tr class="tableview">
|
||||
<td id="subjectSearchHeader" class="td_header"><var:string label:value="Subject" /></td>
|
||||
<td id="fromSearchHeader" class="td_header"><var:string label:value="From"/></td>
|
||||
<td id="toSearchHeader" class="td_header"><var:string label:value="To" /></td>
|
||||
<td id="dateSearchHeader" class="td_header"><var:string label:value="Date" /></td>
|
||||
<td id="locationSearchHeader" class="td_header"><var:string label:value="Location" /></td>
|
||||
<td id="buttonExpandHeader" class="td_header"
|
||||
><a href="#" id="listCollapse"
|
||||
><img rsrc:src="collapse.png" class="collapse" onclick="onResizeClick()"
|
||||
/></a
|
||||
></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6" id="noSearchResults"><var:string label:value="No matches found" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="optionsButtons">
|
||||
<a class="button" name="open" id="openButton" onclick="onOpenClick(this)">
|
||||
<span><var:string label:value="Open" /></span></a>
|
||||
<a class="button" name="delete" id="deleteButton" onclick="onDeleteClick(this)">
|
||||
<span><var:string label:value="Delete" /></span></a>
|
||||
</div>
|
||||
<div id="resultsFound">
|
||||
</div>
|
||||
</div>
|
||||
@@ -432,6 +432,43 @@ function onDocumentKeydown(event) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Search mail, call the template and open inside a dialog windoƒw */
|
||||
function onSearchMail(event) {
|
||||
var element = Event.findElement(event);
|
||||
if (element.disabled == false || element.disabled == undefined) {
|
||||
element.disabled = true;
|
||||
element.writeAttribute("id", "toolbarSearchButton");
|
||||
if ($("searchMailView")) {
|
||||
$("searchMailView").style.display = "block";
|
||||
$("bgDialogDiv").style.display = "block";
|
||||
initSearchMailView();
|
||||
}
|
||||
else {
|
||||
var urlstr = ApplicationBaseURL + "/search";
|
||||
|
||||
// Return the template for the searchMail feature
|
||||
triggerAjaxRequest(urlstr, displaySearchMailCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function displaySearchMailCallback(http) {
|
||||
if (http.readyState == 4 && http.status == 200) {
|
||||
var fields = createElement("div", null); // (tagName, id, classes, attributes, htmlAttributes, parentNode)
|
||||
var title = _("Search mail");
|
||||
var id = _("searchMailView");
|
||||
fields.innerHTML = http.responseText;
|
||||
|
||||
var dialog = createDialog(id, title, null, fields, "searchMail"); // (id, title, legend, content, positionClass)
|
||||
document.body.appendChild(dialog);
|
||||
|
||||
if (Prototype.Browser.IE)
|
||||
jQuery('#bgDialogDiv').css('opacity', 0.4);
|
||||
jQuery(dialog).fadeIn('fast');
|
||||
initSearchMailView();
|
||||
}
|
||||
}
|
||||
|
||||
/* bulk delete of messages */
|
||||
|
||||
function deleteSelectedMessages(sender) {
|
||||
@@ -780,7 +817,7 @@ function composeNewMessage() {
|
||||
function openMailbox(mailbox, reload) {
|
||||
if (mailbox != Mailer.currentMailbox || reload) {
|
||||
var url = ApplicationBaseURL + encodeURI(mailbox.unescapeHTML());
|
||||
var urlParams = new Hash();
|
||||
var urlParams = {};
|
||||
|
||||
if (!reload) {
|
||||
var messageContent = $("messageContent");
|
||||
@@ -791,13 +828,28 @@ function openMailbox(mailbox, reload) {
|
||||
|
||||
var searchValue = search["mail"]["value"];
|
||||
if (searchValue && searchValue.length > 0) {
|
||||
urlParams.set("search", search["mail"]["criteria"]);
|
||||
urlParams.set("value", escape(searchValue.utf8encode()));
|
||||
var searchCriteria = [];
|
||||
if (search["mail"]["criteria"] == "subject")
|
||||
searchCriteria.push("subject");
|
||||
else if (search["mail"]["criteria"] == "sender")
|
||||
searchCriteria.push("from");
|
||||
else if (search["mail"]["criteria"] == "subject_or_sender")
|
||||
searchCriteria.push("subject", "from");
|
||||
else if (search["mail"]["criteria"] == "to_or_cc")
|
||||
searchCriteria.push("to", "cc");
|
||||
else if (search["mail"]["criteria"] == "entire_message")
|
||||
searchCriteria.push("body");
|
||||
|
||||
var filters = [];
|
||||
for (i = 0; i < searchCriteria.length; i++)
|
||||
filters.push({"searchBy": searchCriteria[i], "searchArgument": "doesContain", "searchInput": searchValue});
|
||||
|
||||
urlParams.filters = filters;
|
||||
}
|
||||
var sortAttribute = sorting["attribute"];
|
||||
if (sortAttribute && sortAttribute.length > 0) {
|
||||
urlParams.set("sort", sorting["attribute"]);
|
||||
urlParams.set("asc", sorting["ascending"]);
|
||||
var sortingAttributes = {"sort":sorting["attribute"], "asc":sorting["ascending"], "match":"OR"};
|
||||
urlParams.sortingAttributes = sortingAttributes;
|
||||
|
||||
var sortHeader = $(sorting["attribute"] + "Header");
|
||||
if (sortHeader) {
|
||||
@@ -816,18 +868,15 @@ function openMailbox(mailbox, reload) {
|
||||
|
||||
var messageList = $("messageListBody").down('TBODY');
|
||||
var key = mailbox;
|
||||
if (urlParams.keys().length > 0) {
|
||||
var p = urlParams.keys().collect(function(key) { return key + "=" + urlParams.get(key); }).join("&");
|
||||
key += "?" + p;
|
||||
}
|
||||
|
||||
if (reload) {
|
||||
// Don't change data source, only query UIDs from server and refresh
|
||||
// the view. Cases that end up here:
|
||||
// - performed a search
|
||||
// - clicked on Get Mail button
|
||||
urlParams.set("no_headers", "1");
|
||||
Mailer.dataTable.load(urlParams);
|
||||
urlParams.sortingAttributes.no_headers= "1";
|
||||
var content = Object.toJSON(urlParams);
|
||||
Mailer.dataTable.load(content);
|
||||
Mailer.dataTable.refresh();
|
||||
}
|
||||
else {
|
||||
@@ -843,7 +892,8 @@ function openMailbox(mailbox, reload) {
|
||||
}
|
||||
else
|
||||
// Fetch UIDs and headers from server
|
||||
dataSource.load(urlParams);
|
||||
var content = Object.toJSON(urlParams);
|
||||
dataSource.load(content);
|
||||
// Cache data source
|
||||
Mailer.dataSources.set(key, dataSource);
|
||||
// Update unseen count
|
||||
@@ -851,8 +901,9 @@ function openMailbox(mailbox, reload) {
|
||||
}
|
||||
else {
|
||||
// Data source is cached, query only UIDs from server
|
||||
urlParams.set("no_headers", "1");
|
||||
dataSource.load(urlParams);
|
||||
urlParams.sortingAttributes.no_headers= "1";
|
||||
var content = Object.toJSON(urlParams);
|
||||
dataSource.load(content);
|
||||
}
|
||||
// Associate data source with data table and render the view
|
||||
Mailer.dataTable.setSource(dataSource);
|
||||
|
||||
@@ -118,8 +118,7 @@ var SOGoDataTableInterface = {
|
||||
load: function(urlParams) {
|
||||
if (!this.dataSource) return;
|
||||
// log ("DataTable.load() with parameters [" + urlParams.keys().join(' ') + "]");
|
||||
if (Object.isHash(urlParams) && urlParams.keys().length > 0) this.dataSource.load(urlParams);
|
||||
else this.dataSource.load(new Hash());
|
||||
this.dataSource.load(urlParams);
|
||||
},
|
||||
|
||||
visibleRowCount: function() {
|
||||
|
||||
@@ -72,22 +72,13 @@ SOGoMailDataSource = Class.create({
|
||||
// log ("MailDataSource.init() " + this.uids.length + " UIDs, " + this.cache.keys().length + " headers");
|
||||
},
|
||||
|
||||
load: function(urlParams) {
|
||||
var params;
|
||||
load: function(content) {
|
||||
this.loaded = false;
|
||||
if (urlParams.keys().length > 0) {
|
||||
params = urlParams.keys().collect(function(key) { return key + "=" + urlParams.get(key); }).join("&");
|
||||
}
|
||||
else
|
||||
params = "";
|
||||
this.id = this.url + "?" + params;
|
||||
|
||||
// log ("MailDataSource.load() " + params);
|
||||
triggerAjaxRequest(this.url + "/uids",
|
||||
this._loadCallback.bind(this),
|
||||
null,
|
||||
params,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
content,
|
||||
{ "content-type": "application/json" });
|
||||
},
|
||||
|
||||
_loadCallback: function(http) {
|
||||
|
||||
206
UI/WebServerResources/UIxMailSearch.css
Normal file
206
UI/WebServerResources/UIxMailSearch.css
Normal file
@@ -0,0 +1,206 @@
|
||||
|
||||
/*************** Table adjustment *****************/
|
||||
|
||||
TABLE#searchMailHeader
|
||||
{ width: 100%;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
DIV#searchFiltersList
|
||||
{
|
||||
border: 1px solid #909090;
|
||||
padding-top:2px;
|
||||
border-radius: 3px;
|
||||
max-height:105px;
|
||||
height:105px;
|
||||
overflow-y:auto;
|
||||
overflow-x:hidden;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
DIV#resultsTable
|
||||
{
|
||||
border: 1px solid #909090;
|
||||
margin-top:5px;
|
||||
border-radius: 3px;
|
||||
overflow-y: auto;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
TD#mailAccountsCell {
|
||||
overflow:hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
TR.filterRow, DIV#searchFiltersList > TABLE
|
||||
{
|
||||
width:100%;
|
||||
}
|
||||
|
||||
TR.filterRow > TD
|
||||
{
|
||||
width: 20%;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
TR.filterRow > TD.buttonsCell
|
||||
{
|
||||
width:5%;
|
||||
}
|
||||
|
||||
TR.filterRow > TD.inputsCell
|
||||
{
|
||||
width:55%;
|
||||
}
|
||||
|
||||
.td_table_1, .td_table_2, .td_table_3, .td_table_4 {
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
TD.sortasc {
|
||||
background:#bfc2bf;
|
||||
background-image: url(/SOGo.woa/WebServerResources/arrow-up.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position:right center;
|
||||
}
|
||||
|
||||
TD.sortdesc {
|
||||
background:#bfc2bf;
|
||||
background-image: url(/SOGo.woa/WebServerResources/arrow-down.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position:right center;
|
||||
}
|
||||
|
||||
.td_header {
|
||||
white-space:initial !important;
|
||||
border-bottom: solid #909090 1px;
|
||||
border-right: solid #909090 1px;
|
||||
height:18px;
|
||||
width:20%;
|
||||
cursor:pointer;
|
||||
background: -webkit-linear-gradient(left top, #f0f1f0 , #e6e7e6); /* For Safari 5.1 to 6.0 */
|
||||
background: -o-linear-gradient(bottom right, #f0f1f0, #e6e7e6); /* For Opera 11.1 to 12.0 */
|
||||
background: -moz-linear-gradient(bottom right, #f0f1f0, #e6e7e6); /* For Firefox 3.6 to 15 */
|
||||
background: linear-gradient(to bottom right, #f0f1f0 , #e6e7e6); /* Standard syntax */
|
||||
}
|
||||
|
||||
.td_header:hover
|
||||
{text-decoration: underline; }
|
||||
|
||||
#buttonExpandHeader {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/*************** Button adjustment *****************/
|
||||
|
||||
#headerButtons
|
||||
{
|
||||
width:175px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#searchButton, #cancelButton
|
||||
{
|
||||
margin-top:0;
|
||||
}
|
||||
|
||||
.searchByList, .searchArgumentsList, .searchInput
|
||||
{
|
||||
width:98%;
|
||||
paddin:0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
DIV#optionsButtons
|
||||
{
|
||||
position:relative;
|
||||
height:22px;
|
||||
}
|
||||
|
||||
A#deleteButton, A#openButton
|
||||
{
|
||||
float:left;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
.button
|
||||
{
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
#resizeFrame
|
||||
{
|
||||
text-align: -webkit-right;
|
||||
margin-top:1em;
|
||||
}
|
||||
|
||||
#resizeButton
|
||||
{
|
||||
display:inline-block;
|
||||
text-align: -webkit-center;
|
||||
}
|
||||
|
||||
#resultsFound {
|
||||
position:absolute;
|
||||
bottom:20px;
|
||||
right:10px;
|
||||
}
|
||||
|
||||
#listCollapse
|
||||
{ position: relative;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
#listCollapse img
|
||||
{ position: absolute; }
|
||||
|
||||
#listCollapse img.collapse
|
||||
{ clip: rect(0 18px 18px 0);
|
||||
top: 0;
|
||||
left: 0; }
|
||||
|
||||
#listCollapse img.collapse:hover
|
||||
{ clip: rect(0 36px 18px 18px);
|
||||
top: 0;
|
||||
left: -18px; }
|
||||
|
||||
#listCollapse img.rise
|
||||
{ clip: rect(18px 18px 36px 0);
|
||||
top: -18px;
|
||||
left: 0; }
|
||||
|
||||
#listCollapse img.rise:hover
|
||||
{ clip: rect(18px 36px 36px 18px);
|
||||
top: -18px;
|
||||
left: -18px; }
|
||||
|
||||
#filterButtons
|
||||
{
|
||||
width:40px;
|
||||
}
|
||||
|
||||
IMG.addFilterButton, IMG.removeFilterButton
|
||||
{
|
||||
z-index: 1;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
/* Glow */
|
||||
.glow {
|
||||
display: inline-block;
|
||||
-webkit-transition-duration: 0.3s;
|
||||
transition-duration: 0.3s;
|
||||
-webkit-transition-property: box-shadow;
|
||||
transition-property: box-shadow;
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
|
||||
}
|
||||
.glow:hover, .glow:focus, .glow:active {
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/*************** Lists *****************/
|
||||
.hidden
|
||||
{ display:none; }
|
||||
|
||||
|
||||
|
||||
492
UI/WebServerResources/UIxMailSearch.js
Normal file
492
UI/WebServerResources/UIxMailSearch.js
Normal file
@@ -0,0 +1,492 @@
|
||||
/* -*- Mode: js2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
var searchParams = {
|
||||
searchLocation: "",
|
||||
subfolder: true,
|
||||
filterMatching: "AND",
|
||||
filters: []
|
||||
};
|
||||
|
||||
// This variable allowed the user to stop the ongoing search
|
||||
var stopOngoingSearch = false;
|
||||
|
||||
/************ Search mail header ************/
|
||||
|
||||
function onSearchClick() {
|
||||
// This function updates the searchParams
|
||||
var filterRows = $$(".filterRow");
|
||||
var searchButton = $("searchButton").down().innerHTML;
|
||||
var mailAccountsList = $("mailAccountsList").options;
|
||||
|
||||
if (searchButton == _("Search")) {
|
||||
searchParams.filters = [];
|
||||
stopOngoingSearch = false;
|
||||
|
||||
// Get the mailboxe(s)
|
||||
for (i = 0; i < mailAccountsList.length ; i++) {
|
||||
if (mailAccountsList[i].selected) {
|
||||
searchParams.searchLocation = mailAccountsList[i].innerHTML;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < filterRows.length; i++){
|
||||
// Get the information from every filter row before triggering the AJAX call
|
||||
var filter = {};
|
||||
var searchByOptions = filterRows[i].down(".searchByList").options;
|
||||
var searchArgumentsOptions = filterRows[i].down(".searchArgumentsList").options;
|
||||
var searchInput = filterRows[i].down(".searchInput");
|
||||
|
||||
// Get the searchBy
|
||||
for (j = 0; j < searchByOptions.length ; j++) {
|
||||
if (searchByOptions[j].selected) {
|
||||
filter.searchBy = searchByOptions[j].innerHTML;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the searchArgument
|
||||
for (j = 0; j < searchArgumentsOptions.length ; j++) {
|
||||
if (searchArgumentsOptions[j].selected) {
|
||||
filter.searchArgument = searchArgumentsOptions[j].innerHTML;
|
||||
filter.negative = false;
|
||||
if (filter.searchArgument == "contains") {
|
||||
filter.searchArgument = "doesContain";
|
||||
}
|
||||
else if (filter.searchArgument == "does not contain") {
|
||||
filter.searchArgument = "doesContain";
|
||||
filter.negative = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the input text
|
||||
filter.searchInput = searchInput.getValue();
|
||||
|
||||
// Add the filter inside the searchParams.filters if the input is not empty
|
||||
if (!filter.searchInput.empty())
|
||||
searchParams.filters.push(filter);
|
||||
}
|
||||
// Send the request only if there is at least one filter
|
||||
if (searchParams.filters.length > 0) {
|
||||
$("searchButton").down().innerHTML = _("Stop");
|
||||
searchMails();
|
||||
}
|
||||
else
|
||||
alert(_("Please specify at least one filter"));
|
||||
}
|
||||
else {
|
||||
stopOngoingSearch = true;
|
||||
onSearchEnd();
|
||||
}
|
||||
}
|
||||
|
||||
function searchMails() {
|
||||
// Variables for the subfolders search
|
||||
var optionsList = $("mailAccountsList").options;
|
||||
var nbOptions = optionsList.length;
|
||||
var selectedIndex = optionsList.selectedIndex;
|
||||
var accountNumber, accountUser, folderPath, folderName;
|
||||
var mailAccountIndex = mailAccounts.indexOf(searchParams.searchLocation);
|
||||
|
||||
if (mailAccountIndex != -1) {
|
||||
accountNumber = "/" + mailAccountIndex;
|
||||
folderName = accountNumber + "/folderINBOX";
|
||||
accountUser = userNames[mailAccountIndex];
|
||||
folderPath = accountUser;
|
||||
}
|
||||
else {
|
||||
var searchLocation = searchParams.searchLocation.split("/");
|
||||
accountUser = searchLocation[0];
|
||||
accountNumber = "/" + userNames.indexOf(accountUser);
|
||||
|
||||
var position = searchLocation.length;
|
||||
folderName = accountNumber + "/folder" + searchLocation[1].asCSSIdentifier();
|
||||
for (i = 2; i < position; i++)
|
||||
folderName += "/folder" + searchLocation[i];
|
||||
|
||||
folderPath = optionsList[selectedIndex].innerHTML;
|
||||
}
|
||||
|
||||
var subfolders = [];
|
||||
if (searchParams.subfolder === true) {
|
||||
for (i = 0; i < nbOptions; i++) {
|
||||
if ((optionsList[i].innerHTML.search(folderPath) != -1) && (i != selectedIndex)) {
|
||||
var splitArray = optionsList[i].innerHTML.split("/");
|
||||
// Remove the user information since it is not required
|
||||
splitArray.splice(0, 1);
|
||||
var subfolder = [];
|
||||
var level = splitArray.length;
|
||||
for(j = 0; j < level; j++) {
|
||||
subfolder += "/folder" + splitArray[j];
|
||||
}
|
||||
subfolders.push(accountNumber + subfolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var urlstr = (ApplicationBaseURL + folderName + "/uids");
|
||||
var callbackData = {"folderName" : folderName, "subfolders" : subfolders, "newSearch" : true};
|
||||
var object = {"filters":searchParams.filters, "sortingAttributes":{"match":searchParams.filterMatching}};
|
||||
var content = Object.toJSON(object);
|
||||
document.searchMailsAjaxRequest = triggerAjaxRequest(urlstr, searchMailsCallback, callbackData, content, {"content-type": "application/json"});
|
||||
}
|
||||
|
||||
function searchMailsCallback(http) {
|
||||
if (http.readyState == 4 && http.status == 200 && !stopOngoingSearch) {
|
||||
var response = http.responseText.evalJSON();
|
||||
var table = $("searchMailFooter").down("tbody");
|
||||
|
||||
// Erase all previous entries before proceeding with the current request
|
||||
if (http.callbackData.newSearch) {
|
||||
var oldEntries = table.rows;
|
||||
var count = oldEntries.length - 1;
|
||||
for (var x = count; x >= 0; x--){
|
||||
$(oldEntries[x]).remove();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ["To", "Attachment", "Flagged", "Subject", "From", "Unread", "Priority", "Date", "Size", "rowClasses", "labels", "rowID", "uid"]
|
||||
if (response.headers.length > 1) {
|
||||
if ($("noSearchResults"))
|
||||
$("noSearchResults").remove();
|
||||
|
||||
for (var i = 1; i < response.headers.length; i++) { // Starts at 1 because the position 0 in the array are the headers of the table
|
||||
var row = document.createElement("tr");
|
||||
Element.addClassName(row, "resultsRow");
|
||||
row.setAttribute("uid", response.headers[i][12]);
|
||||
row.setAttribute("folderName", http.callbackData.folderName);
|
||||
|
||||
var cell1 = document.createElement("td");
|
||||
Element.addClassName(cell1, "td_table_1");
|
||||
cell1.innerHTML = response.headers[i][3];
|
||||
row.appendChild(cell1);
|
||||
|
||||
var cell2 = document.createElement("td");
|
||||
Element.addClassName(cell2, "td_table_2");
|
||||
cell2.innerHTML = response.headers[i][4];
|
||||
row.appendChild(cell2);
|
||||
|
||||
var cell3 = document.createElement("td");
|
||||
Element.addClassName(cell3, "td_table_3");
|
||||
cell3.innerHTML = response.headers[i][0];
|
||||
row.appendChild(cell3);
|
||||
|
||||
var cell4 = document.createElement("td");
|
||||
Element.addClassName(cell4, "td_table_4");
|
||||
cell4.innerHTML = response.headers[i][7];
|
||||
row.appendChild(cell4);
|
||||
|
||||
var cell5 = document.createElement("td");
|
||||
Element.addClassName(cell5, "td_table_5");
|
||||
cell5.setAttribute("colspan", "2");
|
||||
var folderPath = http.callbackData.folderName.split("/");
|
||||
var folderLocation = folderPath[folderPath.length - 1]; // get the last element of the array (location)
|
||||
folderLocation = folderLocation.substr(6); // strip down the prefix folder
|
||||
cell5.innerHTML = folderLocation;
|
||||
row.appendChild(cell5);
|
||||
|
||||
table.appendChild(row);
|
||||
}
|
||||
|
||||
}
|
||||
else if (http.callbackData.newSearch) {
|
||||
if (!table.down("tr")) {
|
||||
var row = table.insertRow(0);
|
||||
var cell = row.insertCell(0);
|
||||
var element = document.createElement("span");
|
||||
|
||||
cell.setAttribute("id", "noSearchResults");
|
||||
cell.setAttribute("colspan", "4");
|
||||
element.innerHTML = _("No matches found");
|
||||
cell.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (http.callbackData.subfolders.length > 0) {
|
||||
var folderName = http.callbackData.subfolders[0];
|
||||
var subfolders = http.callbackData.subfolders;
|
||||
subfolders.splice(0, 1);
|
||||
|
||||
var urlstr = (ApplicationBaseURL + folderName + "/uids");
|
||||
var callbackData = {"folderName" : folderName, "subfolders" : subfolders, "newSearch" : false};
|
||||
|
||||
// TODO - need to add these following contents ; asc, no-headers, sort
|
||||
var object = {"filters":searchParams.filters, "sortingAttributes":{"match":searchParams.filterMatching}};
|
||||
var content = Object.toJSON(object);
|
||||
document.searchMailsAjaxRequest = triggerAjaxRequest(urlstr, searchMailsCallback, callbackData, content, {"content-type": "application/json"});
|
||||
}
|
||||
else {
|
||||
onSearchEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSearchEnd() {
|
||||
$("searchButton").down().innerHTML = _("Search");
|
||||
var nbResults = $$(".resultsRow").length;
|
||||
if (nbResults == 1)
|
||||
$("resultsFound").innerHTML = nbResults + " " + _("result found");
|
||||
else if (nbResults > 0)
|
||||
$("resultsFound").innerHTML = nbResults + " " + _("results found");
|
||||
else
|
||||
$("resultsFound").innerHTML = "";
|
||||
|
||||
TableKit.reloadSortableTable($("searchMailFooter"));
|
||||
$("buttonExpandHeader").addClassName("nosort");
|
||||
}
|
||||
|
||||
function onCancelClick() {
|
||||
disposeDialog();
|
||||
$("searchMailView").remove();
|
||||
$("toolbarSearchButton").disabled = false;
|
||||
|
||||
}
|
||||
|
||||
function onSearchSubfoldersCheck(event) {
|
||||
searchParams.subfolder = (event.checked ? true : false);
|
||||
}
|
||||
|
||||
function onMatchFilters(event) {
|
||||
searchParams.filterMatching = ((event.getAttribute("id") == "matchAllFilters") ? "AND" : "OR");
|
||||
}
|
||||
|
||||
/**** Search mail body ****/
|
||||
|
||||
function onAddFilter() {
|
||||
var table = $("searchFiltersList").down("TABLE");
|
||||
var searchByList = $("searchByList").getElementsByTagName("li");
|
||||
var stringArgumentsList = $("stringArgumentsList").getElementsByTagName("li");
|
||||
|
||||
var rowCount = table.rows.length;
|
||||
var row = table.insertRow(rowCount);
|
||||
Element.addClassName(row, "filterRow");
|
||||
|
||||
var cell1 = row.insertCell(0);
|
||||
var element1 = document.createElement("select");
|
||||
Element.addClassName(element1, "searchByList");
|
||||
element1.setAttribute("id", "searchByListRow" + rowCount);
|
||||
for (var i = 0; i < searchByList.length; i++) {
|
||||
var option = document.createElement("option");
|
||||
option.innerHTML = searchByList[i].innerHTML;
|
||||
element1.appendChild(option);
|
||||
}
|
||||
cell1.appendChild(element1);
|
||||
|
||||
var cell2 = row.insertCell(1);
|
||||
var element2 = document.createElement("select");
|
||||
Element.addClassName(element2, "searchArgumentsList");
|
||||
element2.setAttribute("id", "searchArgumentsListRow" + rowCount);
|
||||
for (var i = 0; i < stringArgumentsList.length; i++) {
|
||||
var option = document.createElement("option");
|
||||
option.innerHTML = stringArgumentsList[i].innerHTML;
|
||||
element2.appendChild(option);
|
||||
}
|
||||
cell2.appendChild(element2);
|
||||
|
||||
var cell3 = row.insertCell(2);
|
||||
Element.addClassName(cell3, "inputsCell");
|
||||
var element3 = document.createElement("input");
|
||||
Element.addClassName(element3, "searchInput");
|
||||
element3.setAttribute("type", "text");
|
||||
element3.setAttribute("name", "searchInput");
|
||||
element3.setAttribute("id", "searchInputRow" + rowCount);
|
||||
cell3.appendChild(element3);
|
||||
|
||||
var cell4 = row.insertCell(3);
|
||||
Element.addClassName(cell4, "buttonsCell");
|
||||
cell4.setAttribute("align", "center");
|
||||
|
||||
var buttonsDiv = document.createElement("div");
|
||||
var imageAddFilter = document.createElement("img");
|
||||
var imageRemoveFilter = document.createElement("img");
|
||||
imageAddFilter.setAttribute("src", "/SOGo.woa/WebServerResources/add-icon.png");
|
||||
imageRemoveFilter.setAttribute("src", "/SOGo.woa/WebServerResources/remove-icon.png");
|
||||
Element.addClassName(imageAddFilter, "addFilterButton");
|
||||
Element.addClassName(imageAddFilter, "glow");
|
||||
Element.addClassName(imageRemoveFilter, "removeFilterButton");
|
||||
Element.addClassName(imageRemoveFilter, "glow");
|
||||
imageAddFilter.setAttribute("name", "addFilter");
|
||||
imageAddFilter.setAttribute("id", "addFilterButtonRow" + rowCount);
|
||||
$(imageAddFilter).on("click", onAddFilter);
|
||||
imageRemoveFilter.setAttribute("name", "removeFilter");
|
||||
imageRemoveFilter.setAttribute("id", "removeFilterButtonRow" + rowCount);
|
||||
$(imageRemoveFilter).on("click", onRemoveFilter);
|
||||
buttonsDiv.setAttribute("id", "filterButtons");
|
||||
|
||||
buttonsDiv.appendChild(imageAddFilter);
|
||||
buttonsDiv.appendChild(imageRemoveFilter);
|
||||
|
||||
cell4.appendChild(buttonsDiv);
|
||||
}
|
||||
|
||||
function onRemoveFilter() {
|
||||
var rows = $("searchFiltersList").getElementsByTagName("tr");
|
||||
var currentRow = this.up(".filterRow");
|
||||
|
||||
if(rows.length > 1)
|
||||
$(currentRow).remove();
|
||||
}
|
||||
|
||||
/**** Search mail Footer ****/
|
||||
|
||||
function onResultSelectionChange(event) {
|
||||
var table = $("searchMailFooter").down("tbody");
|
||||
|
||||
if (event && (event.target.innerHTML != _("No matches found"))) {
|
||||
var node = getTarget(event);
|
||||
|
||||
if (node.tagName == "SPAN")
|
||||
node = node.parentNode;
|
||||
|
||||
// Update rows selection
|
||||
onRowClick(event, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**** Search mail optionsButtons ****/
|
||||
|
||||
function onOpenClick(event) {
|
||||
// This function is linked with the openButton and the doubleClick on a message
|
||||
var selectedRow = $("searchMailFooter").down("._selected");
|
||||
var msguid = selectedRow.getAttribute("uid");
|
||||
var folderName = selectedRow.getAttribute("folderName");
|
||||
var accountUser = userNames[0];
|
||||
|
||||
var url = "/SOGo/so/" + accountUser + "/Mail" + folderName + "/" + msguid + "/popupview";
|
||||
if (selectedRow) {
|
||||
openMessageWindow(msguid, url);
|
||||
}
|
||||
}
|
||||
|
||||
function onDeleteClick(event) {
|
||||
var messageList = $("resultsTable").down("TABLE");
|
||||
var row = $(messageList).getSelectedRows()[0];
|
||||
if (row) {
|
||||
var rowIds = row.getAttribute("uid");
|
||||
var uids = new Array(); // message IDs
|
||||
var paths = new Array(); // row IDs
|
||||
var unseenCount = 0;
|
||||
var refreshFolder = false;
|
||||
if (rowIds) {
|
||||
messageList.deselectAll();
|
||||
if (unseenCount < 1) {
|
||||
if (row.hasClassName("mailer_unreadmail"))
|
||||
unseenCount--;
|
||||
else
|
||||
unseenCount = 1;
|
||||
|
||||
$(row).remove();
|
||||
}
|
||||
var uid = rowIds;
|
||||
var path = Mailer.currentMailbox + "/" + uid;
|
||||
uids.push(uid);
|
||||
paths.push(path);
|
||||
deleteMessageRequestCount++;
|
||||
|
||||
deleteCachedMessage(path);
|
||||
if (Mailer.currentMessages[Mailer.currentMailbox] == uid) {
|
||||
if (messageContent) messageContent.innerHTML = '';
|
||||
Mailer.currentMessages[Mailer.currentMailbox] = null;
|
||||
}
|
||||
Mailer.dataTable.remove(uid);
|
||||
updateMessageListCounter(0 - rowIds.length, true);
|
||||
if (unseenCount < 0) {
|
||||
var node = mailboxTree.getMailboxNode(Mailer.currentMailbox);
|
||||
if (node) {
|
||||
updateUnseenCount(node, unseenCount, true);
|
||||
}
|
||||
}
|
||||
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/batchDelete";
|
||||
var parameters = "uid=" + uids.join(",");
|
||||
var data = { "id": uids, "mailbox": Mailer.currentMailbox, "path": paths, "refreshUnseenCount": (unseenCount > 0), "refreshFolder": refreshFolder };
|
||||
triggerAjaxRequest(url, deleteMessageCallback, data, parameters,
|
||||
{ "Content-type": "application/x-www-form-urlencoded" });
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function deleteMessageCallback (http){
|
||||
if (isHttpStatus204(http.status) || http.status == 200) {
|
||||
var data = http.callbackData;
|
||||
if (http.status == 200) {
|
||||
// The answer contains quota information
|
||||
var rdata = http.responseText.evalJSON(true);
|
||||
if (rdata.quotas && data["mailbox"].startsWith('/0/'))
|
||||
updateQuotas(rdata.quotas);
|
||||
}
|
||||
if (data["refreshUnseenCount"])
|
||||
// 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"),
|
||||
_("The messages could not be moved to the trash folder. Would you like to delete them immediately?"),
|
||||
deleteMessagesWithoutTrash.bind(document, http.callbackData),
|
||||
function() { refreshCurrentFolder(); disposeDialog(); });
|
||||
}
|
||||
else {
|
||||
var html = new Element('div').update(http.responseText);
|
||||
log ("Messages deletion failed (" + http.status + ") : ");
|
||||
log (html.down('p').innerHTML);
|
||||
showAlertDialog(_("Operation failed"));
|
||||
refreshCurrentFolder();
|
||||
}
|
||||
onSearchEnd();
|
||||
}
|
||||
|
||||
function onResizeClick() {
|
||||
var searchFiltersList = jQuery("#searchFiltersList");
|
||||
var img = $("listCollapse").select('img').first();
|
||||
var dialogWindowHeight = $("searchMailView").getHeight();
|
||||
var state = "collapse";
|
||||
|
||||
if (searchFiltersList[0].visible()) {
|
||||
state = "rise";
|
||||
searchFiltersList.fadeOut(300, function() {
|
||||
adjustResultsTable(state);
|
||||
img.removeClassName('collapse').addClassName('rise');
|
||||
});
|
||||
}
|
||||
else {
|
||||
adjustResultsTable(state);
|
||||
searchFiltersList.fadeIn();
|
||||
img.removeClassName('rise').addClassName('collapse');
|
||||
}
|
||||
}
|
||||
|
||||
function adjustResultsTable(state) {
|
||||
var resultsTable = $("resultsTable");
|
||||
var height = "innerHeight" in $("searchMailView") ? $("searchMailView").innerHeight : $("searchMailView").offsetHeight;
|
||||
if (state == "collapse") {
|
||||
height -= 266;
|
||||
}
|
||||
else
|
||||
height -= 152;
|
||||
$(resultsTable).style.height = height + "px";
|
||||
}
|
||||
|
||||
/*************** Init ********************/
|
||||
|
||||
function initSearchMailView () {
|
||||
|
||||
// Add one filterRow
|
||||
onAddFilter();
|
||||
adjustResultsTable("collapse");
|
||||
|
||||
// Observers : Event.on(element, eventName[, selector], callback)
|
||||
$("searchMailFooter").down("tbody").on("mousedown", "tr", onResultSelectionChange);
|
||||
$("searchMailFooter").down("tbody").on("dblclick", "tr", onOpenClick);
|
||||
Event.observe(window, "resize", function() {
|
||||
var state = ($("searchFiltersList").visible() ? "collapse": "rise");
|
||||
adjustResultsTable(state);
|
||||
});
|
||||
}
|
||||
@@ -659,6 +659,19 @@ DIV.dialog > DIV
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
DIV.dialog.searchMail {
|
||||
position: relative;
|
||||
padding: 0px;
|
||||
opacity: 1;
|
||||
width: 75%;
|
||||
height: 75%;
|
||||
margin: 2em auto;
|
||||
}
|
||||
|
||||
DIV.dialog.searchMail > DIV {
|
||||
min-height:500px;
|
||||
}
|
||||
|
||||
DIV.dialog.none
|
||||
{ position: relative;
|
||||
margin: 0px;
|
||||
|
||||
@@ -1998,7 +1998,7 @@ function createDialog(id, title, legend, content, positionClass) {
|
||||
var newDialog = createElement("div", id, ["dialog", positionClass]);
|
||||
newDialog.setStyle({"display": "none"});
|
||||
|
||||
if (positionClass == "none") {
|
||||
if (positionClass == "none" || positionClass == "searchMail") {
|
||||
var bgDiv = $("bgDialogDiv");
|
||||
if (bgDiv) {
|
||||
bgDiv.show();
|
||||
|
||||
@@ -242,6 +242,12 @@ Object.extend(TableKit, {
|
||||
if(op.resizable) {TableKit.Resizable.init(table);}
|
||||
if(op.editable) {TableKit.Editable.init(table);}
|
||||
},
|
||||
reloadSortableTable : function(table){
|
||||
table = $(table);
|
||||
TableKit.unloadTable(table);
|
||||
var op = TableKit.option('sortable', table.id);
|
||||
if(op.sortable) {TableKit.Sortable.init(table);}
|
||||
},
|
||||
reload : function() {
|
||||
for(var k in TableKit.tables) {
|
||||
TableKit.reloadTable(k);
|
||||
|
||||
Reference in New Issue
Block a user