MDL-65896 message: add emoji auto complete to message app
authorRyan Wyllie <ryan@moodle.com>
Mon, 21 Oct 2019 02:54:01 +0000 (10:54 +0800)
committerRyan Wyllie <ryan@moodle.com>
Wed, 23 Oct 2019 02:59:59 +0000 (10:59 +0800)
19 files changed:
message/amd/build/message_drawer_view_conversation.min.js
message/amd/build/message_drawer_view_conversation.min.js.map
message/amd/build/message_drawer_view_conversation_constants.min.js
message/amd/build/message_drawer_view_conversation_constants.min.js.map
message/amd/build/message_drawer_view_conversation_patcher.min.js
message/amd/build/message_drawer_view_conversation_patcher.min.js.map
message/amd/build/message_drawer_view_conversation_renderer.min.js
message/amd/build/message_drawer_view_conversation_renderer.min.js.map
message/amd/build/message_drawer_view_conversation_state_manager.min.js
message/amd/build/message_drawer_view_conversation_state_manager.min.js.map
message/amd/src/message_drawer_view_conversation.js
message/amd/src/message_drawer_view_conversation_constants.js
message/amd/src/message_drawer_view_conversation_patcher.js
message/amd/src/message_drawer_view_conversation_renderer.js
message/amd/src/message_drawer_view_conversation_state_manager.js
message/templates/message_drawer_view_conversation_footer_content.mustache
theme/boost/scss/moodle/message.scss
theme/boost/style/moodle.css
theme/classic/style/moodle.css

index eb2ce6c..f3bcd8c 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation.min.js and b/message/amd/build/message_drawer_view_conversation.min.js differ
index 81efcb0..0713f09 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation.min.js.map and b/message/amd/build/message_drawer_view_conversation.min.js.map differ
index 855afc1..2157c18 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_constants.min.js and b/message/amd/build/message_drawer_view_conversation_constants.min.js differ
index f8a9827..c63609d 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_constants.min.js.map and b/message/amd/build/message_drawer_view_conversation_constants.min.js.map differ
index 4d79811..899dbf3 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_patcher.min.js and b/message/amd/build/message_drawer_view_conversation_patcher.min.js differ
index 3c9c74b..a69d049 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_patcher.min.js.map and b/message/amd/build/message_drawer_view_conversation_patcher.min.js.map differ
index 783198d..b24dd69 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_renderer.min.js and b/message/amd/build/message_drawer_view_conversation_renderer.min.js differ
index e06f275..aeb811f 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_renderer.min.js.map and b/message/amd/build/message_drawer_view_conversation_renderer.min.js.map differ
index 67b196b..71db5be 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_state_manager.min.js and b/message/amd/build/message_drawer_view_conversation_state_manager.min.js differ
index 833ea30..d848b36 100644 (file)
Binary files a/message/amd/build/message_drawer_view_conversation_state_manager.min.js.map and b/message/amd/build/message_drawer_view_conversation_state_manager.min.js.map differ
index 2f3b2b3..7e3c0da 100644 (file)
@@ -69,6 +69,7 @@ define(
     'core_message/message_drawer_view_conversation_state_manager',
     'core_message/message_drawer_router',
     'core_message/message_drawer_routes',
+    'core/emoji/auto_complete',
     'core/emoji/picker'
 ],
 function(
@@ -87,6 +88,7 @@ function(
     StateManager,
     MessageDrawerRouter,
     MessageDrawerRoutes,
+    initialiseEmojiAutoComplete,
     initialiseEmojiPicker
 ) {
 
@@ -1556,6 +1558,7 @@ function(
         var isLoadingMoreMessages = false;
         var messagesContainer = getMessagesContainer(body);
         var emojiPickerElement = footer.find(SELECTORS.EMOJI_PICKER);
+        var emojiAutoCompleteContainer = footer.find(SELECTORS.EMOJI_AUTO_COMPLETE_CONTAINER);
         var messageTextArea = footer.find(SELECTORS.MESSAGE_TEXT_AREA);
         var headerActivateHandlers = [
             [SELECTORS.ACTION_REQUEST_BLOCK, generateConfirmActionHandler(requestBlockUser)],
@@ -1597,6 +1600,30 @@ function(
 
         AutoRows.init(footer);
 
+        initialiseEmojiAutoComplete(
+            emojiAutoCompleteContainer[0],
+            messageTextArea[0],
+            function(hasSuggestions) {
+                var newState = StateManager.setShowEmojiAutoComplete(viewState, hasSuggestions);
+                render(newState);
+            },
+            function(emoji) {
+                var newState = StateManager.setShowEmojiAutoComplete(viewState, false);
+                render(newState);
+
+                messageTextArea.focus();
+                var cursorPos = messageTextArea.prop('selectionStart');
+                var currentText = messageTextArea.val();
+                var textBefore = currentText.substring(0, cursorPos).replace(/\S*$/, '');
+                var textAfter = currentText.substring(cursorPos).replace(/^\S*/, '');
+
+                messageTextArea.val(textBefore + emoji + textAfter);
+                // Set the cursor position to after the inserted emoji.
+                messageTextArea.prop('selectionStart', textBefore.length + emoji.length);
+                messageTextArea.prop('selectionEnd', textBefore.length + emoji.length);
+            }
+        );
+
         initialiseEmojiPicker(emojiPickerElement[0], function(emoji) {
             var newState = StateManager.setShowEmojiPicker(viewState, !viewState.showEmojiPicker);
             render(newState);
index 47c36ca..e22d008 100644 (file)
@@ -65,6 +65,7 @@ define([], function() {
         DAY_MESSAGES_CONTAINER: '[data-region="day-messages-container"]',
         DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE: '[data-region="delete-messages-for-all-users-toggle"]',
         DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER: '[data-region="delete-messages-for-all-users-toggle-container"]',
+        EMOJI_AUTO_COMPLETE_CONTAINER: '[data-region="emoji-auto-complete-container"]',
         EMOJI_PICKER_CONTAINER: '[data-region="emoji-picker-container"]',
         EMOJI_PICKER: '[data-region="emoji-picker"]',
         EMOJI_PICKER_SEARCH_INPUT: '[data-region="search-input"]',
index e8029a7..c969b68 100644 (file)
@@ -601,6 +601,23 @@ function(
         }
     };
 
+    /**
+     * Determine if we should show the emoji auto complete.
+     *
+     * @param  {Object} state The current state.
+     * @param  {Object} newState The new state.
+     * @return {Bool|Null}
+     */
+    var buildShowEmojiAutoComplete = function(state, newState) {
+        if (!state.showEmojiAutoComplete && newState.showEmojiAutoComplete) {
+            return true;
+        } else if (state.showEmojiAutoComplete && !newState.showEmojiAutoComplete) {
+            return false;
+        } else {
+            return null;
+        }
+    };
+
     /**
      * Get the user Object of user to be blocked if pending.
      *
@@ -1353,7 +1370,8 @@ function(
                 selectedMessages: buildSelectedMessages,
                 isFavourite: buildIsFavourite,
                 isMuted: buildIsMuted,
-                showEmojiPicker: buildShowEmojiPicker
+                showEmojiPicker: buildShowEmojiPicker,
+                showEmojiAutoComplete: buildShowEmojiAutoComplete
             }
         };
         // These build functions are only applicable to private conversations.
index 226d63c..dbbb871 100644 (file)
@@ -430,6 +430,16 @@ function(
         return footer.find(SELECTORS.EMOJI_PICKER_CONTAINER);
     };
 
+    /**
+     * Get the emoji picker container element.
+     *
+     * @param  {Object} footer Conversation footer container element.
+     * @return {Object} The emoji picker container element.
+     */
+    var getEmojiAutoCompleteContainer = function(footer) {
+        return footer.find(SELECTORS.EMOJI_AUTO_COMPLETE_CONTAINER);
+    };
+
     /**
      * Get a message element.
      *
@@ -1001,6 +1011,26 @@ function(
         }
     };
 
+    /**
+     * Hide or show the emoji auto complete.
+     *
+     * @param {Object} header The header container element.
+     * @param {Object} body The body container element.
+     * @param {Object} footer The footer container element.
+     * @param {Bool} show Should the emoji picker be visible.
+     */
+    var renderShowEmojiAutoComplete = function(header, body, footer, show) {
+        var container = getEmojiAutoCompleteContainer(footer);
+
+        if (show) {
+            container.removeClass('hidden');
+            container.attr('aria-hidden', false);
+        } else {
+            container.addClass('hidden');
+            container.attr('aria-hidden', true);
+        }
+    };
+
     /**
      * Show a confirmation dialogue
      *
@@ -1669,7 +1699,8 @@ function(
                 isMuted: renderIsMuted,
                 loadingConfirmAction: renderLoadingConfirmAction,
                 inEditMode: renderInEditMode,
-                showEmojiPicker: renderShowEmojiPicker
+                showEmojiPicker: renderShowEmojiPicker,
+                showEmojiAutoComplete: renderShowEmojiAutoComplete,
             },
             {
                 // Scrolling should be last to make sure everything
index 7adbf47..ac227bd 100644 (file)
@@ -145,6 +145,7 @@ define(['jquery'], function($) {
             pendingSendMessageIds: [],
             pendingDeleteConversation: false,
             selectedMessageIds: [],
+            showEmojiAutoComplete: false,
             showEmojiPicker: false
         };
     };
@@ -541,6 +542,19 @@ define(['jquery'], function($) {
         return newState;
     };
 
+    /**
+     * Set whether emojis auto complete suggestions should be shown.
+     *
+     * @param  {Object} state Current state.
+     * @param  {Bool} show Show the autocomplete
+     * @return {Object} New state with array of pending delete message ids.
+     */
+    var setShowEmojiAutoComplete = function(state, show) {
+        var newState = cloneState(state);
+        newState.showEmojiAutoComplete = show;
+        return newState;
+    };
+
     /**
      * Set the state pending block userids.
      *
@@ -845,6 +859,7 @@ define(['jquery'], function($) {
         setMessagesSendPendingById: setMessagesSendPendingById,
         setMessagesSendSuccessById: setMessagesSendSuccessById,
         setMessagesSendFailById: setMessagesSendFailById,
+        setShowEmojiAutoComplete: setShowEmojiAutoComplete,
         setShowEmojiPicker: setShowEmojiPicker,
         addPendingBlockUsersById: addPendingBlockUsersById,
         addPendingRemoveContactsById: addPendingRemoveContactsById,
index 0e49ea2..683d65a 100644 (file)
 
 }}
 
+<div
+    class="emoji-auto-complete-container w-100 hidden"
+    data-region="emoji-auto-complete-container"
+    aria-live="polite"
+    aria-hidden="true"
+>
+</div>
 <div class="d-flex mt-1">
     <textarea
         dir="auto"
index 94ca183..0da4ff2 100644 (file)
@@ -679,4 +679,19 @@ $message-day-color: color-yiq($message-app-bg) !default;
             right: -1 * map-get($spacers, 2);
         }
     }
+
+    .emoji-auto-complete-container {
+        overflow: auto;
+        // Add a 50px buffer to account for scroll bars.
+        max-height: $picker-row-height + 50px;
+        transition: max-height .15s ease-in-out;
+        visibility: visible;
+
+        &.hidden {
+            display: block;
+            max-height: 0;
+            visibility: hidden;
+            transition: max-height .15s ease-in-out, visibility 0s linear .15s;
+        }
+    }
 }
index 34179b5..2f23851 100644 (file)
@@ -14901,6 +14901,17 @@ a.ygtvspacer:hover {
     .message-app .emoji-picker-container {
       right: -0.5rem; } }
 
+.message-app .emoji-auto-complete-container {
+  overflow: auto;
+  max-height: 90px;
+  transition: max-height .15s ease-in-out;
+  visibility: visible; }
+  .message-app .emoji-auto-complete-container.hidden {
+    display: block;
+    max-height: 0;
+    visibility: hidden;
+    transition: max-height .15s ease-in-out, visibility 0s linear .15s; }
+
 /* Question */
 .questionbank h2 {
   margin-top: 0; }
index 17f5911..1f33875 100644 (file)
@@ -15163,6 +15163,17 @@ a.ygtvspacer:hover {
     .message-app .emoji-picker-container {
       right: -0.5rem; } }
 
+.message-app .emoji-auto-complete-container {
+  overflow: auto;
+  max-height: 90px;
+  transition: max-height .15s ease-in-out;
+  visibility: visible; }
+  .message-app .emoji-auto-complete-container.hidden {
+    display: block;
+    max-height: 0;
+    visibility: hidden;
+    transition: max-height .15s ease-in-out, visibility 0s linear .15s; }
+
 /* Question */
 .questionbank h2 {
   margin-top: 0; }