aboutsummaryrefslogtreecommitdiff
path: root/resources/vue/components/blubber/Comment.vue
blob: a91648d46d707e96f3a3235c750bcd9d31efa165 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<template>
    <li :class="{ 'talk-bubble-own-post': ownComment }" class="talk-bubble-wrapper">
        <div v-if="!ownComment" class="talk-bubble-avatar">
            <a :href="userProfileURL" :title="comment.author['formatted-name']">
                <img :src="commentAvatar" />
            </a>
        </div>
        <div class="talk-bubble" :class="{ editing }">
            <div class="talk-bubble-content">
                <header v-if="!ownComment" class="talk-bubble-header">
                    <a :href="userProfileURL">{{ comment.author['formatted-name'] }}</a>
                </header>
                <div class="talk-bubble-talktext">
                    <template v-if="!editing">
                        <div ref="html" v-html="comment['content-html']" class="html"></div>
                        <div class="talk-bubble-footer">
                            <span class="talk-bubble-talktext-time"><studip-date-time :timestamp="commentMkdate"
                                    :relative="true"></studip-date-time></span>
                            <a href="#" v-if="comment['is-writable']" @click.prevent.stop="editComment" class="edit_comment"
                                :title="$gettext('Bearbeiten')">
                                <studip-icon shape="edit" :size="14" />
                            </a>
                            <a href="#" @click.prevent="answerComment" class="answer_comment"
                                :title="$gettext('Hierauf antworten')">
                                <studip-icon shape="reply" :size="14" />
                            </a>

                        </div>
                    </template>
                    <div v-else class="talk-bubble-edit">
                        <textarea
                            v-model="localText"
                            ref="textarea"
                            @input="setTextareaSize"
                            @focus="setTextareaSize"
                            @keydown.enter.exact.prevent="saveComment"
                            @keyup.escape.exact="doneEditing"
                        ></textarea>
                        <button @click="saveComment" :title="$gettext('Speichern')">
                            <studip-icon shape="accept" />
                        </button>
                        <button @click="doneEditing" :title="$gettext('Abbrechen')">
                            <studip-icon shape="decline" />
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </li>
</template>

<script>
export default {
    name: 'BlubberComment',
    emits: ['answer-comment', 'change-comment', 'edit-comment', 'remove-comment'],
    data: () => ({
        localText: '',
        commentWidth: 0,
    }),
    props: {
        comment: {
            type: Object,
            required: true,
        },
        editing: {
            type: Boolean,
            default: false,
        },
    },
    computed: {
        commentAvatar() {
            return this.comment.author?.avatar.medium ?? '';
        },
        commentClass() {
            return this.comment.isMine() ? 'mine' : 'theirs';
        },
        commentMkdate() {
            return new Date(this.comment.mkdate) / 1000;
        },
        userProfileURL() {
            const user_id = this.comment.author.id;
            const username = this.comment.author.username;
            if (username) {
                return window.STUDIP.URLHelper.getURL('dispatch.php/profile', { username });
            } else {
                return window.STUDIP.URLHelper.getURL('dispatch.php/profile/extern/' + user_id);
            }
        },
        ownComment() {
            return this.comment.isMine();
        }
    },
    methods: {
        answerComment() {
            this.$emit('answer-comment', this.comment);
        },
        editComment() {
            this.$emit('edit-comment', this.comment);
            this.resetContent();
            this.focusContent();
        },
        doneEditing() {
            this.resetContent();
            this.$emit('edit-comment', null);
        },
        focusContent() {
            this.$nextTick(() => {
                const textarea = this.$refs.textarea;
                textarea.focus();
                textarea.setSelectionRange(textarea.value.length, textarea.value.length);
            });
        },
        resetContent() {
            this.localText = this.comment.content;
        },
        saveComment() {
            if (this.localText.trim().length > 0) {
                this.$emit('change-comment', { ...this.comment, content: this.localText });
            } else {
                this.$emit('remove-comment', this.comment);
            }
        },
        setTextareaSize() {
            const textarea = this.$refs.textarea;
            const style = getComputedStyle(textarea);
            const height = textarea.scrollHeight - parseInt(style.paddingTop, 10) - parseInt(style.paddingBottom, 10);

            textarea.style.width = this.commentWidth + 'px';
            textarea.style.height = height + 'px';
        }
    },
    mounted() {
        this.resetContent();
        this.$nextTick(() => {
            window.STUDIP.Markup.element(this.$refs.html);
            this.commentWidth = this.$refs.html.offsetWidth;
        });
    },
    watch: {
        editing(newValue, oldValue) {
            if (!oldValue && newValue) {
                this.focusContent();
            }
        },
    },
};
</script>