diff --git a/Gruntfile.js b/Gruntfile.js index 7db0f06..09268ee 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -185,6 +185,7 @@ module.exports = function(grunt) { 'test/unit/navigation-ctrl-test.js', 'test/unit/mail-list-ctrl-test.js', 'test/unit/write-ctrl-test.js', + 'test/unit/action-bar-ctrl-test.js', 'test/unit/outbox-bo-test.js', 'test/unit/invitation-dao-test.js', 'test/unit/update-handler-test.js', @@ -301,6 +302,7 @@ module.exports = function(grunt) { }, options: { mangle: false, + compress: false, sourceMap: true, sourceMapIn: 'test/unit/index.browserified.js.map', sourceMapIncludeSources: true, @@ -319,6 +321,7 @@ module.exports = function(grunt) { }, options: { mangle: false, + compress: false, sourceMap: true, sourceMapIn: 'test/integration/index.browserified.js.map', sourceMapIncludeSources: true, @@ -417,7 +420,7 @@ module.exports = function(grunt) { tasks: ['dist-css', 'manifest'] }, js: { - files: ['src/js/**/*.js'], + files: ['src/js/**/*.js', 'test/unit/*.js', 'test/integration/*.js'], tasks: ['dist-js', 'manifest'] }, icons: { diff --git a/src/js/app.js b/src/js/app.js index 36412fb..46fdd1f 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -31,6 +31,7 @@ var DialogCtrl = require('./controller/dialog'), ReadCtrl = require('./controller/read'), WriteCtrl = require('./controller/write'), NavigationCtrl = require('./controller/navigation'), + ActionBarCtrl = require('./controller/action-bar'), errorUtil = require('./util/error'), backButtonUtil = require('./util/backbutton-handler'); require('./directives/common'); @@ -113,4 +114,5 @@ app.controller('SetPassphraseCtrl', SetPassphraseCtrl); app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl); app.controller('ContactsCtrl', ContactsCtrl); app.controller('AboutCtrl', AboutCtrl); -app.controller('DialogCtrl', DialogCtrl); \ No newline at end of file +app.controller('DialogCtrl', DialogCtrl); +app.controller('ActionBarCtrl', ActionBarCtrl); \ No newline at end of file diff --git a/src/js/controller/action-bar.js b/src/js/controller/action-bar.js new file mode 100644 index 0000000..d1d6aa3 --- /dev/null +++ b/src/js/controller/action-bar.js @@ -0,0 +1,168 @@ +'use strict'; + +var appController = require('../app-controller'), + emailDao; + +// +// Controller +// + +var ActionBarCtrl = function($scope) { + + emailDao = appController._emailDao; + + /** + * Move a single message from the currently selected folder to another folder + * @param {Object} message The message that is to be moved + * @param {Object} destination The folder object where the message should be moved to + */ + $scope.moveMessage = function(message, destination) { + if (!message) { + return; + } + + // close read state + $scope.state.read.open = false; + + $scope.state.mailList.updateStatus('Moving message...'); + + emailDao.moveMessage({ + folder: currentFolder(), + destination: destination, + message: message + }, function(err) { + if (err) { + // show errors where appropriate + if (err.code === 42) { + $scope.select(message); + $scope.state.mailList.updateStatus('Unable to move message in offline mode!'); + return; + } + $scope.state.mailList.updateStatus('Error during move!'); + $scope.onError(err); + return; + } + $scope.state.mailList.updateStatus('Message moved.'); + $scope.$apply(); + }); + }; + + /** + * Move all checked messages from the currently selected folder to another folder + * @param {Object} destination The folder object where the message should be moved to + */ + $scope.moveCheckedMessages = function(destination) { + getCheckMessages().forEach(function(message) { + $scope.moveMessage(message, destination); + }); + }; + + /** + * Delete a message. This moves the message from the current folder to the trash folder, + * or if the current folder is the trash folder, the message will be purged. + * @param {Object} message The message that is to be deleted + */ + $scope.deleteMessage = function(message) { + if (!message) { + return; + } + + // close read state + $scope.state.read.open = false; + + $scope.state.mailList.updateStatus('Deleting message...'); + + emailDao.deleteMessage({ + folder: currentFolder(), + message: message + }, function(err) { + if (err) { + // show errors where appropriate + if (err.code === 42) { + $scope.select(message); + $scope.state.mailList.updateStatus('Unable to delete message in offline mode!'); + return; + } + $scope.state.mailList.updateStatus('Error during delete!'); + $scope.onError(err); + return; + } + $scope.state.mailList.updateStatus('Message deleted.'); + $scope.$apply(); + }); + }; + + /** + * Delete all of the checked messages. This moves the messages from the current folder to the trash folder, + * or if the current folder is the trash folder, the messages will be purged. + */ + $scope.deleteCheckedMessages = function() { + getCheckMessages().forEach($scope.deleteMessage); + }; + + /** + * Mark a single message as either read or unread + * @param {Object} message The message to be marked + * @param {boolean} unread If the message should be marked as read or unread + */ + $scope.markMessage = function(message, unread) { + if (!message) { + return; + } + + $scope.state.mailList.updateStatus('Updating unread flag...'); + + // close read state + $scope.state.read.open = false; + + var originalState = message.unread; + message.unread = unread; + emailDao.setFlags({ + folder: currentFolder(), + message: message + }, function(err) { + if (err && err.code === 42) { + // offline, restore + message.unread = originalState; + $scope.state.mailList.updateStatus('Unable to mark message in offline mode!'); + return; + } + + if (err) { + $scope.state.mailList.updateStatus('Error on sync!'); + $scope.onError(err); + return; + } + + $scope.state.mailList.updateStatus('Online'); + $scope.$apply(); + }); + }; + + /** + * Mark all of the checked messages as either read or unread. + * @param {boolean} unread If the message should be marked as read or unread + */ + $scope.markCheckedMessages = function(unread) { + getCheckMessages().forEach(function(message) { + $scope.markMessage(message, unread); + }); + }; + + // share local scope functions with root state + $scope.state.actionBar = { + markMessage: $scope.markMessage + }; + + function currentFolder() { + return $scope.state.nav.currentFolder; + } + + function getCheckMessages() { + return currentFolder().messages.filter(function(message) { + return message.checked; + }); + } +}; + +module.exports = ActionBarCtrl; \ No newline at end of file diff --git a/src/js/controller/mail-list.js b/src/js/controller/mail-list.js index a2b14d4..968238c 100644 --- a/src/js/controller/mail-list.js +++ b/src/js/controller/mail-list.js @@ -97,74 +97,13 @@ var MailListCtrl = function($scope, $routeParams) { } } - $scope.toggleUnread(email); - } - }; - - /** - * Mark an email as unread or read, respectively - */ - $scope.toggleUnread = function(message) { - updateStatus('Updating unread flag...'); - - message.unread = !message.unread; - emailDao.setFlags({ - folder: currentFolder(), - message: message - }, function(err) { - if (err && err.code === 42) { - // offline, restore - message.unread = !message.unread; - updateStatus('Unable to mark unread flag in offline mode!'); - return; - } - - if (err) { - updateStatus('Error on sync!'); - $scope.onError(err); - return; - } - - updateStatus('Online'); - $scope.$apply(); - }); - }; - - /** - * Delete a message - */ - $scope.remove = function(message) { - if (!message) { - return; - } - - updateStatus('Deleting message...'); - remove(); - - function remove() { - emailDao.deleteMessage({ - folder: currentFolder(), - message: message - }, function(err) { - if (err) { - // show errors where appropriate - if (err.code === 42) { - $scope.select(message); - updateStatus('Unable to delete message in offline mode!'); - return; - } - updateStatus('Error during delete!'); - $scope.onError(err); - } - updateStatus('Message deleted!'); - $scope.$apply(); - }); + $scope.state.actionBar.markMessage(email, false); } }; // share local scope functions with root state $scope.state.mailList = { - remove: $scope.remove + updateStatus: updateStatus }; // diff --git a/src/sass/blocks/layout/_nav.scss b/src/sass/blocks/layout/_nav.scss index b227cfa..102746c 100755 --- a/src/sass/blocks/layout/_nav.scss +++ b/src/sass/blocks/layout/_nav.scss @@ -132,6 +132,10 @@ } &__folders + .nav__folders { border-top-color: $color-border-light; + + .nav__folder { + margin-bottom: 8px; + } } &__folder { font-size: $font-size-base; @@ -151,9 +155,6 @@ top: 0.25em; } } - &__folder__other { - margin-bottom: 8px; - } &__counter { display: inline; position: static; diff --git a/src/tpl/action-bar.html b/src/tpl/action-bar.html index 20692bc..44f9b5a 100644 --- a/src/tpl/action-bar.html +++ b/src/tpl/action-bar.html @@ -1,18 +1,20 @@ -
+ +