diff --git a/resources/assets/js/vues/components/comments/comment-reply.js b/resources/assets/js/vues/components/comments/comment-reply.js new file mode 100644 index 000000000..83cbdf467 --- /dev/null +++ b/resources/assets/js/vues/components/comments/comment-reply.js @@ -0,0 +1,125 @@ +const MarkdownIt = require("markdown-it"); +const md = new MarkdownIt({html: true}); + +var template = ` +
+
+ + + + +
+
+`; + +const props = { + pageId: {}, + commentObj: {}, + isReply: { + default: false, + type: Boolean + }, isEdit: { + default: false, + type: Boolean + }}; + +function data () { + var comment = null; + // initialize comment if not passed. + if (!this.commentObj || this.isReply) { + comment = { + text: '' + }; + + if (this.isReply) { + comment.page_id = this.commentObj.page_id; + comment.id = this.commentObj.id; + } + } else { + comment = this.commentObj; + } + + return { + trans: trans, + parentId: null, + comment: comment + }; +} + +const methods = { + saveComment: function (event) { + let pageId = this.comment.page_id || this.pageId; + let commentText = this.comment.text; + if (!commentText) { + return this.$emit('evt.empty-comment'); + } + let commentHTML = md.render(commentText); + let serviceUrl = `/ajax/page/${pageId}/comment/`; + let httpMethod = 'post'; + let reqObj = { + text: commentText, + html: commentHTML + }; + + if (this.isEdit === true) { + // this will be set when editing the comment. + serviceUrl = `/ajax/page/${pageId}/comment/${this.comment.id}`; + httpMethod = 'put'; + } else if (this.isReply === true) { + // if its reply, get the parent comment id + reqObj.parent_id = this.comment.id; + } + + $http[httpMethod](window.baseUrl(serviceUrl), reqObj).then(resp => { + if (!isCommentOpSuccess(resp)) { + return; + } + // hide the comments first, and then retrigger the refresh + if (this.isEdit) { + this.$emit('comment-edited', event, resp.data.comment); + } else { + this.comment.text = ''; + this.$emit('comment-added', event); + if (this.isReply === true) { + this.$emit('comment-replied', event, resp.data.comment); + } else { + this.$parent.$emit('new-comment', event, resp.data.comment); + } + this.$emit('evt.comment-success', null, true); + } + + }, checkError); + }, + closeBox: function (event) { + this.$emit('editor-removed', event); + } +}; + +const computed = {}; + +function isCommentOpSuccess(resp) { + if (resp && resp.data && resp.data.status === 'success') { + return true; + } + return false; +} + +function checkError(msgKey) { + return function(response) { + let msg = null; + if (isCommentOpSuccess(response)) { + // all good + return; + } else if (response.data) { + msg = response.data.message; + } else { + msg = trans(msgKey); + } + if (msg) { + events.emit('success', msg); + } + } +} + +module.exports = {name: 'comment-reply', template, data, props, methods, computed}; + diff --git a/resources/assets/js/vues/components/comments/comment.js b/resources/assets/js/vues/components/comments/comment.js new file mode 100644 index 000000000..4152ba61f --- /dev/null +++ b/resources/assets/js/vues/components/comments/comment.js @@ -0,0 +1,174 @@ +const commentReply = require('./comment-reply'); + +const template = ` +
+
+
+ user avatar +
+
+ +
+ +
+
+ {{ trans('entities.comment_deleted') }} +
+
+ +
+
+ + +
+ + +
+
+
+`; + +const props = ['initialComment', 'index', 'level']; + +function data () { + return { + trans: trans, + commentHref: null, + comments: [], + showEditor: false, + comment: this.initialComment, + nextLevel: this.level + 1 + }; +} + +const methods = { + deleteComment: function () { + var resp = window.confirm(trans('entities.comment_delete_confirm')); + if (!resp) { + return; + } + this.$http.delete(window.baseUrl(`/ajax/comment/${this.comment.id}`)).then(resp => { + if (!isCommentOpSuccess(resp)) { + return; + } + updateComment(this.comment, resp.data, true); + }, function (resp) { + if (isCommentOpSuccess(resp)) { + this.$events.emit('success', trans('entities.comment_deleted')); + } else { + this.$events.emit('error', trans('error.comment_delete')); + } + }); + }, + replyComment: function () { + this.toggleEditor(false); + }, + editComment: function () { + this.toggleEditor(true); + }, + hideComment: function () { + this.showEditor = false; + }, + toggleEditor: function (isEdit) { + this.showEditor = false; + this.isEdit = isEdit; + this.isReply = !isEdit; + this.showEditor = true; + }, + commentReplied: function (event, comment) { + this.comments.push(comment); + this.showEditor = false; + }, + commentEdited: function (event, comment) { + this.comment = comment; + this.showEditor = false; + }, + commentAdded: function (event, comment) { + // this is to handle non-parent child relationship + // we want to make it go up. + this.$emit('comment-added', event); + } +}; + +const computed = { + commentId: { + get: function () { + return `comment-${this.comment.page_id}-${this.comment.id}`; + }, + set: function () { + this.commentHref = `#?cm=${this.commentId}` + } + }, + canUpdate: function () { + return true; + }, + canDelete: function () { + return true; + }, + canComment: function () { + return true; + }, + canUpdate: function () { + return true; + } +}; + +function mounted () { + if (this.comment.sub_comments && this.comment.sub_comments.length) { + // set this so that we can render the next set of sub comments. + this.comments = this.comment.sub_comments; + } +} + +function isCommentOpSuccess(resp) { + if (resp && resp.data && resp.data.status === 'success') { + return true; + } + return false; +} + +function updateComment(comment, resp, isDelete) { + comment.text = resp.comment.text; + comment.updated = resp.comment.updated; + comment.updated_by = resp.comment.updated_by; + comment.active = resp.comment.active; + if (isDelete && !resp.comment.active) { + comment.html = trans('entities.comment_deleted'); + } else { + comment.html = resp.comment.html; + } +} + +module.exports = { + name: 'comment', + template, data, props, methods, computed, mounted, components: { + commentReply +}}; + diff --git a/resources/assets/js/vues/page-comments.js b/resources/assets/js/vues/page-comments.js new file mode 100644 index 000000000..fd0ed6826 --- /dev/null +++ b/resources/assets/js/vues/page-comments.js @@ -0,0 +1,109 @@ +const comment = require('./components/comments/comment'); +const commentReply = require('./components/comments/comment-reply'); + +// 1. Remove code from controllers +// 2. Remove code from services. +// 3. + +let data = { + totalCommentsStr: trans('entities.comments_loading'), + comments: [], + permissions: null, + current_user_id: null, + trans: trans, + commentCount: 0 +}; + +let methods = { + commentAdded: function () { + ++this.totalComments; + } +} + +let computed = { + totalComments: { + get: function () { + return this.commentCount; + }, + set: function (value) { + this.commentCount = value; + if (value === 0) { + this.totalCommentsStr = trans('entities.no_comments'); + } else if (value === 1) { + this.totalCommentsStr = trans('entities.one_comment'); + } else { + this.totalCommentsStr = trans('entities.x_comments', { + numComments: value + }); + } + } + }, + canComment: function () { + return true; + } +} + +function mounted() { + this.pageId = Number(this.$el.getAttribute('page-id')); + // let linkedCommentId = this.$route.query.cm; + let linkedCommentId = null; + this.$http.get(window.baseUrl(`/ajax/page/${this.pageId}/comments/`)).then(resp => { + if (!isCommentOpSuccess(resp)) { + // just show that no comments are available. + vm.totalComments = 0; + return; + } + this.comments = resp.data.comments; + this.totalComments = +resp.data.total; + this.permissions = resp.data.permissions; + this.current_user_id = resp.data.user_id; + if (!linkedCommentId) { + return; + } + $timeout(function() { + // wait for the UI to render. + focusLinkedComment(linkedCommentId); + }); + }, checkError('errors.comment_list')); +} + +function isCommentOpSuccess(resp) { + if (resp && resp.data && resp.data.status === 'success') { + return true; + } + return false; +} + +function checkError(msgKey) { + return function(response) { + let msg = null; + if (isCommentOpSuccess(response)) { + // all good + return; + } else if (response.data) { + msg = response.data.message; + } else { + msg = trans(msgKey); + } + if (msg) { + events.emit('success', msg); + } + } +} + +function created () { + this.$on('new-comment', function (event, comment) { + this.comments.push(comment); + }) +} + +function beforeDestroy() { + this.$off('new-comment'); +} + +module.exports = { + data, methods, mounted, computed, components : { + comment, commentReply + }, + created, beforeDestroy +}; \ No newline at end of file