#4: Added a basic template for the comment design. Comments now display nested. Renamed the columns in the database table so the default validation error messages look better. Corrected a few issues with the TinyMCE implementation.

This commit is contained in:
Andy Heathershaw 2018-09-19 09:44:20 +01:00
parent 60e747bd75
commit 1802aa84d8
9 changed files with 98 additions and 35 deletions

View File

@ -74,7 +74,7 @@ class PhotoCommentController extends Controller
if (is_null($parentComment))
{
$request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
//TODO $request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
return redirect($photo->url());
}
}
@ -82,14 +82,14 @@ class PhotoCommentController extends Controller
try
{
$this->validate($request, [
'commentor_name' => 'required|max:255',
'commentor_email' => 'sometimes|max:255|email',
'comment_text' => 'required'
'name' => 'required|max:255',
'email' => 'sometimes|max:255|email',
'comment' => 'required'
]);
$comment = new PhotoComment();
$comment->photo_id = $photo->id;
$comment->fill($request->only(['commentor_email', 'commentor_name', 'comment_text']));
$comment->fill($request->only(['name', 'email', 'comment']));
if (!is_null($parentComment))
{

View File

@ -12,9 +12,9 @@ class PhotoComment extends Model
* @var array
*/
protected $fillable = [
'commentor_name',
'commentor_email',
'comment_text'
'name',
'email',
'comment'
];
public function approvedBy()
@ -22,6 +22,21 @@ class PhotoComment extends Model
return $this->belongsTo(User::class, 'approved_user_id');
}
public function approvedChildren()
{
return $this->children()->whereNotNull('approved_at');
}
public function authorDisplayName()
{
return is_null($this->createdBy) ? $this->name : $this->createdBy->name;
}
public function children()
{
return $this->hasMany(PhotoComment::class, 'parent_comment_id');
}
public function createdBy()
{
return $this->belongsTo(User::class, 'created_user_id');
@ -45,4 +60,17 @@ class PhotoComment extends Model
{
return $this->belongsTo(PhotoComment::class, 'parent_comment_id');
}
public function textAsHtml()
{
$start = '<p>';
$end = '</p>';
$isHtml = (
strlen($this->comment) > (strlen($start) + strlen($end)) && // text contains both our start + end string
strtolower(substr($this->comment, 0, strlen($start))) == strtolower($start) && // text starts with our start string
strtolower(substr($this->comment, strlen($this->comment) - strlen($end))) == strtolower($end) // text ends with our end string
);
return $isHtml ? $this->comment : sprintf('<p>%s</p>', $this->comment);
}
}

View File

@ -16,9 +16,9 @@ class CreatePhotoCommentsTable extends Migration
Schema::create('photo_comments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('photo_id');
$table->string('commentor_name');
$table->string('commentor_email');
$table->text('comment_text');
$table->string('name');
$table->string('email');
$table->text('comment');
$table->unsignedInteger('created_user_id')->nullable(true);
$table->unsignedInteger('approved_user_id')->nullable(true);
$table->dateTime('approved_at')->nullable(true);

View File

@ -41569,12 +41569,21 @@ function PhotoViewModel(urls) {
self.is_reply_form_loading = false;
});
});
$('#comment-reply-modal').on('hide.bs.modal', function (event) {
tinymce.remove('#comment-text-reply');
});
},
postCommentReply: function() {
var form = $('form', '#comment-reply-form-content');
var formUrl = $(form).attr('action');
// Seems like the TinyMCE editor in the BS modal does not persist back to the textarea correctly - so do
// this manually (bit of a hack!)
$('#comment-text-reply', form).html(tinymce.get('comment-text-reply').getContent());
var formData = form.serialize();
$.post(formUrl, formData, function(result)
{
if (result.redirect_url)
@ -41583,7 +41592,9 @@ function PhotoViewModel(urls) {
}
else
{
tinymce.remove('#comment-text-reply');
$('#comment-reply-form-content').html(result);
initTinyMce('#comment-text-reply');
}
});
},
@ -41593,6 +41604,9 @@ function PhotoViewModel(urls) {
this.is_reply_form_loading = true;
$('#comment-reply-modal').modal('show');
e.preventDefault();
return false;
}
};
}

File diff suppressed because one or more lines are too long

View File

@ -33,12 +33,21 @@ function PhotoViewModel(urls) {
self.is_reply_form_loading = false;
});
});
$('#comment-reply-modal').on('hide.bs.modal', function (event) {
tinymce.remove('#comment-text-reply');
});
},
postCommentReply: function() {
var form = $('form', '#comment-reply-form-content');
var formUrl = $(form).attr('action');
// Seems like the TinyMCE editor in the BS modal does not persist back to the textarea correctly - so do
// this manually (bit of a hack!)
$('#comment-text-reply', form).html(tinymce.get('comment-text-reply').getContent());
var formData = form.serialize();
$.post(formUrl, formData, function(result)
{
if (result.redirect_url)
@ -47,7 +56,9 @@ function PhotoViewModel(urls) {
}
else
{
tinymce.remove('#comment-text-reply');
$('#comment-reply-form-content').html(result);
initTinyMce('#comment-text-reply');
}
});
},
@ -57,6 +68,9 @@ function PhotoViewModel(urls) {
this.is_reply_form_loading = true;
$('#comment-reply-modal').modal('show');
e.preventDefault();
return false;
}
};
}

View File

@ -8,11 +8,9 @@
@include(Theme::viewName('partials.photo_comments_reply_form'))
@if ($photo->approvedComments()->count() > 0)
<ul>
@foreach ($photo->approvedComments as $comment)
@include(Theme::viewName('partials.photo_single_comment'))
@endforeach
</ul>
@foreach ($photo->approvedComments as $comment)
@include(Theme::viewName('partials.photo_single_comment'))
@endforeach
@endif
</div>
</div>

View File

@ -4,9 +4,9 @@ $is_reply = isset($reply_comment);
{{-- Show a previous of the comment we're replying to --}}
@if ($is_reply)
<ul class="mb-3">
<div class="mb-3">
@include (Theme::viewName('partials.photo_single_comment'), ['comment' => $reply_comment, 'is_reply' => true])
</ul>
</div>
@endif
<form action="{{ $photo->postCommentUrl() }}" method="post">
@ -18,33 +18,33 @@ $is_reply = isset($reply_comment);
<div class="form-group">
<label for="commentor-name">@lang('forms.name_label')</label>
<input type="text" class="form-control{{ $errors->has('commentor_name') ? ' is-invalid' : '' }}" id="commentor-name" name="commentor_name" value="{{ old('commentor_name') }}"/>
<input type="text" class="form-control{{ $errors->has('name') ? ' is-invalid' : '' }}" id="commentor-name" name="name" value="{{ old('name') }}"/>
@if ($errors->has('commentor_name'))
@if ($errors->has('name'))
<div class="invalid-feedback">
<strong>{{ $errors->first('commentor_name') }}</strong>
<strong>{{ $errors->first('name') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<label for="commentor-email">@lang('forms.email_label')</label>
<input type="text" class="form-control{{ $errors->has('commentor_email') ? ' is-invalid' : '' }}" id="commentor-email" name="commentor_email" value="{{ old('commentor_email') }}" placeholder="@lang('forms.email_placeholder')"/>
<input type="text" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" id="commentor-email" name="email" value="{{ old('email') }}" placeholder="@lang('forms.email_placeholder')"/>
@if ($errors->has('commentor_email'))
@if ($errors->has('email'))
<div class="invalid-feedback">
<strong>{{ $errors->first('commentor_email') }}</strong>
<strong>{{ $errors->first('email') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<label for="comment-text{{ $is_reply ? '-reply' : '' }}">@lang('forms.photo_comment_text_label')</label>
<textarea class="form-control{{ $errors->has('comment_text') ? ' is-invalid' : '' }}" id="comment-text{{ $is_reply ? '-reply' : '' }}" name="comment_text" rows="10">{{ old('comment_text') }}</textarea>
<textarea class="form-control{{ $errors->has('comment') ? ' is-invalid' : '' }}" id="comment-text{{ $is_reply ? '-reply' : '' }}" name="comment" rows="10">{{ old('comment') }}</textarea>
@if ($errors->has('comment_text'))
@if ($errors->has('comment'))
<div class="invalid-feedback">
<strong>{{ $errors->first('comment_text') }}</strong>
<strong>{{ $errors->first('comment') }}</strong>
</div>
@endif
</div>

View File

@ -2,11 +2,20 @@
$is_reply = (isset($is_reply) && $is_reply);
@endphp
<li class="photo-comment" data-comment-id="{{ $comment->id }}">
Comment by <b>{{ $comment->createdBy->name }}</b>:<br/>
{{ $comment->comment_text }}
<div class="card photo-comment mt-2" data-comment-id="{{ $comment->id }}"@if (!$is_reply) style="margin-left: {{ $comment->depth() * 20 }}px;"@endif>
<div class="card-body">
<h5 class="card-title"><b>{{ $comment->authorDisplayName() }}</b>:</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ date(UserConfig::get('date_format'), strtotime($comment->created_at)) }}</h6>
<p>{!! $comment->textAsHtml() !!}</p>
@if (!$is_reply && $comment->depth() < UserConfig::get('photo_comments_thread_depth'))
<p><button v-on:click="replyToComment" class="btn btn-sm btn-outline-primary">@lang('gallery.photo_comments_reply_action')</button></p>
@endif
</li>
@if (!$is_reply && $comment->depth() < UserConfig::get('photo_comments_thread_depth'))
<a href="{{ $photo->replyToCommentFormUrl($comment->id) }}" v-on:click="replyToComment" class="card-link">@lang('gallery.photo_comments_reply_action')</a>
@endif
</div>
</div>
@if (!$is_reply)
@foreach ($comment->approvedChildren as $childComment)
@include(Theme::viewName('partials.photo_single_comment'), ['comment' => $childComment])
@endforeach
@endif