· 8 years ago · Dec 07, 2017, 06:24 PM
1/*
2 kliment 1 aug 17
3 -begin
4
5 dsm 13 aug 17
6 -user_image "1/0000001-0000001%s.jpg" ==> http://my.brownhanky.com/file/pic/user/1/0000001-0000001_50_square.jpg
7 EG sprintf(user_image,'_50_square')
8 I would expect to put this a "user model". A utility function? A computed value?
9
10 -add comment does not update display
11 -delete should work?
12 -kill REPLY for now, the server side does not support threaded yet. <a>Reply</a> Hmm. Funny anchor.
13 -server sends timestamp. I guess you want "Hours ago" ?
14 -need an EDIT button (server side has update_comment ) Only show when owner=logged guy or role=UG_ADMIN
15 -"Load more" ==> Showing N on M. Load next P.
16
17
18
19 dsm 26 nov 17 : Review for threaded comments
20
21 1. Why is this a dumb component? Who is doing the heavy lifting? Presumably video view page.
22
23 2. Comments for all site sections are stored in the same table. Here type="video". Other types are "photo", "blog", "event","shop",...
24
25 So this component takes a type ("video) and an item_id (video_id)
26 On the blog page it would take type="blog" and item_id = blog_id
27
28CREATE TABLE IF NOT EXISTS `phpfox2_comment` (
29`comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
30`parent_id` int(10) unsigned NOT NULL DEFAULT '0',
31`type_id` varchar(75) NOT NULL,
32`item_id` int(10) unsigned NOT NULL,
33`user_id` int(10) unsigned NOT NULL,
34`owner_user_id` int(10) unsigned NOT NULL DEFAULT '0',
35`time_stamp` int(10) unsigned NOT NULL,
36`update_time` int(10) unsigned NOT NULL DEFAULT '0',
37`update_user` varchar(100) DEFAULT NULL,
38`rating` varchar(10) DEFAULT NULL,
39`ip_address` varchar(15) NOT NULL,
40`author` varchar(255) DEFAULT NULL,
41`author_email` varchar(100) DEFAULT NULL,
42`author_url` varchar(255) DEFAULT NULL,
43`view_id` tinyint(1) NOT NULL DEFAULT '0',
44`child_total` smallint(4) unsigned NOT NULL DEFAULT '0',
45`upgrade_item_id` int(11) DEFAULT NULL, DEPRECATED. WILL BE REMOVED.
46`total_like` int(10) unsigned NOT NULL DEFAULT '0',
47`total_dislike` int(10) unsigned NOT NULL DEFAULT '0',
48PRIMARY KEY (`comment_id`),
49KEY `user_id` (`user_id`,`view_id`),
50KEY `owner_user_id` (`owner_user_id`,`view_id`),
51KEY `type_id` (`type_id`,`item_id`,`view_id`),
52KEY `parent_id` (`parent_id`,`view_id`),
53KEY `parent_id_2` (`parent_id`,`type_id`,`item_id`,`view_id`),
54KEY `view_id` (`view_id`),
55KEY `upgrade_item_id` (`upgrade_item_id`)
56) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=605479 ;
57
58
59 What the fuck is the difference between owner, author and user? ! Wow. Who knows what they had in mind.
60 todo: find out and make sure we aren't breaking somwething we might want later. Yuck.
61
62 How do threaded comments work?
63 Looks like every comment has a parent_id, and every non-zero parent_id has a child_total.
64 So this is recursive. Any given reply, at any level, can have pages of data.
65
66
67 getComments( type, item_id, pageNo, pageSize) ==> {
68 "success": true,
69 "total": "2", // total dataset size
70 "data": [], // items
71 "count": 2, // items on current page
72 "iPage": 0, // current page
73 "iPageSize": 10 // page size
74 }
75 updateComment(comment_id,text)
76 deleteComment(comment_id)
77 addComment(parent_id, user_id, item_id, type, text)
78
79 1) Send type='video'
80 2) Send parent_id on add (0 for none)
81 3) child_total > 1 --> "Open replies" otherwise prompt is hidden
82 4) icons pencil=edit X=delete mail-reply=add mail-reply-all=open replies
83
84 How do you cancel "open replies" (need X or ESC or CANCEL button)?
85 Open replies does what? It opens edit box and duplicates original comment below edit box (why?)
86
87
88 Server side logic is complicated by feed and privacy.
89*/
90
91<template>
92 <div class="comments-thread">
93 <article class="media">
94 <figure class="media-left">
95 <p class="image is-64x64">
96 <img :src="thisUser && thisUser.avatar">
97 </p>
98 </figure>
99 <div class="media-content">
100 <div class="field">
101 <p class="control">
102 <textarea class="textarea" :placeholder="$t('xlat_add_your_comments')" v-model="newComment"></textarea>
103 </p>
104 </div>
105 <div class="field">
106 <p class="control">
107 <button class="button" @click="addComment">{{currentComment? $t('core.xlat_edit'): $t('core.xlat_post')}}</button>
108 </p>
109 </div>
110 </div>
111 </article>
112 <article class="media" v-for="(comment, index) in getComments()">
113 <figure class="media-left">
114 <p class="image is-64x64">
115 <a :href="'http://my.brownhanky.com/men/' + comment.user_name">
116 <img :src="getImageUrl(comment.user_image)">
117 </a>
118 </p>
119 </figure>
120 <div class="media-content">
121 <div class="content">
122 <div>
123 <strong>{{comment.user_name}}</strong> # {{comment.comment_id}} P {{comment.parent_id}}, C {{comment.child_total}}
124 <br>
125 <div v-html="convertText(comment.text)"></div>
126 <br>
127 <small>
128 <span v-if="(thisUser && thisUser.user_id == comment.user_id) || (thisUser && thisUser.role == '1')" ><a @click="deleteComment(comment)">Delete</a> · </span>
129 <span v-if="(thisUser && thisUser.user_id == comment.user_id) || (thisUser && thisUser.role == '1')" ><a @click="editComment(comment)">Edit</a> · </span>
130 {{comment.post_convert_time}}
131 <a @click="openThread(index, comment)"
132 v-if="comment.child_total > 0">Open replies ({{comment.child_total}})</a>
133 <a @click="openThread(index, comment)"
134 v-else>Post reply</a>
135 </small>
136 </div>
137 </div>
138 <comments-thread
139 v-if="openedThreads[index]" :comments="comment.thread"
140 :parent-comment-id="comment.comment_id"
141 :item-id="itemId"
142 :type="type"
143 :total-comments="comment.child_total"
144 :load-more-active="comment.child_total > comment.thread.length"
145 @new-comment="onNewComment($event, comment)"
146 @load-more="loadMoreThread(comment)"
147 @edit-comment="editChildComment($event, comment)"
148 ></comments-thread>
149 </div>
150
151 </article>
152 <h4 style="text-align: center; cursor: pointer;"
153 @click="loadMoreComments()"
154 v-if="loadMoreActive">
155 <!-- Aw fuck. I will be here all day. No help from phpStorm with this syntax gumbo -->
156 {{$t('xlat_showing_comments')}} {{comments.length}} {{$t('core.xlat_of')}} {{totalComments}}
157 <br />
158 <!-- Life is hard enough. We cannot pass this shit to google translate api. I do not have all day to code a tranlsation system. Wah.
159 {{$t('xlat.showing_comments', {current: comments.length, total: totalComments })}}
160 $KLIMENT i will connect the translations with the server API and search if there if translation exists
161 -->
162 <br /> {{$t('core.xlat_load_more', {limit: (totalComments - comments.length) < 10? (totalComments - comments.length): 10})}}</h4>
163
164 <h4 style="text-align: center;" v-if="!loadMoreActive">{{$t('xlat_no_more_comments')}}</h4>
165 <loading v-if="isLoading"></loading>
166 </div>
167</template>
168<script>
169 import {
170 addComment,
171 addComment2,
172 addThreadComment,
173 deleteComment,
174 editComment,
175 getCommentThread,
176 loadEditComment
177 } from "../../services/comments";
178 import {mapState} from 'vuex';
179 import Loading from '../loading/loading.vue';
180
181 export default {
182 components: {
183 Loading
184 },
185 name: 'comments-thread',
186 i18n: { // `i18n` option
187 messages: {
188 en: {
189 xlat_add_your_comments: 'Add your comments',
190 xlat_showing_comments: 'Showing comments',
191 xlat_no_more_comments: 'No more comments'
192 }
193 }
194 },
195 props: {
196 comments: {
197 type: Array
198 },
199 totalComments: {
200 type: Number
201 },
202 loadMoreActive: {
203 type: Boolean
204 },
205 itemId: { // what about photos, blogs, events and such? item_id = video_id
206 type: String
207 },
208 type: {
209 type: String
210 },
211 parentCommentId: {
212 // expected number got string. What is this thing? type: Number
213 // Why isnt the prop a comment row?
214 }
215 },
216 data: () => ({
217 openedThreads: {},
218 newComment: null,
219 currentComment: null,
220 isLoading: false
221 }),
222 computed: {
223 ...mapState({
224 thisUser: state => state.users.thisUser
225 })
226 },
227 methods: {
228 openThread(index, comment) {
229
230 this.$set(comment, 'thread', []);
231 if(comment.child_total > 0) {
232 this.isLoading = true;
233 getCommentThread({item_id: this.itemId, parent_id: comment.comment_id, type: this.type, page: 1, limit: 10}).then(res => {
234 this.$set(this.openedThreads, index, true);
235 this.$set(comment, 'thread', res.data);
236 this.$set(comment, 'child_total', parseInt(res.total));
237 this.isLoading = false;
238 }).catch(err => {
239 this.isLoading = true;
240 })
241 } else {
242 this.$set(this.openedThreads, index, true);
243 }
244
245 },
246 loadMoreComments() {
247 this.$emit('load-more');
248 },
249 loadMoreThread(comment) {
250 if(comment.child_total > comment.thread.length) {
251 let page = Math.floor(comment.thread.length/10) + 1;
252 this.isLoading = true;
253 getCommentThread({item_id: this.itemId, parent_id: comment.comment_id, type: this.type, page, limit: 10}).then(res => {
254 this.$set(comment, 'thread', [...comment.thread, ...res.data]);
255 this.$set(comment, 'child_total', parseInt(res.total));
256
257 console.log(comment.thread);
258 this.isLoading = false;
259 }).catch(err => {
260 this.isLoading = false;
261 })
262 }
263 },
264 getComments() {
265 return this.comments;
266 },
267 addComment() {
268 if(this.currentComment) {
269 this.isLoading = true;
270 editComment({
271 comment_id: this.currentComment.comment_id,
272 text: this.newComment
273 }).then(res => {
274
275 this.$emit('edit-comment', Object.assign({}, this.currentComment, res.data));
276 this.currentComment = null;
277 this.newComment = null;
278 this.isLoading = false;
279 }).catch(err => {
280 this.isLoading = false;
281 })
282
283 } else {
284
285 // There is no comment record.
286 // I don't get it. Who is feeding us comments?
287 // Props for comments is what : type="video" so we know what to add.
288 // Then we need to surface or emit "number of comments" since we can change it.
289
290 console.log('currentComment', this.currentComment) // undef
291 console.log('parentCommentId', this.parentCommentId) // valid but wrong type (is string should be int)
292
293 // I DO NOT UNDERSTAND "MORE CONTROL". SEEMS LIKE A PITA TO ME.
294 this.isLoading = true;
295 addComment2({item_id: this.itemId, type: this.type, parent_id: this.parentCommentId, text: this.newComment}).then(res => {
296 this.newComment = null;
297 this.$emit('new-comment', res.data);
298 this.isLoading = false;
299 }).catch(err => {
300 this.isLoading = false;
301 })
302
303
304// if (false){
305// //if comment has parent id that means that this comment thread is not root and belongs to comment
306// if(this.parentCommentId) {
307// addThreadComment({comment_id: this.videoId /* this.parentCommentId */, text: this.newComment})
308// .then(res => {
309// this.newComment = null;
310// this.$emit('new-comment', res.data);
311// })
312// } else {
313// addComment({video_id: this.videoId, text: this.newComment}).then(res => {
314// this.newComment = null;
315// this.$emit('new-comment', res.data);
316// })
317// }
318// }
319 }
320 },
321 editComment(comment) {
322 this.isLoading = true;
323 loadEditComment({comment_id: comment.comment_id}).then(res => {
324 this.currentComment = comment;
325 this.newComment = res.data.raw.decodeHTML();
326 this.isLoading = false;
327 }).catch(() => {
328 this.isLoading = false;
329 });
330 },
331
332 editChildComment(editedComment, parentComment) {
333 console.log(editedComment);
334 let comments = parentComment.thread.map(c => c.comment_id === editedComment.comment_id? editedComment: c);
335 this.$set(parentComment, 'thread', comments);
336 },
337 deleteComment(comment) {
338 this.isLoading = true;
339 deleteComment({comment_id: comment.comment_id}).then(res => {
340 this.$emit('delete-comment', comment);
341 this.$toasted.show('Comment successfully deleted');
342 this.isLoading = false;
343 }).catch(err => {
344 this.isLoading = false;
345 })
346 },
347 getImageUrl(url) {
348 // console.log('comments-th IMG URL', url); = comments-th IMG URL 8/1/3/0/0008130-0008130%s.jpg
349 //if(!url) return 'http://bulma.io/images/placeholders/128x128.png'; // dsm 18 aug 17
350 if(!url) return 'https://my.brownhanky.com/theme/frontend/bhank/style/bhank/image/noimage/profile_100.png';
351 return `https://my.brownhanky.com/file/pic/user/${url}`.replace('%s', '_50_square');
352 //todo add this in gateway and remove %s from api call
353 },
354 convertText(text) {
355 /* This has to be wrong */
356 return text.replace('http://', 'https://');
357 },
358 onNewComment(newComment, parentComment) {
359 if(!parentComment.thread) {
360 this.$set(parentComment, 'thread', []);
361 }
362 parentComment.thread.unshift(newComment);
363// this.$set(parentComment, 'thread', this.comments.thread);
364 }
365 }
366 }
367</script>
368<style lang="scss">
369 @import "comments";
370</style>