MDL-67881 core_message: fix tab order for message drawer
authorBas Brands <bas@moodle.com>
Tue, 17 Mar 2020 12:15:34 +0000 (13:15 +0100)
committerBas Brands <bas@moodle.com>
Mon, 20 Apr 2020 09:37:34 +0000 (11:37 +0200)
15 files changed:
lib/templates/drawer.mustache
message/amd/build/message_drawer.min.js
message/amd/build/message_drawer.min.js.map
message/amd/build/message_drawer_helper.min.js
message/amd/build/message_drawer_helper.min.js.map
message/amd/build/message_popover.min.js
message/amd/build/message_popover.min.js.map
message/amd/build/message_user_button.min.js
message/amd/build/message_user_button.min.js.map
message/amd/src/message_drawer.js
message/amd/src/message_drawer_helper.js
message/amd/src/message_popover.js
message/amd/src/message_user_button.js
message/templates/message_jumpto.mustache [new file with mode: 0644]
message/templates/message_popover.mustache

index e21fd2f..02356d0 100644 (file)
@@ -38,7 +38,7 @@
     aria-hidden="{{#show}}false{{/show}}{{^show}}true{{/show}}"
     data-region="right-hand-drawer"
     role="region"
-    tabindex="-1"
+    tabindex="0"
 >
     {{$drawercontent}}{{/drawercontent}}
 </div>
index fa586cb..f76d054 100644 (file)
Binary files a/message/amd/build/message_drawer.min.js and b/message/amd/build/message_drawer.min.js differ
index c4e093b..ee1a5a9 100644 (file)
Binary files a/message/amd/build/message_drawer.min.js.map and b/message/amd/build/message_drawer.min.js.map differ
index 1147434..ce288e5 100644 (file)
Binary files a/message/amd/build/message_drawer_helper.min.js and b/message/amd/build/message_drawer_helper.min.js differ
index 2ae6d91..b675cf5 100644 (file)
Binary files a/message/amd/build/message_drawer_helper.min.js.map and b/message/amd/build/message_drawer_helper.min.js.map differ
index ef3da77..d8a2983 100644 (file)
Binary files a/message/amd/build/message_popover.min.js and b/message/amd/build/message_popover.min.js differ
index 3fd9a7d..d78b754 100644 (file)
Binary files a/message/amd/build/message_popover.min.js.map and b/message/amd/build/message_popover.min.js.map differ
index 00c0494..f63ca0e 100644 (file)
Binary files a/message/amd/build/message_user_button.min.js and b/message/amd/build/message_user_button.min.js differ
index bf39e7b..7ce2231 100644 (file)
Binary files a/message/amd/build/message_user_button.min.js.map and b/message/amd/build/message_user_button.min.js.map differ
index 67bfe82..ae7ebac 100644 (file)
@@ -57,6 +57,8 @@ function(
 ) {
 
     var SELECTORS = {
+        DRAWER: '[data-region="right-hand-drawer"]',
+        JUMPTO: '.popover-region [data-region="jumpto"]',
         PANEL_BODY_CONTAINER: '[data-region="panel-body-container"]',
         PANEL_HEADER_CONTAINER: '[data-region="panel-header-container"]',
         VIEW_CONTACT: '[data-region="view-contact"]',
@@ -168,6 +170,15 @@ function(
         return true;
     };
 
+    /**
+     * Set Jump from button
+     *
+     * @param {String} buttonid The originating button id
+     */
+    var setJumpFrom = function(buttonid) {
+        $(SELECTORS.DRAWER).attr('data-origin', buttonid);
+    };
+
     /**
      * Listen to and handle events for routing, showing and hiding the message drawer.
      *
@@ -241,6 +252,22 @@ function(
             });
         });
 
+        $(SELECTORS.JUMPTO).focus(function() {
+            var firstInput = $(SELECTORS.HEADER_CONTAINER).find('input:visible');
+            if (firstInput.length) {
+                firstInput.focus();
+            } else {
+                $(SELECTORS.HEADER_CONTAINER).find(SELECTORS.ROUTES_BACK).focus();
+            }
+        });
+
+        $(SELECTORS.DRAWER).focus(function() {
+            var button = $(this).attr('data-origin');
+            if (button) {
+                $('#' + button).focus();
+            }
+        });
+
         if (!alwaysVisible) {
             PubSub.subscribe(Events.SHOW, function() {
                 show(namespace, root);
@@ -250,23 +277,28 @@ function(
                 hide(root);
             });
 
-            PubSub.subscribe(Events.TOGGLE_VISIBILITY, function() {
+            PubSub.subscribe(Events.TOGGLE_VISIBILITY, function(buttonid) {
                 if (isVisible(root)) {
                     hide(root);
+                    $(SELECTORS.JUMPTO).attr('tabindex', -1);
                 } else {
                     show(namespace, root);
+                    setJumpFrom(buttonid);
+                    $(SELECTORS.JUMPTO).attr('tabindex', 0);
                 }
             });
         }
 
-        PubSub.subscribe(Events.SHOW_CONVERSATION, function(conversationId) {
+        PubSub.subscribe(Events.SHOW_CONVERSATION, function(args) {
+            setJumpFrom(args.buttonid);
             show(namespace, root);
-            Router.go(namespace, Routes.VIEW_CONVERSATION, conversationId);
+            Router.go(namespace, Routes.VIEW_CONVERSATION, args.conversationid);
         });
 
-        PubSub.subscribe(Events.CREATE_CONVERSATION_WITH_USER, function(userId) {
+        PubSub.subscribe(Events.CREATE_CONVERSATION_WITH_USER, function(args) {
+            setJumpFrom(args.buttonid);
             show(namespace, root);
-            Router.go(namespace, Routes.VIEW_CONVERSATION, null, 'create', userId);
+            Router.go(namespace, Routes.VIEW_CONVERSATION, null, 'create', args.userid);
         });
 
         PubSub.subscribe(Events.SHOW_SETTINGS, function() {
index e11b089..70975ea 100644 (file)
@@ -36,8 +36,15 @@ function(
      *
      * @param {Number} userId The user id to start a conversation.
      */
-    var createConversationWithUser = function(userId) {
-        PubSub.publish(MessageDrawerEvents.CREATE_CONVERSATION_WITH_USER, userId);
+    var createConversationWithUser = function(args) {
+        PubSub.publish(MessageDrawerEvents.CREATE_CONVERSATION_WITH_USER, args);
+    };
+
+    /**
+     * Trigger an event to hide the message drawer.
+     */
+    var hide = function() {
+        PubSub.publish(MessageDrawerEvents.HIDE);
     };
 
     /**
@@ -52,8 +59,8 @@ function(
      *
      * @param {int} conversationId Id for the conversation to show.
      */
-    var showConversation = function(conversationId) {
-        PubSub.publish(MessageDrawerEvents.SHOW_CONVERSATION, conversationId);
+    var showConversation = function(args) {
+        PubSub.publish(MessageDrawerEvents.SHOW_CONVERSATION, args);
     };
 
     /**
@@ -65,6 +72,7 @@ function(
 
     return {
         createConversationWithUser: createConversationWithUser,
+        hide: hide,
         show: show,
         showConversation: showConversation,
         showSettings: showSettings
index 556e341..e3b4c7d 100644 (file)
@@ -39,21 +39,23 @@ function(
 
     /**
      * Toggle the message drawer visibility.
+     *
+     * @param {String} button The button id for the popover.
      */
-    var toggleMessageDrawerVisibility = function() {
-        PubSub.publish(MessageDrawerEvents.TOGGLE_VISIBILITY);
+    var toggleMessageDrawerVisibility = function(buttonid) {
+        PubSub.publish(MessageDrawerEvents.TOGGLE_VISIBILITY, buttonid);
     };
 
     /**
      * Decrement the unread conversation count in the nav bar if a conversation
      * is read. When there are no unread conversations then hide the counter.
      *
-     * @param {Object} root The root element for the popover.
+     * @param {Object} button The button element for the popover.
      * @return {Function}
      */
-    var handleDecrementConversationCount = function(root) {
+    var handleDecrementConversationCount = function(button) {
         return function() {
-            var countContainer = root.find(SELECTORS.COUNT_CONTAINER);
+            var countContainer = button.find(SELECTORS.COUNT_CONTAINER);
             var count = parseInt(countContainer.text(), 10);
 
             if (isNaN(count)) {
@@ -71,29 +73,30 @@ function(
      * Add events listeners for when the popover icon is clicked and when conversations
      * are read.
      *
-     * @param {Object} root The root element for the popover.
+     * @param {Object} button The button element for the popover.
      */
-    var registerEventListeners = function(root) {
-        CustomEvents.define(root, [CustomEvents.events.activate]);
+    var registerEventListeners = function(button) {
+        CustomEvents.define(button, [CustomEvents.events.activate]);
 
-        root.on(CustomEvents.events.activate, function(e, data) {
-            toggleMessageDrawerVisibility();
+        button.on(CustomEvents.events.activate, function(e, data) {
+            toggleMessageDrawerVisibility(button.attr('id'));
+            button.focus();
             data.originalEvent.preventDefault();
         });
 
-        PubSub.subscribe(MessageDrawerEvents.CONVERSATION_READ, handleDecrementConversationCount(root));
-        PubSub.subscribe(MessageDrawerEvents.CONTACT_REQUEST_ACCEPTED, handleDecrementConversationCount(root));
-        PubSub.subscribe(MessageDrawerEvents.CONTACT_REQUEST_DECLINED, handleDecrementConversationCount(root));
+        PubSub.subscribe(MessageDrawerEvents.CONVERSATION_READ, handleDecrementConversationCount(button));
+        PubSub.subscribe(MessageDrawerEvents.CONTACT_REQUEST_ACCEPTED, handleDecrementConversationCount(button));
+        PubSub.subscribe(MessageDrawerEvents.CONTACT_REQUEST_DECLINED, handleDecrementConversationCount(button));
     };
 
     /**
      * Initialise the message popover.
      *
-     * @param {Object} root The root element for the popover.
+     * @param {Object} button The button element for the popover.
      */
-    var init = function(root) {
-        root = $(root);
-        registerEventListeners(root);
+    var init = function(button) {
+        button = $(button);
+        registerEventListeners(button);
     };
 
     return {
index bedfe91..a2302fe 100644 (file)
  * @copyright  2019 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-define(['jquery', 'core/custom_interaction_events', 'core_message/message_drawer_helper'],
-    function($, CustomEvents, MessageDrawerHelper) {
+define(['jquery', 'core/custom_interaction_events', 'core_message/message_drawer_helper', 'core/templates'],
+    function($, CustomEvents, MessageDrawerHelper, Templates) {
+
+
+        var SELECTORS = {
+            MESSAGE_TEXTAREA: '[data-region="send-message-txt"]',
+            MESSAGE_USER_BUTTON: '#message-user-button',
+            MESSAGE_JUMP: '[data-region="jumpto"]'
+        };
+
+        var TEMPLATES = {
+            CONTENT: 'core_message/message_jumpto'
+        };
 
         /**
          * Get the id for the user being messaged.
@@ -53,15 +64,38 @@ define(['jquery', 'core/custom_interaction_events', 'core_message/message_drawer
         var send = function(element) {
             element = $(element);
 
+            var args = {
+                conversationid: getConversationId(element),
+                buttonid: $(element).attr('id'),
+                userid: getUserId(element)
+            };
+
+            Templates.render(TEMPLATES.CONTENT, {})
+                .then(function(html) {
+                    element.after(html);
+                })
+                .then(function() {
+                    $(SELECTORS.MESSAGE_USER_BUTTON).next().focus(function() {
+                        $(SELECTORS.MESSAGE_TEXTAREA).focus();
+                    });
+                });
+
             CustomEvents.define(element, [CustomEvents.events.activate]);
 
             element.on(CustomEvents.events.activate, function(e, data) {
-                var conversationid = getConversationId(element);
-                if (conversationid) {
-                    MessageDrawerHelper.showConversation(conversationid);
+                if ($(e.target).hasClass('active')) {
+                    MessageDrawerHelper.hide();
+                    $(SELECTORS.MESSAGE_USER_BUTTON).next().attr('tabindex', -1);
                 } else {
-                    MessageDrawerHelper.createConversationWithUser(getUserId(element));
+                    $(SELECTORS.MESSAGE_USER_BUTTON).next().attr('tabindex', 0);
+                    if (args.conversationid) {
+                        MessageDrawerHelper.showConversation(args);
+                    } else {
+                        MessageDrawerHelper.createConversationWithUser(args);
+                    }
                 }
+                $(e.target).focus();
+                $(e.target).toggleClass('active');
                 e.preventDefault();
                 data.originalEvent.preventDefault();
             });
diff --git a/message/templates/message_jumpto.mustache b/message/templates/message_jumpto.mustache
new file mode 100644 (file)
index 0000000..a1e53a4
--- /dev/null
@@ -0,0 +1,27 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_message/message_jump_botton
+
+    This template will render the jump button used for keyboard navigation.
+
+    Example context (json):
+    {
+    }
+
+}}
+<span class="sr-only sr-only-focusable" data-region="jumpto" tabindex="-1"></span>
\ No newline at end of file
index 8f63132..bbebb96 100644 (file)
@@ -42,6 +42,7 @@
         <div class="count-container {{^unreadcount}}hidden{{/unreadcount}}" data-region="count-container"
         aria-label="{{#str}} unreadconversations, core_message, {{unreadcount}} {{/str}}">{{unreadcount}}</div>
     </a>
+    {{> core_message/message_jumpto }}
 </div>
 
 {{#js}}