From aa66beb0c74ebaa950a083ed991f6e5f50f9c9ac Mon Sep 17 00:00:00 2001 From: Jefferson Stachelski Date: Thu, 31 Dec 2015 16:52:49 -0200 Subject: Issue #25 - Implemented shortcuts on UI --- web-ui/app/js/dispatchers/right_pane_dispatcher.js | 10 ++ web-ui/app/js/mail_view/ui/mail_actions.js | 15 +-- web-ui/app/js/mail_view/ui/reply_section.js | 4 + web-ui/app/js/page/default.js | 5 +- web-ui/app/js/page/events.js | 9 ++ web-ui/app/js/page/shortcuts.js | 146 +++++++++++++++++++++ web-ui/app/js/search/search_trigger.js | 5 + web-ui/app/js/services/delete_service.js | 1 + 8 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 web-ui/app/js/page/shortcuts.js (limited to 'web-ui') diff --git a/web-ui/app/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js index 870bcd92..4d28588a 100644 --- a/web-ui/app/js/dispatchers/right_pane_dispatcher.js +++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js @@ -100,12 +100,22 @@ define( this.attr.currentTag = data.tag; }; + this.shortcutOpenComposeBox = function() { + this.trigger(document, events.dispatchers.rightPane.openComposeBox); + }; + + this.shortcutCloseMail = function() { + this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected); + }; + this.after('initialize', function () { this.on(document, events.dispatchers.rightPane.openComposeBox, this.openComposeBox); + this.on(document, events.shortcuts.openComposeBox, this.shortcutOpenComposeBox); this.on(document, events.dispatchers.rightPane.openDraft, this.openDraft); this.on(document, events.ui.mail.open, this.openMail); this.on(document, events.dispatchers.rightPane.openFeedbackBox, this.openFeedbackBox); this.on(document, events.dispatchers.rightPane.openNoMessageSelected, this.openNoMessageSelectedPane); + this.on(document, events.shortcuts.closeMail, this.shortcutCloseMail); this.on(document, events.dispatchers.rightPane.selectTag, this.selectTag); this.on(document, events.ui.tag.selected, this.saveTag); this.on(document, events.ui.tag.select, this.saveTag); diff --git a/web-ui/app/js/mail_view/ui/mail_actions.js b/web-ui/app/js/mail_view/ui/mail_actions.js index 65cd0aaa..aa90169f 100644 --- a/web-ui/app/js/mail_view/ui/mail_actions.js +++ b/web-ui/app/js/mail_view/ui/mail_actions.js @@ -37,11 +37,13 @@ define( moreActions: '#more-actions' }); + this.deleteMail = function () { + this.trigger(document, events.ui.mail.delete, {mail: this.attr.mail}); + this.select('moreActions').hide(); + }; this.displayMailActions = function () { - this.$node.html(templates.mails.mailActions()); - this.select('moreActions').hide(); this.on(this.select('replyButtonTop'), 'click', function () { @@ -53,11 +55,6 @@ define( this.select('moreActions').hide(); }.bind(this)); - this.on(this.select('deleteButtonTop'), 'click', function () { - this.trigger(document, events.ui.mail.delete, {mail: this.attr.mail}); - this.select('moreActions').hide(); - }.bind(this)); - this.on(this.select('viewMoreActions'), 'click', function () { this.select('moreActions').toggle(); }.bind(this)); @@ -72,12 +69,14 @@ define( this.select('moreActions').hide(); } }.bind(this)); - }; this.after('initialize', function () { this.on(document, events.dispatchers.rightPane.clear, this.teardown); + this.on(document, events.shortcuts.deleteMail, this.deleteMail); + this.displayMailActions(); + this.on(this.select('deleteButtonTop'), 'click', this.deleteMail); }); } } diff --git a/web-ui/app/js/mail_view/ui/reply_section.js b/web-ui/app/js/mail_view/ui/reply_section.js index 46dfe863..71e27b1e 100644 --- a/web-ui/app/js/mail_view/ui/reply_section.js +++ b/web-ui/app/js/mail_view/ui/reply_section.js @@ -112,6 +112,10 @@ define( this.on(document, events.mail.draftReply.notFound, this.showButtons); this.on(document, events.mail.draftReply.here, this.showDraftReply); + this.on(document, events.shortcuts.replyMail, this.showReply); + this.on(document, events.shortcuts.replyAllMail, this.showReplyAll); + this.on(document, events.shortcuts.forwardMail, this.showForward); + this.checkForDraftReply(); }); } diff --git a/web-ui/app/js/page/default.js b/web-ui/app/js/page/default.js index e33ec723..91c9c904 100644 --- a/web-ui/app/js/page/default.js +++ b/web-ui/app/js/page/default.js @@ -51,6 +51,7 @@ define( 'mail_view/data/feedback_sender', 'page/version', 'page/unread_count_title', + 'page/shortcuts' ], function ( @@ -88,7 +89,8 @@ define( feedbackBox, feedbackSender, version, - unreadCountTitle) { + unreadCountTitle, + shortcuts) { 'use strict'; function initialize(path) { @@ -129,6 +131,7 @@ define( feedbackSender.attachTo(document); unreadCountTitle.attachTo(document); + shortcuts.attachTo(document); } return initialize; diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js index 406c3b23..6d67e671 100644 --- a/web-ui/app/js/page/events.js +++ b/web-ui/app/js/page/events.js @@ -206,6 +206,15 @@ define(function () { tags: { refreshTagList: 'dispatchers:tag:refresh' } + }, + shortcuts: { + openComposeBox: 'shortcuts:openComposeBox', + closeMail: 'shortcuts:closeMail', + focusSearchField: 'shortcuts:focusSearchField', + replyMail: 'shortcuts:replyMail', + replyAllMail: 'shortcuts:replyAllMail', + forwardMail: 'shortcuts:forwardMail', + deleteMail: 'shortcuts:deleteMail' } }; diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js new file mode 100644 index 00000000..2bb75d8c --- /dev/null +++ b/web-ui/app/js/page/shortcuts.js @@ -0,0 +1,146 @@ +define([ + 'flight/lib/component', + 'page/events' +], +function(defineComponent, events) { +'use strict'; + + return defineComponent(shortcuts); + + function shortcuts() { + function hasInputFieldFocused() { + return $('input').is(':focus') || $('textarea').is(':focus'); + } + + function triggerOpenComposeBoxEvent() { + if(!hasInputFieldFocused()){ + this.trigger(document, events.shortcuts.openComposeBox); + event.preventDefault(); + } + } + + function triggerCloseBoxEvent() { + this.trigger(document, events.shortcuts.closeMail); + event.preventDefault(); + } + + function focusSearchField() { + if(!hasInputFieldFocused()) { + this.trigger(document, events.shortcuts.focusSearchField); + event.preventDefault(); + } + } + + function addTag() { + // TODO: refator to trigger an event that other component will handle + if(!hasInputFieldFocused()) { + event.preventDefault(); + $('#new-tag-button').click(); + } + } + + function triggerReplyEvent() { + if(!hasInputFieldFocused() && $('#reply-button').is(':visible')) { + this.trigger(document, events.shortcuts.replyMail); + } + } + + function triggerReplyAllEvent() { + if(!hasInputFieldFocused() && $('#reply-all-button').is(':visible')) { + this.trigger(document, events.shortcuts.replyAllMail); + } + } + + function triggerForwardEvent() { + if(!hasInputFieldFocused() && $('#forward-button').is(':visible')) { + this.trigger(document, events.shortcuts.forwardMail); + } + } + + function deleteMail() { + // TODO: refator to trigger an event that other component will handle + $('#delete-button-top').click(); + } + + function sendMail() { + // TODO: refator to trigger an event that other component will handle + $('#send-button').click(); + } + + function previousMail() { + if(!hasInputFieldFocused()) { + // TODO: implement previous mail logic + console.log('previous mail'); + } + } + + function nextMail() { + if(!hasInputFieldFocused()) { + // TODO: implement next mail logic + console.log('next mail'); + } + } + + var SPECIAL_CHARACTERES = { + 13: 'ENTER', + 27: 'ESC', + 33: 'PAGE-UP', + 34: 'PAGE-DOWN', + 37: 'LEFT', + 38: 'UP', + 39: 'RIGHT', + 40: 'DOWN', + 191: '/' + }; + + var SHORTCUT_MAP = { + 'C': triggerOpenComposeBoxEvent, + 'ESC': triggerCloseBoxEvent, + '/': focusSearchField, + 'S': focusSearchField, + 'T': addTag, + 'R': triggerReplyEvent, + 'A': triggerReplyAllEvent, + 'F': triggerForwardEvent, + 'SHIFT+3': deleteMail, + 'CTRL+ENTER': sendMail, + 'J': previousMail, + 'UP': previousMail, + 'K': nextMail, + 'DOWN': nextMail + }; + + this.convertCodeToShortcut = function(event) { + var shortcut = ''; + if(event.ctrlKey) { + shortcut += 'CTRL+'; + } + if(event.altKey) { + shortcut += 'ALT+'; + } + if(event.shiftKey) { + shortcut += 'SHIFT+'; + } + + if(SPECIAL_CHARACTERES.hasOwnProperty(event.which)) { + shortcut += SPECIAL_CHARACTERES[event.which]; + } else { + shortcut += String.fromCharCode(event.which); + } + + return shortcut; + }; + + this.riseEventFromShortcut = function(event) { + var shortcut = this.convertCodeToShortcut(event); + + if(SHORTCUT_MAP.hasOwnProperty(shortcut)) { + SHORTCUT_MAP[shortcut].apply(this); + } + }; + + this.after('initialize', function() { + this.on(document, 'keydown', this.riseEventFromShortcut); + }); + } +}); diff --git a/web-ui/app/js/search/search_trigger.js b/web-ui/app/js/search/search_trigger.js index 4b9cb1dc..cb670239 100644 --- a/web-ui/app/js/search/search_trigger.js +++ b/web-ui/app/js/search/search_trigger.js @@ -68,6 +68,10 @@ define( } }; + this.shortcutFocusSearchField = function() { + this.$node.find('input[type=search]').focus(); + }; + this.after('initialize', function () { this.render(); this.on(this.select('form'), 'submit', this.search); @@ -75,6 +79,7 @@ define( this.on(this.select('input'), 'blur', this.showSearchTermsAndPlaceHolder); this.on(document, events.ui.tag.selected, this.clearInput); this.on(document, events.ui.tag.select, this.clearInput); + this.on(document, events.shortcuts.focusSearchField, this.shortcutFocusSearchField); }); } } diff --git a/web-ui/app/js/services/delete_service.js b/web-ui/app/js/services/delete_service.js index 5cf86d63..92b5838b 100644 --- a/web-ui/app/js/services/delete_service.js +++ b/web-ui/app/js/services/delete_service.js @@ -53,6 +53,7 @@ define(['flight/lib/component', 'page/events', 'views/i18n'], function (defineCo this.after('initialize', function () { this.on(document, events.ui.mail.delete, this.deleteEmail); this.on(document, events.ui.mail.deleteMany, this.deleteManyEmails); + this.on(document, events.shortcuts.deleteMail, this.deleteEmail); }); }); -- cgit v1.2.3