mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 19:32:29 +01:00
Added loading icons, Added comment activity
This commit is contained in:
parent
41f56e659d
commit
0275d2ad58
@ -1,5 +1,6 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Repos\CommentRepo;
|
||||
use BookStack\Repos\EntityRepo;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
@ -51,7 +52,8 @@ class CommentController extends Controller
|
||||
|
||||
// Create a new comment.
|
||||
$this->checkPermission('comment-create-all');
|
||||
$comment = $this->commentRepo->create($page, $request->all());
|
||||
$comment = $this->commentRepo->create($page, $request->only(['html', 'text', 'parent_id']));
|
||||
Activity::add($page, 'commented_on', $page->book->id);
|
||||
return view('comments/comment', ['comment' => $comment]);
|
||||
}
|
||||
|
||||
@ -72,7 +74,7 @@ class CommentController extends Controller
|
||||
$this->checkOwnablePermission('page-view', $comment->entity);
|
||||
$this->checkOwnablePermission('comment-update', $comment);
|
||||
|
||||
$comment = $this->commentRepo->update($comment, $request->all());
|
||||
$comment = $this->commentRepo->update($comment, $request->only(['html', 'text']));
|
||||
return view('comments/comment', ['comment' => $comment]);
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,31 @@
|
||||
const MarkdownIt = require("markdown-it");
|
||||
const md = new MarkdownIt({ html: true });
|
||||
const md = new MarkdownIt({ html: false });
|
||||
|
||||
class PageComments {
|
||||
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
this.pageId = Number(elem.getAttribute('page-id'));
|
||||
|
||||
this.formContainer = elem.querySelector('[comment-form-container]');
|
||||
this.form = this.formContainer.querySelector('form');
|
||||
this.formInput = this.form.querySelector('textarea');
|
||||
this.container = elem.querySelector('[comment-container]');
|
||||
|
||||
// TODO - Handle elem usage when no permissions
|
||||
this.form.addEventListener('submit', this.saveComment.bind(this));
|
||||
this.elem.addEventListener('click', this.handleAction.bind(this));
|
||||
this.elem.addEventListener('submit', this.updateComment.bind(this));
|
||||
|
||||
this.editingComment = null;
|
||||
this.parentId = null;
|
||||
|
||||
this.container = elem.querySelector('[comment-container]');
|
||||
this.formContainer = elem.querySelector('[comment-form-container]');
|
||||
|
||||
if (this.formContainer) {
|
||||
this.form = this.formContainer.querySelector('form');
|
||||
this.formInput = this.form.querySelector('textarea');
|
||||
this.form.addEventListener('submit', this.saveComment.bind(this));
|
||||
}
|
||||
|
||||
this.elem.addEventListener('click', this.handleAction.bind(this));
|
||||
this.elem.addEventListener('submit', this.updateComment.bind(this));
|
||||
}
|
||||
|
||||
handleAction(event) {
|
||||
let actionElem = event.target.closest('[action]');
|
||||
if (event.target.matches('a[href^="#"]')) {
|
||||
let id = event.target.href.split('#')[1];
|
||||
console.log(document.querySelector('#' + id));
|
||||
window.scrollAndHighlight(document.querySelector('#' + id));
|
||||
}
|
||||
if (actionElem === null) return;
|
||||
@ -52,6 +52,9 @@ class PageComments {
|
||||
if (this.editingComment) this.closeUpdateForm();
|
||||
commentElem.querySelector('[comment-content]').style.display = 'none';
|
||||
commentElem.querySelector('[comment-edit-container]').style.display = 'block';
|
||||
let textArea = commentElem.querySelector('[comment-edit-container] textarea');
|
||||
let lineCount = textArea.value.split('\n').length;
|
||||
textArea.style.height = (lineCount * 20) + 'px';
|
||||
this.editingComment = commentElem;
|
||||
}
|
||||
|
||||
@ -64,7 +67,7 @@ class PageComments {
|
||||
html: md.render(text),
|
||||
parent_id: this.parentId || null,
|
||||
};
|
||||
// TODO - Loading indicator
|
||||
this.showLoading(form);
|
||||
let commentId = this.editingComment.getAttribute('comment');
|
||||
window.$http.put(window.baseUrl(`/ajax/comment/${commentId}`), reqData).then(resp => {
|
||||
let newComment = document.createElement('div');
|
||||
@ -74,12 +77,13 @@ class PageComments {
|
||||
window.components.init(this.editingComment);
|
||||
this.closeUpdateForm();
|
||||
this.editingComment = null;
|
||||
this.hideLoading(form);
|
||||
});
|
||||
}
|
||||
|
||||
deleteComment(commentElem) {
|
||||
let id = commentElem.getAttribute('comment');
|
||||
// TODO - Loading indicator
|
||||
this.showLoading(commentElem.querySelector('[comment-content]'));
|
||||
window.$http.delete(window.baseUrl(`/ajax/comment/${id}`)).then(resp => {
|
||||
commentElem.parentNode.removeChild(commentElem);
|
||||
window.$events.emit('success', window.trans('entities.comment_deleted_success'));
|
||||
@ -96,7 +100,7 @@ class PageComments {
|
||||
html: md.render(text),
|
||||
parent_id: this.parentId || null,
|
||||
};
|
||||
// TODO - Loading indicator
|
||||
this.showLoading(this.form);
|
||||
window.$http.post(window.baseUrl(`/ajax/page/${this.pageId}/comment`), reqData).then(resp => {
|
||||
let newComment = document.createElement('div');
|
||||
newComment.innerHTML = resp.data;
|
||||
@ -119,6 +123,7 @@ class PageComments {
|
||||
this.formContainer.appendChild(this.form);
|
||||
this.hideForm();
|
||||
this.removeReplyTo();
|
||||
this.hideLoading(this.form);
|
||||
}
|
||||
|
||||
showForm() {
|
||||
@ -149,9 +154,22 @@ class PageComments {
|
||||
this.elem.querySelector('[comment-form-reply-to]').style.display = 'none';
|
||||
}
|
||||
|
||||
showLoading(formElem) {
|
||||
let groups = formElem.querySelectorAll('.form-group');
|
||||
for (let i = 0, len = groups.length; i < len; i++) {
|
||||
groups[i].style.display = 'none';
|
||||
}
|
||||
formElem.querySelector('.form-group.loading').style.display = 'block';
|
||||
}
|
||||
|
||||
hideLoading(formElem) {
|
||||
let groups = formElem.querySelectorAll('.form-group');
|
||||
for (let i = 0, len = groups.length; i < len; i++) {
|
||||
groups[i].style.display = 'block';
|
||||
}
|
||||
formElem.querySelector('.form-group.loading').style.display = 'none';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO - Go to comment if url param set
|
||||
|
||||
|
||||
module.exports = PageComments;
|
@ -1,38 +0,0 @@
|
||||
.comment-box {
|
||||
border: 1px solid #DDD;
|
||||
margin-bottom: $-s;
|
||||
border-radius: 3px;
|
||||
.content {
|
||||
padding: $-s;
|
||||
}
|
||||
.content p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.reply-row {
|
||||
padding: $-xs $-s;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-box .header {
|
||||
padding: $-xs $-s;
|
||||
background-color: #f8f8f8;
|
||||
border-bottom: 1px solid #DDD;
|
||||
.meta {
|
||||
img, a, span {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
a, span {
|
||||
padding: $-xxs 0 $-xxs 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
a { color: #666; }
|
||||
span {
|
||||
color: #888;
|
||||
padding-left: $-xxs;
|
||||
}
|
||||
}
|
||||
.text-muted {
|
||||
color: #999;
|
||||
}
|
||||
}
|
@ -540,4 +540,45 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||
margin-right: $-xs;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-box {
|
||||
border: 1px solid #DDD;
|
||||
margin-bottom: $-s;
|
||||
border-radius: 3px;
|
||||
.content {
|
||||
padding: $-s;
|
||||
font-size: 0.666em;
|
||||
}
|
||||
.content p {
|
||||
font-size: $fs-m;
|
||||
margin: .5em 0;
|
||||
}
|
||||
.reply-row {
|
||||
padding: $-xs $-s;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-box .header {
|
||||
padding: $-xs $-s;
|
||||
background-color: #f8f8f8;
|
||||
border-bottom: 1px solid #DDD;
|
||||
.meta {
|
||||
img, a, span {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
a, span {
|
||||
padding: $-xxs 0 $-xxs 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
a { color: #666; }
|
||||
span {
|
||||
color: #888;
|
||||
padding-left: $-xxs;
|
||||
}
|
||||
}
|
||||
.text-muted {
|
||||
color: #999;
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@
|
||||
@import "header";
|
||||
@import "lists";
|
||||
@import "pages";
|
||||
@import "comments";
|
||||
|
||||
[v-cloak] {
|
||||
display: none; opacity: 0;
|
||||
@ -69,7 +68,6 @@ $loadingSize: 10px;
|
||||
.loading-container {
|
||||
position: relative;
|
||||
display: block;
|
||||
height: $loadingSize;
|
||||
margin: $-xl auto;
|
||||
> div {
|
||||
width: $loadingSize;
|
||||
@ -77,7 +75,8 @@ $loadingSize: 10px;
|
||||
border-radius: $loadingSize;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(-10px, 0, 0);
|
||||
margin-top: $-xs;
|
||||
animation-name: loadingBob;
|
||||
animation-duration: 1.4s;
|
||||
animation-iteration-count: infinite;
|
||||
@ -91,11 +90,17 @@ $loadingSize: 10px;
|
||||
background-color: $color-book;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
> div:last-child {
|
||||
> div:last-of-type {
|
||||
left: $loadingSize+$-xs;
|
||||
background-color: $color-chapter;
|
||||
animation-delay: 0.6s;
|
||||
}
|
||||
> span {
|
||||
margin-left: $-s;
|
||||
font-style: italic;
|
||||
color: #888;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,4 +37,6 @@ return [
|
||||
'book_sort' => 'sorted book',
|
||||
'book_sort_notification' => 'Book Successfully Re-sorted',
|
||||
|
||||
// Other
|
||||
'commented_on' => 'commented on',
|
||||
];
|
||||
|
@ -245,6 +245,8 @@ return [
|
||||
'comment_placeholder' => 'Leave a comment here',
|
||||
'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments',
|
||||
'comment_save' => 'Save Comment',
|
||||
'comment_saving' => 'Saving comment...',
|
||||
'comment_deleting' => 'Deleting comment...',
|
||||
'comment_new' => 'New Comment',
|
||||
'comment_created' => 'commented :createDiff',
|
||||
'comment_updated' => 'Updated :updateDiff by :username',
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="comment-box" comment="{{ $comment->id }}" local-id="{{$comment->local_id}}" parent-id="{{$comment->parent_id || ''}}" id="comment{{$comment->local_id}}">
|
||||
<div class="comment-box" comment="{{ $comment->id }}" local-id="{{$comment->local_id}}" parent-id="{{$comment->parent_id}}" id="comment{{$comment->local_id}}">
|
||||
<div class="header">
|
||||
|
||||
<div class="float right actions">
|
||||
@ -23,17 +23,20 @@
|
||||
<div class="meta">
|
||||
<a href="#comment{{$comment->local_id}}" class="text-muted">#{{$comment->local_id}}</a>
|
||||
|
||||
<img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar" alt="{{ $comment->createdBy->name }}">
|
||||
|
||||
<a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->name }}</a>
|
||||
{{--TODO - Account for deleted user--}}
|
||||
@if ($comment->createdBy)
|
||||
<img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar" alt="{{ $comment->createdBy->name }}">
|
||||
|
||||
<a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->name }}</a>
|
||||
@else
|
||||
<span>{{ trans('common.deleted_user') }}</span>
|
||||
@endif
|
||||
<span title="{{ $comment->created_at }}">
|
||||
{{ trans('entities.comment_created', ['createDiff' => $comment->created]) }}
|
||||
</span>
|
||||
@if($comment->isUpdated())
|
||||
<span title="{{ $comment->updated_at }}">
|
||||
•
|
||||
{{ trans('entities.comment_updated', ['updateDiff' => $comment->updated, 'username' => $comment->updatedBy->name]) }}
|
||||
{{ trans('entities.comment_updated', ['updateDiff' => $comment->updated, 'username' => $comment->updatedBy? $comment->updatedBy->name : trans('common.deleted_user')]) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@ -47,6 +50,9 @@
|
||||
@endif
|
||||
|
||||
<div comment-content class="content">
|
||||
<div class="form-group loading" style="display: none;">
|
||||
@include('partials.loading-icon', ['text' => trans('entities.comment_deleting')])
|
||||
</div>
|
||||
{!! $comment->html !!}
|
||||
</div>
|
||||
|
||||
@ -60,6 +66,9 @@
|
||||
<button type="button" class="button outline" action="closeUpdateForm">{{ trans('common.cancel') }}</button>
|
||||
<button type="submit" class="button pos">{{ trans('entities.comment_save') }}</button>
|
||||
</div>
|
||||
<div class="form-group loading" style="display: none;">
|
||||
@include('partials.loading-icon', ['text' => trans('entities.comment_saving')])
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endif
|
||||
|
@ -25,6 +25,9 @@
|
||||
<button type="button" class="button outline" action="hideForm">{{ trans('common.cancel') }}</button>
|
||||
<button type="submit" class="button pos">{{ trans('entities.comment_save') }}</button>
|
||||
</div>
|
||||
<div class="form-group loading" style="display: none;">
|
||||
@include('partials.loading-icon', ['text' => trans('entities.comment_saving')])
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,4 +2,7 @@
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
@if(isset($text))
|
||||
<span>{{$text}}</span>
|
||||
@endif
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user