From 8dbebaa1756ded673a7ad14f8dc80bf3aaeaf1cd Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Wed, 13 Jul 2016 12:42:00 +0200 Subject: [PATCH 01/12] Open compose box on keyboard shortcut 'c' --- web-ui/app/js/page/default.js | 8 +++-- web-ui/app/js/page/shortcuts.js | 37 ++++++++++++++++++++++ web-ui/test/spec/page/shortcuts.spec.js | 42 +++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 web-ui/app/js/page/shortcuts.js create mode 100644 web-ui/test/spec/page/shortcuts.spec.js diff --git a/web-ui/app/js/page/default.js b/web-ui/app/js/page/default.js index ecaedfd81..747617d5a 100644 --- a/web-ui/app/js/page/default.js +++ b/web-ui/app/js/page/default.js @@ -52,7 +52,8 @@ define( 'page/version', 'page/unread_count_title', 'page/pix_logo', - 'helpers/browser' + 'helpers/browser', + 'page/shortcuts' ], function ( @@ -92,7 +93,8 @@ define( version, unreadCountTitle, pixLogo, - browser) { + browser, + shortcuts) { 'use strict'; function initialize(path) { @@ -137,6 +139,8 @@ define( pixLogo.attachTo(document); + shortcuts.attachTo(document); + $.ajaxSetup({headers: {'X-XSRF-TOKEN': browser.getCookie('XSRF-TOKEN')}}); }); } diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js new file mode 100644 index 000000000..8554474b5 --- /dev/null +++ b/web-ui/app/js/page/shortcuts.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 ThoughtWorks, Inc. + * + * Pixelated is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pixelated is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pixelated. If not, see . + */ + +define([ + 'flight/lib/component', + 'page/events' + ], + function(defineComponent, events) { + 'use strict'; + + return defineComponent(shortcuts); + + function shortcuts() { + this.onKeydown = function(event) { + if ($(event.target).is('input') || $(event.target).is('textarea')) return; + if (String.fromCharCode(event.which) === 'c') this.trigger(document, events.dispatchers.rightPane.openComposeBox); + }; + + this.after('initialize', function() { + this.on(document, 'keypress', this.onKeydown); + }); + } + }); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js new file mode 100644 index 000000000..50e67c69d --- /dev/null +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -0,0 +1,42 @@ +describeComponent('page/shortcuts', function () { + 'use strict'; + + describe('shortcuts', function () { + it('triggers openComposeBox when "c" is pressed and no input is focused', function () { + this.setupComponent(); + var eventSpy = openComposeBoxEventSpy(); + + $(document).trigger(keypressEvent('c')); + + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + + it('does not trigger openComposeBox when "c" is pressed in an input field', function () { + this.setupComponent(); + this.$node.append(''); + var eventSpy = openComposeBoxEventSpy(); + + this.$node.find('input').trigger(keypressEvent('c')); + + expect(eventSpy).not.toHaveBeenTriggeredOn(document) + }); + + it('does not trigger openComposeBox when "c" is pressed in a textarea', function () { + this.setupComponent(); + this.$node.append(''); + var eventSpy = openComposeBoxEventSpy(); + + this.$node.find('textarea').trigger(keypressEvent('c')); + + expect(eventSpy).not.toHaveBeenTriggeredOn(document) + }); + + function openComposeBoxEventSpy() { + return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); + } + + function keypressEvent(char) { + return jQuery.Event('keypress', {which: char.charCodeAt(0)}); + } + }); +}); From 39733bdcc2c54cd49ee5b31b7327466f1945d4bc Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Wed, 13 Jul 2016 16:33:22 +0200 Subject: [PATCH 02/12] Close compose box on keyboard shortcut --- web-ui/app/js/page/shortcuts.js | 16 +++++++++++----- web-ui/test/spec/page/shortcuts.spec.js | 18 +++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 8554474b5..43465011c 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -19,19 +19,25 @@ define([ 'flight/lib/component', 'page/events' ], - function(defineComponent, events) { + function (defineComponent, events) { 'use strict'; return defineComponent(shortcuts); function shortcuts() { - this.onKeydown = function(event) { + this.CHARACTER_CODES = { + ESC: 27, + C: 67 + }; + this.onKeydown = function (event) { + if (event.which === this.CHARACTER_CODES.ESC) this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected); if ($(event.target).is('input') || $(event.target).is('textarea')) return; - if (String.fromCharCode(event.which) === 'c') this.trigger(document, events.dispatchers.rightPane.openComposeBox); + if (event.which === this.CHARACTER_CODES.C) this.trigger(document, events.dispatchers.rightPane.openComposeBox); + event.preventDefault(); }; - this.after('initialize', function() { - this.on(document, 'keypress', this.onKeydown); + this.after('initialize', function () { + this.on(document, 'keydown', this.onKeydown); }); } }); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index 50e67c69d..022984584 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -6,7 +6,7 @@ describeComponent('page/shortcuts', function () { this.setupComponent(); var eventSpy = openComposeBoxEventSpy(); - $(document).trigger(keypressEvent('c')); + $(document).trigger(keydownEvent(this.component.CHARACTER_CODES.C)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); @@ -16,7 +16,7 @@ describeComponent('page/shortcuts', function () { this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('input').trigger(keypressEvent('c')); + this.$node.find('input').trigger(keydownEvent(this.component.CHARACTER_CODES.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); @@ -26,17 +26,25 @@ describeComponent('page/shortcuts', function () { this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('textarea').trigger(keypressEvent('c')); + this.$node.find('textarea').trigger(keydownEvent(this.component.CHARACTER_CODES.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); + it('triggers openNoMessageSelected when is pressed and no input is focused', function () { + this.setupComponent(); + var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); + $(document).trigger(keydownEvent(this.component.CHARACTER_CODES.ESC)); + + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + function openComposeBoxEventSpy() { return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); } - function keypressEvent(char) { - return jQuery.Event('keypress', {which: char.charCodeAt(0)}); + function keydownEvent(code) { + return jQuery.Event('keydown', {which: code}); } }); }); From a85cdc700d1f133984d22af7acbc8bd7f4ef27f6 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Wed, 13 Jul 2016 17:46:02 +0200 Subject: [PATCH 03/12] WIP feature test --- .../keyboard_shortcuts_to_compose.feature | 32 +++++++++++++++++++ .../test/functional/features/steps/compose.py | 19 ++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 service/test/functional/features/keyboard_shortcuts_to_compose.feature diff --git a/service/test/functional/features/keyboard_shortcuts_to_compose.feature b/service/test/functional/features/keyboard_shortcuts_to_compose.feature new file mode 100644 index 000000000..25887987b --- /dev/null +++ b/service/test/functional/features/keyboard_shortcuts_to_compose.feature @@ -0,0 +1,32 @@ +# +# Copyright (c) 2014 ThoughtWorks, Inc. +# +# Pixelated is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pixelated is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Pixelated. If not, see . + +Feature: Using keyboard shortcuts to compose and send a mail + As a user of pixelated + I want to use keyboard shortcuts + So I can compose mails + + Scenario: User composes a mail and sends it using shortcuts + When I use a shortcut to compose a message with + | subject | body | + | Pixelated rocks! | You should definitely use it. Cheers, User. | + And for the 'To' field I enter 'pixelated@friends.org' + And I use a shortcut to send it + When I select the tag 'sent' + And I open the first mail in the mail list + Then I see that the subject reads 'Pixelated rocks!' + Then I see that the body reads 'You should definitely use it. Cheers, User.' + diff --git a/service/test/functional/features/steps/compose.py b/service/test/functional/features/steps/compose.py index 67b1bd518..4ebc66648 100644 --- a/service/test/functional/features/steps/compose.py +++ b/service/test/functional/features/steps/compose.py @@ -13,9 +13,11 @@ # # You should have received a copy of the GNU Affero General Public License # along with Pixelated. If not, see . +from behave import when +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.common.keys import Keys from time import sleep -from behave import when from common import * @@ -29,6 +31,16 @@ def impl(context): fill_by_css_selector(context, 'textarea#text-box', row['body']) +@when('I use a shortcut to compose a message with') +def compose_with_shortcut(context): + body = context.browser.find_element_by_tag_name('body') + body.send_keys('c') + + for row in context.table: + fill_by_css_selector(context, 'input#subject', row['subject']) + fill_by_css_selector(context, 'textarea#text-box', row['body']) + + @when("for the '{recipients_field}' field I enter '{to_type}'") def enter_address_impl(context, recipients_field, to_type): _enter_recipient(context, recipients_field, to_type + "\n") @@ -47,6 +59,11 @@ def send_impl(context): send_button.click() +@when('I use a shortcut to send it') +def send_with_shortcut(context): + ActionChains(context.browser).key_down(Keys.CONTROL).send_keys(Keys.ENTER).key_up(Keys.CONTROL).perform() + + @when(u'I toggle the cc and bcc fields') def collapse_cc_bcc_fields(context): cc_and_bcc_chevron = wait_until_element_is_visible_by_locator(context, (By.CSS_SELECTOR, '#cc-bcc-collapse')) From 7c83aefcdf533b0325809586b743469f72181922 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Thu, 14 Jul 2016 16:59:07 +0200 Subject: [PATCH 04/12] Send mail with shortcut --- web-ui/app/js/page/shortcuts.js | 51 +++++++++++++++++++++---- web-ui/test/spec/page/shortcuts.spec.js | 25 +++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 43465011c..a4c93fa90 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -25,19 +25,54 @@ define([ return defineComponent(shortcuts); function shortcuts() { - this.CHARACTER_CODES = { + this.characterCodes = { ESC: 27, - C: 67 + C: 67, + ENTER: 13 }; - this.onKeydown = function (event) { - if (event.which === this.CHARACTER_CODES.ESC) this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected); - if ($(event.target).is('input') || $(event.target).is('textarea')) return; - if (event.which === this.CHARACTER_CODES.C) this.trigger(document, events.dispatchers.rightPane.openComposeBox); + + var self = this; + + function sendMail() { + this.trigger(document, events.ui.mail.send); + } + + function closeComposeBox() { + this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected); + } + + function openComposeBox() { + this.trigger(document, events.dispatchers.rightPane.openComposeBox); + } + + function isTriggeredOnInputField(event) { + return $(event.target).is('input') || $(event.target).is('textarea'); + } + + function ctrlOrMetaEnterKey(event) { + return (event.ctrlKey === true || event.metaKey === true) && event.which === self.characterCodes.ENTER; + } + + function escapeKey(event) { + return event.which === self.characterCodes.ESC; + } + + function cKey(event) { + return event.which === self.characterCodes.C; + } + + function onKeydown(event) { + if (escapeKey(event)) closeComposeBox.call(this); + if (ctrlOrMetaEnterKey(event)) sendMail.call(this); + + if (isTriggeredOnInputField(event)) return; + + if (cKey(event)) openComposeBox.call(this); event.preventDefault(); - }; + } this.after('initialize', function () { - this.on(document, 'keydown', this.onKeydown); + this.on(document, 'keydown', $.proxy(onKeydown, this)); }); } }); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index 022984584..e8ab0342c 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -6,7 +6,7 @@ describeComponent('page/shortcuts', function () { this.setupComponent(); var eventSpy = openComposeBoxEventSpy(); - $(document).trigger(keydownEvent(this.component.CHARACTER_CODES.C)); + $(document).trigger(keydownEvent(this.component.characterCodes.C)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); @@ -16,7 +16,7 @@ describeComponent('page/shortcuts', function () { this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('input').trigger(keydownEvent(this.component.CHARACTER_CODES.C)); + this.$node.find('input').trigger(keydownEvent(this.component.characterCodes.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); @@ -26,19 +26,34 @@ describeComponent('page/shortcuts', function () { this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('textarea').trigger(keydownEvent(this.component.CHARACTER_CODES.C)); + this.$node.find('textarea').trigger(keydownEvent(this.component.characterCodes.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); - it('triggers openNoMessageSelected when is pressed and no input is focused', function () { + it('triggers openNoMessageSelected when is pressed', function () { this.setupComponent(); var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); - $(document).trigger(keydownEvent(this.component.CHARACTER_CODES.ESC)); + $(document).trigger(keydownEvent(this.component.characterCodes.ESC)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); + it('triggers ui.mail.send when + is pressed', function () { + this.setupComponent(); + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); + $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.characterCodes.ENTER})); + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + + + it('triggers ui.mail.send when / + is pressed', function () { + this.setupComponent(); + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); + $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.characterCodes.ENTER})); + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + function openComposeBoxEventSpy() { return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); } From ec073fac8cf0ccb96145e2d9d42d6e9edae81103 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Thu, 14 Jul 2016 17:03:32 +0200 Subject: [PATCH 05/12] Add "wip" tag to feature test --- .../functional/features/keyboard_shortcuts_to_compose.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/service/test/functional/features/keyboard_shortcuts_to_compose.feature b/service/test/functional/features/keyboard_shortcuts_to_compose.feature index 25887987b..092620752 100644 --- a/service/test/functional/features/keyboard_shortcuts_to_compose.feature +++ b/service/test/functional/features/keyboard_shortcuts_to_compose.feature @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with Pixelated. If not, see . +@wip Feature: Using keyboard shortcuts to compose and send a mail As a user of pixelated I want to use keyboard shortcuts From 6a5d108a57f6abbe9bbd9757fea422e26ae86841 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Fri, 15 Jul 2016 12:04:02 +0200 Subject: [PATCH 06/12] Focus search input field when pressing or --- web-ui/app/js/page/events.js | 3 +- web-ui/app/js/page/shortcuts.js | 60 +++++++++---------- web-ui/app/js/search/search_trigger.js | 5 ++ web-ui/test/spec/page/shortcuts.spec.js | 43 +++++++++---- .../test/spec/search/search_trigger.spec.js | 4 ++ 5 files changed, 69 insertions(+), 46 deletions(-) diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js index 68a6aad1e..af1ccdd04 100644 --- a/web-ui/app/js/page/events.js +++ b/web-ui/app/js/page/events.js @@ -109,7 +109,8 @@ define(function () { results: 'search:results', empty: 'search:empty', highlightResults: 'search:highlightResults', - resetHighlight: 'search:resetHighlight' + resetHighlight: 'search:resetHighlight', + focus: 'search:focus' }, feedback: { submit: 'feedback:submit', diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index a4c93fa90..8c59d2b83 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -25,24 +25,40 @@ define([ return defineComponent(shortcuts); function shortcuts() { - this.characterCodes = { + this.after('initialize', function () { + this.on(document, 'keydown', $.proxy(onKeydown, this)); + }); + + this.keyCodes = { ESC: 27, C: 67, - ENTER: 13 + ENTER: 13, + FORWARD_SLASH: 191, + S: 83 }; - var self = this; + var specialKeyToEvent = {}; + specialKeyToEvent[this.keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; - function sendMail() { - this.trigger(document, events.ui.mail.send); - } + var alphaNumericKeyToEvent = {}; + alphaNumericKeyToEvent[this.keyCodes.S] = events.search.focus; + alphaNumericKeyToEvent[this.keyCodes.FORWARD_SLASH] = events.search.focus; + alphaNumericKeyToEvent[this.keyCodes.C] = events.dispatchers.rightPane.openComposeBox; - function closeComposeBox() { - this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected); + function onKeydown(event) { + if (ctrlOrMetaEnterKey.call(this, event)) sendMail.call(this); + if (specialKeyToEvent.hasOwnProperty(event.which)) + this.trigger(document, specialKeyToEvent[event.which]); + + if (isTriggeredOnInputField(event)) return; + + if (alphaNumericKeyToEvent.hasOwnProperty(event.which)) + this.trigger(document, alphaNumericKeyToEvent[event.which]); + event.preventDefault(); } - function openComposeBox() { - this.trigger(document, events.dispatchers.rightPane.openComposeBox); + function sendMail() { + this.trigger(document, events.ui.mail.send); } function isTriggeredOnInputField(event) { @@ -50,29 +66,7 @@ define([ } function ctrlOrMetaEnterKey(event) { - return (event.ctrlKey === true || event.metaKey === true) && event.which === self.characterCodes.ENTER; + return (event.ctrlKey === true || event.metaKey === true) && event.which === this.keyCodes.ENTER; } - - function escapeKey(event) { - return event.which === self.characterCodes.ESC; - } - - function cKey(event) { - return event.which === self.characterCodes.C; - } - - function onKeydown(event) { - if (escapeKey(event)) closeComposeBox.call(this); - if (ctrlOrMetaEnterKey(event)) sendMail.call(this); - - if (isTriggeredOnInputField(event)) return; - - if (cKey(event)) openComposeBox.call(this); - event.preventDefault(); - } - - this.after('initialize', function () { - this.on(document, 'keydown', $.proxy(onKeydown, this)); - }); } }); diff --git a/web-ui/app/js/search/search_trigger.js b/web-ui/app/js/search/search_trigger.js index 2aff027ca..662242c0f 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.focus = function () { + this.select('input').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.search.focus, this.focus); }); } } diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index e8ab0342c..fc05d6f61 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -1,56 +1,75 @@ describeComponent('page/shortcuts', function () { 'use strict'; + beforeEach(function () { + this.setupComponent(); + }); + describe('shortcuts', function () { it('triggers openComposeBox when "c" is pressed and no input is focused', function () { - this.setupComponent(); var eventSpy = openComposeBoxEventSpy(); - $(document).trigger(keydownEvent(this.component.characterCodes.C)); + $(document).trigger(keydownEvent(this.component.keyCodes.C)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); it('does not trigger openComposeBox when "c" is pressed in an input field', function () { - this.setupComponent(); this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('input').trigger(keydownEvent(this.component.characterCodes.C)); + this.$node.find('input').trigger(keydownEvent(this.component.keyCodes.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); it('does not trigger openComposeBox when "c" is pressed in a textarea', function () { - this.setupComponent(); this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); - this.$node.find('textarea').trigger(keydownEvent(this.component.characterCodes.C)); + this.$node.find('textarea').trigger(keydownEvent(this.component.keyCodes.C)); expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); it('triggers openNoMessageSelected when is pressed', function () { - this.setupComponent(); var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); - $(document).trigger(keydownEvent(this.component.characterCodes.ESC)); + + $(document).trigger(keydownEvent(this.component.keyCodes.ESC)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); it('triggers ui.mail.send when + is pressed', function () { - this.setupComponent(); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.characterCodes.ENTER})); + + $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); + expect(eventSpy).toHaveBeenTriggeredOn(document) }); it('triggers ui.mail.send when / + is pressed', function () { - this.setupComponent(); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.characterCodes.ENTER})); + + $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); + + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + + it('triggers search.focus when is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.search.focus); + + $(document).trigger(keydownEvent(this.component.keyCodes.FORWARD_SLASH)); + + expect(eventSpy).toHaveBeenTriggeredOn(document) + }); + + it('triggers search.focus when is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.search.focus); + + $(document).trigger(keydownEvent(this.component.keyCodes.S)); + expect(eventSpy).toHaveBeenTriggeredOn(document) }); diff --git a/web-ui/test/spec/search/search_trigger.spec.js b/web-ui/test/spec/search/search_trigger.spec.js index 6ba474891..6895f00ed 100644 --- a/web-ui/test/spec/search/search_trigger.spec.js +++ b/web-ui/test/spec/search/search_trigger.spec.js @@ -49,5 +49,9 @@ describeComponent('search/search_trigger', function () { expect(self.component.select('input').val()).toBe(''); }); + it('should focus search input field on focus event', function () { + $(document).trigger(Pixelated.events.search.focus); + expect($(document.activeElement)).toEqual(this.component.select('input')) + }); }); From f15bc413e7c1a18607e7605d858cc3de5126e452 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Fri, 15 Jul 2016 17:23:56 +0200 Subject: [PATCH 07/12] Differenciate between shortcuts on mail composition and others --- web-ui/app/js/page/shortcuts.js | 86 +++++++++++++++++++------ web-ui/test/spec/page/shortcuts.spec.js | 23 +++++-- 2 files changed, 81 insertions(+), 28 deletions(-) diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 8c59d2b83..8435cc111 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -29,44 +29,88 @@ define([ this.on(document, 'keydown', $.proxy(onKeydown, this)); }); - this.keyCodes = { + var composeBoxId = 'compose-box'; + var keyCodes = { ESC: 27, C: 67, ENTER: 13, FORWARD_SLASH: 191, S: 83 }; + var modifierKeys = { + META: "META", + CTRL: "CTRL" + }; - var specialKeyToEvent = {}; - specialKeyToEvent[this.keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; - - var alphaNumericKeyToEvent = {}; - alphaNumericKeyToEvent[this.keyCodes.S] = events.search.focus; - alphaNumericKeyToEvent[this.keyCodes.FORWARD_SLASH] = events.search.focus; - alphaNumericKeyToEvent[this.keyCodes.C] = events.dispatchers.rightPane.openComposeBox; + // make constants public + this.keyCodes = keyCodes; + this.composeBoxId = composeBoxId; function onKeydown(event) { - if (ctrlOrMetaEnterKey.call(this, event)) sendMail.call(this); - if (specialKeyToEvent.hasOwnProperty(event.which)) - this.trigger(document, specialKeyToEvent[event.which]); + tryGlobalKeyEvents(event, triggerOnDocument.call(this)); + + if (composeBoxIsShown()) { + tryMailCompositionKeyEvents(event, triggerOnDocument.call(this)); + } else { + tryMailHandlingKeyEvents(event, triggerOnDocument.call(this)); + } + } + + function triggerOnDocument() { + var self = this; + return function (event) { + self.trigger(document, event); + } + } + + function tryGlobalKeyEvents(event, triggerFunc) { + var globalKeyEvents = {}; + globalKeyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; + + if (globalKeyEvents.hasOwnProperty(event.which)) { + triggerFunc(globalKeyEvents[event.which]); + event.preventDefault(); + } + } + + function tryMailCompositionKeyEvents(event, triggerFunc) { + var mailCompositionKeyEvents = {}; + mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; + mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; + + if (mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { + triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); + event.preventDefault(); + } + } + + function tryMailHandlingKeyEvents(event, triggerFunc) { + if (isTriggeredOnInputField(event.target)) return; - if (isTriggeredOnInputField(event)) return; + var mailHandlingKeyEvents = {}; + mailHandlingKeyEvents[keyCodes.S] = events.search.focus; + mailHandlingKeyEvents[keyCodes.FORWARD_SLASH] = events.search.focus; + mailHandlingKeyEvents[keyCodes.C] = events.dispatchers.rightPane.openComposeBox; - if (alphaNumericKeyToEvent.hasOwnProperty(event.which)) - this.trigger(document, alphaNumericKeyToEvent[event.which]); - event.preventDefault(); + if (mailHandlingKeyEvents.hasOwnProperty(event.which)) { + triggerFunc(mailHandlingKeyEvents[event.which]); + event.preventDefault(); + } } - function sendMail() { - this.trigger(document, events.ui.mail.send); + function modifierKey(event) { + var modifierKey = ""; + if (event.ctrlKey === true) modifierKey = modifierKeys.CTRL; + if (event.metaKey === true) modifierKey = modifierKeys.META; + return modifierKey; } - function isTriggeredOnInputField(event) { - return $(event.target).is('input') || $(event.target).is('textarea'); + function isTriggeredOnInputField(element) { + return $(element).is('input') || $(element).is('textarea'); } - function ctrlOrMetaEnterKey(event) { - return (event.ctrlKey === true || event.metaKey === true) && event.which === this.keyCodes.ENTER; + function composeBoxIsShown() { + return $('#' + composeBoxId).length; } } }); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index fc05d6f61..9066f0f08 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -6,7 +6,7 @@ describeComponent('page/shortcuts', function () { }); describe('shortcuts', function () { - it('triggers openComposeBox when "c" is pressed and no input is focused', function () { + it('triggers openComposeBox when is pressed and no input is focused', function () { var eventSpy = openComposeBoxEventSpy(); $(document).trigger(keydownEvent(this.component.keyCodes.C)); @@ -14,8 +14,8 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); - it('does not trigger openComposeBox when "c" is pressed in an input field', function () { - this.$node.append(''); + it('does not trigger openComposeBox when is pressed in an input field', function () { + this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); this.$node.find('input').trigger(keydownEvent(this.component.keyCodes.C)); @@ -23,7 +23,7 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); - it('does not trigger openComposeBox when "c" is pressed in a textarea', function () { + it('does not trigger openComposeBox when is pressed in a textarea', function () { this.$node.append(''); var eventSpy = openComposeBoxEventSpy(); @@ -40,7 +40,8 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); - it('triggers ui.mail.send when + is pressed', function () { + it('triggers ui.mail.send when + is pressed and compose box is open', function () { + this.$node.append($('
', {id: this.component.composeBoxId})); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); @@ -48,8 +49,8 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); - - it('triggers ui.mail.send when / + is pressed', function () { + it('triggers ui.mail.send when / + is pressed and compose box is open', function () { + this.$node.append($('
', {id: this.component.composeBoxId})); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); @@ -57,6 +58,14 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); + it('does not trigger ui.mail.send when + is pressed and compose box is closed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); + + $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); + + expect(eventSpy).not.toHaveBeenTriggeredOn(document) + }); + it('triggers search.focus when is pressed', function () { var eventSpy = spyOnEvent(document, Pixelated.events.search.focus); From d60e09e6921400df17f704dc1539c57bfae04730 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Tue, 19 Jul 2016 12:10:51 +0200 Subject: [PATCH 08/12] Test all code paths --- web-ui/app/js/page/shortcuts.js | 24 ++--- web-ui/test/spec/page/shortcuts.spec.js | 119 ++++++++++++++++-------- 2 files changed, 90 insertions(+), 53 deletions(-) diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 8435cc111..b3b9c408e 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -67,10 +67,10 @@ define([ var globalKeyEvents = {}; globalKeyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; - if (globalKeyEvents.hasOwnProperty(event.which)) { - triggerFunc(globalKeyEvents[event.which]); - event.preventDefault(); - } + if (!globalKeyEvents.hasOwnProperty(event.which)) return; + + triggerFunc(globalKeyEvents[event.which]); + event.preventDefault(); } function tryMailCompositionKeyEvents(event, triggerFunc) { @@ -78,10 +78,10 @@ define([ mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; - if (mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { - triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); - event.preventDefault(); - } + if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) return; + + event.preventDefault(); + return triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); } function tryMailHandlingKeyEvents(event, triggerFunc) { @@ -92,10 +92,10 @@ define([ mailHandlingKeyEvents[keyCodes.FORWARD_SLASH] = events.search.focus; mailHandlingKeyEvents[keyCodes.C] = events.dispatchers.rightPane.openComposeBox; - if (mailHandlingKeyEvents.hasOwnProperty(event.which)) { - triggerFunc(mailHandlingKeyEvents[event.which]); - event.preventDefault(); - } + if (!mailHandlingKeyEvents.hasOwnProperty(event.which)) return; + + event.preventDefault(); + return triggerFunc(mailHandlingKeyEvents[event.which]); } function modifierKey(event) { diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index 9066f0f08..d621f122a 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -5,43 +5,84 @@ describeComponent('page/shortcuts', function () { this.setupComponent(); }); - describe('shortcuts', function () { - it('triggers openComposeBox when is pressed and no input is focused', function () { - var eventSpy = openComposeBoxEventSpy(); + describe('global shortcuts', function () { + it('triggers openNoMessageSelected when [Esc] is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); - $(document).trigger(keydownEvent(this.component.keyCodes.C)); + $(document).trigger(keydownEvent(this.component.keyCodes.ESC)); expect(eventSpy).toHaveBeenTriggeredOn(document) }); + }); - it('does not trigger openComposeBox when is pressed in an input field', function () { - this.$node.append(''); - var eventSpy = openComposeBoxEventSpy(); + describe('mail list shortcuts', function () { + function shortcutEventAndTriggeredEventSpy() { + return [ + { + eventSpy: openComposeBoxEventSpy(), + shortcutEvent: keydownEvent(this.component.keyCodes.C) + }, + { + eventSpy: spyOnEvent(document, Pixelated.events.search.focus), + shortcutEvent: keydownEvent(this.component.keyCodes.FORWARD_SLASH) + }, + { + eventSpy: spyOnEvent(document, Pixelated.events.search.focus), + shortcutEvent: keydownEvent(this.component.keyCodes.S) + } + ] + } - this.$node.find('input').trigger(keydownEvent(this.component.keyCodes.C)); + it('are triggered when no input or textarea is focused', function () { + shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { + var eventSpy = args.eventSpy; - expect(eventSpy).not.toHaveBeenTriggeredOn(document) + $(document).trigger(args.shortcutEvent); + + expect(eventSpy).toHaveBeenTriggeredOn(document); + }); }); - it('does not trigger openComposeBox when is pressed in a textarea', function () { - this.$node.append(''); - var eventSpy = openComposeBoxEventSpy(); + it('are not triggered when an input is focused', function () { + var self = this; + shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { + self.$node.append(''); + var eventSpy = args.eventSpy; - this.$node.find('textarea').trigger(keydownEvent(this.component.keyCodes.C)); + self.$node.find('input').trigger(args.shortcutEvent); - expect(eventSpy).not.toHaveBeenTriggeredOn(document) + expect(eventSpy).not.toHaveBeenTriggeredOn(document); + }); }); - it('triggers openNoMessageSelected when is pressed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); + it('are not triggered when a textarea is focused', function () { + var self = this; + shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { + self.$node.append(''); + var eventSpy = args.eventSpy; - $(document).trigger(keydownEvent(this.component.keyCodes.ESC)); + self.$node.find('textarea').trigger(args.shortcutEvent); - expect(eventSpy).toHaveBeenTriggeredOn(document) + expect(eventSpy).not.toHaveBeenTriggeredOn(document); + }); }); - it('triggers ui.mail.send when + is pressed and compose box is open', function () { - this.$node.append($('
', {id: this.component.composeBoxId})); + it('are not triggered when the composeBox is opened', function () { + var self = this; + shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { + addComposeBox.call(self); + var eventSpy = args.eventSpy; + + $(document).trigger(args.shortcutEvent); + + expect(eventSpy).not.toHaveBeenTriggeredOn(document); + }); + }); + }); + + describe('mail composition shortcuts', function () { + it('triggers ui.mail.send when [Ctrl] + [Enter] is pressed and compose box is open', function () { + addComposeBox.call(this); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); @@ -49,8 +90,8 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); - it('triggers ui.mail.send when / + is pressed and compose box is open', function () { - this.$node.append($('
', {id: this.component.composeBoxId})); + it('triggers ui.mail.send when [Meta] + [Enter] is pressed and compose box is open', function () { + addComposeBox.call(this); var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); @@ -58,7 +99,7 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).toHaveBeenTriggeredOn(document) }); - it('does not trigger ui.mail.send when + is pressed and compose box is closed', function () { + it('does not trigger ui.mail.send when [Ctrl] + [Enter] is pressed and compose box is closed', function () { var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); @@ -66,28 +107,24 @@ describeComponent('page/shortcuts', function () { expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); - it('triggers search.focus when is pressed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.search.focus); + it('does not trigger ui.mail.send when [Meta] + [Enter] is pressed and compose box is closed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - $(document).trigger(keydownEvent(this.component.keyCodes.FORWARD_SLASH)); + $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); - expect(eventSpy).toHaveBeenTriggeredOn(document) + expect(eventSpy).not.toHaveBeenTriggeredOn(document) }); + }); - it('triggers search.focus when is pressed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.search.focus); - - $(document).trigger(keydownEvent(this.component.keyCodes.S)); - - expect(eventSpy).toHaveBeenTriggeredOn(document) - }); + function openComposeBoxEventSpy() { + return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); + } - function openComposeBoxEventSpy() { - return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); - } + function keydownEvent(code) { + return jQuery.Event('keydown', {which: code}); + } - function keydownEvent(code) { - return jQuery.Event('keydown', {which: code}); - } - }); + function addComposeBox() { + this.$node.append($('
', {id: this.component.composeBoxId})); + } }); From eb9ce7ea91d3b13e2319525d7454ad2a51603c09 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Mon, 25 Jul 2016 12:25:44 +0200 Subject: [PATCH 09/12] Use underscore binding and iterators --- web-ui/app/js/page/shortcuts.js | 41 +++++++++++------- web-ui/test/spec/page/shortcuts.spec.js | 43 ++++++++----------- .../test/spec/search/search_trigger.spec.js | 2 +- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index b3b9c408e..48be57b48 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -26,7 +26,7 @@ define([ function shortcuts() { this.after('initialize', function () { - this.on(document, 'keydown', $.proxy(onKeydown, this)); + this.on(document, 'keydown', _.bind(onKeydown, this)); }); var composeBoxId = 'compose-box'; @@ -47,30 +47,29 @@ define([ this.composeBoxId = composeBoxId; function onKeydown(event) { - tryGlobalKeyEvents(event, triggerOnDocument.call(this)); + tryGlobalKeyEvents(event, _.bind(triggerOnDocument, this)); if (composeBoxIsShown()) { - tryMailCompositionKeyEvents(event, triggerOnDocument.call(this)); + tryMailCompositionKeyEvents(event, _.bind(triggerOnDocument, this)); } else { - tryMailHandlingKeyEvents(event, triggerOnDocument.call(this)); + tryMailHandlingKeyEvents(event, _.bind(triggerOnDocument, this)); } } - function triggerOnDocument() { - var self = this; - return function (event) { - self.trigger(document, event); - } + function triggerOnDocument(event) { + this.trigger(document, event); } function tryGlobalKeyEvents(event, triggerFunc) { var globalKeyEvents = {}; globalKeyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; - if (!globalKeyEvents.hasOwnProperty(event.which)) return; + if (!globalKeyEvents.hasOwnProperty(event.which)) { + return; + } - triggerFunc(globalKeyEvents[event.which]); event.preventDefault(); + return triggerFunc(globalKeyEvents[event.which]); } function tryMailCompositionKeyEvents(event, triggerFunc) { @@ -78,21 +77,27 @@ define([ mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; - if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) return; + if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { + return; + } event.preventDefault(); return triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); } function tryMailHandlingKeyEvents(event, triggerFunc) { - if (isTriggeredOnInputField(event.target)) return; + if (isTriggeredOnInputField(event.target)) { + return; + } var mailHandlingKeyEvents = {}; mailHandlingKeyEvents[keyCodes.S] = events.search.focus; mailHandlingKeyEvents[keyCodes.FORWARD_SLASH] = events.search.focus; mailHandlingKeyEvents[keyCodes.C] = events.dispatchers.rightPane.openComposeBox; - if (!mailHandlingKeyEvents.hasOwnProperty(event.which)) return; + if (!mailHandlingKeyEvents.hasOwnProperty(event.which)) { + return; + } event.preventDefault(); return triggerFunc(mailHandlingKeyEvents[event.which]); @@ -100,8 +105,12 @@ define([ function modifierKey(event) { var modifierKey = ""; - if (event.ctrlKey === true) modifierKey = modifierKeys.CTRL; - if (event.metaKey === true) modifierKey = modifierKeys.META; + if (event.ctrlKey === true) { + modifierKey = modifierKeys.CTRL; + } + if (event.metaKey === true) { + modifierKey = modifierKeys.META; + } return modifierKey; } diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index d621f122a..284079ec4 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -11,7 +11,7 @@ describeComponent('page/shortcuts', function () { $(document).trigger(keydownEvent(this.component.keyCodes.ESC)); - expect(eventSpy).toHaveBeenTriggeredOn(document) + expect(eventSpy).toHaveBeenTriggeredOn(document); }); }); @@ -19,7 +19,7 @@ describeComponent('page/shortcuts', function () { function shortcutEventAndTriggeredEventSpy() { return [ { - eventSpy: openComposeBoxEventSpy(), + eventSpy: spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox), shortcutEvent: keydownEvent(this.component.keyCodes.C) }, { @@ -30,7 +30,7 @@ describeComponent('page/shortcuts', function () { eventSpy: spyOnEvent(document, Pixelated.events.search.focus), shortcutEvent: keydownEvent(this.component.keyCodes.S) } - ] + ]; } it('are triggered when no input or textarea is focused', function () { @@ -44,39 +44,36 @@ describeComponent('page/shortcuts', function () { }); it('are not triggered when an input is focused', function () { - var self = this; - shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { - self.$node.append(''); + _.each(shortcutEventAndTriggeredEventSpy.call(this), function (args) { + this.$node.append(''); var eventSpy = args.eventSpy; - self.$node.find('input').trigger(args.shortcutEvent); + this.$node.find('input').trigger(args.shortcutEvent); expect(eventSpy).not.toHaveBeenTriggeredOn(document); - }); + }, this); }); it('are not triggered when a textarea is focused', function () { - var self = this; - shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { - self.$node.append(''); + _.each(shortcutEventAndTriggeredEventSpy.call(this), function (args) { + this.$node.append(''); var eventSpy = args.eventSpy; - self.$node.find('textarea').trigger(args.shortcutEvent); + this.$node.find('textarea').trigger(args.shortcutEvent); expect(eventSpy).not.toHaveBeenTriggeredOn(document); - }); + }, this); }); it('are not triggered when the composeBox is opened', function () { - var self = this; - shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { - addComposeBox.call(self); + _.each(shortcutEventAndTriggeredEventSpy.call(this), function (args) { + addComposeBox.call(this); var eventSpy = args.eventSpy; $(document).trigger(args.shortcutEvent); expect(eventSpy).not.toHaveBeenTriggeredOn(document); - }); + }, this); }); }); @@ -87,7 +84,7 @@ describeComponent('page/shortcuts', function () { $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); - expect(eventSpy).toHaveBeenTriggeredOn(document) + expect(eventSpy).toHaveBeenTriggeredOn(document); }); it('triggers ui.mail.send when [Meta] + [Enter] is pressed and compose box is open', function () { @@ -96,7 +93,7 @@ describeComponent('page/shortcuts', function () { $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); - expect(eventSpy).toHaveBeenTriggeredOn(document) + expect(eventSpy).toHaveBeenTriggeredOn(document); }); it('does not trigger ui.mail.send when [Ctrl] + [Enter] is pressed and compose box is closed', function () { @@ -104,7 +101,7 @@ describeComponent('page/shortcuts', function () { $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); - expect(eventSpy).not.toHaveBeenTriggeredOn(document) + expect(eventSpy).not.toHaveBeenTriggeredOn(document); }); it('does not trigger ui.mail.send when [Meta] + [Enter] is pressed and compose box is closed', function () { @@ -112,14 +109,10 @@ describeComponent('page/shortcuts', function () { $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); - expect(eventSpy).not.toHaveBeenTriggeredOn(document) + expect(eventSpy).not.toHaveBeenTriggeredOn(document); }); }); - function openComposeBoxEventSpy() { - return spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openComposeBox); - } - function keydownEvent(code) { return jQuery.Event('keydown', {which: code}); } diff --git a/web-ui/test/spec/search/search_trigger.spec.js b/web-ui/test/spec/search/search_trigger.spec.js index 6895f00ed..12026966d 100644 --- a/web-ui/test/spec/search/search_trigger.spec.js +++ b/web-ui/test/spec/search/search_trigger.spec.js @@ -52,6 +52,6 @@ describeComponent('search/search_trigger', function () { it('should focus search input field on focus event', function () { $(document).trigger(Pixelated.events.search.focus); - expect($(document.activeElement)).toEqual(this.component.select('input')) + expect($(document.activeElement)).toEqual(this.component.select('input')); }); }); From 58c86bfc3fbff4fc270949020b3391a13b43e957 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Tue, 26 Jul 2016 11:21:04 +0200 Subject: [PATCH 10/12] Attach ComposeBox shortcuts to the right element --- .../js/dispatchers/right_pane_dispatcher.js | 23 ++++-- .../js/mail_view/ui/compose_box_shortcuts.js | 71 +++++++++++++++++++ web-ui/app/js/page/shortcuts.js | 49 ++----------- .../ui/compose_box_shortcuts.spec.js | 25 +++++++ web-ui/test/spec/page/shortcuts.spec.js | 46 ++---------- 5 files changed, 125 insertions(+), 89 deletions(-) create mode 100644 web-ui/app/js/mail_view/ui/compose_box_shortcuts.js create mode 100644 web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js diff --git a/web-ui/app/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js index 870bcd92e..ba909c770 100644 --- a/web-ui/app/js/dispatchers/right_pane_dispatcher.js +++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js @@ -24,10 +24,21 @@ define( 'mail_view/ui/draft_box', 'mail_view/ui/no_message_selected_pane', 'mail_view/ui/feedback_box', - 'page/events' + 'page/events', + 'mail_view/ui/compose_box_shortcuts' ], - function(defineComponent, ComposeBox, MailView, ReplySection, DraftBox, NoMessageSelectedPane, FeedbackBox, events) { + function( + defineComponent, + ComposeBox, + MailView, + ReplySection, + DraftBox, + NoMessageSelectedPane, + FeedbackBox, + events, + composeBoxShortcuts + ) { 'use strict'; return defineComponent(rightPaneDispatcher); @@ -53,13 +64,13 @@ define( this.reset = function (newContainer) { this.trigger(document, events.dispatchers.rightPane.clear); this.select('rightPane').empty(); - var stage = this.createAndAttach(newContainer); - return stage; + return this.createAndAttach(newContainer); }; this.openComposeBox = function() { - var stage = this.reset(this.attr.composeBox); - ComposeBox.attachTo(stage, {currentTag: this.attr.currentTag}); + var stageId = this.reset(this.attr.composeBox); + ComposeBox.attachTo(stageId, {currentTag: this.attr.currentTag}); + composeBoxShortcuts.attachTo(stageId); }; this.openFeedbackBox = function() { diff --git a/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js b/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js new file mode 100644 index 000000000..636c02447 --- /dev/null +++ b/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014 ThoughtWorks, Inc. + * + * Pixelated is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pixelated is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pixelated. If not, see . + */ + +define([ + 'flight/lib/component', + 'page/events' + ], + function (defineComponent, events) { + 'use strict'; + + return defineComponent(mailViewShortcuts); + + function mailViewShortcuts() { + var keyCodes = { + ENTER: 13 + }; + var modifierKeys = { + META: "META", + CTRL: "CTRL" + }; + + // make constants public + this.keyCodes = keyCodes; + + this.after('initialize', function () { + this.$node.on('keydown', _.bind(onKeydown, this)); + }); + + function onKeydown(event) { + tryMailCompositionKeyEvents(event, _.bind(this.trigger, this, document)); + } + + function tryMailCompositionKeyEvents(event, triggerFunc) { + var mailCompositionKeyEvents = {}; + mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; + mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; + + if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { + return; + } + + event.preventDefault(); + return triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); + } + + function modifierKey(event) { + var modifierKey = ""; + if (event.ctrlKey === true) { + modifierKey = modifierKeys.CTRL; + } + if (event.metaKey === true) { + modifierKey = modifierKeys.META; + } + return modifierKey; + } + } + }); diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 48be57b48..1195c8530 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -25,41 +25,30 @@ define([ return defineComponent(shortcuts); function shortcuts() { - this.after('initialize', function () { - this.on(document, 'keydown', _.bind(onKeydown, this)); - }); - var composeBoxId = 'compose-box'; var keyCodes = { ESC: 27, C: 67, - ENTER: 13, FORWARD_SLASH: 191, S: 83 }; - var modifierKeys = { - META: "META", - CTRL: "CTRL" - }; // make constants public this.keyCodes = keyCodes; this.composeBoxId = composeBoxId; + this.after('initialize', function () { + this.on('keydown', _.bind(onKeydown, this)); + }); + function onKeydown(event) { - tryGlobalKeyEvents(event, _.bind(triggerOnDocument, this)); + tryGlobalKeyEvents(event, _.bind(this.trigger, this, document)); - if (composeBoxIsShown()) { - tryMailCompositionKeyEvents(event, _.bind(triggerOnDocument, this)); - } else { - tryMailHandlingKeyEvents(event, _.bind(triggerOnDocument, this)); + if (!composeBoxIsShown()) { + tryMailHandlingKeyEvents(event, _.bind(this.trigger, this, document)); } } - function triggerOnDocument(event) { - this.trigger(document, event); - } - function tryGlobalKeyEvents(event, triggerFunc) { var globalKeyEvents = {}; globalKeyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; @@ -72,19 +61,6 @@ define([ return triggerFunc(globalKeyEvents[event.which]); } - function tryMailCompositionKeyEvents(event, triggerFunc) { - var mailCompositionKeyEvents = {}; - mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; - mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; - - if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { - return; - } - - event.preventDefault(); - return triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); - } - function tryMailHandlingKeyEvents(event, triggerFunc) { if (isTriggeredOnInputField(event.target)) { return; @@ -103,17 +79,6 @@ define([ return triggerFunc(mailHandlingKeyEvents[event.which]); } - function modifierKey(event) { - var modifierKey = ""; - if (event.ctrlKey === true) { - modifierKey = modifierKeys.CTRL; - } - if (event.metaKey === true) { - modifierKey = modifierKeys.META; - } - return modifierKey; - } - function isTriggeredOnInputField(element) { return $(element).is('input') || $(element).is('textarea'); } diff --git a/web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js b/web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js new file mode 100644 index 000000000..9d33e0252 --- /dev/null +++ b/web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js @@ -0,0 +1,25 @@ +describeComponent('mail_view/ui/compose_box_shortcuts', function () { + 'use strict'; + + beforeEach(function () { + this.setupComponent(); + }); + + describe('mail composition shortcuts', function () { + it('triggers ui.mail.send when [Ctrl] + [Enter] is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); + + this.component.trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); + + expect(eventSpy).toHaveBeenTriggeredOn(document); + }); + + it('triggers ui.mail.send when [Meta] + [Enter] is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); + + this.component.trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); + + expect(eventSpy).toHaveBeenTriggeredOn(document); + }); + }); +}); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index 284079ec4..722c46495 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -9,7 +9,7 @@ describeComponent('page/shortcuts', function () { it('triggers openNoMessageSelected when [Esc] is pressed', function () { var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); - $(document).trigger(keydownEvent(this.component.keyCodes.ESC)); + this.component.trigger(keydownEvent(this.component.keyCodes.ESC)); expect(eventSpy).toHaveBeenTriggeredOn(document); }); @@ -34,13 +34,13 @@ describeComponent('page/shortcuts', function () { } it('are triggered when no input or textarea is focused', function () { - shortcutEventAndTriggeredEventSpy.call(this).forEach(function (args) { + _.each(shortcutEventAndTriggeredEventSpy.call(this), function (args) { var eventSpy = args.eventSpy; - $(document).trigger(args.shortcutEvent); + this.component.trigger(args.shortcutEvent); expect(eventSpy).toHaveBeenTriggeredOn(document); - }); + }, this); }); it('are not triggered when an input is focused', function () { @@ -70,49 +70,13 @@ describeComponent('page/shortcuts', function () { addComposeBox.call(this); var eventSpy = args.eventSpy; - $(document).trigger(args.shortcutEvent); + this.component.trigger(args.shortcutEvent); expect(eventSpy).not.toHaveBeenTriggeredOn(document); }, this); }); }); - describe('mail composition shortcuts', function () { - it('triggers ui.mail.send when [Ctrl] + [Enter] is pressed and compose box is open', function () { - addComposeBox.call(this); - var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - - $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); - - expect(eventSpy).toHaveBeenTriggeredOn(document); - }); - - it('triggers ui.mail.send when [Meta] + [Enter] is pressed and compose box is open', function () { - addComposeBox.call(this); - var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - - $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); - - expect(eventSpy).toHaveBeenTriggeredOn(document); - }); - - it('does not trigger ui.mail.send when [Ctrl] + [Enter] is pressed and compose box is closed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - - $(document).trigger(jQuery.Event('keydown', {ctrlKey: true, which: this.component.keyCodes.ENTER})); - - expect(eventSpy).not.toHaveBeenTriggeredOn(document); - }); - - it('does not trigger ui.mail.send when [Meta] + [Enter] is pressed and compose box is closed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.ui.mail.send); - - $(document).trigger(jQuery.Event('keydown', {metaKey: true, which: this.component.keyCodes.ENTER})); - - expect(eventSpy).not.toHaveBeenTriggeredOn(document); - }); - }); - function keydownEvent(code) { return jQuery.Event('keydown', {which: code}); } From a6381dc333aedc55bce1cc2a13b6cb14197f6d08 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Tue, 26 Jul 2016 12:04:01 +0200 Subject: [PATCH 11/12] Attach generic mail view shortcuts to the right elements --- .../js/dispatchers/right_pane_dispatcher.js | 18 ++++--- .../js/mail_view/ui/compose_box_shortcuts.js | 18 +++---- .../js/mail_view/ui/mail_view_shortcuts.js | 51 +++++++++++++++++++ web-ui/app/js/page/shortcuts.js | 27 ++-------- .../mail_view/ui/mail_view_shortcuts.spec.js | 16 ++++++ web-ui/test/spec/page/shortcuts.spec.js | 10 ---- 6 files changed, 89 insertions(+), 51 deletions(-) create mode 100644 web-ui/app/js/mail_view/ui/mail_view_shortcuts.js create mode 100644 web-ui/test/spec/mail_view/ui/mail_view_shortcuts.spec.js diff --git a/web-ui/app/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js index ba909c770..8ac9a7e3a 100644 --- a/web-ui/app/js/dispatchers/right_pane_dispatcher.js +++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js @@ -25,7 +25,8 @@ define( 'mail_view/ui/no_message_selected_pane', 'mail_view/ui/feedback_box', 'page/events', - 'mail_view/ui/compose_box_shortcuts' + 'mail_view/ui/compose_box_shortcuts', + 'mail_view/ui/mail_view_shortcuts' ], function( @@ -37,7 +38,8 @@ define( NoMessageSelectedPane, FeedbackBox, events, - composeBoxShortcuts + composeBoxShortcuts, + mailViewShortcuts ) { 'use strict'; @@ -71,6 +73,7 @@ define( var stageId = this.reset(this.attr.composeBox); ComposeBox.attachTo(stageId, {currentTag: this.attr.currentTag}); composeBoxShortcuts.attachTo(stageId); + mailViewShortcuts.attachTo(stageId); }; this.openFeedbackBox = function() { @@ -79,11 +82,13 @@ define( }; this.openMail = function(ev, data) { - var stage = this.reset(this.attr.mailView); - MailView.attachTo(stage, data); + var stageId = this.reset(this.attr.mailView); + MailView.attachTo(stageId, data); var replySectionContainer = this.createAndAttach(this.attr.replySection); ReplySection.attachTo(replySectionContainer, { ident: data.ident }); + + mailViewShortcuts.attachTo(stageId); }; this.initializeNoMessageSelectedPane = function () { @@ -99,8 +104,9 @@ define( }; this.openDraft = function (ev, data) { - var stage = this.reset(this.attr.draftBox); - DraftBox.attachTo(stage, { mailIdent: data.ident, currentTag: this.attr.currentTag }); + var stageId = this.reset(this.attr.draftBox); + DraftBox.attachTo(stageId, { mailIdent: data.ident, currentTag: this.attr.currentTag }); + mailViewShortcuts.attachTo(stageId); }; this.selectTag = function(ev, data) { diff --git a/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js b/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js index 636c02447..d8a7066a9 100644 --- a/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js +++ b/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js @@ -37,24 +37,20 @@ define([ this.keyCodes = keyCodes; this.after('initialize', function () { - this.$node.on('keydown', _.bind(onKeydown, this)); + this.on('keydown', _.partial(tryKeyEvents, _.bind(this.trigger, this, document))); }); - function onKeydown(event) { - tryMailCompositionKeyEvents(event, _.bind(this.trigger, this, document)); - } - - function tryMailCompositionKeyEvents(event, triggerFunc) { - var mailCompositionKeyEvents = {}; - mailCompositionKeyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; - mailCompositionKeyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; + function tryKeyEvents(triggerFunc, event) { + var keyEvents = {}; + keyEvents[modifierKeys.CTRL + keyCodes.ENTER] = events.ui.mail.send; + keyEvents[modifierKeys.META + keyCodes.ENTER] = events.ui.mail.send; - if (!mailCompositionKeyEvents.hasOwnProperty(modifierKey(event) + event.which)) { + if (!keyEvents.hasOwnProperty(modifierKey(event) + event.which)) { return; } event.preventDefault(); - return triggerFunc(mailCompositionKeyEvents[modifierKey(event) + event.which]); + return triggerFunc(keyEvents[modifierKey(event) + event.which]); } function modifierKey(event) { diff --git a/web-ui/app/js/mail_view/ui/mail_view_shortcuts.js b/web-ui/app/js/mail_view/ui/mail_view_shortcuts.js new file mode 100644 index 000000000..295683c4a --- /dev/null +++ b/web-ui/app/js/mail_view/ui/mail_view_shortcuts.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 ThoughtWorks, Inc. + * + * Pixelated is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pixelated is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pixelated. If not, see . + */ + +define([ + 'flight/lib/component', + 'page/events' + ], + function (defineComponent, events) { + 'use strict'; + + return defineComponent(mailViewShortcuts); + + function mailViewShortcuts() { + var keyCodes = { + ESC: 27 + }; + + // make constants public + this.keyCodes = keyCodes; + + this.after('initialize', function () { + this.on(document, 'keydown', _.partial(tryKeyEvents, _.bind(this.trigger, this, document))); + }); + + function tryKeyEvents(triggerFunc, event) { + var keyEvents = {}; + keyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; + + if (!keyEvents.hasOwnProperty(event.which)) { + return; + } + + event.preventDefault(); + return triggerFunc(keyEvents[event.which]); + } + } + }); diff --git a/web-ui/app/js/page/shortcuts.js b/web-ui/app/js/page/shortcuts.js index 1195c8530..17771da15 100644 --- a/web-ui/app/js/page/shortcuts.js +++ b/web-ui/app/js/page/shortcuts.js @@ -27,7 +27,6 @@ define([ function shortcuts() { var composeBoxId = 'compose-box'; var keyCodes = { - ESC: 27, C: 67, FORWARD_SLASH: 191, S: 83 @@ -38,31 +37,11 @@ define([ this.composeBoxId = composeBoxId; this.after('initialize', function () { - this.on('keydown', _.bind(onKeydown, this)); + this.on('keydown', _.partial(tryMailHandlingKeyEvents, _.bind(this.trigger, this, document))); }); - function onKeydown(event) { - tryGlobalKeyEvents(event, _.bind(this.trigger, this, document)); - - if (!composeBoxIsShown()) { - tryMailHandlingKeyEvents(event, _.bind(this.trigger, this, document)); - } - } - - function tryGlobalKeyEvents(event, triggerFunc) { - var globalKeyEvents = {}; - globalKeyEvents[keyCodes.ESC] = events.dispatchers.rightPane.openNoMessageSelected; - - if (!globalKeyEvents.hasOwnProperty(event.which)) { - return; - } - - event.preventDefault(); - return triggerFunc(globalKeyEvents[event.which]); - } - - function tryMailHandlingKeyEvents(event, triggerFunc) { - if (isTriggeredOnInputField(event.target)) { + function tryMailHandlingKeyEvents(triggerFunc, event) { + if (isTriggeredOnInputField(event.target) || composeBoxIsShown()) { return; } diff --git a/web-ui/test/spec/mail_view/ui/mail_view_shortcuts.spec.js b/web-ui/test/spec/mail_view/ui/mail_view_shortcuts.spec.js new file mode 100644 index 000000000..8cfc16ba0 --- /dev/null +++ b/web-ui/test/spec/mail_view/ui/mail_view_shortcuts.spec.js @@ -0,0 +1,16 @@ +describeComponent('mail_view/ui/mail_view_shortcuts', function () { + 'use strict'; + + beforeEach(function () { + this.setupComponent(); + }); + + describe('generic mail view shortcuts', function () { + it('triggers openNoMessageSelected when [Esc] is pressed', function () { + var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); + + this.component.trigger(jQuery.Event('keydown', {which: this.component.keyCodes.ESC})); + expect(eventSpy).toHaveBeenTriggeredOn(document); + }); + }); +}); diff --git a/web-ui/test/spec/page/shortcuts.spec.js b/web-ui/test/spec/page/shortcuts.spec.js index 722c46495..0afe43cfc 100644 --- a/web-ui/test/spec/page/shortcuts.spec.js +++ b/web-ui/test/spec/page/shortcuts.spec.js @@ -5,16 +5,6 @@ describeComponent('page/shortcuts', function () { this.setupComponent(); }); - describe('global shortcuts', function () { - it('triggers openNoMessageSelected when [Esc] is pressed', function () { - var eventSpy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); - - this.component.trigger(keydownEvent(this.component.keyCodes.ESC)); - - expect(eventSpy).toHaveBeenTriggeredOn(document); - }); - }); - describe('mail list shortcuts', function () { function shortcutEventAndTriggeredEventSpy() { return [ From 6b8d6efe4af22583d2b0854acdef0621d59f8370 Mon Sep 17 00:00:00 2001 From: Christian Treppo Date: Tue, 26 Jul 2016 12:19:33 +0200 Subject: [PATCH 12/12] Attach mail composition shortcuts to draft mails --- web-ui/app/js/dispatchers/right_pane_dispatcher.js | 7 ++++--- ...pose_box_shortcuts.js => mail_composition_shortcuts.js} | 0 ...hortcuts.spec.js => mail_composition_shortcuts.spec.js} | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename web-ui/app/js/mail_view/ui/{compose_box_shortcuts.js => mail_composition_shortcuts.js} (100%) rename web-ui/test/spec/mail_view/ui/{compose_box_shortcuts.spec.js => mail_composition_shortcuts.spec.js} (91%) diff --git a/web-ui/app/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js index 8ac9a7e3a..ecaca4ad8 100644 --- a/web-ui/app/js/dispatchers/right_pane_dispatcher.js +++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js @@ -25,7 +25,7 @@ define( 'mail_view/ui/no_message_selected_pane', 'mail_view/ui/feedback_box', 'page/events', - 'mail_view/ui/compose_box_shortcuts', + 'mail_view/ui/mail_composition_shortcuts', 'mail_view/ui/mail_view_shortcuts' ], @@ -38,7 +38,7 @@ define( NoMessageSelectedPane, FeedbackBox, events, - composeBoxShortcuts, + mailCompositionShortcuts, mailViewShortcuts ) { 'use strict'; @@ -72,7 +72,7 @@ define( this.openComposeBox = function() { var stageId = this.reset(this.attr.composeBox); ComposeBox.attachTo(stageId, {currentTag: this.attr.currentTag}); - composeBoxShortcuts.attachTo(stageId); + mailCompositionShortcuts.attachTo(stageId); mailViewShortcuts.attachTo(stageId); }; @@ -106,6 +106,7 @@ define( this.openDraft = function (ev, data) { var stageId = this.reset(this.attr.draftBox); DraftBox.attachTo(stageId, { mailIdent: data.ident, currentTag: this.attr.currentTag }); + mailCompositionShortcuts.attachTo(stageId); mailViewShortcuts.attachTo(stageId); }; diff --git a/web-ui/app/js/mail_view/ui/compose_box_shortcuts.js b/web-ui/app/js/mail_view/ui/mail_composition_shortcuts.js similarity index 100% rename from web-ui/app/js/mail_view/ui/compose_box_shortcuts.js rename to web-ui/app/js/mail_view/ui/mail_composition_shortcuts.js diff --git a/web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js b/web-ui/test/spec/mail_view/ui/mail_composition_shortcuts.spec.js similarity index 91% rename from web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js rename to web-ui/test/spec/mail_view/ui/mail_composition_shortcuts.spec.js index 9d33e0252..6838dd8af 100644 --- a/web-ui/test/spec/mail_view/ui/compose_box_shortcuts.spec.js +++ b/web-ui/test/spec/mail_view/ui/mail_composition_shortcuts.spec.js @@ -1,4 +1,4 @@ -describeComponent('mail_view/ui/compose_box_shortcuts', function () { +describeComponent('mail_view/ui/mail_composition_shortcuts', function () { 'use strict'; beforeEach(function () {