MDL-65132 core_message: Update message drawer to delete message for all
authorcescobedo <carlos.escobedo@gmail.com>
Thu, 2 May 2019 14:29:43 +0000 (16:29 +0200)
committercescobedo <carlos.escobedo@gmail.com>
Mon, 6 May 2019 07:48:26 +0000 (09:48 +0200)
Update JS message drawer to allow delete message for all showing a new
checkbox in the confirm dialogue.

14 files changed:
lang/en/message.php
message/amd/build/message_drawer_view_conversation.min.js
message/amd/build/message_drawer_view_conversation_constants.min.js
message/amd/build/message_drawer_view_conversation_patcher.min.js
message/amd/build/message_drawer_view_conversation_renderer.min.js
message/amd/build/message_drawer_view_conversation_state_manager.min.js
message/amd/build/message_repository.min.js
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/amd/src/message_repository.js
message/templates/message_drawer_view_conversation_body_confirm_dialogue.mustache

index 5451eda..86a8a3c 100644 (file)
@@ -55,6 +55,8 @@ $string['deleteallconfirm'] = "Are you sure you would like to delete this entire
 $string['deleteallmessages'] = "Delete all messages";
 $string['deleteallselfconfirm'] = "Are you sure you would like to delete this entire personal conversation?";
 $string['deleteconversation'] = "Delete conversation";
+$string['deleteforeveryone'] = "Delete for me and everyone";
+$string['deleteforeveryoneselectedmessagesconfirm'] = 'Are you sure you would like to delete the selected messages?';
 $string['deleteselectedmessages'] = 'Delete selected messages';
 $string['deleteselectedmessagesconfirm'] = 'Are you sure you would like to delete the selected messages? This will not delete them for other conversation participants.';
 $string['deleteselectedmessagesconfirmselfconversation'] = 'Are you sure you would like to delete the selected personal messages?';
index 8db9ea6..67374e6 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 2c2761d..2abab80 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 1fdea1f..e346c14 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 9646cb8..4714f52 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 c0f4082..baa15c2 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 4b0e943..1a2a05c 100644 (file)
Binary files a/message/amd/build/message_repository.min.js and b/message/amd/build/message_repository.min.js differ
index 899c188..e2ca7e5 100644 (file)
@@ -350,6 +350,7 @@ function(
         newState = StateManager.setIsFavourite(newState, conversation.isfavourite);
         newState = StateManager.setIsMuted(newState, conversation.ismuted);
         newState = StateManager.addMessages(newState, conversation.messages);
+        newState = StateManager.setCanDeleteMessagesForAllUsers(newState, conversation.candeletemessagesforallusers);
         return newState;
     };
 
@@ -886,6 +887,10 @@ function(
         var newState = StateManager.setLoadingConfirmAction(viewState, true);
         return render(newState)
             .then(function() {
+                if (newState.deleteMessagesForAllUsers) {
+                    return Repository.deleteMessagesForAllUsers(viewState.loggedInUserId, messageIds);
+                }
+
                 return Repository.deleteMessages(viewState.loggedInUserId, messageIds);
             })
             .then(function() {
@@ -893,6 +898,7 @@ function(
                 newState = StateManager.removePendingDeleteMessagesById(newState, messageIds);
                 newState = StateManager.removeSelectedMessagesById(newState, messageIds);
                 newState = StateManager.setLoadingConfirmAction(newState, false);
+                newState = StateManager.setDeleteMessagesForAllUsers(newState, false);
 
                 var prevLastMessage = viewState.messages[viewState.messages.length - 1];
                 var newLastMessage = newState.messages.length ? newState.messages[newState.messages.length - 1] : null;
@@ -959,6 +965,7 @@ function(
         newState = StateManager.removePendingBlockUsersById(newState, [userId]);
         newState = StateManager.removePendingDeleteMessagesById(newState, pendingDeleteMessageIds);
         newState = StateManager.setPendingDeleteConversation(newState, false);
+        newState = StateManager.setDeleteMessagesForAllUsers(newState, false);
         return render(newState);
     };
 
@@ -1037,6 +1044,7 @@ function(
         isSendingMessage = true;
         var newState = StateManager.setSendingMessage(viewState, true);
         var newConversationId = null;
+        var newCanDeleteMessagesForAllUsers = false;
         return render(newState)
             .then(function() {
                 if (!conversationId && (viewState.type != CONVERSATION_TYPES.PUBLIC)) {
@@ -1046,6 +1054,7 @@ function(
                     return Repository.sendMessageToUser(otherUserId, text)
                         .then(function(message) {
                             newConversationId = parseInt(message.conversationid, 10);
+                            newCanDeleteMessagesForAllUsers = message.candeletemessagesforallusers;
                             return message;
                         });
                 } else {
@@ -1064,6 +1073,7 @@ function(
                     conversation.id = newConversationId;
                     resetMessagePollTimer(newConversationId);
                     PubSub.publish(MessageDrawerEvents.CONVERSATION_CREATED, conversation);
+                    newState = StateManager.setCanDeleteMessagesForAllUsers(newState, newCanDeleteMessagesForAllUsers);
                 }
 
                 return render(newState)
@@ -1298,6 +1308,18 @@ function(
         data.originalEvent.preventDefault();
     };
 
+    /**
+     * Handle clicking on the checkbox that toggles deleting messages for
+     * all users.
+     *
+     * @param {Object} e Element this event handler is called on.
+     */
+    var handleDeleteMessagesForAllUsersToggle = function(e) {
+        var newValue = $(e.target).prop('checked');
+        var newState = StateManager.setDeleteMessagesForAllUsers(viewState, newValue);
+        render(newState);
+    };
+
     /**
      * Show the view contact page.
      *
@@ -1358,7 +1380,8 @@ function(
             [SELECTORS.ACTION_REQUEST_ADD_CONTACT, generateConfirmActionHandler(requestAddContact)],
             [SELECTORS.ACTION_ACCEPT_CONTACT_REQUEST, generateConfirmActionHandler(acceptContactRequest)],
             [SELECTORS.ACTION_DECLINE_CONTACT_REQUEST, generateConfirmActionHandler(declineContactRequest)],
-            [SELECTORS.MESSAGE, handleSelectMessage]
+            [SELECTORS.MESSAGE, handleSelectMessage],
+            [SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE, handleDeleteMessagesForAllUsersToggle]
         ];
         var footerActivateHandlers = [
             [SELECTORS.SEND_MESSAGE_BUTTON, handleSendMessage],
index 04b6584..00a3bbb 100644 (file)
@@ -61,6 +61,8 @@ define([], function() {
         CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER: '[data-region="content-messages-footer-require-unblock-container"]',
         CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER: '[data-region="content-messages-footer-unable-to-message"]',
         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"]',
         FAVOURITE_ICON_CONTAINER: '[data-region="favourite-icon-container"]',
         FOOTER_CONTAINER: '[data-region="content-messages-footer-container"]',
         HEADER: '[data-region="header-content"]',
index 1d59260..ffff869 100644 (file)
@@ -562,13 +562,22 @@ function(
      *
      * @param  {Object} state The current state.
      * @param  {Object} newState The new state.
-     * @return {int|Null} The conversation type of the messages to be deleted.
+     * @return {Object|Null} The conversation type and if the user can delete  the messages for all users.
      */
     var buildConfirmDeleteSelectedMessages = function(state, newState) {
-        if (newState.pendingDeleteMessageIds.length) {
-            return newState.type;
-        } else if (state.pendingDeleteMessageIds.length) {
-            return false;
+        var oldPendingCount = state.pendingDeleteMessageIds.length;
+        var newPendingCount = newState.pendingDeleteMessageIds.length;
+
+        if (newPendingCount && !oldPendingCount) {
+            return {
+                show: true,
+                type: newState.type,
+                canDeleteMessagesForAllUsers: newState.canDeleteMessagesForAllUsers
+            };
+        } else if (oldPendingCount && !newPendingCount) {
+            return {
+                show: false
+            };
         }
 
         return null;
index ab213b7..c4a8c34 100644 (file)
@@ -1026,6 +1026,7 @@ function(
         var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);
         var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);
 
+        hideCheckDeleteDialogue(body);
         hideConfirmDialogueContainer(body);
         hideConfirmDialogueContainer(footer);
         hideConfirmDialogueContainer(header);
@@ -1143,20 +1144,25 @@ function(
      * @param {Object} header The header container element.
      * @param {Object} body The body container element.
      * @param {Object} footer The footer container element.
-     * @param {int|Null} type The messages conversation type to be removed.
+     * @param {Object} data If the dialogue should show and checkbox shows to delete message for all users.
      * @return {Object} jQuery promise
      */
-    var renderConfirmDeleteSelectedMessages = function(header, body, footer, type) {
+    var renderConfirmDeleteSelectedMessages = function(header, body, footer, data) {
         var showmessage = null;
-        if (type == CONVERSATION_TYPES.SELF) {
+        if (data.type == CONVERSATION_TYPES.SELF) {
             // Message displayed to self-conversations is slighly different.
             showmessage = 'deleteselectedmessagesconfirmselfconversation';
-        } else if (type) {
+        } else {
             // This other message should be displayed.
-            showmessage = 'deleteselectedmessagesconfirm';
+            if (data.canDeleteMessagesForAllUsers) {
+                showCheckDeleteDialogue(body);
+                showmessage = 'deleteforeveryoneselectedmessagesconfirm';
+            } else {
+                showmessage = 'deleteselectedmessagesconfirm';
+            }
         }
 
-        if (showmessage) {
+        if (data.show) {
             return Str.get_string(showmessage, 'core_message')
                 .then(function(string) {
                     return showConfirmDialogue(
@@ -1237,6 +1243,30 @@ function(
         }
     };
 
+    /**
+     * Show the checkbox to allow delete message for all.
+     *
+     * @param {Object} body The body container element.
+     */
+    var showCheckDeleteDialogue = function(body) {
+        var dialogue = getConfirmDialogueContainer(body);
+        var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);
+        checkboxRegion.removeClass('hidden');
+    };
+
+    /**
+     * Hide the checkbox to allow delete message for all.
+     *
+     * @param {Object} body The body container element.
+     */
+    var hideCheckDeleteDialogue = function(body) {
+        var dialogue = getConfirmDialogueContainer(body);
+        var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);
+        var checkbox = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);
+        checkbox.prop('checked', false);
+        checkboxRegion.addClass('hidden');
+    };
+
     /**
      * Show or hide the block / unblock option in the header dropdown menu.
      *
index 98ed99e..3f67cb7 100644 (file)
@@ -40,18 +40,11 @@ define(['jquery'], function($) {
      * @return {Object} newstate A copy of the state to clone.
      */
     var cloneState = function(state) {
-        var newState = $.extend({}, state);
-        newState.messages = state.messages.map(function(message) {
-            return $.extend({}, message);
-        });
-        newState.members = Object.keys(state.members).reduce(function(carry, id) {
-            carry[id] = $.extend({}, state.members[id]);
-            carry[id].contactrequests = state.members[id].contactrequests.map(function(request) {
-                return $.extend({}, request);
-            });
-            return carry;
-        }, {});
-        return newState;
+        // Do a deep extend to make sure we recursively copy objects and
+        // arrays so that the new state doesn't contain any references to
+        // the old state, e.g. adding a value to an array in the new state
+        // shouldn't also add it to the old state.
+        return $.extend(true, {}, state);
     };
 
     /**
@@ -122,6 +115,8 @@ define(['jquery'], function($) {
             imageUrl: null,
             isFavourite: null,
             isMuted: null,
+            canDeleteMessagesForAllUsers: false,
+            deleteMessagesForAllUsers: false,
             members: {},
             messages: [],
             hasTriedToLoadMessages: false,
@@ -658,6 +653,32 @@ define(['jquery'], function($) {
         return newState;
     };
 
+    /**
+     * Set wheter the message of the conversation can delete for all users.
+     *
+     * @param  {Object} state Current state.
+     * @param  {Bool} value If it can delete for all users.
+     * @return {Object} New state.
+     */
+    var setCanDeleteMessagesForAllUsers = function(state, value) {
+        var newState = cloneState(state);
+        newState.canDeleteMessagesForAllUsers = value;
+        return newState;
+    };
+
+    /**
+     * Set wheter the messages of the conversation delete for all users.
+     *
+     * @param  {Object} state Current state.
+     * @param  {Bool} value Delete messages for all users.
+     * @return {Object} New state.
+     */
+    var setDeleteMessagesForAllUsers = function(state, value) {
+        var newState = cloneState(state);
+        newState.deleteMessagesForAllUsers = value;
+        return newState;
+    };
+
     return {
         buildInitialState: buildInitialState,
         addMessages: addMessages,
@@ -674,6 +695,8 @@ define(['jquery'], function($) {
         setType: setType,
         setIsFavourite: setIsFavourite,
         setIsMuted: setIsMuted,
+        setCanDeleteMessagesForAllUsers: setCanDeleteMessagesForAllUsers,
+        setDeleteMessagesForAllUsers: setDeleteMessagesForAllUsers,
         setTotalMemberCount: setTotalMemberCount,
         setImageUrl: setImageUrl,
         setLoadingConfirmAction: setLoadingConfirmAction,
index 31c630d..56b5925 100644 (file)
@@ -431,7 +431,8 @@ define(
                         text: result.text,
                         timecreated: result.timecreated,
                         useridfrom: result.useridfrom,
-                        conversationid: result.conversationid
+                        conversationid: result.conversationid,
+                        candeletemessagesforallusers: result.candeletemessagesforallusers
                     };
                 });
             });
@@ -542,6 +543,25 @@ define(
         })));
     };
 
+    /**
+     * Delete a list of messages for all users.
+     *
+     * @param {int} userId The user to delete messages for
+     * @param {int[]} messageIds List of message ids to delete
+     * @return {object} jQuery promise
+     */
+    var deleteMessagesForAllUsers = function(userId, messageIds) {
+        return $.when.apply(null, Ajax.call(messageIds.map(function(messageId) {
+            return {
+                methodname: 'core_message_delete_message_for_all_users',
+                args: {
+                    messageid: messageId,
+                    userid: userId
+                }
+            };
+        })));
+    };
+
     /**
      * Delete a conversation between two users.
      *
@@ -1138,6 +1158,7 @@ define(
         savePreferences: savePreferences,
         getPreferences: getPreferences,
         deleteMessages: deleteMessages,
+        deleteMessagesForAllUsers: deleteMessagesForAllUsers,
         deleteConversation: deleteConversation,
         getContactRequests: getContactRequests,
         acceptContactRequest: acceptContactRequest,
index 09d8f41..58adafa 100644 (file)
 <div class="p-3 bg-white" data-region="confirm-dialogue" role="alert">
     <h3 class="h6 hidden" data-region="dialogue-header"></h3>
     <p class="text-muted" data-region="dialogue-text"></p>
+    <div class="mb-2 hidden" data-region="delete-messages-for-all-users-toggle-container">
+        <label class="custom-control-label ml-2 text-muted">
+            <input type="checkbox" data-region="delete-messages-for-all-users-toggle">
+            {{#str}} deleteforeveryone, core_message {{/str}}
+        </label>
+    </div>
     <button type="button" class="btn btn-primary btn-block hidden" data-action="confirm-block">
         <span data-region="dialogue-button-text">{{#str}} blockuserconfirmbutton, core_message {{/str}}</span>
         <span class="hidden" data-region="loading-icon-container">{{> core/loading }}</span>