]> BookStack Code Mirror - bookstack/blob - resources/assets/js/vues/components/comments/comment.js
419c0a5fa9890f00affeb64f4694a99acff16744
[bookstack] / resources / assets / js / vues / components / comments / comment.js
1 const commentReply = require('./comment-reply');
2
3 const template = `
4 <div class="comment-box">
5   <div class='page-comment' :id="commentId">
6   <div class="user-image">
7       <img :src="comment.created_by.avatar_url" alt="user avatar">
8   </div>
9   <div class="comment-container">
10       <div class="comment-header">
11           <a :href="comment.created_by.profile_url">{{comment.created_by.name}}</a>
12       </div>
13       <div v-html="comment.html" v-if="comment.active" class="comment-body" v-bind:class="{ 'comment-inactive' : !comment.active }">
14
15       </div>
16       <div v-if="!comment.active" class="comment-body comment-inactive">
17           {{ trans('entities.comment_deleted') }}
18       </div>
19       <div class="comment-actions">
20           <ul>
21               <li v-if="(level < 4 && canComment)">
22                 <a href="#" comment="comment" v-on:click.prevent="replyComment">{{ trans('entities.comment_reply') }}</a>
23               </li>
24               <li v-if="canEditOrDelete('update')">
25                 <a href="#" comment="comment" v-on:click.prevent="editComment">{{ trans('entities.comment_edit') }}</a>
26               </li>
27               <li v-if="canEditOrDelete('delete')">
28                 <a href="#" comment="comment" v-on:click.prevent="deleteComment">{{ trans('entities.comment_delete') }}</a>
29               </li>
30               <li>{{ trans('entities.comment_create') }}
31                 <a :title="comment.created.day_time_str" :href="commentHref">{{comment.created.diff}}</a>
32               </li>
33               <li v-if="comment.updated">
34                 <span :title="comment.updated.day_time_str">{{trans('entities.comment_updated_text', { updateDiff: comment.updated.diff }) }}
35                       <a :href="comment.updated_by.profile_url">{{comment.updated_by.name}}</a>
36                 </span>
37               </li>
38           </ul>
39       </div>
40       <div v-if="showEditor">
41         <comment-reply :page-id="comment.page_id" :comment-obj="comment"
42           v-on:editor-removed.stop.prevent="hideComment"
43           v-on:comment-replied.stop="commentReplied(...arguments)"
44           v-on:comment-edited.stop="commentEdited(...arguments)"
45           v-on:comment-added.stop="commentAdded"
46            :is-reply="isReply" :is-edit="isEdit">
47         </comment-reply>
48       </div>
49       <comment v-for="(comment, index) in comments" :initial-comment="comment" :index="index"
50         :level="nextLevel" :key="comment.id" :permissions="permissions" :current-user-id="currentUserId"
51         v-on:comment-added.stop="commentAdded"></comment>
52
53   </div>
54   </div>
55 </div>
56 `;
57
58 const props = ['initialComment', 'index', 'level', 'permissions', 'currentUserId'];
59
60 function data() {
61     return {
62         trans: trans,
63         comments: [],
64         showEditor: false,
65         comment: this.initialComment,
66         nextLevel: this.level + 1
67     };
68 }
69
70 const methods = {
71     deleteComment: function () {
72         var resp = window.confirm(trans('entities.comment_delete_confirm'));
73         if (!resp) {
74             return;
75         }
76         this.$http.delete(window.baseUrl(`/ajax/comment/${this.comment.id}`)).then(resp => {
77             if (!isCommentOpSuccess(resp)) {
78                 this.$events.emit('error', trans('error.comment_delete'));
79                 return;
80             }
81             this.$events.emit('success', trans('entities.comment_deleted'));
82             this.comment = resp.data.comment;
83         }).catch(err => {
84             this.$events.emit('error', trans('error.comment_delete'));
85         });
86     },
87     replyComment: function () {
88         this.toggleEditor(false);
89     },
90     editComment: function () {
91         this.toggleEditor(true);
92     },
93     hideComment: function () {
94         this.showEditor = false;
95     },
96     toggleEditor: function (isEdit) {
97         this.showEditor = false;
98         this.isEdit = isEdit;
99         this.isReply = !isEdit;
100         this.showEditor = true;
101     },
102     commentReplied: function (event, comment) {
103         this.comments.push(comment);
104         this.showEditor = false;
105     },
106     commentEdited: function (event, comment) {
107         this.comment = comment;
108         this.showEditor = false;
109     },
110     commentAdded: function (event, comment) {
111         // this is to handle non-parent child relationship
112         // we want to make it go up.
113         this.$emit('comment-added', event);
114     },
115     canEditOrDelete: function (prop) {
116         if (!this.comment.active) {
117             return false;
118         }
119
120         if (!this.permissions) {
121             return false;
122         }
123
124         let propAll = 'comment_' + prop + '_all';
125         let propOwn = 'comment_' + prop + '_own';
126
127         if (this.permissions[propAll]) {
128             return true;
129         }
130
131         if (this.permissions[propOwn] && this.comment.created_by.id === this.currentUserId) {
132             return true;
133         }
134
135         return false;
136     },
137     canComment: function () {
138         if (!this.permissions) {
139             return false;
140         }
141         return this.permissions.comment_create === true;
142     }
143 };
144
145 const computed = {
146     commentId: function () {
147         return `comment-${this.comment.page_id}-${this.comment.id}`;
148     },
149     commentHref: function () {
150         return `#?cm=${this.commentId}`;
151     }
152 };
153
154 function mounted() {
155     if (this.comment.sub_comments && this.comment.sub_comments.length) {
156         // set this so that we can render the next set of sub comments.
157         this.comments = this.comment.sub_comments;
158     }
159 }
160
161 function isCommentOpSuccess(resp) {
162     if (resp && resp.data && resp.data.status === 'success') {
163         return true;
164     }
165     return false;
166 }
167
168 module.exports = {
169     name: 'comment',
170     template, data, props, methods, computed, mounted, components: {
171         commentReply
172     }
173 };
174