2013-09-04 15:01:32 -04:00
|
|
|
define(function(require) {
|
2013-09-04 12:39:26 -04:00
|
|
|
'use strict';
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
var angular = require('angular'),
|
2013-12-04 08:15:12 -05:00
|
|
|
_ = require('underscore'),
|
2013-09-11 17:31:08 -04:00
|
|
|
appController = require('js/app-controller'),
|
2014-04-01 07:16:39 -04:00
|
|
|
notification = require('js/util/notification'),
|
2014-07-21 10:05:29 -04:00
|
|
|
emailDao, outboxBo, keychainDao, searchTimeout, firstSelect;
|
2014-07-16 06:47:25 -04:00
|
|
|
|
|
|
|
var INIT_DISPLAY_LEN = 20,
|
2014-09-16 13:01:49 -04:00
|
|
|
SCROLL_DISPLAY_LEN = 10,
|
|
|
|
FOLDER_TYPE_INBOX = 'Inbox';
|
2013-09-04 12:39:26 -04:00
|
|
|
|
2014-08-12 11:09:18 -04:00
|
|
|
var MailListCtrl = function($scope, $routeParams) {
|
2013-11-08 17:31:20 -05:00
|
|
|
//
|
|
|
|
// Init
|
|
|
|
//
|
|
|
|
|
2013-09-15 11:05:37 -04:00
|
|
|
emailDao = appController._emailDao;
|
2013-11-21 11:37:07 -05:00
|
|
|
outboxBo = appController._outboxBo;
|
2014-05-23 04:52:34 -04:00
|
|
|
keychainDao = appController._keychain;
|
2014-04-28 12:09:51 -04:00
|
|
|
|
2014-09-16 13:01:49 -04:00
|
|
|
/**
|
|
|
|
* Gathers unread notifications to be cancelled later
|
|
|
|
*/
|
|
|
|
$scope.pendingNotifications = [];
|
|
|
|
|
2013-09-28 10:08:12 -04:00
|
|
|
//
|
|
|
|
// scope functions
|
|
|
|
//
|
|
|
|
|
2014-02-20 09:42:51 -05:00
|
|
|
$scope.getBody = function(email) {
|
|
|
|
emailDao.getBody({
|
2014-05-23 08:23:50 -04:00
|
|
|
folder: currentFolder(),
|
2014-02-17 08:31:14 -05:00
|
|
|
message: email
|
2014-02-21 10:22:33 -05:00
|
|
|
}, function(err) {
|
2014-04-01 07:16:39 -04:00
|
|
|
if (err && err.code !== 42) {
|
2014-02-21 10:22:33 -05:00
|
|
|
$scope.onError(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// display fetched body
|
2014-04-24 09:44:54 -04:00
|
|
|
$scope.$digest();
|
2014-02-21 10:22:33 -05:00
|
|
|
|
|
|
|
// automatically decrypt if it's the selected email
|
2014-05-23 08:23:50 -04:00
|
|
|
if (email === currentMessage()) {
|
2014-02-24 04:14:07 -05:00
|
|
|
emailDao.decryptBody({
|
2014-02-21 10:22:33 -05:00
|
|
|
message: email
|
|
|
|
}, $scope.onError);
|
|
|
|
}
|
|
|
|
});
|
2014-02-17 08:31:14 -05:00
|
|
|
};
|
|
|
|
|
2014-01-15 09:27:38 -05:00
|
|
|
/**
|
|
|
|
* Called when clicking on an email list item
|
|
|
|
*/
|
2013-11-08 17:31:20 -05:00
|
|
|
$scope.select = function(email) {
|
2014-02-18 11:05:51 -05:00
|
|
|
// unselect an item
|
2013-10-04 12:01:42 -04:00
|
|
|
if (!email) {
|
2013-11-09 07:33:37 -05:00
|
|
|
$scope.state.mailList.selected = undefined;
|
2013-10-04 12:01:42 -04:00
|
|
|
return;
|
|
|
|
}
|
2013-11-18 11:44:59 -05:00
|
|
|
|
2014-02-21 04:47:49 -05:00
|
|
|
$scope.state.mailList.selected = email;
|
2014-07-21 10:05:29 -04:00
|
|
|
|
|
|
|
if (!firstSelect) {
|
|
|
|
// only toggle to read view on 2nd select in mobile mode
|
|
|
|
$scope.state.read.toggle(true);
|
|
|
|
}
|
|
|
|
firstSelect = false;
|
2014-02-21 04:47:49 -05:00
|
|
|
|
2014-05-23 04:52:34 -04:00
|
|
|
keychainDao.refreshKeyForUserId(email.from[0].address, onKeyRefreshed);
|
2014-02-17 08:31:14 -05:00
|
|
|
|
2014-05-23 04:52:34 -04:00
|
|
|
function onKeyRefreshed(err) {
|
|
|
|
if (err) {
|
|
|
|
$scope.onError(err);
|
|
|
|
}
|
2013-12-05 12:28:18 -05:00
|
|
|
|
2014-05-23 04:52:34 -04:00
|
|
|
emailDao.decryptBody({
|
|
|
|
message: email
|
|
|
|
}, $scope.onError);
|
|
|
|
|
|
|
|
// if the email is unread, please sync the new state.
|
|
|
|
// otherweise forget about it.
|
|
|
|
if (!email.unread) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:01:49 -04:00
|
|
|
// let's close pending notifications for unread messages in the inbox
|
|
|
|
if (currentFolder().type === FOLDER_TYPE_INBOX) {
|
|
|
|
while ($scope.pendingNotifications.length) {
|
|
|
|
notification.close($scope.pendingNotifications.shift());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-23 04:52:34 -04:00
|
|
|
$scope.toggleUnread(email);
|
|
|
|
}
|
2013-09-04 12:39:26 -04:00
|
|
|
};
|
2013-09-04 15:01:32 -04:00
|
|
|
|
2014-01-15 09:27:38 -05:00
|
|
|
/**
|
2014-01-16 05:36:30 -05:00
|
|
|
* Mark an email as unread or read, respectively
|
2014-01-15 09:27:38 -05:00
|
|
|
*/
|
2014-05-23 08:23:50 -04:00
|
|
|
$scope.toggleUnread = function(message) {
|
|
|
|
updateStatus('Updating unread flag...');
|
2013-12-05 09:02:41 -05:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
message.unread = !message.unread;
|
|
|
|
emailDao.setFlags({
|
|
|
|
folder: currentFolder(),
|
|
|
|
message: message
|
|
|
|
}, function(err) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (err && err.code === 42) {
|
2014-05-23 08:23:50 -04:00
|
|
|
// offline, restore
|
|
|
|
message.unread = !message.unread;
|
|
|
|
updateStatus('Unable to mark unread flag in offline mode!');
|
2013-12-09 13:21:52 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
if (err) {
|
|
|
|
updateStatus('Error on sync!');
|
|
|
|
$scope.onError(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-11-11 09:53:34 -05:00
|
|
|
|
2014-06-10 08:23:51 -04:00
|
|
|
updateStatus('Online');
|
2013-12-03 14:25:39 -05:00
|
|
|
$scope.$apply();
|
2014-05-23 08:23:50 -04:00
|
|
|
});
|
2013-12-03 13:21:50 -05:00
|
|
|
};
|
2013-11-21 11:37:07 -05:00
|
|
|
|
2014-01-15 09:27:38 -05:00
|
|
|
/**
|
2014-05-23 08:23:50 -04:00
|
|
|
* Delete a message
|
2014-01-15 09:27:38 -05:00
|
|
|
*/
|
2014-05-23 08:23:50 -04:00
|
|
|
$scope.remove = function(message) {
|
|
|
|
if (!message) {
|
2013-11-11 09:53:34 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
updateStatus('Deleting message...');
|
|
|
|
remove();
|
|
|
|
|
|
|
|
function remove() {
|
|
|
|
emailDao.deleteMessage({
|
|
|
|
folder: currentFolder(),
|
|
|
|
message: message
|
|
|
|
}, function(err) {
|
|
|
|
if (err) {
|
|
|
|
// show errors where appropriate
|
|
|
|
if (err.code === 42) {
|
|
|
|
$scope.select(message);
|
|
|
|
updateStatus('Unable to delete message in offline mode!');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
updateStatus('Error during delete!');
|
|
|
|
$scope.onError(err);
|
|
|
|
}
|
|
|
|
updateStatus('Message deleted!');
|
|
|
|
$scope.$apply();
|
2013-12-04 08:15:12 -05:00
|
|
|
});
|
|
|
|
}
|
2013-11-08 17:31:20 -05:00
|
|
|
};
|
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
// share local scope functions with root state
|
|
|
|
$scope.state.mailList = {
|
2014-05-23 08:23:50 -04:00
|
|
|
remove: $scope.remove
|
2013-12-09 13:21:52 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// watch tasks
|
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List emails from folder when user changes folder
|
|
|
|
*/
|
2013-11-21 11:37:07 -05:00
|
|
|
$scope._stopWatchTask = $scope.$watch('state.nav.currentFolder', function() {
|
2014-04-28 12:09:51 -04:00
|
|
|
if (!currentFolder()) {
|
2013-10-10 13:15:16 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
// reset searchFilter
|
|
|
|
$scope.searchText = undefined;
|
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
// in development, display dummy mail objects
|
2014-08-12 11:09:18 -04:00
|
|
|
if ($routeParams.dev) {
|
2013-11-21 11:37:07 -05:00
|
|
|
updateStatus('Last update: ', new Date());
|
2014-04-28 12:09:51 -04:00
|
|
|
currentFolder().messages = createDummyMails();
|
2013-11-21 11:37:07 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-29 16:11:22 -04:00
|
|
|
// display and select first
|
2014-05-23 08:23:50 -04:00
|
|
|
openCurrentFolder();
|
2013-09-04 15:01:32 -04:00
|
|
|
});
|
2013-09-04 12:39:26 -04:00
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
$scope.watchMessages = $scope.$watchCollection('state.nav.currentFolder.messages', function(messages) {
|
2014-06-02 11:54:29 -04:00
|
|
|
if (!messages) {
|
2014-05-23 08:23:50 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
// sort message by uid
|
|
|
|
currentFolder().messages.sort(byUidDescending);
|
|
|
|
// set display buffer to first messages
|
|
|
|
$scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN);
|
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
// Shows the next message based on the uid of the currently selected element
|
2014-07-16 06:47:25 -04:00
|
|
|
if (currentFolder().messages.indexOf(currentMessage()) === -1) {
|
2014-07-21 10:05:29 -04:00
|
|
|
firstSelect = true; // reset first selection
|
|
|
|
$scope.select($scope.displayMessages[0]);
|
2014-05-23 08:23:50 -04:00
|
|
|
}
|
2014-07-16 06:47:25 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* display more items (for infinite scrolling)
|
|
|
|
*/
|
|
|
|
$scope.displayMore = function() {
|
2014-07-01 13:49:19 -04:00
|
|
|
if (!currentFolder() || !$scope.displayMessages) {
|
|
|
|
// folders not yet initialized
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
var len = currentFolder().messages.length,
|
|
|
|
dLen = $scope.displayMessages.length;
|
|
|
|
|
|
|
|
if (dLen === len || $scope.searchText) {
|
|
|
|
// all messages are already displayed or we're in search mode
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy next interval of messages to the end of the display messages array
|
|
|
|
var next = currentFolder().messages.slice(dLen, dLen + SCROLL_DISPLAY_LEN);
|
|
|
|
Array.prototype.push.apply($scope.displayMessages, next);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is called when the user changes the searchText
|
|
|
|
*/
|
|
|
|
$scope.displaySearchResults = function(searchText) {
|
|
|
|
if (searchTimeout) {
|
|
|
|
// remove timeout to wait for user typing query
|
|
|
|
clearTimeout(searchTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!searchText) {
|
|
|
|
// set display buffer to first messages
|
|
|
|
$scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN);
|
|
|
|
$scope.searching = false;
|
|
|
|
updateStatus('Online');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// display searching spinner
|
|
|
|
$scope.searching = true;
|
|
|
|
updateStatus('Searching ...');
|
|
|
|
searchTimeout = setTimeout(function() {
|
|
|
|
$scope.$apply(function() {
|
|
|
|
// filter relevant messages
|
|
|
|
$scope.displayMessages = $scope.search(currentFolder().messages, searchText);
|
|
|
|
$scope.searching = false;
|
|
|
|
updateStatus('Matches in this folder');
|
|
|
|
});
|
|
|
|
}, 500);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do full text search on messages. Parse meta data first
|
|
|
|
*/
|
|
|
|
$scope.search = function(messages, searchText) {
|
|
|
|
// don't filter on empty searchText
|
|
|
|
if (!searchText) {
|
|
|
|
return messages;
|
|
|
|
}
|
|
|
|
|
|
|
|
// escape search string
|
|
|
|
searchText = searchText.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
|
|
|
|
// compare all strings (case insensitive)
|
|
|
|
var regex = new RegExp(searchText, 'i');
|
|
|
|
|
|
|
|
function contains(input) {
|
|
|
|
if (!input) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return regex.test(input);
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkAddresses(header) {
|
|
|
|
if (!header || !header.length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < header.length; i++) {
|
|
|
|
if (contains(header[i].name) || contains(header[i].address)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Filter meta data first and then only look at plaintext and decrypted message bodies
|
|
|
|
*/
|
|
|
|
function matchMetaDataFirst(m) {
|
|
|
|
// compare subject
|
|
|
|
if (contains(m.subject)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// compares address headers
|
|
|
|
if (checkAddresses(m.from) || checkAddresses(m.to) || checkAddresses(m.cc) || checkAddresses(m.bcc)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// compare plaintext body
|
|
|
|
if (m.body && !m.encrypted && contains(m.body)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// compare decrypted body
|
|
|
|
if (m.body && m.encrypted && m.decrypted && contains(m.body)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// compare plaintex html body
|
|
|
|
if (m.html && !m.encrypted && contains(m.html)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// compare decrypted html body
|
|
|
|
if (m.html && m.encrypted && m.decrypted && contains(m.html)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// user native js Array.filter
|
|
|
|
return messages.filter(matchMetaDataFirst);
|
|
|
|
};
|
2014-05-23 08:23:50 -04:00
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
/**
|
|
|
|
* Sync current folder when client comes back online
|
|
|
|
*/
|
2014-07-16 06:47:25 -04:00
|
|
|
$scope.watchOnline = $scope.$watch('account.online', function(isOnline) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (isOnline) {
|
2014-05-23 08:23:50 -04:00
|
|
|
updateStatus('Online');
|
|
|
|
openCurrentFolder();
|
2013-12-09 13:21:52 -05:00
|
|
|
} else {
|
|
|
|
updateStatus('Offline mode');
|
|
|
|
}
|
|
|
|
}, true);
|
2013-11-08 17:31:20 -05:00
|
|
|
|
2013-09-28 10:08:12 -04:00
|
|
|
//
|
2014-05-23 08:23:50 -04:00
|
|
|
// Helper Functions
|
2013-09-28 10:08:12 -04:00
|
|
|
//
|
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
function openCurrentFolder() {
|
|
|
|
emailDao.openFolder({
|
|
|
|
folder: currentFolder()
|
|
|
|
}, function(error) {
|
2014-06-23 07:09:09 -04:00
|
|
|
// dont wait until scroll to load visible mail bodies
|
|
|
|
$scope.loadVisibleBodies();
|
|
|
|
|
|
|
|
// don't display error for offline case
|
2014-05-23 08:23:50 -04:00
|
|
|
if (error && error.code === 42) {
|
2014-04-29 16:11:22 -04:00
|
|
|
return;
|
|
|
|
}
|
2014-05-23 08:23:50 -04:00
|
|
|
$scope.onError(error);
|
2014-04-29 16:11:22 -04:00
|
|
|
});
|
2013-09-26 07:26:57 -04:00
|
|
|
}
|
2013-09-30 15:22:46 -04:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
function updateStatus(lbl, time) {
|
|
|
|
$scope.lastUpdateLbl = lbl;
|
|
|
|
$scope.lastUpdate = (time) ? time : '';
|
|
|
|
}
|
|
|
|
|
2014-04-28 12:09:51 -04:00
|
|
|
function currentFolder() {
|
2013-11-08 17:31:20 -05:00
|
|
|
return $scope.state.nav.currentFolder;
|
2013-09-30 15:22:46 -04:00
|
|
|
}
|
2014-05-08 10:25:20 -04:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
function currentMessage() {
|
|
|
|
return $scope.state.mailList.selected;
|
|
|
|
}
|
2014-05-08 10:25:20 -04:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
//
|
|
|
|
// Notification API
|
|
|
|
//
|
2014-05-08 10:25:20 -04:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
(emailDao || {}).onIncomingMessage = function(msgs) {
|
2014-09-16 13:01:49 -04:00
|
|
|
var note, title, message, unreadMsgs;
|
2014-05-08 10:25:20 -04:00
|
|
|
|
|
|
|
unreadMsgs = msgs.filter(function(msg) {
|
|
|
|
return msg.unread;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (unreadMsgs.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:01:49 -04:00
|
|
|
if (unreadMsgs.length === 1) {
|
|
|
|
title = unreadMsgs[0].from[0].name || unreadMsgs[0].from[0].address;
|
|
|
|
message = unreadMsgs[0].subject;
|
2014-05-08 10:25:20 -04:00
|
|
|
} else {
|
2014-09-16 13:01:49 -04:00
|
|
|
title = unreadMsgs.length + ' new messages';
|
|
|
|
message = _.pluck(unreadMsgs, 'subject').join('\n');
|
2014-05-08 10:25:20 -04:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:01:49 -04:00
|
|
|
note = notification.create({
|
|
|
|
title: title,
|
|
|
|
message: message,
|
|
|
|
onClick: function() {
|
|
|
|
// force toggle into read mode when notification is clicked
|
|
|
|
firstSelect = false;
|
|
|
|
|
|
|
|
// remove from pending notificatiosn
|
|
|
|
var index = $scope.pendingNotifications.indexOf(note);
|
|
|
|
if (index !== -1) {
|
|
|
|
$scope.pendingNotifications.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// mark message as read
|
|
|
|
$scope.select(_.findWhere(currentFolder().messages, {
|
|
|
|
uid: unreadMsgs[0].uid
|
|
|
|
}));
|
|
|
|
}
|
2014-05-08 10:25:20 -04:00
|
|
|
});
|
2014-09-16 13:01:49 -04:00
|
|
|
$scope.pendingNotifications.push(note);
|
2014-05-08 10:25:20 -04:00
|
|
|
};
|
2013-09-26 07:26:57 -04:00
|
|
|
};
|
2013-09-05 05:53:14 -04:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
//
|
|
|
|
// Directives
|
|
|
|
//
|
|
|
|
|
|
|
|
var ngModule = angular.module('mail-list', []);
|
|
|
|
|
2014-06-27 06:36:43 -04:00
|
|
|
ngModule.directive('woTouch', function($parse) {
|
|
|
|
return function(scope, elm, attrs) {
|
|
|
|
var handler = $parse(attrs.woTouch);
|
|
|
|
|
|
|
|
elm.on('touchstart', function() {
|
|
|
|
elm.addClass('active');
|
|
|
|
});
|
2014-07-23 13:37:37 -04:00
|
|
|
elm.on('touchleave touchcancel touchmove touchend', function() {
|
2014-06-27 06:36:43 -04:00
|
|
|
elm.removeClass('active');
|
|
|
|
});
|
|
|
|
|
2014-07-23 13:37:37 -04:00
|
|
|
elm.on('click', function(event) {
|
2014-06-27 06:36:43 -04:00
|
|
|
elm.removeClass('active');
|
|
|
|
scope.$apply(function() {
|
|
|
|
handler(scope, {
|
|
|
|
$event: event
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2014-06-16 08:52:23 -04:00
|
|
|
ngModule.directive('listScroll', function() {
|
2014-05-23 08:23:50 -04:00
|
|
|
return {
|
|
|
|
link: function(scope, elm, attrs) {
|
2014-06-16 08:52:23 -04:00
|
|
|
var model = attrs.listScroll,
|
2014-05-23 08:23:50 -04:00
|
|
|
listEl = elm[0],
|
2014-06-16 08:52:23 -04:00
|
|
|
scrollTimeout;
|
2014-05-23 08:23:50 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* iterates over the mails in the mail list and loads their bodies if they are visible in the viewport
|
|
|
|
*/
|
|
|
|
scope.loadVisibleBodies = function() {
|
|
|
|
var listBorder = listEl.getBoundingClientRect(),
|
|
|
|
top = listBorder.top,
|
|
|
|
bottom = listBorder.bottom,
|
|
|
|
listItems = listEl.children[0].children,
|
|
|
|
inViewport = false,
|
|
|
|
listItem, message,
|
2014-07-16 06:47:25 -04:00
|
|
|
isPartiallyVisibleTop, isPartiallyVisibleBottom, isVisible,
|
|
|
|
displayMessages = scope[model];
|
|
|
|
|
|
|
|
if (!top && !bottom) {
|
|
|
|
// list not visible
|
|
|
|
return;
|
|
|
|
}
|
2014-05-23 08:23:50 -04:00
|
|
|
|
|
|
|
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 message model in the filteredMessages array
|
|
|
|
listItem = listItems.item(i).getBoundingClientRect();
|
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
if (!displayMessages || displayMessages.length <= i) {
|
2014-05-23 08:23:50 -04:00
|
|
|
// stop if i get larger than the size of filtered messages
|
|
|
|
break;
|
|
|
|
}
|
2014-07-16 06:47:25 -04:00
|
|
|
message = displayMessages[i];
|
2014-05-23 08:23:50 -04:00
|
|
|
|
|
|
|
|
|
|
|
isPartiallyVisibleTop = listItem.top < top && listItem.bottom > top; // a portion of the list item is visible on the top
|
|
|
|
isPartiallyVisibleBottom = listItem.top < bottom && listItem.bottom > bottom; // a portion of the list item is visible on the bottom
|
2014-07-16 06:47:25 -04:00
|
|
|
isVisible = (listItem.top || listItem.bottom) && listItem.top >= top && listItem.bottom <= bottom; // the list item is visible as a whole
|
2014-05-23 08:23:50 -04:00
|
|
|
|
|
|
|
if (isPartiallyVisibleTop || isVisible || isPartiallyVisibleBottom) {
|
|
|
|
// we are now iterating over visible elements
|
|
|
|
inViewport = true;
|
|
|
|
// load mail body of visible
|
|
|
|
scope.getBody(message);
|
|
|
|
} else if (inViewport) {
|
|
|
|
// we are leaving the viewport, so stop iterating over the items
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-16 08:52:23 -04:00
|
|
|
// load body when scrolling
|
|
|
|
listEl.onscroll = function() {
|
|
|
|
if (scrollTimeout) {
|
|
|
|
// remove timeout so that only scroll end
|
|
|
|
clearTimeout(scrollTimeout);
|
|
|
|
}
|
|
|
|
scrollTimeout = setTimeout(function() {
|
|
|
|
scope.loadVisibleBodies();
|
|
|
|
}, 300);
|
|
|
|
};
|
2014-05-23 08:23:50 -04:00
|
|
|
|
2014-06-16 08:52:23 -04:00
|
|
|
// load the visible message bodies, when the list is re-initialized and when scrolling stopped
|
2014-05-23 08:23:50 -04:00
|
|
|
scope.$watchCollection(model, function() {
|
|
|
|
scope.loadVisibleBodies();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2014-07-16 06:47:25 -04:00
|
|
|
function byUidDescending(a, b) {
|
|
|
|
if (a.uid < b.uid) {
|
|
|
|
return 1;
|
|
|
|
} else if (b.uid < a.uid) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
// Helper for development mode
|
|
|
|
|
2013-10-09 04:22:29 -04:00
|
|
|
function createDummyMails() {
|
2014-07-16 06:47:25 -04:00
|
|
|
var uid = 1000000;
|
2013-12-03 13:21:50 -05:00
|
|
|
|
2014-07-10 14:07:03 -04:00
|
|
|
var Email = function(unread, attachments, answered) {
|
2014-07-16 06:47:25 -04:00
|
|
|
this.uid = uid--;
|
2013-09-05 05:53:14 -04:00
|
|
|
this.from = [{
|
|
|
|
name: 'Whiteout Support',
|
|
|
|
address: 'support@whiteout.io'
|
|
|
|
}]; // sender address
|
|
|
|
this.to = [{
|
|
|
|
address: 'max.musterman@gmail.com'
|
2014-04-22 13:41:14 -04:00
|
|
|
}, {
|
|
|
|
address: 'max.musterman@gmail.com'
|
2013-09-05 05:53:14 -04:00
|
|
|
}]; // list of receivers
|
2014-04-02 13:47:50 -04:00
|
|
|
this.cc = [{
|
|
|
|
address: 'john.doe@gmail.com'
|
|
|
|
}]; // list of receivers
|
2014-07-31 03:57:57 -04:00
|
|
|
this.attachments = attachments ? [{
|
|
|
|
"filename": "a.md",
|
|
|
|
"filesize": 123,
|
|
|
|
"mimeType": "text/x-markdown",
|
|
|
|
"part": "2",
|
|
|
|
"content": null
|
|
|
|
}, {
|
|
|
|
"filename": "b.md",
|
|
|
|
"filesize": 456,
|
|
|
|
"mimeType": "text/x-markdown",
|
|
|
|
"part": "3",
|
|
|
|
"content": null
|
|
|
|
}, {
|
|
|
|
"filename": "c.md",
|
|
|
|
"filesize": 789,
|
|
|
|
"mimeType": "text/x-markdown",
|
|
|
|
"part": "4",
|
|
|
|
"content": null
|
|
|
|
}] : [];
|
2013-09-05 05:53:14 -04:00
|
|
|
this.unread = unread;
|
2013-09-30 11:29:29 -04:00
|
|
|
this.answered = answered;
|
2013-09-26 07:26:57 -04:00
|
|
|
this.sentDate = new Date('Thu Sep 19 2013 20:41:23 GMT+0200 (CEST)');
|
2013-11-18 11:44:59 -05:00
|
|
|
this.subject = 'Getting started'; // Subject line
|
2014-09-22 11:33:06 -04:00
|
|
|
// this.body = 'And a good day to you too sir. \n' +
|
|
|
|
// '\n' +
|
|
|
|
// 'Thursday, Apr 24, 2014 3:33 PM safewithme.testuser@gmail.com wrote:\n' +
|
|
|
|
// '> adsfadfasdfasdfasfdasdfasdfas\n' +
|
|
|
|
// '\n' +
|
|
|
|
// 'http://example.com\n' +
|
|
|
|
// '\n' +
|
|
|
|
// '> Tuesday, Mar 25, 2014 4:19 PM gianniarcore@gmail.com wrote:\n' +
|
|
|
|
// '>> from 0.7.0.1\n' +
|
|
|
|
// '>>\n' +
|
|
|
|
// '>> God speed!'; // plaintext body
|
|
|
|
this.html = '<!DOCTYPE html><html><head></head><body><h1 style="border: 1px solid red; width: 500px;">Hello there' + Math.random() + '</h1></body></html>';
|
2014-02-20 13:20:24 -05:00
|
|
|
this.encrypted = true;
|
2014-02-21 10:22:33 -05:00
|
|
|
this.decrypted = true;
|
2013-09-05 05:53:14 -04:00
|
|
|
};
|
|
|
|
|
2014-07-31 03:57:57 -04:00
|
|
|
var dummies = [],
|
|
|
|
i = 100;
|
|
|
|
while (i--) {
|
|
|
|
// every second/third/fourth dummy mail with unread/attachments/answered
|
|
|
|
dummies.push(new Email((i % 2 === 0), (i % 3 === 0), (i % 5 === 0)));
|
2014-07-16 06:47:25 -04:00
|
|
|
}
|
2013-09-05 05:53:14 -04:00
|
|
|
|
2014-07-31 03:57:57 -04:00
|
|
|
return dummies;
|
2013-09-05 05:53:14 -04:00
|
|
|
}
|
|
|
|
|
2013-09-18 12:47:18 -04:00
|
|
|
return MailListCtrl;
|
2013-09-04 12:39:26 -04:00
|
|
|
});
|