mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-09 08:53:20 +00:00
Improve display of mail advanced search
This commit is contained in:
@@ -43,6 +43,18 @@
|
||||
"Copy To" = "Copy To";
|
||||
"Add to:" = "Add to:";
|
||||
|
||||
/* Subheader of empty addressbook */
|
||||
"No contact" = "No contact";
|
||||
|
||||
/* Number of contacts in addressbook; string is prefixed by number */
|
||||
"contacts" = "contacts";
|
||||
|
||||
/* No contact matching search criteria */
|
||||
"No matching contact" = "No matching contact";
|
||||
|
||||
/* Number of contacts matching search criteria; string is prefixed by number */
|
||||
"matching contacts" = "matching contacts";
|
||||
|
||||
/* Number of selected contacts in list */
|
||||
"selected" = "selected";
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
<md-icon>arrow_back</md-icon>
|
||||
</md-button>
|
||||
<md-input-container>
|
||||
<input name="folderSearch" type="search" />
|
||||
<input name="folderSearch" type="search" ng-minlength="3"/>
|
||||
</md-input-container>
|
||||
<md-input-container>
|
||||
<md-select>
|
||||
@@ -327,10 +327,22 @@
|
||||
</md-toolbar>
|
||||
|
||||
<md-content id="contactsList" layout="column" class="md-flex">
|
||||
<md-subheader>
|
||||
<md-subheader ng-show="addressbook.service.$query.value">
|
||||
<span ng-switch="addressbook.selectedFolder.cards.length">
|
||||
<span ng-switch-when="0"><var:string label:value="No contact"/></span>
|
||||
<span ng-switch-default="true">{{addressbook.selectedFolder.cards.length}} <var:string label:value="contacts"/></span>
|
||||
<span ng-switch-when="0"><var:string label:value="No matching contact"/></span>
|
||||
<span ng-switch-default="true">{{addressbook.selectedFolder.cards.length}} <var:string label:value="matching contacts"/></span>
|
||||
</span>
|
||||
</md-subheader>
|
||||
<md-subheader ng-hide="addressbook.service.$query.value"
|
||||
ng-switch="addressbook.selectedFolder.isRemote">
|
||||
<span ng-switch-when="1">
|
||||
<var:string label:value="Start a search to browse this address book"/>
|
||||
</span>
|
||||
<span ng-switch-default="true">
|
||||
<span ng-switch="addressbook.selectedFolder.cards.length">
|
||||
<span ng-switch-when="0"><var:string label:value="No contact"/></span>
|
||||
<span ng-switch-default="true">{{addressbook.selectedFolder.cards.length}} <var:string label:value="contacts"/></span>
|
||||
</span>
|
||||
</span>
|
||||
</md-subheader>
|
||||
<md-virtual-repeat-container class="md-flex">
|
||||
|
||||
@@ -7,6 +7,56 @@
|
||||
|
||||
<!-- in virtual mailbox mode -->
|
||||
<md-toolbar ng-hide="!app.showingAdvancedSearch || mailbox.selectedFolder.$selectedCount() > 0">
|
||||
<div class="md-toolbar-tools">
|
||||
<md-input-container>
|
||||
<label><var:string label:value="Search messages in"/></label>
|
||||
<md-select ng-model="app.search.mailbox">
|
||||
<md-option ng-value="">
|
||||
<span>{{app.accounts[0].name}}</span>
|
||||
</md-option>
|
||||
<md-option ng-repeat="folder in
|
||||
app.accounts[0].$flattenMailboxes()
|
||||
track by folder.path"
|
||||
ng-value="folder.path">
|
||||
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
|
||||
</md-option>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
<md-menu>
|
||||
<md-button class="sg-icon-button" label:aria-label="More search options" ng-click="$mdOpenMenu()">
|
||||
<md-icon>settings</md-icon>
|
||||
</md-button>
|
||||
<md-menu-content>
|
||||
<md-menu-item>
|
||||
<md-button ng-href="#">
|
||||
<md-checkbox ng-model="app.search.subfolders"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<var:string label:value="Search subfolders"/>
|
||||
</md-checkbox>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button ng-click="app.search.match='AND'">
|
||||
<md-icon ng-class="{ 'icon-check': app.search.match == 'AND'}">
|
||||
<!-- all --></md-icon><var:string label:value="Match all of the following"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button ng-click="app.search.match='OR'">
|
||||
<md-icon ng-class="{ 'icon-check': app.search.match == 'OR'}">
|
||||
<!-- any --></md-icon><var:string label:value="Match any of the following"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
</md-menu-content>
|
||||
</md-menu>
|
||||
<md-button class="sg-icon-button"
|
||||
ng-click="app.toggleAdvancedSearch()"
|
||||
ng-disabled="app.search.params.length == 0">
|
||||
<md-icon ng-class="{'icon-stop': app.service.selectedFolder.$isLoading,
|
||||
'icon-search': !app.service.selectedFolder.$isLoading}"><!-- icon --></md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<!-- single-selection toolbars -->
|
||||
<md-toolbar ng-hide="app.showingAdvancedSearch || mailbox.selectedFolder.$selectedCount() > 0">
|
||||
@@ -72,7 +122,7 @@
|
||||
<md-icon>arrow_back</md-icon>
|
||||
</md-button>
|
||||
<md-input-container>
|
||||
<input name="folderSearch" type="search" />
|
||||
<input name="folderSearch" type="search" ng-minlength="3"/>
|
||||
</md-input-container>
|
||||
<md-input-container>
|
||||
<md-select>
|
||||
@@ -176,7 +226,8 @@
|
||||
<span class="msg-date"
|
||||
ng-bind-html="currentMessage.relativedate"><!-- date --></span>
|
||||
<div class="sg-md-subhead-multi">
|
||||
<span ng-show="mailbox.service.$virtualMode">({{currentMessage.$mailbox.path}})</span>
|
||||
<span class="sg-label-outline"
|
||||
ng-show="mailbox.service.$virtualMode">{{currentMessage.$mailbox.name}}</span>
|
||||
{{currentMessage.$shortAddress('from')}}
|
||||
</div>
|
||||
<div class="sg-md-body-multi">{{currentMessage.subject}}</div>
|
||||
|
||||
@@ -351,100 +351,56 @@
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="UIxMailFolderTemplate">
|
||||
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main" ng-hide="app.showingAdvancedSearch">
|
||||
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main"
|
||||
ng-hide="app.showingAdvancedSearch">
|
||||
<var:component className="UIxTopnavToolbarTemplate"/>
|
||||
</md-toolbar>
|
||||
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main" ng-show="app.showingAdvancedSearch">
|
||||
<div class="sg-padded" layout="column">
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<md-input-container>
|
||||
<label><var:string label:value="Search messages in"/></label>
|
||||
<md-select ng-model="app.search.mailbox">
|
||||
<md-option ng-value="">
|
||||
<span>{{app.accounts[0].name}}</span>
|
||||
</md-option>
|
||||
<md-option ng-repeat="folder in
|
||||
app.accounts[0].$flattenMailboxes()
|
||||
track by folder.path"
|
||||
ng-value="folder.path">
|
||||
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
|
||||
</md-option>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
<md-menu>
|
||||
<md-button class="sg-icon-button" label:aria-label="More search options" ng-click="$mdOpenMenu()">
|
||||
<md-icon>settings</md-icon>
|
||||
</md-button>
|
||||
<md-menu-content>
|
||||
<md-menu-item>
|
||||
<md-button ng-href="#">
|
||||
<md-checkbox ng-model="app.search.subfolders"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<var:string label:value="Search subfolders"/>
|
||||
</md-checkbox>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button ng-click="app.search.match='AND'">
|
||||
<md-icon ng-class="{ 'icon-check': app.search.match == 'AND'}">
|
||||
<!-- all --></md-icon><var:string label:value="Match all of the following"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button ng-click="app.search.match='OR'">
|
||||
<md-icon ng-class="{ 'icon-check': app.search.match == 'OR'}">
|
||||
<!-- any --></md-icon><var:string label:value="Match any of the following"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
</md-menu-content>
|
||||
</md-menu>
|
||||
<md-chips ng-model="app.search.params"
|
||||
md-on-append="app.newSearchParam($chip)">
|
||||
<input type="text" ng-disabled="app.currentSearchParam.length == 0" sg-placeholder="app.search.options[app.currentSearchParam]"/>
|
||||
<md-chip-template>
|
||||
<span class="md-caption" ng-show="$chip.negative == 0">(match</span>
|
||||
<span class="md-caption" ng-show="$chip.negative == 1">(does not match</span>
|
||||
<span class="md-caption">{{$chip.searchBy}})</span>
|
||||
<span>{{$chip.searchInput}}</span>
|
||||
</md-chip-template>
|
||||
</md-chips>
|
||||
</div>
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<md-button type="button" ng-click="app.addSearchParam('subject')">
|
||||
<var:string label:value="Subject"/>
|
||||
</md-button>
|
||||
<md-button type="button" ng-click="app.addSearchParam('from')">
|
||||
<var:string label:value="From"/>
|
||||
</md-button>
|
||||
<md-button type="button" ng-click="app.addSearchParam('to')">
|
||||
<var:string label:value="To"/>
|
||||
</md-button>
|
||||
<md-button type="button" ng-click="app.addSearchParam('cc')">
|
||||
<var:string label:value="Cc"/>
|
||||
</md-button>
|
||||
<md-button type="button" ng-click="app.addSearchParam('body')">
|
||||
<var:string label:value="Body"/>
|
||||
</md-button>
|
||||
<div class="md-flex"><!-- spacer --></div>
|
||||
<md-button type="button" class="sg-button"
|
||||
ng-disabled="app.search.params.length == 0"
|
||||
ng-hide="app.service. selectedFolder.$isLoading"
|
||||
ng-click="app.startAdvancedSearch()">
|
||||
<md-icon>search</md-icon>
|
||||
</md-button>
|
||||
<md-button type="button" class="sg-button"
|
||||
ng-show="app.service.selectedFolder.$isLoading"
|
||||
ng-click="app.stopAdvancedSearch()">
|
||||
<md-icon>stop</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sg-toolbar-group-last">
|
||||
<md-button type="button" class="sg-button" ng-click="app.hideAdvancedSearch()">
|
||||
|
||||
<!-- Advanced search toolbar -->
|
||||
<md-toolbar layout="column" class="md-tall toolbar-main"
|
||||
ng-show="app.showingAdvancedSearch">
|
||||
<div class="md-toolbar-tools">
|
||||
<md-chips class="md-flex"
|
||||
ng-model="app.search.params"
|
||||
md-on-append="app.newSearchParam($chip)">
|
||||
<input sg-focus-on="advancedSearch" type="text"
|
||||
ng-disabled="app.currentSearchParam.length == 0"
|
||||
sg-placeholder="app.search.options[app.currentSearchParam]"/>
|
||||
<md-chip-template>
|
||||
<span class="md-caption" ng-show="$chip.negative == 0">(match</span>
|
||||
<span class="md-caption" ng-show="$chip.negative == 1">(does not match</span>
|
||||
<span class="md-caption">{{$chip.searchBy}})</span>
|
||||
<span>{{$chip.searchInput}}</span>
|
||||
</md-chip-template>
|
||||
</md-chips>
|
||||
<md-button type="button" class="sg-icon-button" ng-click="app.hideAdvancedSearch()">
|
||||
<md-icon>close</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
<div class="md-toolbar-tools">
|
||||
<div layout="column">
|
||||
<div class="pseudo-input-container--compact">
|
||||
<label class="pseudo-input-label"><var:string label:value="Add a Criteria"/></label>
|
||||
</div>
|
||||
<div layout="row">
|
||||
<a class="sg-outline-button" href="#" ng-click="app.addSearchParam('subject')">
|
||||
<var:string label:value="Subject"/>
|
||||
</a>
|
||||
<a class="sg-outline-button" href="#" ng-click="app.addSearchParam('from')">
|
||||
<var:string label:value="From"/>
|
||||
</a>
|
||||
<a class="sg-outline-button" href="#" ng-click="app.addSearchParam('to')">
|
||||
<var:string label:value="To"/>
|
||||
</a>
|
||||
<a class="sg-outline-button" href="#" ng-click="app.addSearchParam('cc')">
|
||||
<var:string label:value="Cc"/>
|
||||
</a>
|
||||
<a class="sg-outline-button" href="#" ng-click="app.addSearchParam('body')">
|
||||
<var:string label:value="Body"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
|
||||
<div layout="row" class="md-flex">
|
||||
|
||||
@@ -89,11 +89,11 @@
|
||||
// First session query
|
||||
AddressBook.$cards = [];
|
||||
}
|
||||
else if (AddressBook.$query == search) {
|
||||
else if (AddressBook.$query.value == search) {
|
||||
// Query hasn't changed
|
||||
return AddressBook.$q.when(AddressBook.$cards);
|
||||
}
|
||||
AddressBook.$query = search;
|
||||
AddressBook.$query.value = search;
|
||||
|
||||
angular.extend(params, options);
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
AddressBook.$cards.splice(index, 0, card);
|
||||
}
|
||||
});
|
||||
AddressBook.$log.debug(AddressBook.$cards);
|
||||
return AddressBook.$cards;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
AddressBook.selectedFolder = stateAddressbook;
|
||||
|
||||
vm.service = AddressBook;
|
||||
vm.selectedFolder = stateAddressbook;
|
||||
vm.selectCard = selectCard;
|
||||
vm.toggleCardSelection = toggleCardSelection;
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
vm.newSearchParam = newSearchParam;
|
||||
vm.showAdvancedSearch = showAdvancedSearch;
|
||||
vm.hideAdvancedSearch = hideAdvancedSearch;
|
||||
vm.startAdvancedSearch = startAdvancedSearch;
|
||||
vm.stopAdvancedSearch = stopAdvancedSearch;
|
||||
vm.toggleAdvancedSearch = toggleAdvancedSearch;
|
||||
vm.search = {
|
||||
options: {'': l('Select a criteria'),
|
||||
subject: l('Enter Subject'),
|
||||
@@ -67,49 +66,51 @@
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
|
||||
}
|
||||
|
||||
function startAdvancedSearch() {
|
||||
var root, mailboxes = [],
|
||||
_visit = function(folders) {
|
||||
_.each(folders, function(o) {
|
||||
mailboxes.push(o);
|
||||
if (o.children && o.children.length > 0) {
|
||||
_visit(o.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
vm.virtualMailbox = new VirtualMailbox(vm.accounts[0]);
|
||||
|
||||
// Don't set the previous selected mailbox if we're in virtual mode
|
||||
// That allows users to do multiple advanced search but return
|
||||
// correctly to the previously selected mailbox once done.
|
||||
if (!Mailbox.$virtualMode)
|
||||
vm.searchPreviousMailbox = Mailbox.selectedFolder;
|
||||
|
||||
Mailbox.selectedFolder = vm.virtualMailbox;
|
||||
Mailbox.$virtualMode = true;
|
||||
|
||||
if (angular.isDefined(vm.search.mailbox)) {
|
||||
root = vm.accounts[0].$getMailboxByPath(vm.search.mailbox);
|
||||
mailboxes.push(root);
|
||||
if (vm.search.subfolders && root.children.length)
|
||||
_visit(root.children);
|
||||
function toggleAdvancedSearch() {
|
||||
if (Mailbox.selectedFolder.$isLoading) {
|
||||
vm.virtualMailbox.stopSearch();
|
||||
}
|
||||
else {
|
||||
mailboxes = vm.accounts[0].$flattenMailboxes();
|
||||
var root, mailboxes = [],
|
||||
_visit = function(folders) {
|
||||
_.each(folders, function(o) {
|
||||
mailboxes.push(o);
|
||||
if (o.children && o.children.length > 0) {
|
||||
_visit(o.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
vm.virtualMailbox = new VirtualMailbox(vm.accounts[0]);
|
||||
|
||||
// Don't set the previous selected mailbox if we're in virtual mode
|
||||
// That allows users to do multiple advanced search but return
|
||||
// correctly to the previously selected mailbox once done.
|
||||
if (!Mailbox.$virtualMode)
|
||||
vm.searchPreviousMailbox = Mailbox.selectedFolder;
|
||||
|
||||
Mailbox.selectedFolder = vm.virtualMailbox;
|
||||
Mailbox.$virtualMode = true;
|
||||
|
||||
if (angular.isDefined(vm.search.mailbox)) {
|
||||
root = vm.accounts[0].$getMailboxByPath(vm.search.mailbox);
|
||||
mailboxes.push(root);
|
||||
if (vm.search.subfolders && root.children.length)
|
||||
_visit(root.children);
|
||||
}
|
||||
else {
|
||||
mailboxes = vm.accounts[0].$flattenMailboxes();
|
||||
}
|
||||
|
||||
vm.virtualMailbox.setMailboxes(mailboxes);
|
||||
vm.virtualMailbox.startSearch(vm.search.match, vm.search.params);
|
||||
$state.go('mail.account.virtualMailbox', { accountId: vm.accounts[0].id });
|
||||
}
|
||||
|
||||
vm.virtualMailbox.setMailboxes(mailboxes);
|
||||
vm.virtualMailbox.startSearch(vm.search.match, vm.search.params);
|
||||
$state.go('mail.account.virtualMailbox', { accountId: vm.accounts[0].id });
|
||||
}
|
||||
|
||||
function stopAdvancedSearch() {
|
||||
vm.virtualMailbox.stopSearch();
|
||||
}
|
||||
|
||||
function addSearchParam(v) {
|
||||
vm.currentSearchParam = v;
|
||||
focus('advancedSearch');
|
||||
}
|
||||
|
||||
function newSearchParam(v) {
|
||||
|
||||
@@ -129,3 +129,14 @@ md-list md-list-item button.md-button.sg-icon-button {
|
||||
padding: 0;
|
||||
font-size: $iconButton-menu-size;
|
||||
}
|
||||
|
||||
.sg-outline-button {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: $button-border-radius;
|
||||
margin: rem(0.500);
|
||||
padding: rem(0.500);
|
||||
font-size: $sg-font-size-1;
|
||||
font-weight: $sg-font-medium;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -108,12 +108,18 @@ md-icon {
|
||||
&.icon-remove-circle:before {
|
||||
content: "\e15c";
|
||||
}
|
||||
&.icon-search:before {
|
||||
content: "\e8b6";
|
||||
}
|
||||
&.icon-star:before {
|
||||
content: "\e838";
|
||||
}
|
||||
&.icon-star-border:before {
|
||||
content: "\e83a";
|
||||
}
|
||||
&.icon-stop:before {
|
||||
content: "\e047";
|
||||
}
|
||||
&.icon-visibility-off:before {
|
||||
content: "\e8f5";
|
||||
}
|
||||
|
||||
@@ -369,6 +369,18 @@ html p {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.sg-label-outline {
|
||||
// See also .sg-outline-button in button.scss
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: 3px; // $button-border-radius
|
||||
margin: 0;
|
||||
padding: 0 rem(0.500);
|
||||
font-size: $sg-font-size-1;
|
||||
font-weight: $sg-font-medium;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
// Date bloc in use on the toolbar
|
||||
// ----------------------------------------------------------------------------
|
||||
$today-font-size: 72px; // Visualy adjusted
|
||||
|
||||
Reference in New Issue
Block a user