diff options
Diffstat (limited to 'apps/comments/src/components/Comment.vue')
-rw-r--r-- | apps/comments/src/components/Comment.vue | 145 |
1 files changed, 81 insertions, 64 deletions
diff --git a/apps/comments/src/components/Comment.vue b/apps/comments/src/components/Comment.vue index 912eeb28748..80f035530fb 100644 --- a/apps/comments/src/components/Comment.vue +++ b/apps/comments/src/components/Comment.vue @@ -1,27 +1,10 @@ <!-- - - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com> - - - - @author John Molakvoæ <skjnldsv@protonmail.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - This program 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 Affero General Public License for more details. - - - - You should have received a copy of the GNU Affero General Public License - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <component :is="tag" - v-show="!deleted" + v-show="!deleted && !isLimbo" :class="{'comment--loading': loading}" class="comment"> <!-- Comment header toolbar --> @@ -40,22 +23,27 @@ show if we have a message id and current user is author --> <NcActions v-if="isOwnComment && id && !loading" class="comment__actions"> <template v-if="!editing"> - <NcActionButton :close-after-click="true" - icon="icon-rename" + <NcActionButton close-after-click @click="onEdit"> + <template #icon> + <IconPencilOutline :size="20" /> + </template> {{ t('comments', 'Edit comment') }} </NcActionButton> <NcActionSeparator /> - <NcActionButton :close-after-click="true" - icon="icon-delete" + <NcActionButton close-after-click @click="onDeleteWithUndo"> + <template #icon> + <IconTrashCanOutline :size="20" /> + </template> {{ t('comments', 'Delete comment') }} </NcActionButton> </template> - <NcActionButton v-else - icon="icon-close" - @click="onEditCancel"> + <NcActionButton v-else @click="onEditCancel"> + <template #icon> + <IconClose :size="20" /> + </template> {{ t('comments', 'Cancel edit') }} </NcActionButton> </NcActions> @@ -90,8 +78,8 @@ :disabled="isEmptyMessage" @click="onSubmit"> <template #icon> - <span v-if="loading" class="icon-loading-small" /> - <ArrowRight v-else :size="20" /> + <NcLoadingIcon v-if="loading" /> + <IconArrowRight v-else :size="20" /> </template> </NcButton> </div> @@ -102,14 +90,12 @@ </form> <!-- Message content --> - <!-- The html is escaped and sanitized before rendering --> - <!-- eslint-disable vue/no-v-html--> - <div v-else - :class="{'comment__message--expanded': expanded}" + <NcRichText v-else class="comment__message" - @click="onExpand" - v-html="renderedContent" /> - <!-- eslint-enable vue/no-v-html--> + :class="{'comment__message--expanded': expanded}" + :text="richContent.message" + :arguments="richContent.mentions" + @click="onExpand" /> </div> </component> </template> @@ -118,34 +104,47 @@ import { getCurrentUser } from '@nextcloud/auth' import { translate as t } from '@nextcloud/l10n' -import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' -import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' -import NcActionSeparator from '@nextcloud/vue/dist/Components/NcActionSeparator.js' -import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' -import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' -import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js' -import RichEditorMixin from '@nextcloud/vue/dist/Mixins/richEditor.js' -import ArrowRight from 'vue-material-design-icons/ArrowRight.vue' +import NcActionButton from '@nextcloud/vue/components/NcActionButton' +import NcActions from '@nextcloud/vue/components/NcActions' +import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator' +import NcAvatar from '@nextcloud/vue/components/NcAvatar' +import NcButton from '@nextcloud/vue/components/NcButton' +import NcDateTime from '@nextcloud/vue/components/NcDateTime' +import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' +import NcUserBubble from '@nextcloud/vue/components/NcUserBubble' + +import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue' +import IconClose from 'vue-material-design-icons/Close.vue' +import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue' +import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue' import CommentMixin from '../mixins/CommentMixin.js' +import { mapStores } from 'pinia' +import { useDeletedCommentLimbo } from '../store/deletedCommentLimbo.js' // Dynamic loading -const NcRichContenteditable = () => import('@nextcloud/vue/dist/Components/NcRichContenteditable.js') +const NcRichContenteditable = () => import('@nextcloud/vue/components/NcRichContenteditable') +const NcRichText = () => import('@nextcloud/vue/components/NcRichText') export default { name: 'Comment', components: { - ArrowRight, + IconArrowRight, + IconClose, + IconTrashCanOutline, + IconPencilOutline, NcActionButton, NcActions, NcActionSeparator, NcAvatar, NcButton, NcDateTime, + NcLoadingIcon, NcRichContenteditable, + NcRichText, }, - mixins: [RichEditorMixin, CommentMixin], + mixins: [CommentMixin], inheritAttrs: false, @@ -178,6 +177,10 @@ export default { type: Function, required: true, }, + userData: { + type: Object, + default: () => ({}), + }, tag: { type: String, @@ -196,6 +199,7 @@ export default { }, computed: { + ...mapStores(useDeletedCommentLimbo), /** * Is the current user the author of this comment @@ -206,16 +210,25 @@ export default { return getCurrentUser().uid === this.actorId }, - /** - * Rendered content as html string - * - * @return {string} - */ - renderedContent() { - if (this.isEmptyMessage) { - return '' - } - return this.renderContent(this.localMessage) + richContent() { + const mentions = {} + let message = this.localMessage + + Object.keys(this.userData).forEach((user, index) => { + const key = `mention-${index}` + const regex = new RegExp(`@${user}|@"${user}"`, 'g') + message = message.replace(regex, `{${key}}`) + mentions[key] = { + component: NcUserBubble, + props: { + user, + displayName: this.userData[user].label, + primary: this.userData[user].primary, + }, + } + }) + + return { mentions, message } }, isEmptyMessage() { @@ -228,6 +241,10 @@ export default { timestamp() { return Date.parse(this.creationDateTime) }, + + isLimbo() { + return this.deletedCommentLimboStore.checkForId(this.id) + }, }, watch: { @@ -312,7 +329,7 @@ $comment-padding: 10px; } &__actions { - margin-left: $comment-padding !important; + margin-inline-start: $comment-padding !important; } &__author { @@ -324,8 +341,8 @@ $comment-padding: 10px; &_loading, &__timestamp { - margin-left: auto; - text-align: right; + margin-inline-start: auto; + text-align: end; white-space: nowrap; color: var(--color-text-maxcontrast); } @@ -341,13 +358,13 @@ $comment-padding: 10px; &__submit { position: absolute !important; - bottom: 0; - right: 0; + bottom: 5px; + inset-inline-end: 0; } &__message { white-space: pre-wrap; - word-break: break-word; + word-break: normal; max-height: 70px; overflow: hidden; margin-top: -6px; |