Коммит
afb70cf07c
|
@ -4,6 +4,14 @@
|
|||
top: 50%;
|
||||
}
|
||||
|
||||
.emptycontent {
|
||||
padding-top: 30vh;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.emptycontent > h2 {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
|
|
@ -47,7 +47,7 @@ define(function(require) {
|
|||
* @param {boolean} noSelect
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function loadFolderMessages(account, folder, noSelect) {
|
||||
function loadFolderMessages(account, folder, noSelect, searchQuery) {
|
||||
Radio.ui.trigger('composer:leave');
|
||||
|
||||
if (require('state').messagesLoading !== null) {
|
||||
|
@ -59,7 +59,6 @@ define(function(require) {
|
|||
|
||||
// Set folder active
|
||||
Radio.folder.trigger('setactive', account, folder);
|
||||
Radio.ui.trigger('content:loading');
|
||||
|
||||
$('#load-more-mail-messages').hide();
|
||||
|
||||
|
@ -71,11 +70,15 @@ define(function(require) {
|
|||
require('state').currentlyLoading = null;
|
||||
} else {
|
||||
var loadingMessages = Radio.message.request('entities', account, folder, {
|
||||
cache: true
|
||||
cache: true,
|
||||
filter: searchQuery,
|
||||
replace: true
|
||||
});
|
||||
|
||||
$.when(loadingMessages).done(function(messages, cached) {
|
||||
Radio.ui.trigger('foldercontent:show', account, folder);
|
||||
Radio.ui.trigger('foldercontent:show', account, folder, {
|
||||
searchQuery: searchQuery
|
||||
});
|
||||
require('state').currentlyLoading = null;
|
||||
require('state').currentAccount = account;
|
||||
require('state').currentFolder = folder;
|
||||
|
@ -84,9 +87,9 @@ define(function(require) {
|
|||
// Fade out the message composer
|
||||
$('#mail_new_message').prop('disabled', false);
|
||||
|
||||
if (messages.length > 0) {
|
||||
Radio.ui.trigger('messagesview:messages:add', messages);
|
||||
Radio.ui.trigger('messagesview:messages:add', messages);
|
||||
|
||||
if (messages.length > 0) {
|
||||
// Fetch first 10 messages in background
|
||||
_.each(messages.slice(0, 10), function(
|
||||
message) {
|
||||
|
@ -94,15 +97,10 @@ define(function(require) {
|
|||
});
|
||||
|
||||
Radio.message.trigger('load', account, folder, messages.first());
|
||||
// Show 'Load More' button if there are
|
||||
// more messages than the pagination limit
|
||||
if (messages.length > 20) {
|
||||
$('#load-more-mail-messages')
|
||||
.fadeIn()
|
||||
.css('display', 'block');
|
||||
}
|
||||
} else {
|
||||
$('#emptycontent').show();
|
||||
|
||||
$('#load-more-mail-messages')
|
||||
.fadeIn()
|
||||
.css('display', 'block');
|
||||
}
|
||||
|
||||
if (cached) {
|
||||
|
@ -112,7 +110,7 @@ define(function(require) {
|
|||
}
|
||||
});
|
||||
|
||||
$.when(loadingMessages).fail(function(error) {
|
||||
$.when(loadingMessages).fail(function() {
|
||||
// Set the old folder as being active
|
||||
var folder = require('state').currentFolder;
|
||||
Radio.folder.trigger('setactive', account, folder);
|
||||
|
@ -121,12 +119,16 @@ define(function(require) {
|
|||
}
|
||||
}
|
||||
|
||||
var loadFolderMessagesDebounced = _.debounce(loadFolderMessages, 1000);
|
||||
|
||||
/**
|
||||
* @param {Account} account
|
||||
* @param {Folder} folder
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function showFolder(account, folder) {
|
||||
Radio.ui.trigger('search:set', '');
|
||||
Radio.ui.trigger('content:loading');
|
||||
loadFolderMessages(account, folder, false);
|
||||
|
||||
// Save current folder
|
||||
|
@ -135,8 +137,26 @@ define(function(require) {
|
|||
require('state').currentFolder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Account} account
|
||||
* @param {Folder} folder
|
||||
* @param {string} query
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function searchFolder(account, folder, query) {
|
||||
// If this was triggered by a URL change, we set the search input manually
|
||||
Radio.ui.trigger('search:set', query);
|
||||
|
||||
Radio.ui.trigger('composer:leave');
|
||||
Radio.ui.trigger('content:loading', t('mail', 'Searching for {query}', {
|
||||
query: query
|
||||
}));
|
||||
loadFolderMessagesDebounced(account, folder, false, query);
|
||||
}
|
||||
|
||||
return {
|
||||
loadFolder: loadFolders,
|
||||
showFolder: showFolder
|
||||
showFolder: showFolder,
|
||||
searchFolder: searchFolder
|
||||
};
|
||||
});
|
||||
|
|
|
@ -38,6 +38,7 @@ define(function(require) {
|
|||
this.accounts = accounts;
|
||||
|
||||
Radio.navigation.on('folder', _.bind(this.showFolder, this));
|
||||
Radio.navigation.on('search', _.bind(this.searchFolder, this));
|
||||
Radio.navigation.on('setup', _.bind(this.showSetup, this));
|
||||
Radio.navigation.on('accountsettings', _.bind(this.showAccountSettings, this));
|
||||
},
|
||||
|
@ -116,6 +117,29 @@ define(function(require) {
|
|||
}
|
||||
FolderController.showFolder(account, folder, noSelect);
|
||||
},
|
||||
searchFolder: function(accountId, folderId, query) {
|
||||
if (!query || query === '') {
|
||||
this.showFolder(accountId, folderId);
|
||||
return;
|
||||
}
|
||||
|
||||
this._navigate('accounts/' + accountId + '/folders/' + folderId + '/search/' + query);
|
||||
var account = this.accounts.get(accountId);
|
||||
if (_.isUndefined(account)) {
|
||||
// Unknown account id -> redirect
|
||||
Radio.ui.trigger('error:show', t('mail', 'Invalid account'));
|
||||
this.default();
|
||||
return;
|
||||
}
|
||||
|
||||
var folder = account.getFolderById(folderId);
|
||||
if (_.isUndefined(folder)) {
|
||||
folder = account.get('folders').at(0);
|
||||
Radio.ui.trigger('error:show', t('mail', 'Invalid folder'));
|
||||
this._navigate('accounts/' + accountId + '/folders/' + folder.get('id'));
|
||||
}
|
||||
FolderController.searchFolder(account, folder, query);
|
||||
},
|
||||
mailTo: function(params) {
|
||||
this._handleMailto(params);
|
||||
},
|
||||
|
|
|
@ -29,6 +29,7 @@ define(function(require) {
|
|||
appRoutes: {
|
||||
'': 'default',
|
||||
'accounts/:accountId/folders/:folderId': 'showFolder',
|
||||
'accounts/:accountId/folders/:folderId/search/:query': 'searchFolder',
|
||||
'mailto(?:params)': 'mailTo',
|
||||
'setup': 'showSetup',
|
||||
'accounts/:accountId/settings': 'showAccountSettings'
|
||||
|
|
12
js/search.js
12
js/search.js
|
@ -11,18 +11,18 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var Radio = require('radio');
|
||||
var lastQuery = '';
|
||||
|
||||
var debouncedFilter = _.debounce(function debouncedFilterFn(query) {
|
||||
Radio.ui.trigger('messagesview:filter', query);
|
||||
}, 1000);
|
||||
|
||||
function filter(query) {
|
||||
if (query !== lastQuery) {
|
||||
lastQuery = query;
|
||||
debouncedFilter(query);
|
||||
|
||||
if (require('state').currentAccount && require('state').currentFolder) {
|
||||
var accountId = require('state').currentAccount.get('accountId');
|
||||
var folderId = require('state').currentFolder.get('id');
|
||||
Radio.navigation.trigger('search', accountId, folderId, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,10 +44,16 @@ define(function(require) {
|
|||
var defaults = {
|
||||
cache: false,
|
||||
replace: false, // Replace cached folder list
|
||||
force: false
|
||||
force: false,
|
||||
filter: ''
|
||||
};
|
||||
_.defaults(options, defaults);
|
||||
|
||||
// Do not cache search queries
|
||||
if (options.filter !== '') {
|
||||
options.cache = false;
|
||||
}
|
||||
|
||||
// Abort previous requests
|
||||
if (messageListXhr !== null) {
|
||||
messageListXhr.abort();
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<div class="icon-mail"></div>
|
||||
<h2>{{ t 'No messages in this folder!' }}</h2>
|
|
@ -0,0 +1,6 @@
|
|||
{{#if hint}}
|
||||
<div class="emptycontent">
|
||||
<a class="icon-loading"></a>
|
||||
<h2>{{{ hint }}}</h2>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,10 +1,5 @@
|
|||
<div id="mail-message-list-loading"
|
||||
class="icon-loading-small"
|
||||
style="display: none"></div>
|
||||
<div id="emptycontent"
|
||||
style="display: none;">
|
||||
<div class="icon-mail"></div>
|
||||
<h2>{{ t 'No messages in this folder!' }}</h2>
|
||||
</div>
|
||||
<div id="mail-message-list"></div>
|
||||
<div id="load-more-mail-messages"></div>
|
|
@ -57,6 +57,7 @@ define(function(require) {
|
|||
this.listenTo(Radio.ui, 'content:loading', this.showContentLoading);
|
||||
this.listenTo(Radio.ui, 'title:update', this.updateTitle);
|
||||
this.listenTo(Radio.ui, 'accountsettings:show', this.showAccountSettings);
|
||||
this.listenTo(Radio.ui, 'search:set', this.setSearchQuery);
|
||||
|
||||
// Hide notification favicon when switching back from
|
||||
// another browser tab
|
||||
|
@ -159,19 +160,20 @@ define(function(require) {
|
|||
}));
|
||||
}
|
||||
},
|
||||
showFolderContent: function(account, folder) {
|
||||
showFolderContent: function(account, folder, options) {
|
||||
this.activeContent = ContentType.FOLDER_CONTENT;
|
||||
|
||||
this.content.show(new FolderContentView({
|
||||
account: account,
|
||||
folder: folder
|
||||
}));
|
||||
// Merge account, folder into a single options object
|
||||
options.account = account;
|
||||
options.folder = folder;
|
||||
|
||||
this.content.show(new FolderContentView(options));
|
||||
},
|
||||
showContentLoading: function() {
|
||||
if (this.activeContent !== ContentType.LOADING) {
|
||||
this.activeContent = ContentType.LOADING;
|
||||
this.content.show(new LoadingView());
|
||||
}
|
||||
showContentLoading: function(text) {
|
||||
this.activeContent = ContentType.LOADING;
|
||||
this.content.show(new LoadingView({
|
||||
text: text
|
||||
}));
|
||||
},
|
||||
updateTitle: function() {
|
||||
var activeEmail = '';
|
||||
|
@ -208,6 +210,10 @@ define(function(require) {
|
|||
account: account
|
||||
}));
|
||||
}
|
||||
},
|
||||
setSearchQuery: function(val) {
|
||||
val = val || '';
|
||||
$('#searchbox').val(val);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* Mail
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
define(function(require) {
|
||||
'strict';
|
||||
|
||||
var Handlebars = require('handlebars');
|
||||
var Marionette = require('marionette');
|
||||
var EmptyMessagesTemplate = require('text!templates/empty-folder.html');
|
||||
|
||||
var EmptyMessagesView = Marionette.ItemView.extend({
|
||||
id: 'emptycontent',
|
||||
template: Handlebars.compile(EmptyMessagesTemplate)
|
||||
});
|
||||
|
||||
return EmptyMessagesView;
|
||||
});
|
|
@ -43,6 +43,7 @@ define(function(require) {
|
|||
detailView: null,
|
||||
account: null,
|
||||
folder: null,
|
||||
searchQuery: null,
|
||||
composer: null,
|
||||
regions: {
|
||||
messages: '#mail-messages',
|
||||
|
@ -51,6 +52,7 @@ define(function(require) {
|
|||
initialize: function(options) {
|
||||
this.account = options.account;
|
||||
this.folder = options.folder;
|
||||
this.searchQuery = options.searchQuery;
|
||||
|
||||
this.listenTo(Radio.ui, 'message:show', this.onShowMessage);
|
||||
this.listenTo(Radio.ui, 'composer:show', this.onShowComposer);
|
||||
|
@ -69,7 +71,8 @@ define(function(require) {
|
|||
},
|
||||
onShow: function() {
|
||||
this.messages.show(new MessagesView({
|
||||
collection: this.folder.get('messages')
|
||||
collection: this.folder.get('messages'),
|
||||
searchQuery: this.searchQuery
|
||||
}));
|
||||
},
|
||||
onShowMessage: function(message) {
|
||||
|
|
|
@ -20,14 +20,25 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Handlebars = require('handlebars');
|
||||
var Marionette = require('marionette');
|
||||
var LoadingTemplate = require('text!templates/loading.html');
|
||||
|
||||
/**
|
||||
* @class LoadingView
|
||||
*/
|
||||
var LoadingView = Marionette.ItemView.extend({
|
||||
template: false,
|
||||
className: 'icon-loading container'
|
||||
template: Handlebars.compile(LoadingTemplate),
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
hint: this.hint
|
||||
};
|
||||
},
|
||||
className: 'container',
|
||||
hint: '',
|
||||
initialize: function(options) {
|
||||
this.hint = options.text || '';
|
||||
}
|
||||
});
|
||||
|
||||
return LoadingView;
|
||||
|
|
|
@ -26,7 +26,8 @@ define(function(require) {
|
|||
var Radio = require('radio');
|
||||
var MessagesItemView = require('views/messagesitem');
|
||||
var MessageListTemplate = require('text!templates/message-list.html');
|
||||
var NoSearchResultMessageListView = require('views/nosearchresultmessagelistview');
|
||||
var EmptyFolderView = require('views/emptyfolderview');
|
||||
var NoSearchResultView = require('views/nosearchresultmessagelistview');
|
||||
|
||||
return Backbone.Marionette.CompositeView.extend({
|
||||
collection: null,
|
||||
|
@ -35,13 +36,15 @@ define(function(require) {
|
|||
childViewContainer: '#mail-message-list',
|
||||
template: Handlebars.compile(MessageListTemplate),
|
||||
currentMessage: null,
|
||||
searchQuery: null,
|
||||
loadingMore: false,
|
||||
reloaded: false,
|
||||
filterCriteria: null,
|
||||
events: {
|
||||
'wheel': 'onScroll',
|
||||
},
|
||||
initialize: function() {
|
||||
initialize: function(options) {
|
||||
this.searchQuery = options.searchQuery;
|
||||
|
||||
var _this = this;
|
||||
Radio.ui.reply('messagesview:collection', function() {
|
||||
return _this.collection;
|
||||
|
@ -50,7 +53,6 @@ define(function(require) {
|
|||
this.listenTo(Radio.ui, 'messagesview:messages:add', this.addMessages);
|
||||
this.listenTo(Radio.ui, 'messagesview:messageflag:set', this.setMessageFlag);
|
||||
this.listenTo(Radio.ui, 'messagesview:filter', this.filterCurrentMailbox);
|
||||
this.listenTo(Radio.ui, 'messagesview:filter:clear', this.clearFilter);
|
||||
this.listenTo(Radio.ui, 'messagesview:message:setactive', this.setActiveMessage);
|
||||
this.listenTo(Radio.message, 'messagesview:message:next', this.selectNextMessage);
|
||||
this.listenTo(Radio.message, 'messagesview:message:prev', this.selectPreviousMessage);
|
||||
|
@ -60,12 +62,16 @@ define(function(require) {
|
|||
this.$scrollContainer.scroll(_.bind(this.onScroll, this));
|
||||
},
|
||||
getEmptyView: function() {
|
||||
if (this.filterCriteria) {
|
||||
return NoSearchResultMessageListView;
|
||||
if (this.searchQuery && this.searchQuery !== '') {
|
||||
return NoSearchResultView;
|
||||
} else {
|
||||
return EmptyFolderView;
|
||||
}
|
||||
},
|
||||
emptyViewOptions: function() {
|
||||
return {filterCriteria: this.filterCriteria};
|
||||
return {
|
||||
searchQuery: this.searchQuery
|
||||
};
|
||||
},
|
||||
setMessageFlag: function(messageId, flag, val) {
|
||||
var message = this.collection.get(messageId);
|
||||
|
@ -191,10 +197,6 @@ define(function(require) {
|
|||
};
|
||||
this.loadMessages(true);
|
||||
},
|
||||
clearFilter: function() {
|
||||
$('#searchbox').val('');
|
||||
this.filterCriteria = null;
|
||||
},
|
||||
loadMessages: function(reload) {
|
||||
reload = reload || false;
|
||||
var from = this.collection.size();
|
||||
|
@ -219,8 +221,8 @@ define(function(require) {
|
|||
{
|
||||
from: from,
|
||||
to: from + 20,
|
||||
filter: this.filterCriteria ? this.filterCriteria.text : null,
|
||||
force: true,
|
||||
filter: this.searchQuery || '',
|
||||
// Replace cached message list on reload
|
||||
replace: reload
|
||||
});
|
||||
|
@ -254,6 +256,8 @@ define(function(require) {
|
|||
_this.loadingMore = false;
|
||||
},
|
||||
});
|
||||
} else {
|
||||
_this.loadingMore = false;
|
||||
}
|
||||
// Reload scrolls the list to the top, hence a unwanted
|
||||
// scroll event is fired, which we want to ignore
|
||||
|
|
|
@ -39,8 +39,6 @@ define(function(require) {
|
|||
* @returns {undefined}
|
||||
*/
|
||||
setFolderActive: function(account, folder) {
|
||||
Radio.ui.trigger('messagesview:filter:clear');
|
||||
|
||||
// disable all other folders for all accounts
|
||||
require('state').accounts.each(function(acnt) {
|
||||
var localAccount = require('state').folderView.collection.get(acnt.get('accountId'));
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
* @copyright Christoph Wurst 2015
|
||||
* @copyright Christoph Wurst 2015, 2016
|
||||
*/
|
||||
|
||||
define(function(require) {
|
||||
|
@ -18,12 +18,9 @@ define(function(require) {
|
|||
|
||||
return Marionette.ItemView.extend({
|
||||
initialize: function(options) {
|
||||
this.model.set('searchTerm', options.filterCriteria.text || '');
|
||||
this.model.set('searchTerm', options.searchQuery);
|
||||
},
|
||||
template: Handlebars.compile(NoSearchResultMessageListViewTemplate),
|
||||
onRender: function() {
|
||||
this.$('#load-more-mail-messages').hide();
|
||||
}
|
||||
template: Handlebars.compile(NoSearchResultMessageListViewTemplate)
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче