diff --git a/Gruntfile.js b/Gruntfile.js index 4d31d0d..b3d5e78 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -159,7 +159,6 @@ module.exports = function(grunt) { 'test/unit/util/dialog-test.js', 'test/unit/util/connection-doctor-test.js', 'test/unit/util/update-handler-test.js', - 'test/unit/util/backbutton-handler-test.js', 'test/unit/util/status-display-test.js', 'test/unit/crypto/pgp-test.js', 'test/unit/crypto/crypto-test.js', diff --git a/README.md b/README.md index fd03301..1a1cb80 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ For development you can start a connect dev server: grunt dev -Then visit [http://localhost:8580/dist/#/desktop?dev=true](http://localhost:8580/dist/#/desktop?dev=true) for front-end code or [http://localhost:8580/test/unit/](http://localhost:8580/test/unit/) to test JavaScript changes. You can also start a watch task so you don't have rebuild everytime you make a change: +Then visit [http://localhost:8580/dist/#/account?dev=true](http://localhost:8580/dist/#/account?dev=true) for front-end code or [http://localhost:8580/test/unit/](http://localhost:8580/test/unit/) to test JavaScript changes. You can also start a watch task so you don't have rebuild everytime you make a change: grunt watch diff --git a/src/js/app.js b/src/js/app.js index d54d92f..94d005a 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -35,8 +35,7 @@ var axe = require('axe-logger'), WriteCtrl = require('./controller/app/write'), NavigationCtrl = require('./controller/app/navigation'), ActionBarCtrl = require('./controller/app/action-bar'), - StatusDisplayCtrl = require('./controller/app/status-display'), - backButtonUtil = require('./util/backbutton-handler'); + StatusDisplayCtrl = require('./controller/app/status-display'); // include angular modules require('./app-config'); @@ -104,9 +103,10 @@ app.config(function($routeProvider, $animateProvider) { templateUrl: 'tpl/login-privatekey-download.html', controller: LoginPrivateKeyDownloadCtrl }); - $routeProvider.when('/desktop', { + $routeProvider.when('/account', { templateUrl: 'tpl/desktop.html', - controller: NavigationCtrl + controller: NavigationCtrl, + reloadOnSearch: false // don't reload controllers in main app when query params change }); $routeProvider.otherwise({ redirectTo: '/login' @@ -119,10 +119,6 @@ app.config(function($routeProvider, $animateProvider) { app.run(function($rootScope) { // global state... inherited to all child scopes $rootScope.state = {}; - - // attach the back button handler to the root scope - backButtonUtil.attachHandler($rootScope); - // attach fastclick FastClick.attach(document.body); }); diff --git a/src/js/controller/app/about.js b/src/js/controller/app/about.js index b5f1269..bdec213 100644 --- a/src/js/controller/app/about.js +++ b/src/js/controller/app/about.js @@ -2,6 +2,10 @@ var AboutCtrl = function($scope, appConfig) { + // + // scope state + // + $scope.state.about = { toggle: function(to) { $scope.state.lightbox = (to) ? 'about' : undefined; @@ -15,9 +19,6 @@ var AboutCtrl = function($scope, appConfig) { $scope.version = appConfig.config.appVersion + ' (beta)'; $scope.date = new Date(); - // - // scope functions - // }; module.exports = AboutCtrl; \ No newline at end of file diff --git a/src/js/controller/app/account.js b/src/js/controller/app/account.js index 2e4270e..0ad4204 100644 --- a/src/js/controller/app/account.js +++ b/src/js/controller/app/account.js @@ -6,6 +6,10 @@ var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dia return; } + // + // scope state + // + $scope.state.account = { toggle: function(to) { $scope.state.lightbox = (to) ? 'account' : undefined; @@ -46,6 +50,7 @@ var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dia }); }); }; + }; module.exports = AccountCtrl; \ No newline at end of file diff --git a/src/js/controller/app/action-bar.js b/src/js/controller/app/action-bar.js index dfaa147..e718a49 100644 --- a/src/js/controller/app/action-bar.js +++ b/src/js/controller/app/action-bar.js @@ -2,7 +2,11 @@ var JUNK_FOLDER_TYPE = 'Junk'; -var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { +var ActionBarCtrl = function($scope, email, dialog, status) { + + // + // scope functions + // /** * Move a single message from the currently selected folder to another folder @@ -15,9 +19,9 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { } // close read state - $scope.state.read.open = false; - - statusDisplay.update('Moving message...'); + status.setReading(false); + // show message + status.update('Moving message...'); email.moveMessage({ folder: currentFolder(), @@ -28,14 +32,14 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { // show errors where appropriate if (err.code === 42) { $scope.select(message); - statusDisplay.update('Unable to move message in offline mode!'); + status.update('Unable to move message in offline mode!'); return; } - statusDisplay.update('Error during move!'); + status.update('Error during move!'); dialog.error(err); return; } - statusDisplay.update('Message moved.'); + status.update('Message moved.'); $scope.$apply(); }); }; @@ -76,9 +80,8 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { } // close read state - $scope.state.read.open = false; - - statusDisplay.update('Deleting message...'); + status.setReading(false); + status.update('Deleting message...'); email.deleteMessage({ folder: currentFolder(), @@ -88,14 +91,14 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { // show errors where appropriate if (err.code === 42) { $scope.select(message); - statusDisplay.update('Unable to delete message in offline mode!'); + status.update('Unable to delete message in offline mode!'); return; } - statusDisplay.update('Error during delete!'); + status.update('Error during delete!'); dialog.error(err); return; } - statusDisplay.update('Message deleted.'); + status.update('Message deleted.'); $scope.$apply(); }); }; @@ -118,11 +121,11 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { return; } - statusDisplay.update('Updating unread flag...'); + status.update('Updating unread flag...'); // close read state if (!keepOpen) { - $scope.state.read.open = false; + status.setReading(false); } var originalState = message.unread; @@ -134,17 +137,17 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { if (err && err.code === 42) { // offline, restore message.unread = originalState; - statusDisplay.update('Unable to mark message in offline mode!'); + status.update('Unable to mark message in offline mode!'); return; } if (err) { - statusDisplay.update('Error on sync!'); + status.update('Error on sync!'); dialog.error(err); return; } - statusDisplay.update('Online'); + status.update('Online'); $scope.$apply(); }); }; @@ -169,7 +172,7 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { return; } - statusDisplay.update(flagged ? 'Adding star to message...' : 'Removing star from message'); + status.update(flagged ? 'Adding star to message...' : 'Removing star from message'); var originalState = message.flagged; message.flagged = flagged; @@ -180,17 +183,17 @@ var ActionBarCtrl = function($scope, email, dialog, statusDisplay) { if (err && err.code === 42) { // offline, restore message.unread = originalState; - statusDisplay.update('Unable to ' + (flagged ? 'add star to' : 'remove star from') + ' message in offline mode!'); + status.update('Unable to ' + (flagged ? 'add star to' : 'remove star from') + ' message in offline mode!'); return; } if (err) { - statusDisplay.update('Error on sync!'); + status.update('Error on sync!'); dialog.error(err); return; } - statusDisplay.update('Online'); + status.update('Online'); $scope.$apply(); }); }; diff --git a/src/js/controller/app/contacts.js b/src/js/controller/app/contacts.js index b957ca3..7286199 100644 --- a/src/js/controller/app/contacts.js +++ b/src/js/controller/app/contacts.js @@ -6,10 +6,13 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) { + // + // scope state + // + $scope.state.contacts = { toggle: function(to) { $scope.state.lightbox = (to) ? 'contacts' : undefined; - $scope.listKeys(); } }; @@ -93,6 +96,7 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) { $scope.listKeys(); }); }; + }; // diff --git a/src/js/controller/app/dialog.js b/src/js/controller/app/dialog.js index 880c332..e9d5779 100644 --- a/src/js/controller/app/dialog.js +++ b/src/js/controller/app/dialog.js @@ -2,6 +2,10 @@ var DialogCtrl = function($scope, dialog) { + // + // scope state + // + $scope.state.dialog = { open: false }; diff --git a/src/js/controller/app/mail-list.js b/src/js/controller/app/mail-list.js index f0e949f..d033f91 100644 --- a/src/js/controller/app/mail-list.js +++ b/src/js/controller/app/mail-list.js @@ -1,20 +1,20 @@ 'use strict'; -var searchTimeout, firstSelect; +var searchTimeout; // // Constants // -var INIT_DISPLAY_LEN = 20, +var INIT_DISPLAY_LEN = 50, SCROLL_DISPLAY_LEN = 10, FOLDER_TYPE_INBOX = 'Inbox', NOTIFICATION_INBOX_TIMEOUT = 5000; -var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDisplay, notification, email, keychain, dialog, search, dummy) { +var MailListCtrl = function($scope, $timeout, $location, $filter, status, notification, email, keychain, dialog, search, dummy) { // - // Init + // scope state // $scope.state.mailList = {}; @@ -24,6 +24,30 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl */ $scope.pendingNotifications = []; + // + // url/history handling + // + + /** + * Set the route to a message which will go to read mode + */ + $scope.navigate = function(message) { + $location.search('uid', message.uid); + }; + + $scope.loc = $location; + $scope.$watch('(loc.search()).uid', function(uid) { + if (typeof uid === 'undefined') { + // no uid specified in url... select no message + $scope.select(); + return; + } + // select the message specified by the uid in the url + $scope.select(_.findWhere(currentFolder().messages, { + uid: typeof uid === 'string' ? parseInt(uid, 10) : uid + })); + }); + // // scope functions // @@ -62,11 +86,10 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl $scope.state.mailList.selected = message; - if (!firstSelect) { - // only toggle to read view on 2nd select in mobile mode - $scope.state.read.toggle(true); + if ($location.search().dev) { + // stop here in dev mode + return; } - firstSelect = false; keychain.refreshKeyForUserId({ userId: message.from[0].address @@ -132,8 +155,8 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl $scope.searchText = undefined; // in development, display dummy mail objects - if ($routeParams.dev) { - statusDisplay.update('Last update: ', new Date()); + if ($location.search().dev) { + status.update('Last update: ', new Date()); currentFolder().messages = dummy.listMails(); return; } @@ -148,15 +171,13 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl } // sort message by uid - currentFolder().messages.sort(byUidDescending); - // set display buffer to first messages - $scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN); - - // Shows the next message based on the uid of the currently selected element - if (currentFolder().messages.indexOf(currentMessage()) === -1) { - firstSelect = true; // reset first selection - $scope.select($scope.displayMessages[0]); + messages.sort(byUidDescending); + // Unselect message if it has been deleted from the messages array + if (messages.indexOf(currentMessage()) === -1) { + $scope.select(); } + // set display buffer to first messages + $scope.displayMessages = messages.slice(0, INIT_DISPLAY_LEN); }); /** @@ -200,20 +221,20 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl if (!searchText) { // set display buffer to first messages $scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN); - statusDisplay.setSearching(false); - statusDisplay.update('Online'); + status.setSearching(false); + status.update('Online'); return; } // display searching spinner - statusDisplay.setSearching(true); - statusDisplay.update('Searching ...'); + status.setSearching(true); + status.update('Searching ...'); searchTimeout = setTimeout(function() { $scope.$apply(function() { // filter relevant messages $scope.displayMessages = search.filter(currentFolder().messages, searchText); - statusDisplay.setSearching(false); - statusDisplay.update('Matches in this folder'); + status.setSearching(false); + status.update('Matches in this folder'); }); }, 500); }; @@ -225,10 +246,10 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl // wait one cycle for the status display controllers to init $timeout(function() { if (isOnline) { - statusDisplay.update('Online'); + status.update('Online'); openCurrentFolder(); } else { - statusDisplay.update('Offline mode'); + status.update('Offline mode'); } }); }, true); @@ -268,7 +289,7 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl // Notification API // - (email || {}).onIncomingMessage = function(msgs) { + email.onIncomingMessage = function(msgs) { var note, title, message, unreadMsgs; unreadMsgs = msgs.filter(function(msg) { @@ -291,17 +312,13 @@ var MailListCtrl = function($scope, $timeout, $routeParams, $filter, statusDispl 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, { + // open the message + $scope.navigate(_.findWhere(currentFolder().messages, { uid: unreadMsgs[0].uid })); }, diff --git a/src/js/controller/app/navigation.js b/src/js/controller/app/navigation.js index 5986b8c..f66a02f 100644 --- a/src/js/controller/app/navigation.js +++ b/src/js/controller/app/navigation.js @@ -1,7 +1,5 @@ 'use strict'; -var backBtnHandler = require('../../util/backbutton-handler'); - // // Constants // @@ -13,8 +11,8 @@ var NOTIFICATION_SENT_TIMEOUT = 2000; // Controller // -var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox, notification, appConfig, dialog) { - if (!$routeParams.dev && !account.isLoggedIn()) { +var NavigationCtrl = function($scope, $location, account, email, outbox, notification, appConfig, dialog, dummy) { + if (!$location.search().dev && !account.isLoggedIn()) { $location.path('/'); // init app return; } @@ -23,7 +21,7 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o config = appConfig.config; // - // scope functions + // scope state // $scope.state.nav = { @@ -33,6 +31,36 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o } }; + // + // url/history handling + // + + $scope.loc = $location; + + // nav open/close state url watcher + $scope.$watch('(loc.search()).nav', function(open) { + // synchronize the url to the scope state + $scope.state.nav.toggle(!!open); + }); + $scope.$watch('state.nav.open', function(value) { + // synchronize the scope state to the url + $location.search('nav', value ? true : null); + }); + + // lightbox state url watcher + $scope.$watch('(loc.search()).lightbox', function(value) { + // synchronize the url to the scope state + $scope.state.lightbox = (value) ? value : undefined; + }); + $scope.$watch('state.lightbox', function(value) { + // synchronize the scope state to the url + $location.search('lightbox', value ? value : null); + }); + + // + // scope functions + // + $scope.openFolder = function(folder) { $scope.state.nav.currentFolder = folder; $scope.state.nav.toggle(false); @@ -72,15 +100,23 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o // Start // - // handle back button - backBtnHandler.start(); // init folders initializeFolders(); - // select inbox as the current folder on init - if ($scope.account.folders && $scope.account.folders.length > 0) { - $scope.openFolder($scope.account.folders[0]); - } + // folder index url watcher + $scope.$watch('(loc.search()).folder', function(folderIndex) { + if (typeof folderIndex === 'undefined') { + $location.search('folder', 0); // navigate to inbox by default + return; + } + // select current folder + folderIndex = typeof folderIndex === 'string' ? parseInt(folderIndex, 10) : folderIndex; + if ($scope.account.folders && $scope.account.folders.length > folderIndex) { + // navigate to the selected folder index + $scope.openFolder($scope.account.folders[folderIndex]); + } + }); + // connect imap/smtp clients on first startup account.onConnect(function(err) { if (err) { @@ -101,8 +137,9 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o function initializeFolders() { // create dummy folder in dev environment only - if ($routeParams.dev) { - createDummyFolders(); + if ($location.search().dev) { + $scope.$root.account = {}; + $scope.account.folders = dummy.listFolders(); return; } @@ -122,33 +159,6 @@ var NavigationCtrl = function($scope, $routeParams, $location, account, email, o timeout: NOTIFICATION_SENT_TIMEOUT }, function() {}); } - - - // attach dummy folders for development - function createDummyFolders() { - $scope.$root.account = {}; - $scope.account.folders = [{ - type: 'Inbox', - count: 2, - path: 'INBOX' - }, { - type: 'Sent', - count: 0, - path: 'SENT' - }, { - type: config.outboxMailboxType, - count: 0, - path: config.outboxMailboxPath - }, { - type: 'Drafts', - count: 0, - path: 'DRAFTS' - }, { - type: 'Trash', - count: 0, - path: 'TRASH' - }]; - } }; // diff --git a/src/js/controller/app/privatekey-upload.js b/src/js/controller/app/privatekey-upload.js index eb70450..f8c8f9d 100644 --- a/src/js/controller/app/privatekey-upload.js +++ b/src/js/controller/app/privatekey-upload.js @@ -4,6 +4,10 @@ var util = require('crypto-lib').util; var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) { + // + // scope state + // + $scope.state.privateKeyUpload = { toggle: function(to) { // open lightbox @@ -33,6 +37,10 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) { } }; + // + // scope functions + // + $scope.checkServerForKey = function(callback) { var keyParams = pgp.getKeyParams(); keychain.hasPrivateKey({ diff --git a/src/js/controller/app/read.js b/src/js/controller/app/read.js index 4092644..f60b552 100644 --- a/src/js/controller/app/read.js +++ b/src/js/controller/app/read.js @@ -4,12 +4,13 @@ // Controller // -var ReadCtrl = function($scope, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) { +var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) { var str = appConfig.string; - // set default value so that the popover height is correct on init - $scope.keyId = 'No key found.'; + // + // scope state + // $scope.state.read = { open: false, @@ -18,7 +19,39 @@ var ReadCtrl = function($scope, email, invitation, outbox, pgp, keychain, appCon } }; + $scope.$on('read', function(e, state) { + $scope.state.read.toggle(state); + }); + + // set default value so that the popover height is correct on init + $scope.keyId = 'No key found.'; + + // + // url/history handling + // + + // read state url watcher + $scope.loc = $location; + $scope.$watch('(loc.search()).uid', function(uid) { + // synchronize the url to the scope state + $scope.state.read.toggle(!!uid); + }); + $scope.$watch('state.read.open', function(value) { + // close read mode by navigating to folder view + if (!value) { + $location.search('uid', null); + } + }); + + // + // scope functions + // + $scope.getKeyId = function(address) { + if ($location.search().dev || !address) { + return; + } + $scope.keyId = 'Searching...'; keychain.getReceiverPublicKey(address, function(err, pubkey) { if (err) { @@ -41,7 +74,7 @@ var ReadCtrl = function($scope, email, invitation, outbox, pgp, keychain, appCon }; $scope.$watch('state.mailList.selected', function(mail) { - if (!mail) { + if ($location.search().dev || !mail) { return; } diff --git a/src/js/controller/login/login-existing.js b/src/js/controller/login/login-existing.js index 505f1d2..206dea4 100644 --- a/src/js/controller/login/login-existing.js +++ b/src/js/controller/login/login-existing.js @@ -43,7 +43,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, k return; } - $location.path('/desktop'); + $location.path('/account'); $scope.$apply(); }); } diff --git a/src/js/controller/login/login-initial.js b/src/js/controller/login/login-initial.js index 08408d6..9ac9e13 100644 --- a/src/js/controller/login/login-initial.js +++ b/src/js/controller/login/login-initial.js @@ -65,7 +65,7 @@ var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter, ema return; } - $location.path('/desktop'); + $location.path('/account'); $scope.$apply(); }); }); diff --git a/src/js/controller/login/login-new-device.js b/src/js/controller/login/login-new-device.js index 44a3292..fe0de28 100644 --- a/src/js/controller/login/login-new-device.js +++ b/src/js/controller/login/login-new-device.js @@ -95,7 +95,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, p return; } - $location.path('/desktop'); + $location.path('/account'); $scope.$apply(); }); } diff --git a/src/js/controller/login/login-privatekey-download.js b/src/js/controller/login/login-privatekey-download.js index 5c3a58c..3ae1b32 100644 --- a/src/js/controller/login/login-privatekey-download.js +++ b/src/js/controller/login/login-privatekey-download.js @@ -100,7 +100,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams, auth return; } - $scope.goTo('/desktop'); + $scope.goTo('/account'); }); }); }); diff --git a/src/js/controller/login/login.js b/src/js/controller/login/login.js index 3d04571..7b4bc3a 100644 --- a/src/js/controller/login/login.js +++ b/src/js/controller/login/login.js @@ -60,7 +60,7 @@ var LoginCtrl = function($scope, $timeout, $location, updateHandler, account, au return dialog.error(err); } - $scope.goTo('/desktop'); + $scope.goTo('/account'); }); }); } else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) { diff --git a/src/js/util/backbutton-handler.js b/src/js/util/backbutton-handler.js deleted file mode 100644 index 2990bc7..0000000 --- a/src/js/util/backbutton-handler.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -var axe = require('axe-logger'), - DEBUG_TAG = 'backbutton handler'; - -/** - * The back button handler introduces meaningful behavior fo rthe back button: - * if there's an open lightbox, close it; - * if the reader is open in mobile mode, close it; - * if the navigation is open, close it; - * if there's nothing else open, shut down the app; - * - * @type {Object} - */ -var backBtnHandler = { - attachHandler: function(scope) { - this.scope = scope; - }, - start: function() { - document.addEventListener("backbutton", handleBackButton, false); - }, - stop: function() { - document.removeEventListener("backbutton", handleBackButton, false); - } -}; - -function handleBackButton(event) { - axe.debug(DEBUG_TAG, 'back button pressed'); - - // this disarms the default behavior which we NEVER want - event.preventDefault(); - event.stopPropagation(); - - if (backBtnHandler.scope.state.lightbox) { - // closes the lightbox (error msgs, writer, ...) - backBtnHandler.scope.state.lightbox = undefined; - axe.debug(DEBUG_TAG, 'lightbox closed'); - backBtnHandler.scope.$apply(); - } else if (backBtnHandler.scope.state.read && backBtnHandler.scope.state.read.open) { - // closes the reader - backBtnHandler.scope.state.read.toggle(false); - axe.debug(DEBUG_TAG, 'reader closed'); - backBtnHandler.scope.$apply(); - } else if (backBtnHandler.scope.state.nav && backBtnHandler.scope.state.nav.open) { - // closes the navigation - backBtnHandler.scope.state.nav.toggle(false); - axe.debug(DEBUG_TAG, 'navigation closed'); - backBtnHandler.scope.$apply(); - } else { - // exits the app - navigator.app.exitApp(); - } -} - -module.exports = backBtnHandler; \ No newline at end of file diff --git a/src/js/util/dummy.js b/src/js/util/dummy.js index b9a257b..2c9ee89 100644 --- a/src/js/util/dummy.js +++ b/src/js/util/dummy.js @@ -6,6 +6,50 @@ module.exports = Dummy; function Dummy() {} +Dummy.prototype.listFolders = function() { + var dummies = [{ + type: 'Inbox', + count: 2, + path: 'INBOX', + wellknown: true + }, { + type: 'Sent', + count: 0, + path: 'SENT', + wellknown: true + }, { + type: 'Outbox', + count: 0, + path: 'OUTBOX', + wellknown: true + }, { + type: 'Drafts', + count: 0, + path: 'DRAFTS', + wellknown: true + }, { + type: 'Trash', + count: 0, + path: 'TRASH', + wellknown: true + }, { + type: 'Flagged', + count: 0, + path: 'FLAGGED', + wellknown: true + }, { + name: 'Archive', + count: 0, + path: 'ARCHIVE' + }, { + name: 'Junk', + count: 0, + path: 'JUNK' + }]; + + return dummies; +}; + Dummy.prototype.listMails = function() { var uid = 1000000; diff --git a/src/js/util/index.js b/src/js/util/index.js index 86c9d72..35fd1db 100644 --- a/src/js/util/index.js +++ b/src/js/util/index.js @@ -7,6 +7,6 @@ require('./dummy'); require('./dialog'); require('./connection-doctor'); require('./update/update-handler'); -require('./status-display'); +require('./status'); require('./download'); require('./notification'); \ No newline at end of file diff --git a/src/js/util/status-display.js b/src/js/util/status.js similarity index 59% rename from src/js/util/status-display.js rename to src/js/util/status.js index 4379b18..8134027 100644 --- a/src/js/util/status-display.js +++ b/src/js/util/status.js @@ -1,13 +1,13 @@ 'use strict'; var ngModule = angular.module('woUtil'); -ngModule.service('statusDisplay', StatusDisplay); -module.exports = StatusDisplay; +ngModule.service('status', Status); +module.exports = Status; /** * A central service to display status updates to the user */ -function StatusDisplay($rootScope, axe) { +function Status($rootScope, axe) { this._rootScope = $rootScope; this._axe = axe; } @@ -17,7 +17,7 @@ function StatusDisplay($rootScope, axe) { * @param {String} text The status message that is to be displayed to the user * @param {Date} time The time of the last update */ -StatusDisplay.prototype.update = function(text, time) { +Status.prototype.update = function(text, time) { this._axe.info('status display', text); this._rootScope.$broadcast('status', text, time); }; @@ -26,6 +26,14 @@ StatusDisplay.prototype.update = function(text, 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) { +Status.prototype.setSearching = function(state) { this._rootScope.$broadcast('searching', state); +}; + +/** + * Update the reading status to communicate between controllers, if we're in read mode. + * @param {Boolean} state If the reade mode should be open or not + */ +Status.prototype.setReading = function(state) { + this._rootScope.$broadcast('read', state); }; \ No newline at end of file diff --git a/src/sass/blocks/views/_mail-list.scss b/src/sass/blocks/views/_mail-list.scss index c1e493a..39d6125 100755 --- a/src/sass/blocks/views/_mail-list.scss +++ b/src/sass/blocks/views/_mail-list.scss @@ -130,11 +130,6 @@ overflow-y: scroll; // allow scrolling on iOS -webkit-overflow-scrolling: touch; - - // hide scrollbar in webkit - &::-webkit-scrollbar { - display: none; - } } &__entries { display: table; // import for mail list entry desktop layout @@ -295,7 +290,8 @@ // Modifiers - &:hover { + &:hover, + &.wo-touch-active { background-color: rgba($color-main, 0.15); } &--unread { diff --git a/src/tpl/login-set-credentials.html b/src/tpl/login-set-credentials.html index 8a978e3..3f8f722 100644 --- a/src/tpl/login-set-credentials.html +++ b/src/tpl/login-set-credentials.html @@ -41,7 +41,7 @@


- + {{showDetails ? "Hide Options" : "Show Options"}}

diff --git a/src/tpl/mail-list.html b/src/tpl/mail-list.html index 64016e1..e0c758e 100644 --- a/src/tpl/mail-list.html +++ b/src/tpl/mail-list.html @@ -27,7 +27,7 @@ infinite-scroll-distance="1" infinite-scroll-parent="true">