]> BookStack Code Mirror - bookstack/commitdiff
Merge branch 'Abijeet-master' to convert comment system to vue
authorDan Brown <redacted>
Sat, 2 Sep 2017 16:40:40 +0000 (17:40 +0100)
committerDan Brown <redacted>
Sat, 2 Sep 2017 16:40:40 +0000 (17:40 +0100)
resources/assets/js/controllers.js
resources/assets/js/directives.js
resources/assets/js/vues/components/comments/comment-reply.js [new file with mode: 0644]
resources/assets/js/vues/components/comments/comment.js [new file with mode: 0644]
resources/assets/js/vues/page-comments.js [new file with mode: 0644]
resources/assets/js/vues/vues.js
resources/lang/en/errors.php
resources/views/comments/comment-reply.blade.php [deleted file]
resources/views/comments/comments.blade.php
resources/views/comments/list-item.blade.php [deleted file]

index 8b37379fa18543cbeca92b542f61f88c1475ba6c..32ff76fa167bc9dad0a470a2429ed147ad4a3718 100644 (file)
@@ -144,226 +144,4 @@ module.exports = function (ngApp, events) {
         };
 
     }]);
-
-    // Controller used to reply to and add new comments
-    ngApp.controller('CommentReplyController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
-        const MarkdownIt = require("markdown-it");
-        const md = new MarkdownIt({html: true});
-        let vm = this;
-
-        vm.saveComment = function () {
-            let pageId = $scope.comment.pageId || $scope.pageId;
-            let comment = $scope.comment.text;
-            if (!comment) {
-                return events.emit('warning', trans('errors.empty_comment'));
-            }
-            let commentHTML = md.render($scope.comment.text);
-            let serviceUrl = `/ajax/page/${pageId}/comment/`;
-            let httpMethod = 'post';
-            let reqObj = {
-                text: comment,
-                html: commentHTML
-            };
-
-            if ($scope.isEdit === true) {
-                // this will be set when editing the comment.
-                serviceUrl = `/ajax/page/${pageId}/comment/${$scope.comment.id}`;
-                httpMethod = 'put';
-            } else if ($scope.isReply === true) {
-                // if its reply, get the parent comment id
-                reqObj.parent_id = $scope.parentId;
-            }
-            $http[httpMethod](window.baseUrl(serviceUrl), reqObj).then(resp => {
-                if (!isCommentOpSuccess(resp)) {
-                     return;
-                }
-                // hide the comments first, and then retrigger the refresh
-                if ($scope.isEdit) {
-                    updateComment($scope.comment, resp.data);
-                    $scope.$emit('evt.comment-success', $scope.comment.id);
-                } else {
-                    $scope.comment.text = '';
-                    if ($scope.isReply === true && $scope.parent.sub_comments) {
-                        $scope.parent.sub_comments.push(resp.data.comment);
-                    } else {
-                        $scope.$emit('evt.new-comment', resp.data.comment);
-                    }
-                    $scope.$emit('evt.comment-success', null, true);
-                }
-                $scope.comment.is_hidden = true;
-                $timeout(function() {
-                    $scope.comment.is_hidden = false;
-                });
-
-                events.emit('success', trans(resp.data.message));
-
-            }, checkError);
-
-        };
-
-        function checkError(response) {
-            let msg = null;
-            if (isCommentOpSuccess(response)) {
-                // all good
-                return;
-            } else if (response.data) {
-                msg = response.data.message;
-            } else {
-                msg = trans('errors.comment_add');
-            }
-            if (msg) {
-                events.emit('success', msg);
-            }
-        }
-    }]);
-
-    // Controller used to delete comments
-    ngApp.controller('CommentDeleteController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
-        let vm = this;
-
-        vm.delete = function(comment) {
-            $http.delete(window.baseUrl(`/ajax/comment/${comment.id}`)).then(resp => {
-                if (!isCommentOpSuccess(resp)) {
-                    return;
-                }
-                updateComment(comment, resp.data, $timeout, true);
-            }, function (resp) {
-                if (isCommentOpSuccess(resp)) {
-                    events.emit('success', trans('entities.comment_deleted'));
-                } else {
-                    events.emit('error', trans('error.comment_delete'));
-                }
-            });
-        };
-    }]);
-
-    // Controller used to fetch all comments for a page
-    ngApp.controller('CommentListController', ['$scope', '$http', '$timeout', '$location', function ($scope, $http, $timeout, $location) {
-        let vm = this;
-        $scope.errors = {};
-        // keep track of comment levels
-        $scope.level = 1;
-        vm.totalCommentsStr = trans('entities.comments_loading');
-        vm.permissions = {};
-        vm.trans = window.trans;
-
-        $scope.$on('evt.new-comment', function (event, comment) {
-            // add the comment to the comment list.
-            vm.comments.push(comment);
-            ++vm.totalComments;
-            setTotalCommentMsg();
-            event.stopPropagation();
-            event.preventDefault();
-        });
-
-        vm.canEditDelete = function (comment, prop) {
-            if (!comment.active) {
-                return false;
-            }
-            let propAll = prop + '_all';
-            let propOwn = prop + '_own';
-
-            if (vm.permissions[propAll]) {
-                return true;
-            }
-
-            if (vm.permissions[propOwn] && comment.created_by.id === vm.current_user_id) {
-                return true;
-            }
-
-            return false;
-        };
-
-        vm.canComment = function () {
-            return vm.permissions.comment_create;
-        };
-
-        // check if there are is any direct linking
-        let linkedCommentId = $location.search().cm;
-
-        $timeout(function() {
-            $http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/`)).then(resp => {
-                if (!isCommentOpSuccess(resp)) {
-                    // just show that no comments are available.
-                    vm.totalComments = 0;
-                    setTotalCommentMsg();
-                    return;
-                }
-                vm.comments = resp.data.comments;
-                vm.totalComments = +resp.data.total;
-                vm.permissions = resp.data.permissions;
-                vm.current_user_id = resp.data.user_id;
-                setTotalCommentMsg();
-                if (!linkedCommentId) {
-                    return;
-                }
-                $timeout(function() {
-                    // wait for the UI to render.
-                    focusLinkedComment(linkedCommentId);
-                });
-            }, checkError);
-        });
-
-        function setTotalCommentMsg () {
-            if (vm.totalComments === 0) {
-                vm.totalCommentsStr = trans('entities.no_comments');
-            } else if (vm.totalComments === 1) {
-                vm.totalCommentsStr = trans('entities.one_comment');
-            } else {
-                vm.totalCommentsStr = trans('entities.x_comments', {
-                    numComments: vm.totalComments
-                });
-            }
-        }
-
-        function focusLinkedComment(linkedCommentId) {
-            let comment = angular.element('#' + linkedCommentId);
-            if (comment.length === 0) {
-                return;
-            }
-
-            window.setupPageShow.goToText(linkedCommentId);
-        }
-
-        function checkError(response) {
-            let msg = null;
-            if (isCommentOpSuccess(response)) {
-                // all good
-                return;
-            } else if (response.data) {
-                msg = response.data.message;
-            } else {
-                msg = trans('errors.comment_list');
-            }
-            if (msg) {
-                events.emit('success', msg);
-            }
-        }
-    }]);
-
-    function updateComment(comment, resp, $timeout, 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;
-        }
-        if (!$timeout) {
-            return;
-        }
-        comment.is_hidden = true;
-        $timeout(function() {
-            comment.is_hidden = false;
-        });
-    }
-
-    function isCommentOpSuccess(resp) {
-        if (resp && resp.data && resp.data.status === 'success') {
-            return true;
-        }
-        return false;
-    }
 };
index 8813eb88183383c57f01923ad6d86d9d30276904..1f28673e1d080f0a9ad34e9e319ba0e2652397ef 100644 (file)
@@ -386,128 +386,4 @@ module.exports = function (ngApp, events) {
             }
         }
     }]);
-
-    ngApp.directive('commentReply', [function () {
-        return {
-            restrict: 'E',
-            templateUrl: 'comment-reply.html',
-            scope: {
-              pageId: '=',
-              parentId: '=',
-              parent: '='
-            },
-            link: function (scope, element) {
-                scope.isReply = true;
-                element.find('textarea').focus();
-                scope.$on('evt.comment-success', function (event) {
-                    // no need for the event to do anything more.
-                    event.stopPropagation();
-                    event.preventDefault();
-                    scope.closeBox();
-                });
-
-                scope.closeBox = function () {
-                    element.remove();
-                    scope.$destroy();
-                };
-            }
-        };
-    }]);
-
-    ngApp.directive('commentEdit', [function () {
-         return {
-            restrict: 'E',
-            templateUrl: 'comment-reply.html',
-            scope: {
-              comment: '='
-            },
-            link: function (scope, element) {
-                scope.isEdit = true;
-                element.find('textarea').focus();
-                scope.$on('evt.comment-success', function (event, commentId) {
-                   // no need for the event to do anything more.
-                   event.stopPropagation();
-                   event.preventDefault();
-                   if (commentId === scope.comment.id && !scope.isNew) {
-                       scope.closeBox();
-                   }
-                });
-
-                scope.closeBox = function () {
-                    element.remove();
-                    scope.$destroy();
-                };
-            }
-        };
-    }]);
-
-
-    ngApp.directive('commentReplyLink', ['$document', '$compile', function ($document, $compile) {
-        return {
-            scope: {
-                comment: '='
-            },
-            link: function (scope, element, attr) {
-                element.on('$destroy', function () {
-                    element.off('click');
-                    scope.$destroy();
-                });
-
-                element.on('click', function (e) {
-                    e.preventDefault();
-                    var $container = element.parents('.comment-actions').first();
-                    if (!$container.length) {
-                        console.error('commentReplyLink directive should be placed inside a container with class comment-box!');
-                        return;
-                    }
-                    if (attr.noCommentReplyDupe) {
-                        removeDupe();
-                    }
-
-                    compileHtml($container, scope, attr.isReply === 'true');
-                });
-            }
-        };
-
-        function compileHtml($container, scope, isReply) {
-            let lnkFunc = null;
-            if (isReply) {
-                lnkFunc = $compile('<comment-reply page-id="comment.pageId" parent-id="comment.id" parent="comment"></comment-reply>');
-            } else {
-                lnkFunc = $compile('<comment-edit comment="comment"></comment-add>');
-            }
-            var compiledHTML = lnkFunc(scope);
-            $container.append(compiledHTML);
-        }
-
-        function removeDupe() {
-            let $existingElement = $document.find('.comments-list comment-reply, .comments-list comment-edit');
-            if (!$existingElement.length) {
-                return;
-            }
-
-            $existingElement.remove();
-        }
-    }]);
-
-    ngApp.directive('commentDeleteLink', ['$window', function ($window) {
-        return {
-            controller: 'CommentDeleteController',
-            scope: {
-                comment: '='
-            },
-            link: function (scope, element, attr, ctrl) {
-
-                element.on('click', function(e) {
-                    e.preventDefault();
-                    var resp = $window.confirm(trans('entities.comment_delete_confirm'));
-                    if (!resp) {
-                        return;
-                    }
-
-                    ctrl.delete(scope.comment);
-                });
-            }
-        };
-    }]);
 };
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 (file)
index 0000000..0f65fc2
--- /dev/null
@@ -0,0 +1,113 @@
+const MarkdownIt = require("markdown-it");
+const md = new MarkdownIt({ html: true });
+
+var template = `
+<div class="comment-editor" v-cloak>
+<form novalidate>
+    <textarea name="markdown" rows="3" v-model="comment.text" :placeholder="trans('entities.comment_placeholder')"></textarea>
+    <input type="hidden" v-model="comment.pageId" name="comment.pageId" :value="pageId">
+    <button type="button" v-if="isReply || isEdit" class="button muted" v-on:click="closeBox">{{ trans('entities.comment_cancel') }}</button>
+    <button type="submit" class="button pos" v-on:click.prevent="saveComment">{{ trans('entities.comment_save') }}</button>
+</form>
+</div>
+`;
+
+const props = {
+    pageId: {},
+    commentObj: {},
+    isReply: {
+        default: false,
+        type: Boolean
+    }, isEdit: {
+        default: false,
+        type: Boolean
+    }
+};
+
+function data() {
+    let comment = {
+        text: ''
+    };
+
+    if (this.isReply) {
+        comment.page_id = this.commentObj.page_id;
+        comment.id = this.commentObj.id;
+    } else if (this.isEdit) {
+        comment = this.commentObj;
+    }
+
+    return {
+        comment: comment,
+        trans: trans
+    };
+}
+
+const methods = {
+    saveComment: function (event) {
+        let pageId = this.comment.page_id || this.pageId;
+        let commentText = this.comment.text;
+        if (!commentText) {
+            return this.$events.emit('error', trans('errors.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)) {
+                this.$events.emit('error', getErrorMsg(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.$events.emit('success', resp.data.message);
+        }).catch(err => {
+            this.$events.emit('error', trans('errors.comment_add'))
+        });
+    },
+    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 getErrorMsg(response) {
+    if (response.data) {
+        return response.data.message;
+    } else {
+        return trans('errors.comment_add');
+    }
+}
+
+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 (file)
index 0000000..419c0a5
--- /dev/null
@@ -0,0 +1,174 @@
+const commentReply = require('./comment-reply');
+
+const template = `
+<div class="comment-box">
+  <div class='page-comment' :id="commentId">
+  <div class="user-image">
+      <img :src="comment.created_by.avatar_url" alt="user avatar">
+  </div>
+  <div class="comment-container">
+      <div class="comment-header">
+          <a :href="comment.created_by.profile_url">{{comment.created_by.name}}</a>
+      </div>
+      <div v-html="comment.html" v-if="comment.active" class="comment-body" v-bind:class="{ 'comment-inactive' : !comment.active }">
+
+      </div>
+      <div v-if="!comment.active" class="comment-body comment-inactive">
+          {{ trans('entities.comment_deleted') }}
+      </div>
+      <div class="comment-actions">
+          <ul>
+              <li v-if="(level < 4 && canComment)">
+                <a href="#" comment="comment" v-on:click.prevent="replyComment">{{ trans('entities.comment_reply') }}</a>
+              </li>
+              <li v-if="canEditOrDelete('update')">
+                <a href="#" comment="comment" v-on:click.prevent="editComment">{{ trans('entities.comment_edit') }}</a>
+              </li>
+              <li v-if="canEditOrDelete('delete')">
+                <a href="#" comment="comment" v-on:click.prevent="deleteComment">{{ trans('entities.comment_delete') }}</a>
+              </li>
+              <li>{{ trans('entities.comment_create') }}
+                <a :title="comment.created.day_time_str" :href="commentHref">{{comment.created.diff}}</a>
+              </li>
+              <li v-if="comment.updated">
+                <span :title="comment.updated.day_time_str">{{trans('entities.comment_updated_text', { updateDiff: comment.updated.diff }) }}
+                      <a :href="comment.updated_by.profile_url">{{comment.updated_by.name}}</a>
+                </span>
+              </li>
+          </ul>
+      </div>
+      <div v-if="showEditor">
+        <comment-reply :page-id="comment.page_id" :comment-obj="comment"
+          v-on:editor-removed.stop.prevent="hideComment"
+          v-on:comment-replied.stop="commentReplied(...arguments)"
+          v-on:comment-edited.stop="commentEdited(...arguments)"
+          v-on:comment-added.stop="commentAdded"
+           :is-reply="isReply" :is-edit="isEdit">
+        </comment-reply>
+      </div>
+      <comment v-for="(comment, index) in comments" :initial-comment="comment" :index="index"
+        :level="nextLevel" :key="comment.id" :permissions="permissions" :current-user-id="currentUserId"
+        v-on:comment-added.stop="commentAdded"></comment>
+
+  </div>
+  </div>
+</div>
+`;
+
+const props = ['initialComment', 'index', 'level', 'permissions', 'currentUserId'];
+
+function data() {
+    return {
+        trans: trans,
+        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)) {
+                this.$events.emit('error', trans('error.comment_delete'));
+                return;
+            }
+            this.$events.emit('success', trans('entities.comment_deleted'));
+            this.comment = resp.data.comment;
+        }).catch(err => {
+            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);
+    },
+    canEditOrDelete: function (prop) {
+        if (!this.comment.active) {
+            return false;
+        }
+
+        if (!this.permissions) {
+            return false;
+        }
+
+        let propAll = 'comment_' + prop + '_all';
+        let propOwn = 'comment_' + prop + '_own';
+
+        if (this.permissions[propAll]) {
+            return true;
+        }
+
+        if (this.permissions[propOwn] && this.comment.created_by.id === this.currentUserId) {
+            return true;
+        }
+
+        return false;
+    },
+    canComment: function () {
+        if (!this.permissions) {
+            return false;
+        }
+        return this.permissions.comment_create === true;
+    }
+};
+
+const computed = {
+    commentId: function () {
+        return `comment-${this.comment.page_id}-${this.comment.id}`;
+    },
+    commentHref: function () {
+        return `#?cm=${this.commentId}`;
+    }
+};
+
+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;
+}
+
+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 (file)
index 0000000..e42cdbf
--- /dev/null
@@ -0,0 +1,117 @@
+const comment = require('./components/comments/comment');
+const commentReply = require('./components/comments/comment-reply');
+
+let data = {
+    totalCommentsStr: trans('entities.comments_loading'),
+    comments: [],
+    permissions: null,
+    currentUserId: 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 () {
+        if (!this.permissions) {
+            return false;
+        }
+        return this.permissions.comment_create === true;
+    }
+}
+
+function mounted() {
+    this.pageId = Number(this.$el.getAttribute('page-id'));
+    let linkedCommentId = getUrlParameter('cm');
+    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;
+            this.$events.emit('error', getErrorMsg(resp));
+            return;
+        }
+        this.comments = resp.data.comments;
+        this.totalComments = +resp.data.total;
+        this.permissions = resp.data.permissions;
+        this.currentUserId = resp.data.user_id;
+        if (!linkedCommentId) {
+            return;
+        }
+
+        // adding a setTimeout to give the comment list some time to render
+        // before focusing the comment.
+        setTimeout(function() {
+            focusLinkedComment(linkedCommentId);
+        });
+    }).catch(err => {
+        this.$events.emit('error', trans('errors.comment_list'));
+    });
+}
+
+function isCommentOpSuccess(resp) {
+    if (resp && resp.data && resp.data.status === 'success') {
+        return true;
+    }
+    return false;
+}
+
+function getErrorMsg(response) {
+    if (response.data) {
+        return response.data.message;
+    } else {
+        return trans('errors.comment_add');
+    }
+}
+
+function created() {
+    this.$on('new-comment', function (event, comment) {
+        this.comments.push(comment);
+    })
+}
+
+function beforeDestroy() {
+    this.$off('new-comment');
+}
+
+function getUrlParameter(name) {
+    name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
+    var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
+    var results = regex.exec(location.hash);
+    return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
+}
+
+function focusLinkedComment(linkedCommentId) {
+    let comment = document.getElementById(linkedCommentId);
+    if (comment && comment.length !== 0) {
+        window.setupPageShow.goToText(linkedCommentId);
+    }
+}
+
+module.exports = {
+    data, methods, mounted, computed, components: {
+        comment, commentReply
+    },
+    created, beforeDestroy
+};
\ No newline at end of file
index a70d32009a04a6747f68a4f4daf06d67b8ed31c2..d4c4c4574645b8136900fbd95a5691692acf536a 100644 (file)
@@ -11,6 +11,7 @@ let vueMapping = {
     'image-manager': require('./image-manager'),
     'tag-manager': require('./tag-manager'),
     'attachment-manager': require('./attachment-manager'),
+    'page-comments': require('./page-comments')
 };
 
 window.vues = {};
index 71bcd1f9aafbeb4186795ed444fd15dc5d137cec..09158caac04d696965d12e199c752a7409f42607 100644 (file)
@@ -63,7 +63,7 @@ return [
     // Comments
     'comment_list' => 'An error occurred while fetching the comments.',
     'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.',
-    'comment_add' => 'An error occurred while adding the comment.',
+    'comment_add' => 'An error occurred while adding / updating the comment.',
     'comment_delete' => 'An error occurred while deleting the comment.',
     'empty_comment' => 'Cannot add an empty comment.',
 
diff --git a/resources/views/comments/comment-reply.blade.php b/resources/views/comments/comment-reply.blade.php
deleted file mode 100644 (file)
index 0253534..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="comment-editor" ng-controller="CommentReplyController as vm" ng-cloak>
-    <form novalidate>
-        <textarea name="markdown" rows="3" ng-model="comment.text" placeholder="{{ trans('entities.comment_placeholder') }}"></textarea>
-        <input type="hidden" ng-model="comment.pageId" name="comment.pageId" value="{{$pageId}}" ng-init="comment.pageId = {{$pageId }}">
-        <button type="button" ng-if="::(isReply || isEdit)" class="button muted" ng-click="closeBox()">{{ trans('entities.comment_cancel') }}</button>
-        <button type="submit" class="button pos" ng-click="vm.saveComment()">{{ trans('entities.comment_save') }}</button>
-    </form>
-</div>
-
-@if($errors->has('markdown'))
-    <div class="text-neg text-small">{{ $errors->first('markdown') }}</div>
-@endif
\ No newline at end of file
index ffa75cfed227638fc72e1615c32803134994045e..fcf284b2655e7dc487c4e5cb6c8cd905c7644e12 100644 (file)
@@ -1,18 +1,11 @@
-<script type="text/ng-template" id="comment-list-item.html">
-    @include('comments/list-item')
-</script>
-<script type="text/ng-template" id="comment-reply.html">
-    @include('comments/comment-reply', ['pageId' => $pageId])
-</script>
-<div ng-controller="CommentListController as vm" ng-init="pageId = <?= $page->id ?>" class="comments-list" ng-cloak>
-<h3>@{{vm.totalCommentsStr}}</h3>
-<hr>
-    <div class="comment-box" ng-repeat="comment in vm.comments track by comment.id">
-        <div ng-include src="'comment-list-item.html'">
-
-        </div>
-    </div>
-    <div ng-if="::vm.canComment()">
-        @include('comments/comment-reply', ['pageId' => $pageId])
-    </div>
+<div id="page-comments" page-id="<?= $page->id ?>" class="comments-list" v-cloak>
+  <h3>@{{totalCommentsStr}}</h3>
+  <hr>
+  <comment v-for="(comment, index) in comments" :initial-comment="comment" :index="index" :level=1
+     v-on:comment-added.stop="commentAdded"
+     :current-user-id="currentUserId" :key="comment.id" :permissions="permissions"></comment>
+  <div v-if="canComment">
+     <comment-reply v-on:comment-added.stop="commentAdded" :page-id="<?= $page->id ?>">
+     </comment-reply>
+  </div>
 </div>
\ No newline at end of file
diff --git a/resources/views/comments/list-item.blade.php b/resources/views/comments/list-item.blade.php
deleted file mode 100644 (file)
index f274d2e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<div class='page-comment' id="comment-@{{::pageId}}-@{{::comment.id}}">
-    <div class="user-image">
-        <img ng-src="@{{::comment.created_by.avatar_url}}" alt="user avatar">
-    </div>
-    <div class="comment-container">
-        <div class="comment-header">
-            <a href="@{{::comment.created_by.profile_url}}">@{{ ::comment.created_by.name }}</a>
-        </div>
-        <div ng-bind-html="comment.html" ng-if="::comment.active" class="comment-body" ng-class="!comment.active ? 'comment-inactive' : ''">
-
-        </div>
-        <div ng-if="::!comment.active" class="comment-body comment-inactive">
-            {{ trans('entities.comment_deleted') }}
-        </div>
-        <div class="comment-actions">
-            <ul ng-if="!comment.is_hidden">
-                <li ng-if="::(level < 3 && vm.canComment())"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" is-reply="true">{{ trans('entities.comment_reply') }}</a></li>
-                <li ng-if="::vm.canEditDelete(comment, 'comment_update')"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" >{{ trans('entities.comment_edit') }}</a></li>
-                <li ng-if="::vm.canEditDelete(comment, 'comment_delete')"><a href="#" comment-delete-link comment="comment" >{{ trans('entities.comment_delete') }}</a></li>
-                <li>{{ trans('entities.comment_create') }} <a title="@{{::comment.created.day_time_str}}" href="#?cm=comment-@{{::pageId}}-@{{::comment.id}}">@{{::comment.created.diff}}</a></li>
-                <li ng-if="::comment.updated"><span title="@{{::comment.updated.day_time_str}}">@{{ ::vm.trans('entities.comment_updated_text', { updateDiff: comment.updated.diff }) }}
-                        <a href="@{{::comment.updated_by.profile_url}}">@{{::comment.updated_by.name}}</a></span></li>
-            </ul>
-        </div>
-        <div class="comment-box" ng-repeat="comment in comments = comment.sub_comments track by comment.id" ng-init="level = level + 1">
-            <div ng-include src="'comment-list-item.html'">
-            </div>
-        </div>
-    </div>
-</div>
\ No newline at end of file