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