mirror of
https://github.com/moparisthebest/mail
synced 2024-11-26 02:42:17 -05:00
Refactor app controller to use new services
This commit is contained in:
parent
4c04ba4e74
commit
da5a9e2c17
@ -35,8 +35,8 @@ var axe = require('axe-logger'),
|
||||
WriteCtrl = require('./controller/write'),
|
||||
NavigationCtrl = require('./controller/navigation'),
|
||||
ActionBarCtrl = require('./controller/action-bar'),
|
||||
errorUtil = require('./util/error'),
|
||||
backButtonUtil = require('./util/backbutton-handler');
|
||||
backButtonUtil = require('./util/backbutton-handler'),
|
||||
StatusDisplayCtrl = require('./controller/app/status-display');
|
||||
|
||||
// include angular modules
|
||||
require('./app-config');
|
||||
@ -121,9 +121,6 @@ app.run(function($rootScope) {
|
||||
// global state... inherited to all child scopes
|
||||
$rootScope.state = {};
|
||||
|
||||
// attach global error handler
|
||||
errorUtil.attachHandler($rootScope);
|
||||
|
||||
// attach the back button handler to the root scope
|
||||
backButtonUtil.attachHandler($rootScope);
|
||||
|
||||
@ -142,6 +139,7 @@ app.controller('ContactsCtrl', ContactsCtrl);
|
||||
app.controller('AboutCtrl', AboutCtrl);
|
||||
app.controller('DialogCtrl', DialogCtrl);
|
||||
app.controller('ActionBarCtrl', ActionBarCtrl);
|
||||
app.controller('StatusDisplayCtrl', StatusDisplayCtrl);
|
||||
|
||||
//
|
||||
// Manual angular bootstraping
|
||||
|
@ -1,12 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var cfg = require('../app-config').config;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var AboutCtrl = function($scope) {
|
||||
var AboutCtrl = function($scope, appConfig) {
|
||||
|
||||
$scope.state.about = {
|
||||
toggle: function(to) {
|
||||
@ -18,7 +12,7 @@ var AboutCtrl = function($scope) {
|
||||
// scope variables
|
||||
//
|
||||
|
||||
$scope.version = cfg.appVersion + ' (beta)';
|
||||
$scope.version = appConfig.config.appVersion + ' (beta)';
|
||||
$scope.date = new Date();
|
||||
|
||||
//
|
||||
|
@ -1,18 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
dl = require('../util/download'),
|
||||
config = require('../app-config').config,
|
||||
pgp, keychain, userId;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var AccountCtrl = function($scope) {
|
||||
userId = appController._emailDao._account.emailAddress;
|
||||
keychain = appController._keychain;
|
||||
pgp = appController._pgp;
|
||||
var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dialog) {
|
||||
var userId = auth.emailAddress;
|
||||
|
||||
$scope.state.account = {
|
||||
toggle: function(to) {
|
||||
@ -31,7 +20,7 @@ var AccountCtrl = function($scope) {
|
||||
var fpr = keyParams.fingerprint;
|
||||
$scope.fingerprint = fpr.slice(0, 4) + ' ' + fpr.slice(4, 8) + ' ' + fpr.slice(8, 12) + ' ' + fpr.slice(12, 16) + ' ' + fpr.slice(16, 20) + ' ' + fpr.slice(20, 24) + ' ' + fpr.slice(24, 28) + ' ' + fpr.slice(28, 32) + ' ' + fpr.slice(32, 36) + ' ' + fpr.slice(36);
|
||||
$scope.keysize = keyParams.bitSize;
|
||||
$scope.publicKeyUrl = config.cloudUrl + '/' + userId;
|
||||
$scope.publicKeyUrl = appConfig.config.cloudUrl + '/' + userId;
|
||||
|
||||
//
|
||||
// scope functions
|
||||
@ -40,14 +29,14 @@ var AccountCtrl = function($scope) {
|
||||
$scope.exportKeyFile = function() {
|
||||
keychain.getUserKeyPair(userId, function(err, keys) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var keyId = keys.publicKey._id;
|
||||
var file = 'whiteout_mail_' + userId + '_' + keyId.substring(8, keyId.length);
|
||||
|
||||
dl.createDownload({
|
||||
download.createDownload({
|
||||
content: keys.publicKey.publicKey + '\r\n' + keys.privateKey.encryptedKey,
|
||||
filename: file + '.asc',
|
||||
contentType: 'text/plain'
|
||||
|
@ -1,15 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
emailDao;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var ActionBarCtrl = function($scope) {
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
var ActionBarCtrl = function($scope, email, dialog, statusDisplay) {
|
||||
|
||||
/**
|
||||
* Move a single message from the currently selected folder to another folder
|
||||
@ -24,9 +15,9 @@ var ActionBarCtrl = function($scope) {
|
||||
// close read state
|
||||
$scope.state.read.open = false;
|
||||
|
||||
$scope.state.mailList.updateStatus('Moving message...');
|
||||
statusDisplay.update('Moving message...');
|
||||
|
||||
emailDao.moveMessage({
|
||||
email.moveMessage({
|
||||
folder: currentFolder(),
|
||||
destination: destination,
|
||||
message: message
|
||||
@ -35,14 +26,14 @@ var ActionBarCtrl = function($scope) {
|
||||
// show errors where appropriate
|
||||
if (err.code === 42) {
|
||||
$scope.select(message);
|
||||
$scope.state.mailList.updateStatus('Unable to move message in offline mode!');
|
||||
statusDisplay.update('Unable to move message in offline mode!');
|
||||
return;
|
||||
}
|
||||
$scope.state.mailList.updateStatus('Error during move!');
|
||||
$scope.onError(err);
|
||||
statusDisplay.update('Error during move!');
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
$scope.state.mailList.updateStatus('Message moved.');
|
||||
statusDisplay.update('Message moved.');
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
@ -70,9 +61,9 @@ var ActionBarCtrl = function($scope) {
|
||||
// close read state
|
||||
$scope.state.read.open = false;
|
||||
|
||||
$scope.state.mailList.updateStatus('Deleting message...');
|
||||
statusDisplay.update('Deleting message...');
|
||||
|
||||
emailDao.deleteMessage({
|
||||
email.deleteMessage({
|
||||
folder: currentFolder(),
|
||||
message: message
|
||||
}, function(err) {
|
||||
@ -80,14 +71,14 @@ var ActionBarCtrl = function($scope) {
|
||||
// show errors where appropriate
|
||||
if (err.code === 42) {
|
||||
$scope.select(message);
|
||||
$scope.state.mailList.updateStatus('Unable to delete message in offline mode!');
|
||||
statusDisplay.update('Unable to delete message in offline mode!');
|
||||
return;
|
||||
}
|
||||
$scope.state.mailList.updateStatus('Error during delete!');
|
||||
$scope.onError(err);
|
||||
statusDisplay.update('Error during delete!');
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
$scope.state.mailList.updateStatus('Message deleted.');
|
||||
statusDisplay.update('Message deleted.');
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
@ -110,31 +101,31 @@ var ActionBarCtrl = function($scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.mailList.updateStatus('Updating unread flag...');
|
||||
statusDisplay.update('Updating unread flag...');
|
||||
|
||||
// close read state
|
||||
$scope.state.read.open = false;
|
||||
|
||||
var originalState = message.unread;
|
||||
message.unread = unread;
|
||||
emailDao.setFlags({
|
||||
email.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!');
|
||||
statusDisplay.update('Unable to mark message in offline mode!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
$scope.state.mailList.updateStatus('Error on sync!');
|
||||
$scope.onError(err);
|
||||
statusDisplay.update('Error on sync!');
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.mailList.updateStatus('Online');
|
||||
statusDisplay.update('Online');
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
@ -1,15 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
keychain, pgp;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var ContactsCtrl = function($scope) {
|
||||
keychain = appController._keychain,
|
||||
pgp = appController._pgp;
|
||||
var ContactsCtrl = function($scope, keychain, pgp, dialog) {
|
||||
|
||||
$scope.state.contacts = {
|
||||
toggle: function(to) {
|
||||
@ -26,7 +21,7 @@ var ContactsCtrl = function($scope) {
|
||||
$scope.listKeys = function() {
|
||||
keychain.listLocalPublicKeys(function(err, keys) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -54,7 +49,7 @@ var ContactsCtrl = function($scope) {
|
||||
|
||||
// verifiy public key string
|
||||
if (publicKeyArmored.indexOf('-----BEGIN PGP PUBLIC KEY BLOCK-----') < 0) {
|
||||
$scope.onError({
|
||||
dialog.error({
|
||||
showBugReporter: false,
|
||||
message: 'Invalid public key!'
|
||||
});
|
||||
@ -64,7 +59,7 @@ var ContactsCtrl = function($scope) {
|
||||
try {
|
||||
keyParams = pgp.getKeyParams(publicKeyArmored);
|
||||
} catch (e) {
|
||||
$scope.onError(new Error('Error reading public key params!'));
|
||||
dialog.error(new Error('Error reading public key params!'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,7 +73,7 @@ var ContactsCtrl = function($scope) {
|
||||
|
||||
keychain.saveLocalPublicKey(pubkey, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,7 +85,7 @@ var ContactsCtrl = function($scope) {
|
||||
$scope.removeKey = function(key) {
|
||||
keychain.removeLocalPublicKey(key._id, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
var DialogCtrl = function($scope) {
|
||||
$scope.confirm = function(ok) {
|
||||
$scope.state.dialog.open = false;
|
||||
var axe = require('axe-logger');
|
||||
|
||||
if ($scope.state.dialog.callback) {
|
||||
$scope.state.dialog.callback(ok);
|
||||
var DialogCtrl = function($scope, $q, dialog) {
|
||||
|
||||
var callback;
|
||||
|
||||
//
|
||||
// Set dialog disply functions
|
||||
//
|
||||
|
||||
dialog.displayInfo = function(options) {
|
||||
return $q(function(resolve) {
|
||||
setOptions(options);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
dialog.displayError = function(options) {
|
||||
return $q(function(resolve) {
|
||||
if (options) {
|
||||
axe.error((options.errMsg || options.message) + (options.stack ? ('\n' + options.stack) : ''));
|
||||
|
||||
setOptions(options);
|
||||
$scope.title = options.title || 'Error';
|
||||
$scope.showBugReporter = (typeof options.showBugReporter !== 'undefined' ? options.showBugReporter : !options.title); // if title is set, presume it's not an error by default
|
||||
}
|
||||
$scope.state.dialog.callback = undefined;
|
||||
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
dialog.displayConfirm = function(options) {
|
||||
return $q(function(resolve) {
|
||||
setOptions(options);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
function setOptions(options) {
|
||||
$scope.open = true;
|
||||
$scope.title = options.title;
|
||||
$scope.message = options.errMsg || options.message;
|
||||
$scope.faqLink = options.faqLink;
|
||||
$scope.positiveBtnStr = options.positiveBtnStr || 'Ok';
|
||||
$scope.negativeBtnStr = options.negativeBtnStr || 'Cancel';
|
||||
$scope.showNegativeBtn = options.showNegativeBtn || false;
|
||||
|
||||
callback = options.callback;
|
||||
}
|
||||
|
||||
//
|
||||
// Scope functions
|
||||
//
|
||||
|
||||
$scope.confirm = function(ok) {
|
||||
$scope.open = false;
|
||||
|
||||
if (callback) {
|
||||
callback(ok);
|
||||
}
|
||||
callback = undefined;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
notification = require('../util/notification'),
|
||||
emailDao, outboxBo, keychainDao, searchTimeout, firstSelect;
|
||||
var searchTimeout, firstSelect;
|
||||
|
||||
//
|
||||
// Constants
|
||||
@ -13,15 +11,11 @@ var INIT_DISPLAY_LEN = 20,
|
||||
FOLDER_TYPE_INBOX = 'Inbox',
|
||||
NOTIFICATION_INBOX_TIMEOUT = 5000;
|
||||
|
||||
var MailListCtrl = function($scope, $routeParams) {
|
||||
var MailListCtrl = function($scope, $routeParams, statusDisplay, notification, email, keychain, dialog) {
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
outboxBo = appController._outboxBo;
|
||||
keychainDao = appController._keychain;
|
||||
|
||||
/**
|
||||
* Gathers unread notifications to be cancelled later
|
||||
*/
|
||||
@ -31,39 +25,39 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
// scope functions
|
||||
//
|
||||
|
||||
$scope.getBody = function(email) {
|
||||
emailDao.getBody({
|
||||
$scope.getBody = function(message) {
|
||||
email.getBody({
|
||||
folder: currentFolder(),
|
||||
message: email
|
||||
message: message
|
||||
}, function(err) {
|
||||
if (err && err.code !== 42) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// display fetched body
|
||||
$scope.$digest();
|
||||
|
||||
// automatically decrypt if it's the selected email
|
||||
if (email === currentMessage()) {
|
||||
emailDao.decryptBody({
|
||||
message: email
|
||||
}, $scope.onError);
|
||||
// automatically decrypt if it's the selected message
|
||||
if (message === currentMessage()) {
|
||||
email.decryptBody({
|
||||
message: message
|
||||
}, dialog.error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when clicking on an email list item
|
||||
* Called when clicking on an message list item
|
||||
*/
|
||||
$scope.select = function(email) {
|
||||
$scope.select = function(message) {
|
||||
// unselect an item
|
||||
if (!email) {
|
||||
if (!message) {
|
||||
$scope.state.mailList.selected = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.mailList.selected = email;
|
||||
$scope.state.mailList.selected = message;
|
||||
|
||||
if (!firstSelect) {
|
||||
// only toggle to read view on 2nd select in mobile mode
|
||||
@ -71,22 +65,22 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
}
|
||||
firstSelect = false;
|
||||
|
||||
keychainDao.refreshKeyForUserId({
|
||||
userId: email.from[0].address
|
||||
keychain.refreshKeyForUserId({
|
||||
userId: message.from[0].address
|
||||
}, onKeyRefreshed);
|
||||
|
||||
function onKeyRefreshed(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
}
|
||||
|
||||
emailDao.decryptBody({
|
||||
message: email
|
||||
}, $scope.onError);
|
||||
email.decryptBody({
|
||||
message: message
|
||||
}, dialog.error);
|
||||
|
||||
// if the email is unread, please sync the new state.
|
||||
// if the message is unread, please sync the new state.
|
||||
// otherweise forget about it.
|
||||
if (!email.unread) {
|
||||
if (!message.unread) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -97,21 +91,16 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
}
|
||||
}
|
||||
|
||||
$scope.state.actionBar.markMessage(email, false);
|
||||
$scope.state.actionBar.markMessage(message, false);
|
||||
}
|
||||
};
|
||||
|
||||
// share local scope functions with root state
|
||||
$scope.state.mailList = {
|
||||
updateStatus: updateStatus
|
||||
};
|
||||
|
||||
//
|
||||
// watch tasks
|
||||
//
|
||||
|
||||
/**
|
||||
* List emails from folder when user changes folder
|
||||
* List messages from folder when user changes folder
|
||||
*/
|
||||
$scope._stopWatchTask = $scope.$watch('state.nav.currentFolder', function() {
|
||||
if (!currentFolder()) {
|
||||
@ -123,7 +112,7 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
|
||||
// in development, display dummy mail objects
|
||||
if ($routeParams.dev) {
|
||||
updateStatus('Last update: ', new Date());
|
||||
statusDisplay.update('Last update: ', new Date());
|
||||
currentFolder().messages = createDummyMails();
|
||||
return;
|
||||
}
|
||||
@ -183,20 +172,20 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
if (!searchText) {
|
||||
// set display buffer to first messages
|
||||
$scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN);
|
||||
setSearching(false);
|
||||
updateStatus('Online');
|
||||
statusDisplay.setSearching(false);
|
||||
statusDisplay.update('Online');
|
||||
return;
|
||||
}
|
||||
|
||||
// display searching spinner
|
||||
setSearching(true);
|
||||
updateStatus('Searching ...');
|
||||
statusDisplay.setSearching(true);
|
||||
statusDisplay.update('Searching ...');
|
||||
searchTimeout = setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
// filter relevant messages
|
||||
$scope.displayMessages = $scope.search(currentFolder().messages, searchText);
|
||||
setSearching(false);
|
||||
updateStatus('Matches in this folder');
|
||||
statusDisplay.setSearching(false);
|
||||
statusDisplay.update('Matches in this folder');
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
@ -276,10 +265,10 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
*/
|
||||
$scope.watchOnline = $scope.$watch('account.online', function(isOnline) {
|
||||
if (isOnline) {
|
||||
updateStatus('Online');
|
||||
statusDisplay.update('Online');
|
||||
openCurrentFolder();
|
||||
} else {
|
||||
updateStatus('Offline mode');
|
||||
statusDisplay.update('Offline mode');
|
||||
}
|
||||
}, true);
|
||||
|
||||
@ -292,7 +281,7 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
emailDao.openFolder({
|
||||
email.openFolder({
|
||||
folder: currentFolder()
|
||||
}, function(error) {
|
||||
// dont wait until scroll to load visible mail bodies
|
||||
@ -302,19 +291,10 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
if (error && error.code === 42) {
|
||||
return;
|
||||
}
|
||||
$scope.onError(error);
|
||||
dialog.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function updateStatus(lbl, time) {
|
||||
$scope.state.mailList.lastUpdateLbl = lbl;
|
||||
$scope.state.mailList.lastUpdate = (time) ? time : '';
|
||||
}
|
||||
|
||||
function setSearching(state) {
|
||||
$scope.state.mailList.searching = state;
|
||||
}
|
||||
|
||||
function currentFolder() {
|
||||
return $scope.state.nav.currentFolder;
|
||||
}
|
||||
@ -327,7 +307,7 @@ var MailListCtrl = function($scope, $routeParams) {
|
||||
// Notification API
|
||||
//
|
||||
|
||||
(emailDao || {}).onIncomingMessage = function(msgs) {
|
||||
(email || {}).onIncomingMessage = function(msgs) {
|
||||
var note, title, message, unreadMsgs;
|
||||
|
||||
unreadMsgs = msgs.filter(function(msg) {
|
||||
@ -402,7 +382,7 @@ ngModule.directive('listScroll', function() {
|
||||
}
|
||||
|
||||
for (var i = 0, len = listItems.length; i < len; i++) {
|
||||
// the n-th list item (the dom representation of an email) corresponds to
|
||||
// the n-th list item (the dom representation of an message) corresponds to
|
||||
// the n-th message model in the filteredMessages array
|
||||
listItem = listItems.item(i).getBoundingClientRect();
|
||||
|
||||
|
@ -1,11 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
notification = require('../util/notification'),
|
||||
backBtnHandler = require('../util/backbutton-handler'),
|
||||
appCfg = require('../app-config'),
|
||||
config = appCfg.config,
|
||||
str = appCfg.string;
|
||||
var backBtnHandler = require('../util/backbutton-handler');
|
||||
|
||||
//
|
||||
// Constants
|
||||
@ -18,9 +13,12 @@ var NOTIFICATION_SENT_TIMEOUT = 2000;
|
||||
// Controller
|
||||
//
|
||||
|
||||
var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox) {
|
||||
var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox, notification, appConfig, dialog) {
|
||||
!$routeParams.dev && !account.isLoggedIn() && $location.path('/'); // init app
|
||||
|
||||
var str = appConfig.string,
|
||||
config = appConfig.config;
|
||||
|
||||
//
|
||||
// scope functions
|
||||
//
|
||||
@ -39,7 +37,7 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o
|
||||
|
||||
$scope.onOutboxUpdate = function(err, count) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -52,19 +50,18 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o
|
||||
|
||||
email.refreshFolder({
|
||||
folder: ob
|
||||
}, $scope.onError);
|
||||
}, dialog.error);
|
||||
};
|
||||
|
||||
$scope.logout = function() {
|
||||
$scope.onError({
|
||||
dialog.confirm({
|
||||
title: str.logoutTitle,
|
||||
message: str.logoutMessage,
|
||||
callback: function(confirm) {
|
||||
if (confirm) {
|
||||
appController.logout();
|
||||
account.logout();
|
||||
}
|
||||
}
|
||||
},
|
||||
sync: true
|
||||
});
|
||||
};
|
||||
|
||||
@ -82,9 +79,9 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o
|
||||
$scope.openFolder($scope.account.folders[0]);
|
||||
}
|
||||
// connect imap/smtp clients on first startup
|
||||
appController.onConnect(function(err) {
|
||||
account.onConnect(function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
util = require('crypto-lib').util,
|
||||
keychain, pgp;
|
||||
var util = require('crypto-lib').util;
|
||||
|
||||
var PrivateKeyUploadCtrl = function($scope) {
|
||||
keychain = appController._keychain;
|
||||
pgp = keychain._pgp;
|
||||
var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
|
||||
|
||||
$scope.state.privateKeyUpload = {
|
||||
toggle: function(to) {
|
||||
@ -24,7 +20,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
// close lightbox
|
||||
$scope.state.lightbox = undefined;
|
||||
// show message
|
||||
$scope.onError({
|
||||
dialog.info({
|
||||
title: 'Info',
|
||||
message: 'Your PGP key has already been synced.'
|
||||
});
|
||||
@ -64,7 +60,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
keyId: keyParams._id
|
||||
}, function(err, privateKeySynced) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -93,8 +89,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
|
||||
if (inputCode.toUpperCase() !== $scope.code) {
|
||||
var err = new Error('The code does not match. Please go back and check the generated code.');
|
||||
err.sync = true;
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -106,7 +101,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
};
|
||||
|
||||
$scope.encryptAndUploadKey = function(callback) {
|
||||
var userId = appController._emailDao._account.emailAddress;
|
||||
var userId = auth.emailAddress;
|
||||
var code = $scope.code;
|
||||
|
||||
// register device to keychain service
|
||||
@ -114,7 +109,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
userId: userId
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -147,7 +142,7 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
// set device name to local storage
|
||||
$scope.setDeviceName(function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -158,14 +153,14 @@ var PrivateKeyUploadCtrl = function($scope) {
|
||||
// init key sync
|
||||
$scope.encryptAndUploadKey(function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// close sync dialog
|
||||
$scope.state.privateKeyUpload.toggle(false);
|
||||
// show success message
|
||||
$scope.onError({
|
||||
dialog.info({
|
||||
title: 'Success',
|
||||
message: 'Whiteout Keychain setup successful!'
|
||||
});
|
||||
|
@ -1,21 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
download = require('../util/download'),
|
||||
str = require('../app-config').string,
|
||||
emailDao, invitationDao, outbox, pgp, keychain;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var ReadCtrl = function($scope) {
|
||||
var ReadCtrl = function($scope, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) {
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
invitationDao = appController._invitationDao;
|
||||
outbox = appController._outboxBo;
|
||||
pgp = appController._pgp;
|
||||
keychain = appController._keychain;
|
||||
var str = appConfig.string;
|
||||
|
||||
// set default value so that the popover height is correct on init
|
||||
$scope.keyId = 'No key found.';
|
||||
@ -31,7 +22,7 @@ var ReadCtrl = function($scope) {
|
||||
$scope.keyId = 'Searching...';
|
||||
keychain.getReceiverPublicKey(address, function(err, pubkey) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -71,7 +62,7 @@ var ReadCtrl = function($scope) {
|
||||
|
||||
keychain.getReceiverPublicKey(user.address, function(err, pubkey) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -97,12 +88,12 @@ var ReadCtrl = function($scope) {
|
||||
}
|
||||
|
||||
var folder = $scope.state.nav.currentFolder;
|
||||
var email = $scope.state.mailList.selected;
|
||||
emailDao.getAttachment({
|
||||
var message = $scope.state.mailList.selected;
|
||||
email.getAttachment({
|
||||
folder: folder,
|
||||
uid: email.uid,
|
||||
uid: message.uid,
|
||||
attachment: attachment
|
||||
}, $scope.onError);
|
||||
}, dialog.error);
|
||||
};
|
||||
|
||||
$scope.invite = function(user) {
|
||||
@ -113,15 +104,15 @@ var ReadCtrl = function($scope) {
|
||||
|
||||
$scope.keyId = 'Sending invitation...';
|
||||
|
||||
var sender = emailDao._account.emailAddress,
|
||||
var sender = auth.emailAddress,
|
||||
recipient = user.address;
|
||||
|
||||
invitationDao.invite({
|
||||
invitation.invite({
|
||||
recipient: recipient,
|
||||
sender: sender
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -139,7 +130,7 @@ var ReadCtrl = function($scope) {
|
||||
};
|
||||
|
||||
// send invitation mail
|
||||
outbox.put(invitationMail, $scope.onError);
|
||||
outbox.put(invitationMail, dialog.error);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -1,16 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
pgp, keychain;
|
||||
var SetPassphraseCtrl = function($scope, pgp, keychain, dialog) {
|
||||
|
||||
//
|
||||
// Controller
|
||||
// scope variables
|
||||
//
|
||||
|
||||
var SetPassphraseCtrl = function($scope) {
|
||||
keychain = appController._keychain;
|
||||
pgp = appController._pgp;
|
||||
|
||||
$scope.state.setPassphrase = {
|
||||
toggle: function(to) {
|
||||
$scope.state.lightbox = (to) ? 'set-passphrase' : undefined;
|
||||
@ -22,10 +17,6 @@ var SetPassphraseCtrl = function($scope) {
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// scope variables
|
||||
//
|
||||
|
||||
//
|
||||
// scope functions
|
||||
//
|
||||
@ -87,7 +78,7 @@ var SetPassphraseCtrl = function($scope) {
|
||||
var keyId = pgp.getKeyParams()._id;
|
||||
keychain.lookupPrivateKey(keyId, function(err, savedKey) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -102,7 +93,7 @@ var SetPassphraseCtrl = function($scope) {
|
||||
function onPassphraseChanged(err, newPrivateKeyArmored) {
|
||||
if (err) {
|
||||
err.showBugReporter = false;
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -120,13 +111,13 @@ var SetPassphraseCtrl = function($scope) {
|
||||
|
||||
function onKeyPersisted(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.setPassphrase.toggle(false);
|
||||
$scope.$apply();
|
||||
$scope.onError({
|
||||
dialog.info({
|
||||
title: 'Success',
|
||||
message: 'Passphrase change complete.'
|
||||
});
|
||||
|
20
src/js/controller/app/status-display.js
Normal file
20
src/js/controller/app/status-display.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var StatusDisplayCtrl = function($scope, statusDisplay) {
|
||||
|
||||
// set the show functions
|
||||
statusDisplay.showStatus = updateStatus;
|
||||
statusDisplay.showSearching = setSearching;
|
||||
|
||||
function updateStatus(lbl, time) {
|
||||
$scope.lastUpdateLbl = lbl;
|
||||
$scope.lastUpdate = (time) ? time : '';
|
||||
}
|
||||
|
||||
function setSearching(state) {
|
||||
$scope.searching = state;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = StatusDisplayCtrl;
|
@ -1,21 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller'),
|
||||
axe = require('axe-logger'),
|
||||
util = require('crypto-lib').util,
|
||||
str = require('../app-config').string,
|
||||
pgp, emailDao, outbox, keychainDao, auth;
|
||||
var axe = require('axe-logger'),
|
||||
util = require('crypto-lib').util;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var WriteCtrl = function($scope, $filter, $q) {
|
||||
pgp = appController._pgp;
|
||||
auth = appController._auth;
|
||||
emailDao = appController._emailDao;
|
||||
outbox = appController._outboxBo;
|
||||
keychainDao = appController._keychain;
|
||||
var WriteCtrl = function($scope, $filter, $q, appConfig, auth, keychain, pgp, email, outbox, dialog) {
|
||||
|
||||
var str = appConfig.string;
|
||||
|
||||
// set default value so that the popover height is correct on init
|
||||
$scope.keyId = 'XXXXXXXX';
|
||||
@ -133,7 +127,7 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
}
|
||||
if (replyAll) {
|
||||
re.to.concat(re.cc).forEach(function(recipient) {
|
||||
var me = emailDao._account.emailAddress;
|
||||
var me = auth.emailAddress;
|
||||
if (recipient.address === me && replyTo !== me) {
|
||||
// don't reply to yourself
|
||||
return;
|
||||
@ -225,15 +219,15 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
return;
|
||||
}
|
||||
|
||||
// keychainDao is undefined in local dev environment
|
||||
if (keychainDao) {
|
||||
// keychain is undefined in local dev environment
|
||||
if (keychain) {
|
||||
// check if to address is contained in known public keys
|
||||
// when we write an email, we always need to work with the latest keys available
|
||||
keychainDao.refreshKeyForUserId({
|
||||
keychain.refreshKeyForUserId({
|
||||
userId: recipient.address
|
||||
}, function(err, key) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -318,13 +312,13 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
//
|
||||
|
||||
$scope.sendToOutbox = function() {
|
||||
var email;
|
||||
var message;
|
||||
|
||||
// build email model for smtp-client
|
||||
email = {
|
||||
message = {
|
||||
from: [{
|
||||
name: emailDao._account.realname,
|
||||
address: emailDao._account.emailAddress
|
||||
name: auth.realname,
|
||||
address: auth.emailAddress
|
||||
}],
|
||||
to: $scope.to.filter(filterEmptyAddresses),
|
||||
cc: $scope.cc.filter(filterEmptyAddresses),
|
||||
@ -337,11 +331,11 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
};
|
||||
|
||||
if ($scope.inReplyTo) {
|
||||
email.headers['in-reply-to'] = '<' + $scope.inReplyTo + '>';
|
||||
message.headers['in-reply-to'] = '<' + $scope.inReplyTo + '>';
|
||||
}
|
||||
|
||||
if ($scope.references && $scope.references.length) {
|
||||
email.headers.references = $scope.references.map(function(reference) {
|
||||
message.headers.references = $scope.references.map(function(reference) {
|
||||
return '<' + reference + '>';
|
||||
}).join(' ');
|
||||
}
|
||||
@ -350,9 +344,9 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
$scope.state.writer.close();
|
||||
|
||||
// persist the email to disk for later sending
|
||||
outbox.put(email, function(err) {
|
||||
outbox.put(message, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -363,12 +357,12 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
}
|
||||
|
||||
$scope.replyTo.answered = true;
|
||||
emailDao.setFlags({
|
||||
email.setFlags({
|
||||
folder: currentFolder(),
|
||||
message: $scope.replyTo
|
||||
}, function(err) {
|
||||
if (err && err.code !== 42) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -396,9 +390,9 @@ var WriteCtrl = function($scope, $filter, $q) {
|
||||
|
||||
if (!$scope.addressBookCache) {
|
||||
// populate address book cache
|
||||
keychainDao.listLocalPublicKeys(function(err, keys) {
|
||||
keychain.listLocalPublicKeys(function(err, keys) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth) {
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth, dialog) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.getAccountSettings = function() {
|
||||
@ -36,7 +36,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth)
|
||||
|
||||
$scope.oauthPossible = function() {
|
||||
// ask user to use the platform's native OAuth api
|
||||
$scope.onError({
|
||||
dialog.confirm({
|
||||
title: 'Google Account Login',
|
||||
message: 'You are signing into a Google account. Would you like to sign in with Google or just continue with a password login?',
|
||||
positiveBtnStr: 'Google sign in',
|
||||
@ -59,7 +59,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth)
|
||||
// fetches the email address from the chrome identity api
|
||||
auth.getOAuthToken(function(err) {
|
||||
if (err) {
|
||||
return $scope.onError(err);
|
||||
return dialog.error(err);
|
||||
}
|
||||
$scope.setCredentials();
|
||||
$scope.$apply();
|
||||
|
@ -9,7 +9,7 @@ var axe = require('axe-logger'),
|
||||
PgpMailer = require('pgpmailer'),
|
||||
ImapClient = require('imap-client');
|
||||
|
||||
function Account(appConfig, auth, admin, mailConfig, keychain, pgpbuilder, email, outbox, deviceStorage, updateHandler) {
|
||||
function Account(appConfig, auth, admin, mailConfig, keychain, pgpbuilder, email, outbox, accountStore, updateHandler) {
|
||||
this._appConfig = appConfig;
|
||||
this._auth = auth;
|
||||
this._admin = admin;
|
||||
@ -18,7 +18,7 @@ function Account(appConfig, auth, admin, mailConfig, keychain, pgpbuilder, email
|
||||
this._emailDao = email;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._outbox = outbox;
|
||||
this._deviceStorage = deviceStorage;
|
||||
this._accountStore = accountStore;
|
||||
this._updateHandler = updateHandler;
|
||||
this._accounts = []; // init accounts list
|
||||
}
|
||||
@ -61,7 +61,7 @@ Account.prototype.init = function(options, callback) {
|
||||
|
||||
// Pre-Flight check: initialize and prepare user's local database
|
||||
function prepareDatabase() {
|
||||
self._deviceStorage.init(options.emailAddress, function(err) {
|
||||
self._accountStore.init(options.emailAddress, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ var MSG_PART_TYPE_HTML = 'html';
|
||||
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
||||
* @param {Object} mailreader Parses MIME messages received from IMAP
|
||||
*/
|
||||
function Email(keychain, pgp, deviceStorage, pgpbuilder, mailreader, dialog) {
|
||||
function Email(keychain, pgp, accountStore, pgpbuilder, mailreader, dialog) {
|
||||
this._keychain = keychain;
|
||||
this._pgp = pgp;
|
||||
this._devicestorage = deviceStorage;
|
||||
this._devicestorage = accountStore;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._mailreader = mailreader;
|
||||
|
||||
|
@ -13,7 +13,7 @@ var util = require('crypto-lib').util,
|
||||
* The local outbox takes care of the emails before they are being sent.
|
||||
* It also checks periodically if there are any mails in the local device storage to be sent.
|
||||
*/
|
||||
function Outbox(email, keychain, deviceStorage) {
|
||||
function Outbox(email, keychain, accountStore) {
|
||||
/** @private */
|
||||
this._emailDao = email;
|
||||
|
||||
@ -21,7 +21,7 @@ function Outbox(email, keychain, deviceStorage) {
|
||||
this._keychain = keychain;
|
||||
|
||||
/** @private */
|
||||
this._devicestorage = deviceStorage;
|
||||
this._devicestorage = accountStore;
|
||||
|
||||
/**
|
||||
* Semaphore-esque flag to avoid 'concurrent' calls to _processOutbox when the timeout fires, but a call is still in process.
|
||||
|
@ -1,15 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woServices');
|
||||
ngModule.service('appConfigStore', AppConfigStore);
|
||||
module.exports = AppConfigStore;
|
||||
|
||||
/**
|
||||
* A service for storing app configuration and user credential data locally
|
||||
*/
|
||||
function AppConfigStore(lawnchairDAO) {
|
||||
this._localDbDao = lawnchairDAO;
|
||||
this._localDbDao.init('app-config');
|
||||
}
|
||||
|
||||
// TODO: inherit DeviceStorage service api
|
@ -1,18 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woServices');
|
||||
ngModule.service('deviceStorage', DeviceStorage);
|
||||
ngModule.factory('deviceStorage', function(lawnchairDAO) {
|
||||
return new DeviceStorage(lawnchairDAO);
|
||||
});
|
||||
module.exports = DeviceStorage;
|
||||
|
||||
// expose an instance with the static dbName 'app-config' to store configuration data
|
||||
ngModule.factory('appConfigStore', function(deviceStorage) {
|
||||
deviceStorage.init('app-config');
|
||||
return deviceStorage;
|
||||
});
|
||||
|
||||
// expose a singleton instance of DeviceStorage called 'accountStore' to persist user data
|
||||
ngModule.service('accountStore', DeviceStorage);
|
||||
|
||||
/**
|
||||
* High level storage api that handles all persistence of a user's data on the device.
|
||||
*/
|
||||
function DeviceStorage(lawnchairDAO) {
|
||||
this._localDbDao = lawnchairDAO;
|
||||
this._lawnchairDAO = lawnchairDAO;
|
||||
}
|
||||
|
||||
DeviceStorage.prototype.init = function(dbName) {
|
||||
this._localDbDao.init(dbName);
|
||||
this._lawnchairDAO.init(dbName);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -46,14 +57,14 @@ DeviceStorage.prototype.storeList = function(list, type, callback) {
|
||||
});
|
||||
});
|
||||
|
||||
this._localDbDao.batch(items, callback);
|
||||
this._lawnchairDAO.batch(items, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes items of a certain type from storage
|
||||
*/
|
||||
DeviceStorage.prototype.removeList = function(type, callback) {
|
||||
this._localDbDao.removeList(type, callback);
|
||||
this._lawnchairDAO.removeList(type, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -64,14 +75,14 @@ DeviceStorage.prototype.removeList = function(type, callback) {
|
||||
*/
|
||||
DeviceStorage.prototype.listItems = function(type, offset, num, callback) {
|
||||
// fetch all items of a certain type from the data-store
|
||||
this._localDbDao.list(type, offset, num, callback);
|
||||
this._lawnchairDAO.list(type, offset, num, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the whole device data-store
|
||||
*/
|
||||
DeviceStorage.prototype.clear = function(callback) {
|
||||
this._localDbDao.clear(callback);
|
||||
this._lawnchairDAO.clear(callback);
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -12,6 +12,5 @@ require('./publickey');
|
||||
require('./admin');
|
||||
require('./lawnchair');
|
||||
require('./devicestorage');
|
||||
require('./app-config-store');
|
||||
require('./auth');
|
||||
require('./keychain');
|
@ -6,8 +6,14 @@ module.exports = Dialog;
|
||||
|
||||
function Dialog() {}
|
||||
|
||||
Dialog.prototype.error = function() {};
|
||||
Dialog.prototype.info = function(options) {
|
||||
this.displayInfo(options);
|
||||
};
|
||||
|
||||
Dialog.prototype.info = function() {};
|
||||
Dialog.prototype.error = function(options) {
|
||||
this.displayError(options);
|
||||
};
|
||||
|
||||
Dialog.prototype.confirm = function() {};
|
||||
Dialog.prototype.confirm = function(options) {
|
||||
this.displayConfirm(options);
|
||||
};
|
@ -1,10 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woUtil');
|
||||
ngModule.service('download', Download);
|
||||
module.exports = Download;
|
||||
|
||||
var util = require('crypto-lib').util;
|
||||
|
||||
var dl = {};
|
||||
/**
|
||||
* A download helper to abstract platform specific behavior
|
||||
*/
|
||||
function Download() {}
|
||||
|
||||
dl.createDownload = function(options) {
|
||||
/**
|
||||
* Create download link and click on it.
|
||||
*/
|
||||
Download.prototype.createDownload = function(options) {
|
||||
var contentType = options.contentType || 'application/octet-stream';
|
||||
var filename = options.filename || 'file';
|
||||
var content = options.content;
|
||||
@ -54,5 +64,3 @@ dl.createDownload = function(options) {
|
||||
window.open('data:' + contentType + ';base64,' + btoa(content), "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = dl;
|
@ -1,33 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe-logger');
|
||||
|
||||
var er = {};
|
||||
er.attachHandler = function(scope) {
|
||||
scope.onError = function(options) {
|
||||
if (!options) {
|
||||
scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
axe.error((options.errMsg || options.message) + (options.stack ? ('\n' + options.stack) : ''));
|
||||
|
||||
scope.state.dialog = {
|
||||
open: true,
|
||||
title: options.title || 'Error',
|
||||
message: options.errMsg || options.message,
|
||||
faqLink: options.faqLink,
|
||||
positiveBtnStr: options.positiveBtnStr || 'Ok',
|
||||
negativeBtnStr: options.negativeBtnStr || 'Cancel',
|
||||
showNegativeBtn: options.showNegativeBtn || false,
|
||||
showBugReporter: (typeof options.showBugReporter !== 'undefined' ? options.showBugReporter : !options.title), // if title is set, presume it's not an error by default
|
||||
callback: options.callback
|
||||
};
|
||||
// don't call apply for synchronous calls
|
||||
if (!options.sync) {
|
||||
scope.$apply();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = er;
|
@ -5,3 +5,6 @@ angular.module('woUtil', []);
|
||||
require('./dialog');
|
||||
require('./connection-doctor');
|
||||
require('./update/update-handler');
|
||||
require('./status-display');
|
||||
require('./download');
|
||||
require('./notification');
|
@ -1,11 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var cfg = require('../app-config').config;
|
||||
var ngModule = angular.module('woUtil');
|
||||
ngModule.service('notification', Notif);
|
||||
module.exports = Notif;
|
||||
|
||||
var notif = {};
|
||||
function Notif(appConfig) {
|
||||
this._appConfig = appConfig;
|
||||
|
||||
if (window.Notification) {
|
||||
notif.hasPermission = Notification.permission === "granted";
|
||||
this.hasPermission = Notification.permission === "granted";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -17,25 +21,27 @@ if (window.Notification) {
|
||||
* @param {Function} options.onClick (optional) callback when the notification is clicked
|
||||
* @returns {Notification} A notification instance
|
||||
*/
|
||||
notif.create = function(options) {
|
||||
Notif.prototype.create = function(options) {
|
||||
var self = this;
|
||||
|
||||
options.onClick = options.onClick || function() {};
|
||||
|
||||
if (!window.Notification) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!notif.hasPermission) {
|
||||
if (!self.hasPermission) {
|
||||
// don't wait until callback returns
|
||||
Notification.requestPermission(function(permission) {
|
||||
if (permission === "granted") {
|
||||
notif.hasPermission = true;
|
||||
self.hasPermission = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var notification = new Notification(options.title, {
|
||||
body: options.message,
|
||||
icon: cfg.iconPath
|
||||
icon: self._appConfig.config.iconPath
|
||||
});
|
||||
notification.onclick = function() {
|
||||
window.focus();
|
||||
@ -51,8 +57,6 @@ notif.create = function(options) {
|
||||
return notification;
|
||||
};
|
||||
|
||||
notif.close = function(notification) {
|
||||
Notif.prototype.close = function(notification) {
|
||||
notification.close();
|
||||
};
|
||||
|
||||
module.exports = notif;
|
24
src/js/util/status-display.js
Normal file
24
src/js/util/status-display.js
Normal file
@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woUtil');
|
||||
ngModule.service('statusDisplay', StatusDisplay);
|
||||
module.exports = StatusDisplay;
|
||||
|
||||
function StatusDisplay() {}
|
||||
|
||||
/**
|
||||
* Update the status disply in the lower left of the screen
|
||||
* @param {String} msg The status message that is to be displayed to the user
|
||||
* @param {Date} time The time of the last update
|
||||
*/
|
||||
StatusDisplay.prototype.update = function(msg, time) {
|
||||
this.showStatus(msg, time);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the searching status to show a spinner while searching
|
||||
* @param {Boolean} state If the spinner should be displayed or not
|
||||
*/
|
||||
StatusDisplay.prototype.setSearching = function(state) {
|
||||
this.showSearching(state);
|
||||
};
|
@ -1,19 +1,19 @@
|
||||
<div class="lightbox__body" ng-controller="DialogCtrl">
|
||||
<header class="lightbox__header">
|
||||
<h2>{{state.dialog.title}}</h2>
|
||||
<h2>{{title}}</h2>
|
||||
<button class="lightbox__close" wo-touch="confirm(false)" data-action="lightbox-close">
|
||||
<svg><use xlink:href="#icon-close" /><title>Close</title></svg>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="lightbox__content">
|
||||
<p class="typo-paragraph">{{state.dialog.message}} <a ng-show="state.dialog.faqLink" href="{{state.dialog.faqLink}}" target="_blank">Learn more</a></p>
|
||||
<p class="typo-paragraph">{{message}} <a ng-show="faqLink" href="{{faqLink}}" target="_blank">Learn more</a></p>
|
||||
</div>
|
||||
|
||||
<footer class="lightbox__controls">
|
||||
<button wo-touch="confirm(false)" class="btn btn--secondary" ng-show="state.dialog.showNegativeBtn">{{state.dialog.negativeBtnStr}}</button>
|
||||
<button wo-touch="confirm(false)" class="btn btn--secondary" ng-show="showNegativeBtn">{{negativeBtnStr}}</button>
|
||||
<!-- only show bug report button if we can actually report a bug, i.e. the writer is attached to the scope -->
|
||||
<button wo-touch="confirm(true)" class="btn" ng-show="!state.writer || !state.dialog.showBugReporter">{{state.dialog.positiveBtnStr}}</button>
|
||||
<button wo-touch="confirm(true); state.writer.reportBug()" class="btn" ng-show="state.writer && state.dialog.showBugReporter">Report bug</button>
|
||||
<button wo-touch="confirm(true)" class="btn" ng-show="!state.writer || !showBugReporter">{{positiveBtnStr}}</button>
|
||||
<button wo-touch="confirm(true); state.writer.reportBug()" class="btn" ng-show="state.writer && showBugReporter">Report bug</button>
|
||||
</footer>
|
||||
</div>
|
@ -17,7 +17,7 @@
|
||||
<svg><use xlink:href="#icon-search" /><title>Search</title></svg>
|
||||
<input class="input-text" type="text" ng-model="searchText"
|
||||
ng-change="displaySearchResults(searchText)"
|
||||
placeholder="Search" wo-focus-me="state.mailList.searching">
|
||||
placeholder="Search">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -71,13 +71,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<span class="spinner" ng-show="account.loggingIn || account.busy || state.mailList.searching"></span>
|
||||
<footer ng-controller="StatusDisplayCtrl">
|
||||
<span class="spinner" ng-show="account.loggingIn || account.busy || searching"></span>
|
||||
<span class="text" ng-switch="account.online">
|
||||
<span ng-switch-when="false">
|
||||
<svg><use xlink:href="#icon-offline" /></svg>
|
||||
</span>
|
||||
{{state.mailList.lastUpdateLbl}} {{state.mailList.lastUpdate | date:'shortTime'}}
|
||||
{{lastUpdateLbl}} {{lastUpdate | date:'shortTime'}}
|
||||
</span>
|
||||
</footer>
|
||||
</div>
|
@ -69,13 +69,13 @@
|
||||
</li>
|
||||
</ul><!--/nav__secondary-->
|
||||
|
||||
<footer>
|
||||
<span class="spinner" ng-show="account.loggingIn || account.busy || state.mailList.searching"></span>
|
||||
<footer ng-controller="StatusDisplayCtrl">
|
||||
<span class="spinner" ng-show="account.loggingIn || account.busy || searching"></span>
|
||||
<span class="text" ng-switch="account.online">
|
||||
<span ng-switch-when="false">
|
||||
<svg><use xlink:href="#icon-offline" /></svg>
|
||||
</span>
|
||||
{{state.mailList.lastUpdateLbl}} {{state.mailList.lastUpdate | date:'shortTime'}}
|
||||
{{lastUpdateLbl}} {{lastUpdate | date:'shortTime'}}
|
||||
</span>
|
||||
</footer>
|
||||
</nav>
|
Loading…
Reference in New Issue
Block a user