Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Christoph Borchardt <hey@jancborchardt.net>2016-08-05 18:49:20 +0300
committerGitHub <noreply@github.com>2016-08-05 18:49:20 +0300
commitafb70cf07c10b5fa22cf287b7480449da9b894b3 (patch)
tree53b3ccb52b2dd80470cb04b2cdf4754fc6e939c3
parent55220f7386612db23aba197cb5320e5ff3833b83 (diff)
parentd7c148df49598fbe84825dd34904f24c15f1c7cb (diff)
Merge pull request #1609 from owncloud/search-rework
Search rework
-rwxr-xr-xcss/mail.css8
-rw-r--r--js/controller/foldercontroller.js54
-rw-r--r--js/routecontroller.js24
-rw-r--r--js/router.js1
-rw-r--r--js/search.js12
-rw-r--r--js/service/messageservice.js8
-rw-r--r--js/templates/empty-folder.html2
-rw-r--r--js/templates/loading.html6
-rw-r--r--js/templates/message-list.html5
-rw-r--r--js/views/appview.js26
-rw-r--r--js/views/emptyfolderview.js33
-rw-r--r--js/views/foldercontent.js5
-rw-r--r--js/views/loadingview.js15
-rw-r--r--js/views/messagesview.js28
-rw-r--r--js/views/navigation-accounts.js2
-rw-r--r--js/views/nosearchresultmessagelistview.js9
16 files changed, 176 insertions, 62 deletions
diff --git a/css/mail.css b/css/mail.css
index e4e656cae..ed93ad815 100755
--- a/css/mail.css
+++ b/css/mail.css
@@ -4,6 +4,14 @@
top: 50%;
}
+.emptycontent {
+ padding-top: 30vh;
+ margin-top: 0px;
+}
+.emptycontent > h2 {
+ padding-top: 20px;
+}
+
.container {
position: relative;
width: 100%;
diff --git a/js/controller/foldercontroller.js b/js/controller/foldercontroller.js
index 7eb8c6b93..e9626f698 100644
--- a/js/controller/foldercontroller.js
+++ b/js/controller/foldercontroller.js
@@ -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
};
});
diff --git a/js/routecontroller.js b/js/routecontroller.js
index 62690f288..480dae3d0 100644
--- a/js/routecontroller.js
+++ b/js/routecontroller.js
@@ -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);
},
diff --git a/js/router.js b/js/router.js
index eb3df37c7..139e8d94a 100644
--- a/js/router.js
+++ b/js/router.js
@@ -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'
diff --git a/js/search.js b/js/search.js
index 58ade8a5b..12c93ff9b 100644
--- a/js/search.js
+++ b/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);
+ }
}
}
diff --git a/js/service/messageservice.js b/js/service/messageservice.js
index d8cdb97be..068a862f3 100644
--- a/js/service/messageservice.js
+++ b/js/service/messageservice.js
@@ -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();
diff --git a/js/templates/empty-folder.html b/js/templates/empty-folder.html
new file mode 100644
index 000000000..88528a5fb
--- /dev/null
+++ b/js/templates/empty-folder.html
@@ -0,0 +1,2 @@
+<div class="icon-mail"></div>
+<h2>{{ t 'No messages in this folder!' }}</h2> \ No newline at end of file
diff --git a/js/templates/loading.html b/js/templates/loading.html
new file mode 100644
index 000000000..7d4460261
--- /dev/null
+++ b/js/templates/loading.html
@@ -0,0 +1,6 @@
+{{#if hint}}
+<div class="emptycontent">
+ <a class="icon-loading"></a>
+ <h2>{{{ hint }}}</h2>
+</div>
+{{/if}} \ No newline at end of file
diff --git a/js/templates/message-list.html b/js/templates/message-list.html
index 36e5f459c..a117d63f2 100644
--- a/js/templates/message-list.html
+++ b/js/templates/message-list.html
@@ -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> \ No newline at end of file
diff --git a/js/views/appview.js b/js/views/appview.js
index 251185a4e..1494a7f66 100644
--- a/js/views/appview.js
+++ b/js/views/appview.js
@@ -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);
}
});
diff --git a/js/views/emptyfolderview.js b/js/views/emptyfolderview.js
new file mode 100644
index 000000000..f45e9486d
--- /dev/null
+++ b/js/views/emptyfolderview.js
@@ -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;
+});
diff --git a/js/views/foldercontent.js b/js/views/foldercontent.js
index c344e4c7f..c5616d0e1 100644
--- a/js/views/foldercontent.js
+++ b/js/views/foldercontent.js
@@ -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) {
diff --git a/js/views/loadingview.js b/js/views/loadingview.js
index 4d30e6fdb..db81e9c5f 100644
--- a/js/views/loadingview.js
+++ b/js/views/loadingview.js
@@ -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;
diff --git a/js/views/messagesview.js b/js/views/messagesview.js
index 5f73bd5d0..e8501c590 100644
--- a/js/views/messagesview.js
+++ b/js/views/messagesview.js
@@ -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
diff --git a/js/views/navigation-accounts.js b/js/views/navigation-accounts.js
index d1ce964cf..0f1fbf3cd 100644
--- a/js/views/navigation-accounts.js
+++ b/js/views/navigation-accounts.js
@@ -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'));
diff --git a/js/views/nosearchresultmessagelistview.js b/js/views/nosearchresultmessagelistview.js
index 1981bd63c..573becf25 100644
--- a/js/views/nosearchresultmessagelistview.js
+++ b/js/views/nosearchresultmessagelistview.js
@@ -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)
});
});