]> BookStack Code Mirror - bookstack/blob - resources/assets/js/vues/components/comments/comment.js
Fixed formatting and added error messages.
[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         commentHref: null,
63         trans: trans,
64         comments: [],
65         showEditor: false,
66         comment: this.initialComment,
67         nextLevel: this.level + 1
68     };
69 }
70
71 const methods = {
72     deleteComment: function () {
73         var resp = window.confirm(trans('entities.comment_delete_confirm'));
74         if (!resp) {
75             return;
76         }
77         this.$http.delete(window.baseUrl(`/ajax/comment/${this.comment.id}`)).then(resp => {
78             if (!isCommentOpSuccess(resp)) {
79                 this.$events.emit('error', trans('error.comment_delete'));
80                 return;
81             }
82             this.$events.emit('success', trans('entities.comment_deleted'));
83             this.comment = resp.data.comment;
84         }).catch(err => {
85             this.$events.emit('error', trans('error.comment_delete'));
86         });
87     },
88     replyComment: function () {
89         this.toggleEditor(false);
90     },
91     editComment: function () {
92         this.toggleEditor(true);
93     },
94     hideComment: function () {
95         this.showEditor = false;
96     },
97     toggleEditor: function (isEdit) {
98         this.showEditor = false;
99         this.isEdit = isEdit;
100         this.isReply = !isEdit;
101         this.showEditor = true;
102     },
103     commentReplied: function (event, comment) {
104         this.comments.push(comment);
105         this.showEditor = false;
106     },
107     commentEdited: function (event, comment) {
108         this.comment = comment;
109         this.showEditor = false;
110     },
111     commentAdded: function (event, comment) {
112         // this is to handle non-parent child relationship
113         // we want to make it go up.
114         this.$emit('comment-added', event);
115     },
116     canEditOrDelete: function (prop) {
117         if (!this.comment.active) {
118             return false;
119         }
120
121         if (!this.permissions) {
122             return false;
123         }
124
125         let propAll = 'comment_' + prop + '_all';
126         let propOwn = 'comment_' + prop + '_own';
127
128         if (this.permissions[propAll]) {
129             return true;
130         }
131
132         if (this.permissions[propOwn] && this.comment.created_by.id === this.currentUserId) {
133             return true;
134         }
135
136         return false;
137     },
138     canComment: function () {
139         if (!this.permissions) {
140             return false;
141         }
142         return this.permissions.comment_create === true;
143     }
144 };
145
146 const computed = {
147     commentId: {
148         get: function () {
149             return `comment-${this.comment.page_id}-${this.comment.id}`;
150         },
151         set: function () {
152             this.commentHref = `#?cm=${this.commentId}`
153         }
154     }
155 };
156
157 function mounted() {
158     if (this.comment.sub_comments && this.comment.sub_comments.length) {
159         // set this so that we can render the next set of sub comments.
160         this.comments = this.comment.sub_comments;
161     }
162 }
163
164 function isCommentOpSuccess(resp) {
165     if (resp && resp.data && resp.data.status === 'success') {
166         return true;
167     }
168     return false;
169 }
170
171 module.exports = {
172     name: 'comment',
173     template, data, props, methods, computed, mounted, components: {
174         commentReply
175     }
176 };
177