From 5e855779b94e5812d80cebbea17a328fdf77ded9 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Thu, 8 Dec 2016 21:31:40 +0300 Subject: [PATCH] Support edit messages Closes #1155 --- app/js/controllers.js | 178 ++++++++++++++---- app/js/directives.js | 61 +++++- app/js/locales/en-us.json | 5 + app/js/message_composer.js | 8 + app/js/messages_manager.js | 132 +++++++++++-- app/js/services.js | 15 ++ app/less/app.less | 9 +- app/less/desktop.less | 8 + app/less/mobile.less | 4 + app/partials/desktop/im.html | 8 +- app/partials/desktop/message.html | 5 +- app/partials/desktop/reply_message.html | 5 +- app/partials/mobile/im.html | 4 +- app/partials/mobile/message.html | 5 +- .../mobile/message_actions_modal.html | 1 + 15 files changed, 380 insertions(+), 68 deletions(-) diff --git a/app/js/controllers.js b/app/js/controllers.js index b240eeb2..4b0b9c8e 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -502,6 +502,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) channelActions: false, canReply: false, canDelete: false, + canEdit: false, actions: function () { return $scope.historyState.selectActions ? 'selected' : ($scope.historyState.botActions ? 'bot' : ($scope.historyState.channelActions ? 'channel' : false)) }, @@ -1130,6 +1131,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.selectedDelete = selectedDelete $scope.selectedForward = selectedForward $scope.selectedReply = selectedReply + $scope.selectedEdit = selectedEdit $scope.selectedCancel = selectedCancel $scope.selectedFlush = selectedFlush $scope.selectInlineBot = selectInlineBot @@ -1610,8 +1612,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) } if (target.className && target.className.indexOf('im_message_date') != -1) { - if (AppPeersManager.isChannel(peerID) && - !AppPeersManager.isMegagroup(peerID)) { + if (AppPeersManager.isBroadcast(peerID)) { quickForward(messageID) } else { selectedReply(messageID) @@ -1630,6 +1631,8 @@ angular.module('myApp.controllers', ['myApp.i18n']) } if (Config.Mobile) { + $scope.historyState.canEdit = AppMessagesManager.canEditMessage(messageID) + $modal.open({ templateUrl: templateUrl('message_actions_modal'), windowClass: 'message_actions_modal_window', @@ -1640,6 +1643,10 @@ angular.module('myApp.controllers', ['myApp.i18n']) selectedReply(messageID) break + case 'edit': + selectedEdit(messageID) + break + case 'delete': selectedDelete(messageID) break @@ -1704,6 +1711,11 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.$broadcast('ui_panel_update') } } + if ($scope.selectedCount == 1) { + angular.forEach($scope.selectedMsgs, function (t, messageID) { + $scope.historyState.canEdit = AppMessagesManager.canEditMessage(messageID) + }) + } $scope.$broadcast('messages_select') } @@ -1813,6 +1825,18 @@ angular.module('myApp.controllers', ['myApp.i18n']) } } + function selectedEdit (selectedMessageID) { + if (!selectedMessageID && $scope.selectedCount == 1) { + angular.forEach($scope.selectedMsgs, function (t, messageID) { + selectedMessageID = messageID + }) + } + if (selectedMessageID) { + selectedCancel() + $scope.$broadcast('edit_selected', selectedMessageID) + } + } + function toggleEdit () { if ($scope.historyState.selectActions) { selectedCancel() @@ -2202,13 +2226,18 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.$on('reply_selected', function (e, messageID) { replySelect(messageID, true) }) + $scope.$on('edit_selected', function (e, messageID) { + setEditDraft(messageID, true) + }) + $scope.$on('ui_typing', onTyping) $scope.draftMessage = { text: '', - send: sendMessage, + send: submitMessage, replyClear: replyClear, - fwdsClear: fwdsClear + fwdsClear: fwdsClear, + type: 'new' } $scope.mentions = {} $scope.commands = {} @@ -2232,6 +2261,8 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.$on('inline_bots_popular', updateMentions) + $scope.$on('last_message_edit', setEditLastMessage) + $scope.replyKeyboardToggle = replyKeyboardToggle $scope.toggleSlash = toggleSlash @@ -2257,38 +2288,58 @@ angular.module('myApp.controllers', ['myApp.i18n']) var replyToMarkup = false var forceDraft = false + var editMessageID = false - function sendMessage (e) { + function submitMessage (e) { $scope.$broadcast('ui_message_before_send') $timeout(function () { - var text = $scope.draftMessage.text + if (editMessageID) { + editMessage() + } else { + sendMessage() + } + }) - if (angular.isString(text) && text.length > 0) { - text = RichTextProcessor.parseEmojis(text) + return cancelEvent(e) + } - var options = { - replyToMsgID: $scope.draftMessage.replyToMsgID, - clearDraft: true - } - do { - AppMessagesManager.sendText($scope.curDialog.peerID, text.substr(0, 4096), options) - text = text.substr(4096) - options = angular.copy(options) - delete options.clearDraft - } while (text.length) - } - fwdsSend() + function sendMessage() { + var text = $scope.draftMessage.text - if (forceDraft == $scope.curDialog.peer) { - forceDraft = false + if (angular.isString(text) && text.length > 0) { + text = RichTextProcessor.parseEmojis(text) + + var options = { + replyToMsgID: $scope.draftMessage.replyToMsgID, + clearDraft: true } + do { + AppMessagesManager.sendText($scope.curDialog.peerID, text.substr(0, 4096), options) + text = text.substr(4096) + options = angular.copy(options) + delete options.clearDraft + } while (text.length) + } + fwdsSend() + + if (forceDraft == $scope.curDialog.peer) { + forceDraft = false + } + + resetDraft() + $scope.$broadcast('ui_message_send') + } + + function editMessage() { + var text = $scope.draftMessage.text + + AppMessagesManager.editMessage(editMessageID, text).then(function () { + editMessageID = false resetDraft() $scope.$broadcast('ui_message_send') }) - - return cancelEvent(e) } function updateMentions () { @@ -2402,6 +2453,8 @@ angular.module('myApp.controllers', ['myApp.i18n']) return } + editMessageID = false + updateMentions() updateCommands() replyClear() @@ -2413,7 +2466,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) // console.log(dT(), 'reset draft', $scope.curDialog.peer, forceDraft) if (forceDraft) { if (forceDraft == $scope.curDialog.peer) { - $scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID) && !AppPeersManager.isMegagroup($scope.curDialog.peerID) + $scope.draftMessage.isBroadcast = AppPeersManager.isBroadcast($scope.curDialog.peerID) $scope.$broadcast('ui_peer_draft') return } else { @@ -2427,9 +2480,25 @@ angular.module('myApp.controllers', ['myApp.i18n']) function getDraft () { if ($scope.curDialog.peerID) { - DraftsManager.getDraft($scope.curDialog.peerID).then(function (draftData) { + var draftDataPromise + if (editMessageID) { + draftDataPromise = AppMessagesManager.getMessageEditData(editMessageID).then(function (draftData) { + draftData.replyToMsgID = editMessageID + return draftData + }, function (error) { + console.warn(error) + editMessageID = false + getDraft() + return $q.reject() + }) + } else { + draftDataPromise = DraftsManager.getDraft($scope.curDialog.peerID) + } + draftDataPromise.then(function (draftData) { + console.warn('draft', editMessageID, draftData) + $scope.draftMessage.type = editMessageID ? 'edit' : 'new' $scope.draftMessage.text = draftData ? draftData.text : '' - $scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID) && !AppPeersManager.isMegagroup($scope.curDialog.peerID) + $scope.draftMessage.isBroadcast = AppPeersManager.isBroadcast($scope.curDialog.peerID) if (draftData.replyToMsgID) { var replyToMsgID = draftData.replyToMsgID replySelect(replyToMsgID) @@ -2493,11 +2562,15 @@ angular.module('myApp.controllers', ['myApp.i18n']) } function replySelect (messageID, byUser) { + if (editMessageID && byUser) { + replyClear() + return + } $scope.draftMessage.replyToMsgID = messageID $scope.$broadcast('ui_peer_reply') replyToMarkup = false - if (byUser) { + if (byUser && !editMessageID) { DraftsManager.changeDraft($scope.curDialog.peerID, { text: $scope.draftMessage.text, replyToMsgID: messageID @@ -2505,7 +2578,33 @@ angular.module('myApp.controllers', ['myApp.i18n']) } } + function setEditDraft(messageID) { + editMessageID = messageID + getDraft() + } + + function setEditLastMessage() { + if (editMessageID || + !$scope.curDialog.peerID) { + return false + } + AppMessagesManager.getHistory($scope.curDialog.peerID).then(function (historyResult) { + for (var i = 0, messageID; i < historyResult.history.length; i++) { + messageID = historyResult.history[i] + if (AppMessagesManager.canEditMessage(messageID)) { + setEditDraft(messageID) + break + } + } + }) + } + function replyClear (byUser) { + if (editMessageID) { + editMessageID = false + getDraft() + return + } var mid = $scope.draftMessage.replyToMsgID if (mid && $scope.historyState.replyKeyboard && @@ -2608,16 +2707,18 @@ angular.module('myApp.controllers', ['myApp.i18n']) } } if ($scope.curDialog.peerID) { - var replyToMsgID = $scope.draftMessage.replyToMsgID - if (replyToMsgID && - $scope.historyState.replyKeyboard && - $scope.historyState.replyKeyboard.mid == replyToMsgID) { - replyToMsgID = 0; + if (!editMessageID) { + var replyToMsgID = $scope.draftMessage.replyToMsgID + if (replyToMsgID && + $scope.historyState.replyKeyboard && + $scope.historyState.replyKeyboard.mid == replyToMsgID) { + replyToMsgID = 0; + } + DraftsManager.changeDraft($scope.curDialog.peerID, { + text: newVal, + replyToMsgID: replyToMsgID + }) } - DraftsManager.changeDraft($scope.curDialog.peerID, { - text: newVal, - replyToMsgID: replyToMsgID - }) checkInlinePattern(newVal) } } @@ -2685,8 +2786,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) } function onTyping () { - if (AppPeersManager.isChannel($scope.curDialog.peerID) && - !AppPeersManager.isMegagroup($scope.curDialog.peerID)) { + if (AppPeersManager.isBroadcast($scope.curDialog.peerID)) { return false } MtpApiManager.invokeApi('messages.setTyping', { diff --git a/app/js/directives.js b/app/js/directives.js index b0308f26..c6ac6a98 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -527,16 +527,19 @@ angular.module('myApp.directives', ['myApp.filters']) function link ($scope, element, attrs) { if (attrs.watch) { $scope.$parent.$watch(attrs.myReplyMessage, function (mid) { - checkMessage($scope, element, mid) + var isEdit = $scope.$parent.$eval(attrs.edit) + checkMessage($scope, element, mid, isEdit) }) } else { var mid = $scope.$parent.$eval(attrs.myReplyMessage) - checkMessage($scope, element, mid) + var isEdit = $scope.$parent.$eval(attrs.edit) + checkMessage($scope, element, mid, isEdit) } } - function checkMessage ($scope, element, mid) { + function checkMessage ($scope, element, mid, isEdit) { var message = $scope.replyMessage = AppMessagesManager.wrapSingleMessage(mid) + $scope.isEdit = isEdit || false if (message.loading) { var stopWaiting = $scope.$on('messages_downloaded', function (e, mids) { if (mids.indexOf(mid) != -1) { @@ -667,6 +670,49 @@ angular.module('myApp.directives', ['myApp.filters']) } }) + .directive('myMessageEdited', function (_, $timeout, AppMessagesManager) { + + var editedLabel = _('message_edited') + + return { + scope: {}, + link: link + } + + function link($scope, element, attrs) { + var messageID = $scope.$parent.$eval(attrs.myMessageEdited) + console.log(attrs.myMessageEdited, messageID) + if (checkEdited($scope, element, messageID)) { + $scope.$on('message_edit', function (e, data) { + var messageID = $scope.$parent.$eval(attrs.myMessageEdited) + if (data.mid == messageID) { + checkEdited($scope, element, messageID) + } + }) + } + } + + function checkEdited($scope, element, messageID) { + var message = AppMessagesManager.getMessage(messageID) + console.warn('check edited', messageID, message.canBeEdited, message.edit_date) + if (!message.canBeEdited) { + $timeout(function () { + $scope.$destroy() + element.remove() + }) + return false + } + if (message.edit_date) { + element.html(editedLabel).show() + $timeout(function () { + $scope.$destroy() + }) + return false + } + return true + } + }) + .directive('myDialogs', function ($modalStack, $transition, $window, $timeout) { return { link: link @@ -1528,6 +1574,7 @@ angular.module('myApp.directives', ['myApp.filters']) mentions: $scope.mentions, commands: $scope.commands, onMessageSubmit: onMessageSubmit, + onDirectionKey: onDirectionKey, onInlineResultSend: onInlineResultSend, onFilePaste: onFilePaste, onCommandSend: function (command) { @@ -1601,6 +1648,14 @@ angular.module('myApp.directives', ['myApp.filters']) }) } + function onDirectionKey(e) { + if (e.keyCode == 38) { + $scope.$emit('last_message_edit') + return cancelEvent(e) + } + return true + } + function updateValue () { if (richTextarea) { composer.onChange() diff --git a/app/js/locales/en-us.json b/app/js/locales/en-us.json index 936c97c2..320c5c69 100644 --- a/app/js/locales/en-us.json +++ b/app/js/locales/en-us.json @@ -361,6 +361,7 @@ "message_service_scored_X": "{'one': 'scored {}', 'other': 'scored {}'}", "message_action_reply": "Reply", + "message_action_edit": "Edit", "message_action_delete": "Delete", "message_action_forward": "Forward", "message_action_select": "Select", @@ -485,6 +486,7 @@ "im_delete": "Delete {count}", "im_forward": "Forward {count}", "im_reply": "Reply", + "im_edit": "Edit", "im_start": "Start", "im_channel_join": "+ Join", "im_channel_mute": "Mute", @@ -501,6 +503,8 @@ "im_attach_file_title": "Send file", "im_emoji_btn_title": "Insert emoticon", "im_submit_message": "Send", + "im_submit_edit_message": "Save", + "im_edit_message_title": "Edit message", "login_sign_in": "Sign in", "login_enter_number_description": "Please choose your country and enter your full phone number.", @@ -556,6 +560,7 @@ "message_forwarded_message": "Forwarded message", "message_via_bot": "via {bot}", + "message_edited": "edited", "message_forwarded_message_mobile": "Forwarded from {from}", "message_forwarded_via_message_mobile": "Forwarded from {from} via {bot}", diff --git a/app/js/message_composer.js b/app/js/message_composer.js index b6309808..14849ae3 100644 --- a/app/js/message_composer.js +++ b/app/js/message_composer.js @@ -708,6 +708,7 @@ function MessageComposer (textarea, options) { this.onTyping = options.onTyping this.onMessageSubmit = options.onMessageSubmit + this.onDirectionKey = options.onDirectionKey this.getSendOnEnter = options.getSendOnEnter this.onFilePaste = options.onFilePaste this.onCommandSend = options.onCommandSend @@ -941,6 +942,13 @@ MessageComposer.prototype.onKeyEvent = function (e) { return cancelEvent(e) } } + + // Control keys when content is empty + if ([33, 34, 35, 36, 38, 39].indexOf(e.keyCode) != -1 && + this.richTextareaEl && + !this.richTextareaEl[0].textContent.length) { + return this.onDirectionKey(e) + } } } diff --git a/app/js/messages_manager.js b/app/js/messages_manager.js index 805172b3..ddd4a510 100644 --- a/app/js/messages_manager.js +++ b/app/js/messages_manager.js @@ -877,6 +877,64 @@ angular.module('myApp.services') return messagesStorage[messageID] || {deleted: true} } + function canMessageBeEdited(message) { + var goodMedias = ['messageMediaPhoto', 'messageMediaDocument', 'messageMediaWebPage', 'messageMediaPending'] + if (message._ != 'message' || + message.deleted || + message.fwd_from || + message.via_bot_id || + message.media && goodMedias.indexOf(message.media._) == -1 || + message.fromID && AppUsersManager.isBot(message.fromID)) { + return false + } + + return true + } + + function canEditMessage(messageID) { + if (messageID <= 0 || + !messagesStorage[messageID]) { + return false + } + var message = messagesStorage[messageID] + if (!message || + !message.canBeEdited || + !message.pFlags.out || + message.date < tsNow(true) - 2 * 86400) { + return false + } + + return true + } + + function getMessageEditData(messageID) { + if (!canEditMessage(messageID)) { + return $q.reject() + } + var message = getMessage(messageID) + if (message.media && + message.media._ != 'messageMediaEmpty' && + message.media._ != 'messageMediaWebPage') { + + return $q.when({ + caption: true, + text: typeof message.media.caption === 'string' ? message.media.caption : '' + }) + } + + var text = typeof message.message === 'string' ? message.message : '' + var entities = RichTextProcessor.parseEntities(text) + var serverEntities = message.entities || [] + entities = RichTextProcessor.mergeEntities(entities, serverEntities) + + text = RichTextProcessor.wrapDraftText(text, {entities: entities}) + + return $q.when({ + caption: false, + text: text + }) + } + function deleteMessages (messageIDs) { var splitted = AppMessagesIDsManager.splitMessageIDsByChannels(messageIDs) var promises = [] @@ -1126,7 +1184,7 @@ angular.module('myApp.services') var peerID = getMessagePeer(apiMessage) var isChannel = apiMessage.to_id._ == 'peerChannel' var channelID = isChannel ? -peerID : 0 - var isBroadcast = isChannel && !AppChatsManager.isMegagroup(channelID) + var isBroadcast = isChannel && AppChatsManager.isBroadcast(channelID) var mid = AppMessagesIDsManager.getFullMessageID(apiMessage.id, channelID) apiMessage.mid = mid @@ -1266,6 +1324,8 @@ angular.module('myApp.services') apiMessage.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !apiMessage.pending) } + apiMessage.canBeEdited = canMessageBeEdited(apiMessage) + if (!options.isEdited) { messagesStorage[mid] = apiMessage } @@ -1285,18 +1345,7 @@ angular.module('myApp.services') return } - var sendEntites = entities - if (entities.length) { - sendEntites = angular.copy(entities) - angular.forEach(sendEntites, function (entity) { - if (entity._ == 'messageEntityMentionName') { - entity._ = 'inputMessageEntityMentionName' - entity.user_id = AppUsersManager.getUserInput(entity.user_id) - } - }) - } - - + var sendEntites = getInputEntities(entities) var messageID = tempID-- var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)] var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString() @@ -2038,6 +2087,51 @@ angular.module('myApp.services') return false } + function getInputEntities(entities) { + var sendEntites = angular.copy(entities) + angular.forEach(sendEntites, function (entity) { + if (entity._ == 'messageEntityMentionName') { + entity._ = 'inputMessageEntityMentionName' + entity.user_id = AppUsersManager.getUserInput(entity.user_id) + } + }) + return sendEntites + } + + function editMessage(messageID, text) { + if (!angular.isString(text) || + !canEditMessage(messageID)) { + return $q.reject() + } + var entities = [] + text = RichTextProcessor.parseMarkdown(text, entities) + + var message = getMessage(messageID) + var peerID = getMessagePeer(message) + var flags = 8 | (1 << 11) + + return MtpApiManager.invokeApi('messages.editMessage', { + flags: flags, + peer: AppPeersManager.getInputPeerByID(peerID), + id: AppMessagesIDsManager.getMessageLocalID(messageID), + message: text, + entities: getInputEntities(entities) + }).then(function (updates) { + ApiUpdatesManager.processUpdateMessage(updates) + }, function (error) { + if (error && + error.type == 'MESSAGE_NOT_MODIFIED') { + error.handled = true + return + } + if (error && + error.type == 'MESSAGE_EMPTY') { + error.handled = true + } + return $q.reject(error) + }) + } + function getMessagePeer (message) { var toID = message.to_id && AppPeersManager.getPeerID(message.to_id) || 0 @@ -2250,9 +2344,11 @@ angular.module('myApp.services') var fromUser = message.from_id && AppUsersManager.getUser(message.from_id) var fromBot = fromUser && fromUser.pFlags.bot && fromUser.username || false var toPeerID = AppPeersManager.getPeerID(message.to_id) - var withBot = (fromBot || - toPeerID < 0 && !(AppChatsManager.isChannel(-toPeerID) && !AppChatsManager.isMegagroup(-toPeerID)) || - toPeerID > 0 && AppUsersManager.isBot(toPeerID)) + var withBot = ( + fromBot || + AppPeersManager.isBot(toPeerID) || + AppPeersManager.isAnyGroup(toPeerID) + ) var options = { noCommands: !withBot, @@ -3258,10 +3354,14 @@ angular.module('myApp.services') forwardMessages: forwardMessages, startBot: startBot, shareGame: shareGame, + editMessage: editMessage, convertMigratedPeer: convertMigratedPeer, getMessagePeer: getMessagePeer, getMessageThumb: getMessageThumb, getMessageShareLink: getMessageShareLink, + canMessageBeEdited: canMessageBeEdited, + canEditMessage: canEditMessage, + getMessageEditData: getMessageEditData, clearDialogCache: clearDialogCache, wrapForDialog: wrapForDialog, wrapForHistory: wrapForHistory, diff --git a/app/js/services.js b/app/js/services.js index 9008cf77..dfdbf324 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -709,6 +709,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) return false } + function isBroadcast (id) { + return isChannel(id) && !isMegagroup(id) + } + function getChatInput (id) { return id || 0 } @@ -827,6 +831,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) getChat: getChat, isChannel: isChannel, isMegagroup: isMegagroup, + isBroadcast: isBroadcast, hasRights: hasRights, saveChannelAccess: saveChannelAccess, saveIsMegagroup: saveIsMegagroup, @@ -987,6 +992,14 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) return (peerID < 0) && AppChatsManager.isMegagroup(-peerID) } + function isAnyGroup (peerID) { + return (peerID < 0) && !AppChatsManager.isBroadcast(-peerID) + } + + function isBroadcast (id) { + return isChannel(id) && !isMegagroup(id) + } + function isBot (peerID) { return (peerID > 0) && AppUsersManager.isBot(peerID) } @@ -1002,7 +1015,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) getPeerPhoto: getPeerPhoto, resolveUsername: resolveUsername, isChannel: isChannel, + isAnyGroup: isAnyGroup, isMegagroup: isMegagroup, + isBroadcast: isBroadcast, isBot: isBot } }) diff --git a/app/less/app.less b/app/less/app.less index 20f7b299..5fb2d2a6 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -2103,7 +2103,11 @@ img.im_message_document_thumb { padding: 0 0 20px 10px; } -.im_message_date { +.im_message_edited { + display: none; +} + +.im_message_date_text { cursor: pointer; &:hover { text-decoration: underline; @@ -3908,7 +3912,8 @@ ul.chat_modal_migrate_list { .audio_player_size, .im_message_fwd_date, .im_message_views_cnt, - .im_message_sign_link { + .im_message_sign_link, + .im_message_edited { color: #899daf; } diff --git a/app/less/desktop.less b/app/less/desktop.less index 5af9b6bb..e08b030e 100644 --- a/app/less/desktop.less +++ b/app/less/desktop.less @@ -881,6 +881,14 @@ a.footer_link.active:active { } } +.im_submit_edit_label, +.im_submit_edit .im_submit_send_label { + display: none; +} +.im_submit_edit .im_submit_edit_label { + display: inline; +} + .composer_emoji_panel { display: block; height: 30px; diff --git a/app/less/mobile.less b/app/less/mobile.less index 76935d8d..a5cb2a79 100644 --- a/app/less/mobile.less +++ b/app/less/mobile.less @@ -856,6 +856,10 @@ img.im_message_video_thumb, font-size: 10px; padding: 0; } +.im_message_edited { + position: absolute; + top: -11px; +} .im_message_out { .im_message_fwd_date { diff --git a/app/partials/desktop/im.html b/app/partials/desktop/im.html index dd108393..4e2dbaae 100644 --- a/app/partials/desktop/im.html +++ b/app/partials/desktop/im.html @@ -168,6 +168,7 @@ + @@ -189,7 +190,7 @@
- +
@@ -210,7 +211,10 @@
- +
diff --git a/app/partials/desktop/message.html b/app/partials/desktop/message.html index c7a750b2..a4dd1f90 100644 --- a/app/partials/desktop/message.html +++ b/app/partials/desktop/message.html @@ -38,7 +38,10 @@
- + + + +
diff --git a/app/partials/desktop/reply_message.html b/app/partials/desktop/reply_message.html index 36302303..ea83612a 100644 --- a/app/partials/desktop/reply_message.html +++ b/app/partials/desktop/reply_message.html @@ -11,9 +11,10 @@ watch="true" />
-
+
- + +
diff --git a/app/partials/mobile/im.html b/app/partials/mobile/im.html index 3eb0ee54..32e043e9 100644 --- a/app/partials/mobile/im.html +++ b/app/partials/mobile/im.html @@ -136,11 +136,11 @@
-
+
- +
diff --git a/app/partials/mobile/message.html b/app/partials/mobile/message.html index 54ec3a9f..e7ab17bb 100644 --- a/app/partials/mobile/message.html +++ b/app/partials/mobile/message.html @@ -37,7 +37,10 @@ - + + + +
diff --git a/app/partials/mobile/message_actions_modal.html b/app/partials/mobile/message_actions_modal.html index 73a44121..1449171b 100644 --- a/app/partials/mobile/message_actions_modal.html +++ b/app/partials/mobile/message_actions_modal.html @@ -2,6 +2,7 @@
+