1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 19:02:20 -05:00

refactor mail list

This commit is contained in:
Tankred Hase 2013-11-08 23:31:20 +01:00
parent a82c2ca20a
commit 342105cb4c
7 changed files with 100 additions and 88 deletions

View File

@ -14,6 +14,10 @@ define(function(require) {
num = 100, num = 100,
firstSelect = true; firstSelect = true;
//
// Init
//
emailDao = appController._emailDao; emailDao = appController._emailDao;
if (emailDao) { if (emailDao) {
emailDao.onIncomingMessage = function(email) { emailDao.onIncomingMessage = function(email) {
@ -50,7 +54,7 @@ define(function(require) {
// scope functions // scope functions
// //
$scope.$parent.select = $scope.select = function(email) { $scope.select = function(email) {
if (!email) { if (!email) {
return; return;
} }
@ -64,15 +68,14 @@ define(function(require) {
} }
}); });
} }
$scope.selected = email;
// set selected in parent scope ro it can be displayed in the read view $scope.state.mailList.selected = email;
$scope.$parent.selected = $scope.selected;
// mark selected message as 'read' // mark selected message as 'read'
markAsRead(email); markAsRead(email);
}; };
$scope.$parent.synchronize = $scope.synchronize = function(callback) { $scope.synchronize = function(callback) {
updateStatus('Syncing ...'); updateStatus('Syncing ...');
// sync from imap to local db // sync from imap to local db
syncImapFolder({ syncImapFolder({
@ -94,7 +97,60 @@ define(function(require) {
}); });
}; };
$scope.$watch('currentFolder', function() { $scope.remove = function(email) {
if (!email) {
return;
}
var index;
removeLocalAndShowNext();
removeRemote();
function removeLocalAndShowNext() {
index = $scope.emails.indexOf(email);
// show the next mail
if ($scope.emails.length > 1) {
// if we're about to delete the last entry of the array, show the previous (i.e. the one below in the list),
// otherwise show the next one (i.e. the one above in the list)
$scope.select(_.last($scope.emails) === email ? $scope.emails[index - 1] : $scope.emails[index + 1]);
} else {
// if we have only one email in the array, show nothing
$scope.select();
$scope.state.mailList.selected = undefined;
}
$scope.emails.splice(index, 1);
}
function removeRemote() {
var trashFolder = _.findWhere($scope.folders, {
type: 'Trash'
});
if (getFolder() === trashFolder) {
emailDao.imapDeleteMessage({
folder: getFolder().path,
uid: email.uid
}, moved);
return;
}
emailDao.imapMoveMessage({
folder: getFolder().path,
uid: email.uid,
destination: trashFolder.path
}, moved);
}
function moved(err) {
if (err) {
console.error(err);
$scope.emails.splice(index, 0, email);
$scope.$apply();
return;
}
}
};
$scope.$watch('state.nav.currentFolder', function() {
if (!getFolder()) { if (!getFolder()) {
return; return;
} }
@ -108,10 +164,16 @@ define(function(require) {
// development... display dummy mail objects // development... display dummy mail objects
firstSelect = true; firstSelect = true;
updateStatus('Last update: ', new Date()); updateStatus('Last update: ', new Date());
$scope.$parent.emails = $scope.emails = createDummyMails(); $scope.emails = createDummyMails();
$scope.select($scope.emails[0]); $scope.select($scope.emails[0]);
}); });
// share local scope functions with root state
$scope.state.mailList = {
remove: $scope.remove,
synchronize: $scope.synchronize
};
// //
// helper functions // helper functions
// //
@ -185,8 +247,6 @@ define(function(require) {
function updateStatus(lbl, time) { function updateStatus(lbl, time) {
$scope.lastUpdateLbl = lbl; $scope.lastUpdateLbl = lbl;
$scope.lastUpdate = (time) ? time : ''; $scope.lastUpdate = (time) ? time : '';
$scope.$parent.lastUpdateLbl = $scope.lastUpdateLbl;
$scope.$parent.lastUpdate = $scope.lastUpdate;
} }
function displayEmails(emails) { function displayEmails(emails) {
@ -202,13 +262,13 @@ define(function(require) {
return -e.uid; return -e.uid;
}); });
$scope.$parent.emails = $scope.emails = emails; $scope.emails = emails;
$scope.select($scope.emails[0]); $scope.select($scope.emails[0]);
$scope.$apply(); $scope.$apply();
} }
function getFolder() { function getFolder() {
return $scope.$parent.currentFolder; return $scope.state.nav.currentFolder;
} }
function markAsRead(email) { function markAsRead(email) {

View File

@ -39,7 +39,7 @@ define(function(require) {
}; };
$scope.openFolder = function(folder) { $scope.openFolder = function(folder) {
$scope.currentFolder = folder; $scope.state.nav.currentFolder = folder;
$scope.state.nav.toggle(false); $scope.state.nav.toggle(false);
}; };
@ -50,59 +50,6 @@ define(function(require) {
$scope.accountOpen = false; $scope.accountOpen = false;
}; };
$scope.remove = function(email) {
if (!email) {
return;
}
var index;
removeLocalAndShowNext();
removeRemote();
function removeLocalAndShowNext() {
index = $scope.emails.indexOf(email);
// show the next mail
if ($scope.emails.length > 1) {
// if we're about to delete the last entry of the array, show the previous (i.e. the one below in the list),
// otherwise show the next one (i.e. the one above in the list)
$scope.select(_.last($scope.emails) === email ? $scope.emails[index - 1] : $scope.emails[index + 1]);
} else {
// if we have only one email in the array, show nothing
$scope.select();
$scope.selected = undefined;
}
$scope.emails.splice(index, 1);
}
function removeRemote() {
var trashFolder = _.findWhere($scope.folders, {
type: 'Trash'
});
if ($scope.currentFolder === trashFolder) {
emailDao.imapDeleteMessage({
folder: $scope.currentFolder.path,
uid: email.uid
}, moved);
return;
}
emailDao.imapMoveMessage({
folder: $scope.currentFolder.path,
uid: email.uid,
destination: trashFolder.path
}, moved);
}
function moved(err) {
if (err) {
console.error(err);
$scope.emails.splice(index, 0, email);
$scope.$apply();
return;
}
}
};
$scope.emptyOutbox = function() { $scope.emptyOutbox = function() {
var dbType = 'email_OUTBOX', var dbType = 'email_OUTBOX',
outbox = _.findWhere($scope.folders, { outbox = _.findWhere($scope.folders, {
@ -267,15 +214,20 @@ define(function(require) {
elm.bind('keydown', function(e) { elm.bind('keydown', function(e) {
var cs = scope.$$childTail; var cs = scope.$$childTail;
if (e.keyCode === 78 && !scope.state.writer.open) { // global state is not yet set, ignore keybaord shortcuts
if (!scope.state) {
return;
}
if (e.keyCode === 78 && scope.state.writer && !scope.state.writer.open) {
// n -> new mail // n -> new mail
e.preventDefault(); e.preventDefault();
scope.state.writer.write(); scope.state.writer.write();
} else if (e.keyCode === 82 && !scope.state.writer.open && cs.selected) { } else if (e.keyCode === 82 && scope.state.writer && !scope.state.writer.open && scope.state.mailList.selected) {
// r -> reply // r -> reply
e.preventDefault(); e.preventDefault();
scope.state.writer.write(cs.selected); scope.state.writer.write(scope.state.mailList.selected);
} else if (e.keyCode === 27 && scope.state.writer.open) { } else if (e.keyCode === 27 && scope.state.writer.open) {
// escape -> close writer // escape -> close writer
@ -287,10 +239,10 @@ define(function(require) {
e.preventDefault(); e.preventDefault();
cs.closeAccount(); cs.closeAccount();
} else if (e.keyCode === 83 && !scope.state.writer.open && cs.synchronize) { } else if (e.keyCode === 83 && scope.state.writer && !scope.state.writer.open && scope.state.mailList.synchronize) {
// s -> sync folder // s -> sync folder
e.preventDefault(); e.preventDefault();
cs.synchronize(); scope.state.mailList.synchronize();
} }
scope.$apply(); scope.$apply();

View File

@ -166,7 +166,7 @@ define(function(require) {
return; return;
} }
$scope.closeWriter(); $scope.state.writer.close();
$scope.$apply(); $scope.$apply();
$scope.emptyOutbox(); $scope.emptyOutbox();
}); });

View File

@ -8,7 +8,7 @@
<section class="content main-content" ng-class="{'shift-right': state.read.open}"> <section class="content main-content" ng-class="{'shift-right': state.read.open}">
<!-- left column: containing list view and navigation header --> <!-- left column: containing list view and navigation header -->
<div class="column column-left" ng-include="'tpl/mail-list.html'" ng-controller="MailListCtrl"></div> <div class="column column-left" ng-include="'tpl/mail-list.html'"></div>
<!-- right column: containing list read view --> <!-- right column: containing list read view -->
<div class="column" ng-include="'tpl/read.html'"></div> <div class="column" ng-include="'tpl/read.html'"></div>

View File

@ -1,12 +1,12 @@
<div class="view-mail-list"> <div class="view-mail-list" ng-controller="MailListCtrl">
<!-- nav controll and section headline --> <!-- nav controll and section headline -->
<header data-icon="&#xe004;" ng-click="state.nav.toggle(true); $event.stopPropagation()"> <header data-icon="&#xe004;" ng-click="state.nav.toggle(true); $event.stopPropagation()">
<h2>{{currentFolder.type}}</h2> <h2>{{state.nav.currentFolder.type}}</h2>
</header> </header>
<div class="list-wrapper" ng-iscroll> <div class="list-wrapper" ng-iscroll>
<ul class="mail-list"> <ul class="mail-list">
<li ng-class="{'mail-list-active': email === selected, 'mail-list-attachment': email.attachments !== undefined && email.attachments.length > 0, 'mail-list-unread': email.unread, 'mail-list-replied': email.answered}" ng-click="select(email)" ng-repeat="email in emails"> <li ng-class="{'mail-list-active': email === state.mailList.selected, 'mail-list-attachment': email.attachments !== undefined && email.attachments.length > 0, 'mail-list-unread': email.unread, 'mail-list-replied': email.answered}" ng-click="select(email)" ng-repeat="email in emails">
<h3>{{email.from[0].name || email.from[0].address}}</h3> <h3>{{email.from[0].name || email.from[0].address}}</h3>
<div class="head"> <div class="head">
<p class="subject">{{email.subject || 'No subject'}}</p> <p class="subject">{{email.subject || 'No subject'}}</p>

View File

@ -1,29 +1,29 @@
<div class="controls"> <div class="controls">
<button ng-click="remove(selected)" class="btn-icon" title="Delete mail">&#xe005;</button> <button ng-click="state.mailList.remove(state.mailList.selected)" class="btn-icon" title="Delete mail">&#xe005;</button>
<button ng-click="state.writer.write(selected)" class="btn-icon" title="Reply to">&#xe002;</button> <button ng-click="state.writer.write(state.mailList.selected)" class="btn-icon" title="Reply to">&#xe002;</button>
<button ng-click="state.writer.write()" class="btn-icon" title="New mail">&#xe006;</button> <button ng-click="state.writer.write()" class="btn-icon" title="New mail">&#xe006;</button>
</div><!--/.controls--> </div><!--/.controls-->
<div class="view-read" ng-controller="ReadCtrl"> <div class="view-read" ng-controller="ReadCtrl">
<div class="headers"> <div class="headers">
<p class="subject" ng-click="state.read.toggle(false)">{{selected.subject || 'No subject'}}</p> <p class="subject" ng-click="state.read.toggle(false)">{{state.mailList.selected.subject || 'No subject'}}</p>
<p class="date">{{selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p> <p class="date">{{state.mailList.selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p>
<p class="address">From: <span class="label" data-icon-append="&#xe009;">{{selected.from[0].name || selected.from[0].address}}</span></p> <p class="address">From: <span class="label" data-icon-append="&#xe009;">{{state.mailList.selected.from[0].name || state.mailList.selected.from[0].address}}</span></p>
<p class="address">To: <span class="label" data-icon-append="&#xe009;" ng-repeat="t in selected.to">{{t.address}} </span></p> <p class="address">To: <span class="label" data-icon-append="&#xe009;" ng-repeat="t in state.mailList.selected.to">{{t.address}} </span></p>
<div ng-switch="selected.cc !== undefined"> <div ng-switch="state.mailList.selected.cc !== undefined">
<p class="address" ng-switch-when="true"> <p class="address" ng-switch-when="true">
CC: <span class="label" ng-repeat="t in selected.cc">{{t.address}} </span> CC: <span class="label" ng-repeat="t in state.mailList.selected.cc">{{t.address}} </span>
</p> </p>
</div> </div>
</div><!--/.headers--> </div><!--/.headers-->
<div class="seperator-line"></div> <div class="seperator-line"></div>
<div class="body" ng-switch="selected.html === true"> <div class="body" ng-switch="state.mailList.selected.html === true">
<!-- sandbox untrusted markup from html emails in an iframe. The "allow-same-origin" attribute is required to dynamically adjust the height of the iframe. Script execution is not allowed. --> <!-- sandbox untrusted markup from html emails in an iframe. The "allow-same-origin" attribute is required to dynamically adjust the height of the iframe. Script execution is not allowed. -->
<iframe ng-switch-when="true" sandbox="allow-same-origin" srcdoc="{{selected.body}}" seamless frame-load></iframe> <iframe ng-switch-when="true" sandbox="allow-same-origin" srcdoc="{{state.mailList.selected.body}}" seamless frame-load></iframe>
<!-- Render parts of a text only email in paragraphs for easier styling --> <!-- Render parts of a text only email in paragraphs for easier styling -->
<p ng-repeat="part in selected.bodyDisplayParts track by $index">{{part}}</p> <p ng-repeat="part in state.mailList.selected.bodyDisplayParts track by $index">{{part}}</p>
</div><!--/.body--> </div><!--/.body-->
</div><!--/.view-read--> </div><!--/.view-read-->

View File

@ -9,7 +9,7 @@
<div class="headers"> <div class="headers">
<p> <p>
<span>To:</span> <span>To:</span>
<input type="email" ng-model="to" ng-change="verifyTo()" ng-class="{'label': toSecure === true, 'label label-primary': toSecure === false}" tabindex="1" focus-me="writerOpen && !writerReply" auto-size="to" spellcheck="false"> <input type="email" ng-model="to" ng-change="verifyTo()" ng-class="{'label': toSecure === true, 'label label-primary': toSecure === false}" tabindex="1" focus-me="state.writer.open && writerTitle !== 'Reply'" auto-size="to" spellcheck="false">
</p> </p>
<p> <p>
<span>Cc:</span> <span>Cc:</span>
@ -27,7 +27,7 @@
</div><!--/.subject-box--> </div><!--/.subject-box-->
<div class="body"> <div class="body">
<p ng-model="body" contentEditable="true" ng-change="updatePreview()" tabindex="4" focus-me="writerOpen && writerReply"></p> <p ng-model="body" contentEditable="true" ng-change="updatePreview()" tabindex="4" focus-me="state.writer.open && writerTitle === 'Reply'"></p>
<div class="encrypt-preview"> <div class="encrypt-preview">
<p>-----BEGIN ENCRYPTED PREVIEW-----<br>{{ciphertextPreview}}<br>-----END ENCRYPTED PREVIEW-----</p> <p>-----BEGIN ENCRYPTED PREVIEW-----<br>{{ciphertextPreview}}<br>-----END ENCRYPTED PREVIEW-----</p>