mirror of
https://github.com/moparisthebest/mail
synced 2024-11-26 02:42:17 -05:00
[WO-629] implement move, delete, mark unread for desktop and mobile ui
This commit is contained in:
parent
2b15eabcd0
commit
e8964cde39
@ -185,6 +185,7 @@ module.exports = function(grunt) {
|
|||||||
'test/unit/navigation-ctrl-test.js',
|
'test/unit/navigation-ctrl-test.js',
|
||||||
'test/unit/mail-list-ctrl-test.js',
|
'test/unit/mail-list-ctrl-test.js',
|
||||||
'test/unit/write-ctrl-test.js',
|
'test/unit/write-ctrl-test.js',
|
||||||
|
'test/unit/action-bar-ctrl-test.js',
|
||||||
'test/unit/outbox-bo-test.js',
|
'test/unit/outbox-bo-test.js',
|
||||||
'test/unit/invitation-dao-test.js',
|
'test/unit/invitation-dao-test.js',
|
||||||
'test/unit/update-handler-test.js',
|
'test/unit/update-handler-test.js',
|
||||||
@ -301,6 +302,7 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
mangle: false,
|
mangle: false,
|
||||||
|
compress: false,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
sourceMapIn: 'test/unit/index.browserified.js.map',
|
sourceMapIn: 'test/unit/index.browserified.js.map',
|
||||||
sourceMapIncludeSources: true,
|
sourceMapIncludeSources: true,
|
||||||
@ -319,6 +321,7 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
mangle: false,
|
mangle: false,
|
||||||
|
compress: false,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
sourceMapIn: 'test/integration/index.browserified.js.map',
|
sourceMapIn: 'test/integration/index.browserified.js.map',
|
||||||
sourceMapIncludeSources: true,
|
sourceMapIncludeSources: true,
|
||||||
@ -417,7 +420,7 @@ module.exports = function(grunt) {
|
|||||||
tasks: ['dist-css', 'manifest']
|
tasks: ['dist-css', 'manifest']
|
||||||
},
|
},
|
||||||
js: {
|
js: {
|
||||||
files: ['src/js/**/*.js'],
|
files: ['src/js/**/*.js', 'test/unit/*.js', 'test/integration/*.js'],
|
||||||
tasks: ['dist-js', 'manifest']
|
tasks: ['dist-js', 'manifest']
|
||||||
},
|
},
|
||||||
icons: {
|
icons: {
|
||||||
|
@ -31,6 +31,7 @@ var DialogCtrl = require('./controller/dialog'),
|
|||||||
ReadCtrl = require('./controller/read'),
|
ReadCtrl = require('./controller/read'),
|
||||||
WriteCtrl = require('./controller/write'),
|
WriteCtrl = require('./controller/write'),
|
||||||
NavigationCtrl = require('./controller/navigation'),
|
NavigationCtrl = require('./controller/navigation'),
|
||||||
|
ActionBarCtrl = require('./controller/action-bar'),
|
||||||
errorUtil = require('./util/error'),
|
errorUtil = require('./util/error'),
|
||||||
backButtonUtil = require('./util/backbutton-handler');
|
backButtonUtil = require('./util/backbutton-handler');
|
||||||
require('./directives/common');
|
require('./directives/common');
|
||||||
@ -114,3 +115,4 @@ app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
|
|||||||
app.controller('ContactsCtrl', ContactsCtrl);
|
app.controller('ContactsCtrl', ContactsCtrl);
|
||||||
app.controller('AboutCtrl', AboutCtrl);
|
app.controller('AboutCtrl', AboutCtrl);
|
||||||
app.controller('DialogCtrl', DialogCtrl);
|
app.controller('DialogCtrl', DialogCtrl);
|
||||||
|
app.controller('ActionBarCtrl', ActionBarCtrl);
|
168
src/js/controller/action-bar.js
Normal file
168
src/js/controller/action-bar.js
Normal file
@ -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;
|
@ -97,74 +97,13 @@ var MailListCtrl = function($scope, $routeParams) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleUnread(email);
|
$scope.state.actionBar.markMessage(email, false);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// share local scope functions with root state
|
// share local scope functions with root state
|
||||||
$scope.state.mailList = {
|
$scope.state.mailList = {
|
||||||
remove: $scope.remove
|
updateStatus: updateStatus
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -132,6 +132,10 @@
|
|||||||
}
|
}
|
||||||
&__folders + .nav__folders {
|
&__folders + .nav__folders {
|
||||||
border-top-color: $color-border-light;
|
border-top-color: $color-border-light;
|
||||||
|
|
||||||
|
.nav__folder {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__folder {
|
&__folder {
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
@ -151,9 +155,6 @@
|
|||||||
top: 0.25em;
|
top: 0.25em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__folder__other {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
&__counter {
|
&__counter {
|
||||||
display: inline;
|
display: inline;
|
||||||
position: static;
|
position: static;
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
<div class="action-bar">
|
<div class="action-bar" ng-controller="ActionBarCtrl">
|
||||||
<div class="action-bar__primary">
|
<div class="action-bar__primary">
|
||||||
<button class="btn btn--light">Delete</button>
|
<button class="btn btn--light" wo-touch="state.read.open ? deleteMessage(state.mailList.selected) : deleteCheckedMessages()">Delete</button>
|
||||||
<button class="btn btn--light">Spam</button>
|
<button class="btn btn--light" disabled>Spam</button>
|
||||||
<button class="btn btn--light-dropdown" wo-dropdown="#dropdown-folder">
|
<button class="btn btn--light-dropdown" wo-dropdown="#dropdown-folder">
|
||||||
<svg><use xlink:href="#icon-folder" /><title>Folder</title></svg>
|
<svg><use xlink:href="#icon-folder" /><title>Folder</title></svg>
|
||||||
<svg class="btn__dropdown" role="presentation"><use xlink:href="#icon-dropdown" /></svg>
|
<svg class="btn__dropdown" role="presentation"><use xlink:href="#icon-dropdown" /></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div><!--/action-bar__primary-->
|
||||||
|
|
||||||
<div class="action-bar__secondary">
|
<div class="action-bar__secondary">
|
||||||
<button class="btn btn--light-dropdown" wo-dropdown="#dropdown-more">
|
<button class="btn btn--light-dropdown" wo-dropdown="#dropdown-more">
|
||||||
More
|
More
|
||||||
<svg class="btn__dropdown" role="presentation"><use xlink:href="#icon-dropdown" /></svg>
|
<svg class="btn__dropdown" role="presentation"><use xlink:href="#icon-dropdown" /></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div><!--/action-bar__secondary-->
|
||||||
|
|
||||||
<div class="action-bar__search">
|
<div class="action-bar__search">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<svg><use xlink:href="#icon-search" /><title>Search</title></svg>
|
<svg><use xlink:href="#icon-search" /><title>Search</title></svg>
|
||||||
@ -20,15 +22,20 @@
|
|||||||
ng-change="displaySearchResults(searchText)"
|
ng-change="displaySearchResults(searchText)"
|
||||||
placeholder="Search" focus-me="state.mailList.searching">
|
placeholder="Search" focus-me="state.mailList.searching">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div><!--/action-bar__search-->
|
||||||
|
|
||||||
<!-- dropdowns -->
|
<!-- dropdowns -->
|
||||||
<ul id="dropdown-folder" class="dropdown">
|
<ul id="dropdown-folder" class="dropdown">
|
||||||
<li><button><svg><use xlink:href="#icon-folder" /></svg> Lorem</button></li>
|
<li ng-repeat="folder in account.folders">
|
||||||
<li><button><svg><use xlink:href="#icon-folder" /></svg> Ipsum</button></li>
|
<button wo-touch="state.read.open ? moveMessage(state.mailList.selected, folder) : moveCheckedMessages(folder)">
|
||||||
</ul>
|
<svg><use xlink:href="#icon-folder" /></svg>
|
||||||
|
{{folder.wellknown ? folder.type : folder.name}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul><!--/dropdown-->
|
||||||
|
|
||||||
<ul id="dropdown-more" class="dropdown">
|
<ul id="dropdown-more" class="dropdown">
|
||||||
<li><button>Mark as read</button></li>
|
<li><button wo-touch="state.read.open ? markMessage(state.mailList.selected, false) : markCheckedMessages(false)">Mark as read</button></li>
|
||||||
<li><button>Mark as unread</button></li>
|
<li><button wo-touch="state.read.open ? markMessage(state.mailList.selected, true) : markCheckedMessages(true)">Mark as unread</button></li>
|
||||||
</ul>
|
</ul><!--/dropdown-->
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
ng-repeat="email in displayMessages">
|
ng-repeat="email in displayMessages">
|
||||||
<ul class="mail-list-entry__flags">
|
<ul class="mail-list-entry__flags">
|
||||||
<li class="mail-list-entry__flags-unread"></li>
|
<li class="mail-list-entry__flags-unread"></li>
|
||||||
<li class="mail-list-entry__flags-checked">
|
<li class="mail-list-entry__flags-checked" wo-touch="$event.stopPropagation()">
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox">
|
<input type="checkbox" ng-model="email.checked">
|
||||||
<span><svg role="presentation"><use xlink:href="#icon-check" /></svg></span>
|
<span><svg role="presentation"><use xlink:href="#icon-check" /></svg></span>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<ul class="nav__folders">
|
<ul class="nav__folders">
|
||||||
<li ng-repeat="folder in account.folders" ng-if="!folder.wellknown"
|
<li ng-repeat="folder in account.folders" ng-if="!folder.wellknown"
|
||||||
class="nav__folder nav__folder__other" ng-class="{'nav__folder--open': state.nav.currentFolder === folder}">
|
class="nav__folder" ng-class="{'nav__folder--open': state.nav.currentFolder === folder}">
|
||||||
<a href="#" wo-touch="$event.preventDefault(); openFolder(folder)">
|
<a href="#" wo-touch="$event.preventDefault(); openFolder(folder)">
|
||||||
<svg role="presentation"><use xlink:href="#icon-folder" /></svg>
|
<svg role="presentation"><use xlink:href="#icon-folder" /></svg>
|
||||||
{{folder.name}}
|
{{folder.name}}
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
{{state.nav.currentFolder.wellknown ? state.nav.currentFolder.type : state.nav.currentFolder.name}}
|
{{state.nav.currentFolder.wellknown ? state.nav.currentFolder.type : state.nav.currentFolder.name}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div><!--/read__folder-toolbar-->
|
||||||
<div class="read__action-toolbar">
|
|
||||||
|
<div class="read__action-toolbar" ng-controller="ActionBarCtrl">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<ul class="toolbar__actions">
|
<ul class="toolbar__actions">
|
||||||
<li>
|
<li>
|
||||||
@ -32,7 +33,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button wo-touch="state.mailList.remove(state.mailList.selected)" class="btn-icon-light" title="Delete mail">
|
<button wo-touch="deleteMessage(state.mailList.selected)" class="btn-icon-light" title="Delete mail">
|
||||||
<svg><use xlink:href="#icon-trash" /><title>Delete mail</title></svg>
|
<svg><use xlink:href="#icon-trash" /><title>Delete mail</title></svg>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@ -51,13 +52,14 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div><!--/read__action-toolbar-->
|
||||||
|
|
||||||
<header class="read__header">
|
<header class="read__header">
|
||||||
<div class="read__controls">
|
<div class="read__controls">
|
||||||
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected)" title="Reply"><svg><use xlink:href="#icon-reply_light" /></svg></button>
|
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected)" title="Reply"><svg><use xlink:href="#icon-reply_light" /></svg></button>
|
||||||
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected, true)" title="Reply All"><svg><use xlink:href="#icon-reply_all_light" /></svg></button>
|
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected, true)" title="Reply All"><svg><use xlink:href="#icon-reply_all_light" /></svg></button>
|
||||||
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected, null, true)" title="Forward"><svg><use xlink:href="#icon-forward_light" /></svg></button>
|
<button class="btn-icon-light" wo-touch="state.writer.write(state.mailList.selected, null, true)" title="Forward"><svg><use xlink:href="#icon-forward_light" /></svg></button>
|
||||||
</div>
|
</div><!--/read__controls-->
|
||||||
|
|
||||||
<h2 class="read__subject" wo-touch="notStripped = !notStripped">
|
<h2 class="read__subject" wo-touch="notStripped = !notStripped">
|
||||||
<button ng-hide="notStripped" class="btn-icon-very-light">
|
<button ng-hide="notStripped" class="btn-icon-very-light">
|
||||||
@ -114,7 +116,7 @@
|
|||||||
{{attachment.filename}}
|
{{attachment.filename}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</header>
|
</header><!--/read__header-->
|
||||||
|
|
||||||
<!-- working spinner -->
|
<!-- working spinner -->
|
||||||
<div class="read__working"
|
<div class="read__working"
|
||||||
@ -140,7 +142,7 @@
|
|||||||
<iframe sandbox="allow-popups allow-scripts" src="tpl/read-sandbox.html"
|
<iframe sandbox="allow-popups allow-scripts" src="tpl/read-sandbox.html"
|
||||||
frame-load>
|
frame-load>
|
||||||
</iframe>
|
</iframe>
|
||||||
</div>
|
</div><!--/read__body-->
|
||||||
|
|
||||||
<!-- tooltips -->
|
<!-- tooltips -->
|
||||||
<div id="fingerprint-info" class="tooltip">
|
<div id="fingerprint-info" class="tooltip">
|
||||||
@ -153,10 +155,15 @@
|
|||||||
<li><button wo-touch="state.writer.write(state.mailList.selected)"><svg><use xlink:href="#icon-reply_light" /></svg> Reply</button></li>
|
<li><button wo-touch="state.writer.write(state.mailList.selected)"><svg><use xlink:href="#icon-reply_light" /></svg> Reply</button></li>
|
||||||
<li><button wo-touch="state.writer.write(state.mailList.selected, true)"><svg><use xlink:href="#icon-reply_all_light" /></svg> Reply All</button></li>
|
<li><button wo-touch="state.writer.write(state.mailList.selected, true)"><svg><use xlink:href="#icon-reply_all_light" /></svg> Reply All</button></li>
|
||||||
<li><button wo-touch="state.writer.write(state.mailList.selected, null, true)"><svg><use xlink:href="#icon-forward_light" /></svg> Forward</button></li>
|
<li><button wo-touch="state.writer.write(state.mailList.selected, null, true)"><svg><use xlink:href="#icon-forward_light" /></svg> Forward</button></li>
|
||||||
</ul>
|
</ul><!--/dropdown-->
|
||||||
<ul id="read-dropdown-folder" class="dropdown">
|
|
||||||
<li><button><svg><use xlink:href="#icon-folder" /></svg> Lorem</button></li>
|
<ul id="read-dropdown-folder" class="dropdown" ng-controller="ActionBarCtrl">
|
||||||
<li><button><svg><use xlink:href="#icon-folder" /></svg> Ipsum</button></li>
|
<li ng-repeat="folder in account.folders">
|
||||||
</ul>
|
<button wo-touch="moveMessage(state.mailList.selected, folder)">
|
||||||
|
<svg><use xlink:href="#icon-folder" /></svg>
|
||||||
|
{{folder.wellknown ? folder.type : folder.name}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul><!--/dropdown-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
149
test/unit/action-bar-ctrl-test.js
Normal file
149
test/unit/action-bar-ctrl-test.js
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var mocks = angular.mock,
|
||||||
|
EmailDAO = require('../../src/js/dao/email-dao'),
|
||||||
|
appController = require('../../src/js/app-controller'),
|
||||||
|
ActionBarCtrl = require('../../src/js/controller/action-bar');
|
||||||
|
|
||||||
|
describe('Action Bar Controller unit test', function() {
|
||||||
|
var scope, actionBarCtrl, emailDaoMock, origEmailDao;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
angular.module('actionbartest', []);
|
||||||
|
mocks.module('actionbartest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {
|
||||||
|
mailList: {
|
||||||
|
updateStatus: function() {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.state.nav = {
|
||||||
|
currentFolder: {
|
||||||
|
type: 'Inbox',
|
||||||
|
path: 'INBOX',
|
||||||
|
messages: [{
|
||||||
|
checked: true
|
||||||
|
}, {
|
||||||
|
checked: false
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.state.read = {
|
||||||
|
open: true
|
||||||
|
};
|
||||||
|
|
||||||
|
actionBarCtrl = $controller(ActionBarCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteMessage', function() {
|
||||||
|
it('should not delete without a selected mail', function() {
|
||||||
|
scope.deleteMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the selected mail', function() {
|
||||||
|
emailDaoMock.deleteMessage.yields();
|
||||||
|
|
||||||
|
scope.deleteMessage({});
|
||||||
|
|
||||||
|
expect(emailDaoMock.deleteMessage.calledOnce).to.be.true;
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteCheckedMessages', function() {
|
||||||
|
var deleteMessageStub;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
deleteMessageStub = sinon.stub(scope, 'deleteMessage');
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
deleteMessageStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the selected mail', function() {
|
||||||
|
scope.deleteCheckedMessages();
|
||||||
|
|
||||||
|
expect(deleteMessageStub.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('moveMessage', function() {
|
||||||
|
it('should not move without a selected mail', function() {
|
||||||
|
scope.moveMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move the selected mail', function() {
|
||||||
|
emailDaoMock.moveMessage.yields();
|
||||||
|
|
||||||
|
scope.moveMessage({}, {});
|
||||||
|
|
||||||
|
expect(emailDaoMock.moveMessage.calledOnce).to.be.true;
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('moveCheckedMessages', function() {
|
||||||
|
var moveMessageStub;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
moveMessageStub = sinon.stub(scope, 'moveMessage');
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
moveMessageStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the selected mail', function() {
|
||||||
|
scope.moveCheckedMessages();
|
||||||
|
|
||||||
|
expect(moveMessageStub.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('markMessage', function() {
|
||||||
|
it('should not move without a selected mail', function() {
|
||||||
|
scope.markMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move the selected mail', function() {
|
||||||
|
emailDaoMock.setFlags.yields();
|
||||||
|
|
||||||
|
scope.markMessage({}, true);
|
||||||
|
|
||||||
|
expect(emailDaoMock.setFlags.calledOnce).to.be.true;
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('markCheckedMessages', function() {
|
||||||
|
var markMessageStub;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
markMessageStub = sinon.stub(scope, 'markMessage');
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
markMessageStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the selected mail', function() {
|
||||||
|
scope.markCheckedMessages();
|
||||||
|
|
||||||
|
expect(markMessageStub.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -29,7 +29,9 @@
|
|||||||
if (window.mochaPhantomJS) {
|
if (window.mochaPhantomJS) {
|
||||||
mochaPhantomJS.run();
|
mochaPhantomJS.run();
|
||||||
} else {
|
} else {
|
||||||
mocha.run();
|
setTimeout(function() {
|
||||||
|
mocha.run();
|
||||||
|
}, 1000)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -241,7 +241,6 @@ describe('Mail List controller unit test', function() {
|
|||||||
describe('scope variables', function() {
|
describe('scope variables', function() {
|
||||||
it('should be set correctly', function() {
|
it('should be set correctly', function() {
|
||||||
expect(scope.select).to.exist;
|
expect(scope.select).to.exist;
|
||||||
expect(scope.remove).to.exist;
|
|
||||||
expect(scope.state.mailList).to.exist;
|
expect(scope.state.mailList).to.exist;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -361,6 +360,9 @@ describe('Mail List controller unit test', function() {
|
|||||||
mailList: {},
|
mailList: {},
|
||||||
read: {
|
read: {
|
||||||
toggle: function() {}
|
toggle: function() {}
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
markMessage: function() {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -399,7 +401,9 @@ describe('Mail List controller unit test', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs({userId: mail.from[0].address}).yields();
|
keychainMock.refreshKeyForUserId.withArgs({
|
||||||
|
userId: mail.from[0].address
|
||||||
|
}).yields();
|
||||||
|
|
||||||
scope.select(mail);
|
scope.select(mail);
|
||||||
|
|
||||||
@ -408,42 +412,4 @@ describe('Mail List controller unit test', function() {
|
|||||||
expect(scope.state.mailList.selected).to.equal(mail);
|
expect(scope.state.mailList.selected).to.equal(mail);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('remove', function() {
|
|
||||||
it('should not delete without a selected mail', function() {
|
|
||||||
scope.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the selected mail', function() {
|
|
||||||
var uid, mail, currentFolder;
|
|
||||||
|
|
||||||
scope._stopWatchTask();
|
|
||||||
|
|
||||||
scope.account = {};
|
|
||||||
uid = 123;
|
|
||||||
mail = {
|
|
||||||
uid: uid,
|
|
||||||
from: [{
|
|
||||||
address: 'asd'
|
|
||||||
}],
|
|
||||||
subject: '[whiteout] asdasd',
|
|
||||||
unread: true
|
|
||||||
};
|
|
||||||
currentFolder = {
|
|
||||||
type: 'Inbox',
|
|
||||||
path: 'INBOX',
|
|
||||||
messages: [mail]
|
|
||||||
};
|
|
||||||
scope.account.folders = [currentFolder];
|
|
||||||
scope.state.nav = {
|
|
||||||
currentFolder: currentFolder
|
|
||||||
};
|
|
||||||
emailDaoMock.deleteMessage.yields();
|
|
||||||
|
|
||||||
scope.remove(mail);
|
|
||||||
|
|
||||||
expect(emailDaoMock.deleteMessage.calledOnce).to.be.true;
|
|
||||||
expect(scope.state.mailList.selected).to.exist;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user