#47 - Adds functionality to display child comments. Also has some code towards the reply functionality.

This commit is contained in:
Abijeet 2017-04-27 02:35:29 +05:30
parent d447355a61
commit c3ea0d333e
12 changed files with 127 additions and 34 deletions

View File

@ -34,8 +34,8 @@ class Comment extends Ownable
return $this->belongsTo(User::class);
}
public function getParentCommentsByPage($pageId, $pageNum = 0, $limit = 0) {
$data = ['pageId' => $pageId];
public function getCommentsByPage($pageId, $commentId, $pageNum = 0, $limit = 0) {
$query = static::newQuery();
$query->join('users AS u', 'comments.created_by', '=', 'u.id');
$query->leftJoin('users AS u1', 'comments.updated_by', '=', 'u1.id');
@ -44,7 +44,12 @@ class Comment extends Ownable
. 'u.name AS created_by_name, u1.name AS updated_by_name, '
. '(SELECT count(c.id) FROM bookstack.comments c WHERE c.parent_id = comments.id AND page_id = ?) AS cnt_sub_comments, i.url AS avatar ',
[$pageId]);
$query->whereRaw('page_id = ? AND parent_id IS NULL', [$pageId]);
if (empty($commentId)) {
$query->whereRaw('page_id = ? AND parent_id IS NULL', [$pageId]);
} else {
$query->whereRaw('page_id = ? AND parent_id = ?', [$pageId, $commentId]);
}
$query->orderBy('created_at');
return $query;
}

View File

@ -85,7 +85,11 @@ class CommentController extends Controller
$this->checkOwnablePermission('page-view', $page);
$comments = $this->commentRepo->getCommentsForPage($pageId, $commentId);
if (empty($commentId)) {
// requesting for parent level comments, send the total count as well.
$totalComments = $this->commentRepo->getCommentCount($pageId);
return response()->json(array('success' => true, 'comments'=> $comments, 'total' => $totalComments));
}
return response()->json(array('success' => true, 'comments'=> $comments));
}
}

View File

@ -38,14 +38,13 @@ class CommentRepo {
return $comment;
}
public function getCommentsForPage($pageId, $commentId, $count = 20) {
if (empty($commentId)) {
// requesting parent comments
$query = $this->comment->getParentCommentsByPage($pageId);
return $query->paginate($count);
} else {
// requesting the child comments.
return Comment::whereRaw("page_id = $pageId AND parent_id = $commentId")->get();
}
public function getCommentsForPage($pageId, $commentId, $count = 20) {
// requesting parent comments
$query = $this->comment->getCommentsByPage($pageId, $commentId);
return $query->paginate($count);
}
public function getCommentCount($pageId) {
return $this->comment->where('page_id', '=', $pageId)->count();
}
}

View File

@ -1,3 +1,5 @@
'use strict';
const argv = require('yargs').argv;
const gulp = require('gulp'),
plumber = require('gulp-plumber');

View File

@ -731,14 +731,14 @@ module.exports = function (ngApp, events) {
}
$timeout(function() {
console.log($scope.pageId);
$http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/`)).then(resp => {
if (!resp.data || resp.data.success !== true) {
// TODO : Handle error
return;
}
}
vm.comments = resp.data.comments.data;
vm.totalComments = resp.data.comments.total;
vm.totalComments = resp.data.total;
// TODO : Fetch message from translate.
if (vm.totalComments === 0) {
vm.totalCommentsStr = 'No comments found.';
} else if (vm.totalComments === 1) {
@ -749,6 +749,18 @@ module.exports = function (ngApp, events) {
}, checkError('app'));
});
vm.loadSubComments = function(event, comment) {
event.preventDefault();
$http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/${comment.id}/sub-comments`)).then(resp => {
console.log(resp);
if (!resp.data || resp.data.success !== true) {
return;
}
comment.is_loaded = true;
comment.comments = resp.data.comments.data;
}, checkError('app'));
};
function checkError(errorGroupName) {
$scope.errors[errorGroupName] = {};
return function(response) {

View File

@ -865,5 +865,52 @@ module.exports = function (ngApp, events) {
}
}
}]);
ngApp.directive('commentReply', ['$timeout', function ($timeout) {
return {
restrict: 'E',
templateUrl: 'comment-reply.html',
scope: {
},
link: function (scope, element, attr) {
}
}
}]);
ngApp.directive('commentReplyLink', ['$document', '$compile', function ($document, $compile) {
return {
link: function (scope, element, attr) {
element.on('$destroy', function () {
element.off('click');
scope.$destroy();
});
element.on('click', function () {
var $container = element.parents('.comment-box').first();
if (!$container.length) {
console.error('commentReplyLink directive should be placed inside a container with class comment-box!');
return;
}
if (attr.noCommentReplyDupe) {
removeDupe();
}
var compiledHTML = $compile('<comment-reply></comment-reply>')(scope);
$container.append(compiledHTML);
});
}
};
function removeDupe() {
let $existingElement = $document.find('comment-reply');
if (!$existingElement.length) {
return;
}
$existingElement.remove();
}
}]);
};

View File

@ -1,8 +1,4 @@
@section('head')
<script src="{{ baseUrl("/libs/simplemde/simplemde.min.js") }}"></script>
@stop
<div class="comment-editor" ng-controller="CommentAddController as vm">
<div class="comment-editor" ng-controller="CommentAddController as vm" ng-cloak>
<form novalidate>
<div simple-markdown-input smd-model="comment.newComment" smd-get-content="getCommentHTML" smd-clear="clearInput">
<textarea name="markdown" rows="3"

View File

@ -0,0 +1,10 @@
<!-- TODO :: needs to be merged with add.blade.php -->
<form novalidate>
<div simple-markdown-input smd-model="comment.newComment" smd-get-content="getCommentHTML" smd-clear="clearInput">
<textarea name="markdown" rows="3"
@if($errors->has('markdown')) class="neg" @endif>@if(isset($model) ||
old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
</div>
<input type="hidden" ng-model="pageId" name="comment.pageId" value="{{$pageId}}" ng-init="comment.pageId = {{$pageId }}">
<button type="submit" class="button pos" ng-click="vm.saveComment()">Save</button>
</form>

View File

@ -0,0 +1,19 @@
@section('head')
<script src="{{ baseUrl("/libs/simplemde/simplemde.min.js") }}"></script>
@stop
<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')
</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>
@include('comments/add', ['pageId' => $pageId])

View File

@ -1,19 +1,26 @@
<div class='page-comment'>
<div class="user-image">
<img ng-src="@{{defaultAvatar}}" alt="user avatar">
<img ng-src="@{{::defaultAvatar}}" alt="user avatar">
</div>
<div class="comment-container">
<div class="comment-header">
@{{ ::comment.created_by_name }}
</div>
<div ng-bind-html="comment.html" class="comment-body">
<div ng-bind-html="::comment.html" class="comment-body">
</div>
<div class="comment-actions">
<ul>
<li><a href="#">Reply</a></li>
<li><a href="#" comment-reply-link no-comment-reply-dupe="true">Reply</a></li>
<li><a href="#">@{{::comment.created_at}}</a></li>
</ul>
</div>
</div>
<a href="#" ng-click="vm.loadSubComments($event, comment, $index)" class="load-more-comments" ng-if="comment.cnt_sub_comments > 0 && !comment.is_loaded">
Load @{{::comment.cnt_sub_comments}} more comment(s)
</a>
<div class="comment-box" ng-repeat="comment in comments = comment.comments track by comment.id">
<div ng-include src="'comment-list-item.html'">
</div>
</div>
</div>
</div>

View File

@ -1,8 +0,0 @@
<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">
@include('comments/list-item')
</div>
</div>
@include('comments/add', ['pageId' => $pageId])

View File

@ -113,7 +113,7 @@
<div class="container">
<div class="row">
<div class="col-md-9">
@include('pages/comments', ['pageId' => $page->id])
@include('comments/comments', ['pageId' => $page->id])
</div>
</div>
</div>