Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow-up(Edit message) #11451

Merged
merged 4 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/components/ConversationSettings/EditableTextField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ import NcRichContenteditable from '@nextcloud/vue/dist/Components/NcRichContente
import NcRichText from '@nextcloud/vue/dist/Components/NcRichText.js'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'

import { parseSpecialSymbols } from '../../utils/textParse.js'

export default {
name: 'EditableTextField',
components: {
Expand Down Expand Up @@ -232,12 +234,9 @@ export default {
if (!this.canSubmit) {
return
}
// Remove leading/trailing whitespaces.
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
// FIXME upstream: https://github.com/nextcloud-libraries/nextcloud-vue/issues/4492
const temp = document.createElement('textarea')
temp.innerHTML = this.text.replace(/&/gmi, '&')
this.text = temp.value.replace(/\r\n|\n|\r/gm, '\n').replace(/&/gmi, '&')
.replace(/&lt;/gmi, '<').replace(/&gt;/gmi, '>').replace(/&sect;/gmi, '§').trim()

// Parse special symbols
this.text = parseSpecialSymbols(this.text)

// Submit text
this.$emit('submit-text', this.text)
Expand Down
14 changes: 6 additions & 8 deletions src/components/MessagesList/MessagesGroup/Message/Message.vue
Original file line number Diff line number Diff line change
Expand Up @@ -485,14 +485,12 @@ export default {
},

handleEdit() {
this.chatExtrasStore.setMessageIdToEdit(this.token, this.id)
if (this.isFileShareOnly) {
this.chatExtrasStore.setChatEditInput({ token: this.token, text: '' })
} else {
this.chatExtrasStore.setChatEditInput({ token: this.token, text: this.message })
}
EventBus.$emit('editing-message')
EventBus.$emit('focus-chat-input')
this.chatExtrasStore.initiateEditingMessage({
token: this.token,
id: this.id,
message: this.message,
messageParameters: this.messageParameters,
})
},

async handleDelete() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,14 @@
{{ messageDateTime }}
</NcActionText>
<!-- Edited message timestamp -->
<NcActionButtonGroup v-if="lastEditTimestamp">
<NcActionText>
<template #icon>
<ClockEditOutline :size="16" />
</template>
{{ lastEditActorDisplayName }}
</NcActionText>
<NcActionText>
{{ editedDateTime }}
</NcActionText>
</NcActionButtonGroup>
<NcActionText v-if="lastEditTimestamp"
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
class="edit-timestamp"
:name="lastEditActorLabel">
<template #icon>
<ClockEditOutline :size="16" />
</template>
{{ editedDateTime }}
</NcActionText>
<NcActionSeparator />

<NcActionButton v-if="supportReminders"
Expand Down Expand Up @@ -297,7 +294,6 @@ import { showError, showSuccess } from '@nextcloud/dialogs'
import moment from '@nextcloud/moment'

import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionButtonGroup from '@nextcloud/vue/dist/Components/NcActionButtonGroup.js'
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
Expand All @@ -311,15 +307,17 @@ import { getMessageReminder, removeMessageReminder, setMessageReminder } from '.
import { copyConversationLinkToClipboard } from '../../../../../services/urlService.js'
import { useIntegrationsStore } from '../../../../../stores/integrations.js'
import { useReactionsStore } from '../../../../../stores/reactions.js'
import { parseMentions } from '../../../../../utils/textParse.js'

const EmojiIndex = new EmojiIndexFactory(data)
const supportReminders = getCapabilities()?.spreed?.features?.includes('remind-me-later')
const canEditMessage = getCapabilities()?.spreed?.features?.includes('edit-messages')
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
const canDeleteMessageUnlimited = getCapabilities()?.spreed?.features?.includes('delete-messages-unlimited')

export default {
name: 'MessageButtonsBar',

components: {
NcActionButtonGroup,
NcActionButton,
NcActionInput,
NcActionLink,
Expand Down Expand Up @@ -518,7 +516,7 @@ export default {
},

isEditable() {
if (!this.isModifiable || this.isObjectShare
if (!canEditMessage || !this.isModifiable || this.isObjectShare
|| (!this.$store.getters.isModerator && !this.isMyMsg)) {
return false
}
Expand All @@ -531,7 +529,7 @@ export default {
return false
}

return (moment(this.timestamp * 1000).add(6, 'h')) > moment()
return (canDeleteMessageUnlimited || (moment(this.timestamp * 1000).add(6, 'h')) > moment())
&& (this.messageType === 'comment' || this.messageType === 'voice-message')
&& !this.isDeleting
&& (this.isMyMsg
Expand Down Expand Up @@ -675,6 +673,12 @@ export default {
apiVersion: 'v3',
}
},

lastEditActorLabel() {
return t('spreed', 'Edited by {actor}', {
actor: this.lastEditActorDisplayName,
})
},
},

watch: {
Expand All @@ -697,15 +701,7 @@ export default {
},

async handleCopyMessageText() {
let parsedText = this.message

for (const [key, value] of Object.entries(this.messageParameters)) {
if (value?.type === 'call') {
parsedText = parsedText.replace(new RegExp(`{${key}}`, 'g'), '@all')
} else if (value?.type === 'user') {
parsedText = parsedText.replace(new RegExp(`{${key}}`, 'g'), `@${value.id}`)
}
}
const parsedText = parseMentions(this.message, this.messageParameters)

try {
await navigator.clipboard.writeText(parsedText)
Expand Down Expand Up @@ -854,6 +850,9 @@ export default {
},

editMessage() {
if (!canEditMessage) {
return
}
this.$emit('edit')
},
},
Expand All @@ -870,4 +869,8 @@ export default {
background: no-repeat center var(--icon-triangle-e-dark);
}
}

.edit-timestamp :deep(.action-text__longtext-wrapper) {
padding: 0;
}
</style>
59 changes: 52 additions & 7 deletions src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
:can-cancel="!!parentMessage"
:edit-message="!!messageToEdit" />
</div>
<!-- mention editing hint -->
<NcNoteCard v-if="showMentionEditHint" type="warning">
<p>{{ t('spreed','Adding a mention will only notify users who did not read the message.') }}</p>
</NcNoteCard>
<NcRichContenteditable ref="richContenteditable"
v-shortkey.once="$options.disableKeyboardShortcuts ? null : ['c']"
:value.sync="text"
Expand All @@ -99,6 +103,7 @@
dir="auto"
@shortkey="focusInput"
@keydown.esc="handleInputEsc"
@keydown.ctrl.up="handleEditLastMessage"
@tribute-active-true.native="isTributePickerActive = true"
@tribute-active-false.native="isTributePickerActive = false"
@input="handleTyping"
Expand Down Expand Up @@ -194,13 +199,15 @@ import EmoticonOutline from 'vue-material-design-icons/EmoticonOutline.vue'
import Send from 'vue-material-design-icons/Send.vue'

import { getCapabilities } from '@nextcloud/capabilities'
import { showError } from '@nextcloud/dialogs'
import { FilePickerVue } from '@nextcloud/dialogs/filepicker.js'
import { generateOcsUrl } from '@nextcloud/router'

import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcEmojiPicker from '@nextcloud/vue/dist/Components/NcEmojiPicker.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcRichContenteditable from '@nextcloud/vue/dist/Components/NcRichContenteditable.js'

import NewMessageAbsenceInfo from './NewMessageAbsenceInfo.vue'
Expand All @@ -220,9 +227,11 @@ import { useChatExtrasStore } from '../../stores/chatExtras.js'
import { useSettingsStore } from '../../stores/settings.js'
import { fetchClipboardContent } from '../../utils/clipboard.js'
import { isDarkTheme } from '../../utils/isDarkTheme.js'
import { parseSpecialSymbols } from '../../utils/textParse.js'

const disableKeyboardShortcuts = OCP.Accessibility.disableKeyboardShortcuts()
const supportTypingStatus = getCapabilities()?.spreed?.config?.chat?.['typing-privacy'] !== undefined
const canEditMessage = getCapabilities()?.spreed?.features?.includes('edit-messages')

export default {
name: 'NewMessage',
Expand All @@ -235,6 +244,7 @@ export default {
NcActions,
NcButton,
NcEmojiPicker,
NcNoteCard,
NcRichContenteditable,
NewMessageAbsenceInfo,
NewMessageAttachments,
Expand Down Expand Up @@ -452,6 +462,11 @@ export default {
chatEditInput() {
return this.chatExtrasStore.getChatEditInput(this.token)
},

showMentionEditHint() {
const mentionPattern = /(^|\s)@/
return mentionPattern.test(this.chatEditInput)
},
},

watch: {
Expand All @@ -461,7 +476,11 @@ export default {

text(newValue) {
if (this.messageToEdit) {
this.chatExtrasStore.setChatEditInput({ token: this.token, text: newValue })
this.chatExtrasStore.setChatEditInput({
token: this.token,
text: newValue,
parameters: this.messageToEdit.messageParameters
})
} else {
this.chatExtrasStore.setChatInput({ token: this.token, text: newValue })
}
Expand Down Expand Up @@ -599,12 +618,8 @@ export default {
}
}

// FIXME upstream: https://github.com/nextcloud-libraries/nextcloud-vue/issues/4492
if (this.hasText) {
const temp = document.createElement('textarea')
temp.innerHTML = this.text.replace(/&/gmi, '&amp;')
this.text = temp.value.replace(/&amp;/gmi, '&').replace(/&lt;/gmi, '<')
.replace(/&gt;/gmi, '>').replace(/&sect;/gmi, '§')
this.text = parseSpecialSymbols(this.text)
}

if (this.upload) {
Expand All @@ -628,7 +643,6 @@ export default {
token: this.token,
})
this.text = ''
this.resetTypingIndicator()
this.userData = {}
// Scrolls the message list to the last added message
EventBus.$emit('smooth-scroll-chat-to-bottom')
Expand All @@ -638,6 +652,7 @@ export default {
this.broadcast
? await this.broadcastMessage(this.token, temporaryMessage.message)
: await this.postMessage(this.token, temporaryMessage, options)
this.resetTypingIndicator()
}
},

Expand Down Expand Up @@ -683,8 +698,10 @@ export default {
})
this.$store.dispatch('processMessage', { token: this.token, message: response.data.ocs.data })
this.chatExtrasStore.removeMessageIdToEdit(this.token)
this.resetTypingIndicator()
} catch {
this.$emit('failure')
showError(t('spreed', 'The message could not be edited'))
}
},

Expand Down Expand Up @@ -909,11 +926,39 @@ export default {
},

handleInputEsc() {
if (this.messageToEdit && !this.isTributePickerActive) {
this.handleAbortEdit()
this.focusInput()
return
}
// When the tribute picker (e.g. emoji picker or mentions) is open
// ESC should only close the picker but not blur
if (!this.isTributePickerActive) {
this.blurInput()
}

},

handleEditLastMessage() {
if (!canEditMessage || this.upload || this.broadcast || this.isRecordingAudio) {
return
}
const lastMessageByCurrentUser = this.$store.getters.messagesList(this.token).findLast(message => {
return message.actorId === this.$store.getters.getUserId()
&& message.actorType === this.$store.getters.getActorType()
&& !message.isTemporary && !message.systemMessage
})

if (!lastMessageByCurrentUser) {
return
}

this.chatExtrasStore.initiateEditingMessage({
token: this.token,
id: lastMessageByCurrentUser.id,
message: lastMessageByCurrentUser.message,
messageParameters: lastMessageByCurrentUser.messageParameters,
})
},

async checkAbsenceStatus() {
Expand Down
6 changes: 6 additions & 0 deletions src/components/SettingsDialog/SettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@
{{ t('spreed', 'Unfocus the chat input to use shortcuts') }}
</dd>
</div>
<div>
<dt><kbd>Ctrl</kbd> + <kbd>↑</kbd></dt>
<dd class="shortcut-description">
{{ t('spreed', 'Edit your last message') }}
</dd>
</div>
<div>
<dt><kbd>F</kbd></dt>
<dd class="shortcut-description">
Expand Down
Loading
Loading