#9: Started working on converting the analysis and album screens to Bootstrap v4
This commit is contained in:
parent
c1740be802
commit
3c2d50f373
@ -60,4 +60,11 @@ class DbHelper
|
||||
->withCount('photos')
|
||||
->paginate(UserConfig::get('items_per_page'));
|
||||
}
|
||||
|
||||
public static function getAlbumByAliasForCurrentUser($urlAlias)
|
||||
{
|
||||
$album = Album::where('url_alias', $urlAlias)->first();
|
||||
|
||||
return $album;
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ class PhotoController extends Controller
|
||||
{
|
||||
public function download(Request $request, $albumUrlAlias, $photoFilename)
|
||||
{
|
||||
$album = DbHelper::loadAlbumByUrlAlias($albumUrlAlias);
|
||||
$album = DbHelper::getAlbumByAliasForCurrentUser($albumUrlAlias);
|
||||
if (is_null($album))
|
||||
{
|
||||
App::abort(404);
|
||||
@ -75,7 +75,7 @@ class PhotoController extends Controller
|
||||
|
||||
public function show(Request $request, $albumUrlAlias, $photoFilename)
|
||||
{
|
||||
$album = DbHelper::loadAlbumByUrlAlias($albumUrlAlias);
|
||||
$album = DbHelper::getAlbumByAliasForCurrentUser($albumUrlAlias);
|
||||
if (is_null($album))
|
||||
{
|
||||
App::abort(404);
|
||||
|
@ -1,3 +1,130 @@
|
||||
/**
|
||||
* This model is used by admin/analyse_album.blade.php, to analyse all images.
|
||||
* @constructor
|
||||
*/
|
||||
function AnalyseAlbumViewModel() {
|
||||
this.el = '#analyse-album';
|
||||
|
||||
this.data = {
|
||||
imagesFailed: [],
|
||||
imagesToAnalyse: [],
|
||||
imagesInProgress: [],
|
||||
imagesRecentlyCompleted: [],
|
||||
numberSuccessful: 0,
|
||||
numberFailed: 0
|
||||
};
|
||||
|
||||
this.computed = {
|
||||
failedPercentage: function () {
|
||||
var result = 0;
|
||||
|
||||
if (this.numberTotal > 0)
|
||||
{
|
||||
result = (this.numberFailed / this.numberTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
},
|
||||
isCompleted: function () {
|
||||
return this.numberTotal > 0 && (this.numberSuccessful + this.numberFailed >= this.numberTotal);
|
||||
},
|
||||
latestCompletedImages: function() {
|
||||
return this.imagesRecentlyCompleted.slice(
|
||||
(this.imagesRecentlyCompleted.length - 3 < 0
|
||||
? 0
|
||||
: this.imagesRecentlyCompleted.length - 3)
|
||||
, 3);
|
||||
},
|
||||
numberTotal: function () {
|
||||
return this.imagesToAnalyse.length;
|
||||
},
|
||||
successfulPercentage: function () {
|
||||
var result = 0;
|
||||
|
||||
if (this.numberTotal > 0)
|
||||
{
|
||||
result = (this.numberSuccessful / this.numberTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
}
|
||||
};
|
||||
|
||||
this.methods = {
|
||||
// This method is called when an image is added to the array, automatically issue it for analysis
|
||||
// item is an instance of AnalyseImageViewModel
|
||||
analyseImage: function (item) {
|
||||
var self = this;
|
||||
this.imagesToAnalyse.push(item);
|
||||
|
||||
$.ajax(
|
||||
item.url,
|
||||
{
|
||||
beforeSend: function() {
|
||||
self.imagesInProgress.push(item);
|
||||
},
|
||||
dataType: 'json',
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
self.numberFailed++;
|
||||
self.imagesFailed.push({
|
||||
'name': item.name,
|
||||
'reason': textStatus
|
||||
});
|
||||
item.isSuccessful = false;
|
||||
item.isPending = false;
|
||||
},
|
||||
method: 'POST',
|
||||
success: function (data) {
|
||||
if (data.is_successful) {
|
||||
self.numberSuccessful++;
|
||||
item.isSuccessful = true;
|
||||
item.isPending = false;
|
||||
|
||||
// Push into our "recently completed" array
|
||||
self.imagesRecentlyCompleted.push(item);
|
||||
var indexToRemove = self.imagesInProgress.indexOf(item);
|
||||
if (indexToRemove > -1)
|
||||
{
|
||||
self.imagesInProgress.splice(indexToRemove, 1);
|
||||
}
|
||||
|
||||
// Remove it again after a few seconds
|
||||
/*window.setTimeout(function() {
|
||||
var indexToRemove = self.imagesRecentlyCompleted.indexOf(item);
|
||||
if (indexToRemove > -1) {
|
||||
self.imagesRecentlyCompleted.splice(indexToRemove, 1);
|
||||
}
|
||||
}, 2000);*/
|
||||
}
|
||||
else {
|
||||
self.numberFailed++;
|
||||
self.imagesFailed.push({
|
||||
'name': item.name,
|
||||
'reason': data.message
|
||||
});
|
||||
item.isSuccessful = false;
|
||||
item.isPending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This model is used by admin/analyse_album.blade.php, as a sub-model of AnalyseAlbumViewModel.
|
||||
* @param image_info Array of information about the image
|
||||
* @constructor
|
||||
*/
|
||||
function AnalyseImageViewModel(image_info) {
|
||||
this.isPending = true;
|
||||
this.isSuccessful = false;
|
||||
this.name = image_info.name;
|
||||
this.photoID = image_info.photo_id;
|
||||
this.url = image_info.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* This model is used by admin/show_album.blade.php to handle photo uploads.
|
||||
* @param album_id ID of the album the photos are being uploaded to
|
||||
@ -8,6 +135,7 @@
|
||||
*/
|
||||
function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
this.el = '#upload-tab';
|
||||
|
||||
this.data = {
|
||||
currentStatus: '',
|
||||
imagesFailed: 0,
|
||||
@ -17,6 +145,7 @@ function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
isUploadInProgress: false,
|
||||
statusMessages: []
|
||||
};
|
||||
|
||||
this.computed = {
|
||||
failedPercentage: function () {
|
||||
var result = 0;
|
||||
@ -39,6 +168,7 @@ function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
return result.toFixed(2) + '%';
|
||||
}
|
||||
};
|
||||
|
||||
this.methods = {
|
||||
// This method is called when an image is uploaded - regardless if it fails or not
|
||||
onUploadCompleted: function () {
|
||||
|
@ -4,50 +4,53 @@
|
||||
@section('content')
|
||||
<div class="container" style="margin-top: 40px;">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8 col-sm-offset-2">
|
||||
<div class="panel panel-default" data-bind="visible: !isCompleted()">
|
||||
<div class="panel-heading">Analysing...</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-sm-8 offset-sm-2" id="analyse-album">
|
||||
<div class="card" v-if="!isCompleted">
|
||||
<div class="card-header">Analysing...</div>
|
||||
<div class="card-block">
|
||||
<p>Your uploaded photos are now being analysed.</p>
|
||||
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" data-bind="style: { width: successfulPercentage() }">
|
||||
<span class="sr-only"><span class="percentage-success" data-bind="text: successfulPercentage"></span></span>
|
||||
<div class="progress-bar bg-success" v-bind:style="{ width: successfulPercentage }">
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-danger" data-bind="style: { width: failedPercentage() }">
|
||||
<span class="sr-only"><span class="percentage-danger" data-bind="text: failedPercentage"></span></span>
|
||||
<div class="progress-bar bg-danger" v-bind:style="{ width: failedPercentage }">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- We display a queue of 3 recently completed items, and 5 up-next items, as well as a counter saying "... and XYZ more" --}}
|
||||
{{-- That's what the 3's and 5's are in the next couple of blocks --}}
|
||||
<div data-bind="foreach: imagesRecentlyCompleted.slice((imagesRecentlyCompleted().length - 3 < 0) ? 0 : imagesRecentlyCompleted().length - 3, 3)" style="margin-top: 20px;">
|
||||
<p class="text-success"><span data-bind="text: name"></span> ... <i class="fa fa-fw fa-check"></i></p>
|
||||
<div v-for="image in latestCompletedImages" style="margin-top: 20px;">
|
||||
<p class="text-success"><span v-text="image.name"></span> ... <i class="fa fa-fw fa-check"></i></p>
|
||||
</div>
|
||||
<div data-bind="foreach: imagesInProgress.slice(0, 5)" style="margin-top: 20px;">
|
||||
<p><span data-bind="text: name"></span> ... <i data-bind="css: iconClass()"></i></p>
|
||||
<div v-for="image in imagesInProgress.slice(0, 5)" style="margin-top: 20px;">
|
||||
<p><span v-text="image.name"></span> ... <i class="fa fa-fw fa-refresh"></i></p>
|
||||
</div>
|
||||
|
||||
<div data-bind="visible: imagesInProgress().length > 5">
|
||||
<p>@lang('admin.analyse_and_more.and') <span data-bind="text: imagesInProgress().length - 5"></span> @lang('admin.analyse_and_more.others')</p>
|
||||
<div v-if="imagesInProgress.length > 5">
|
||||
<p>@lang('admin.analyse_and_more.and') <span v-text="imagesInProgress.length - 5"></span> @lang('admin.analyse_and_more.others')</p>
|
||||
</div>
|
||||
|
||||
<div v-for="image in imagesFailed" style="margin-top: 20px;">
|
||||
<p class="text-danger"><span v-text="image.name"></span> ... <i class="fa fa-fw fa-times"></i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" data-bind="visible: isCompleted">
|
||||
<div class="panel-heading">Upload completed</div>
|
||||
<div class="panel-body">
|
||||
<div class="card" v-if="isCompleted">
|
||||
<div class="card-header">Upload completed</div>
|
||||
<div class="card-block">
|
||||
<p>Your upload has completed.</p>
|
||||
<div data-bind="visible: numberFailed() > 0">
|
||||
|
||||
<div v-if="numberFailed > 0">
|
||||
<p class="text-danger">@lang('admin.analyse_photos_failed')</p>
|
||||
<ul class="text-danger" data-bind="foreach: imagesFailed">
|
||||
<li><span data-bind="text: name"></span>: <span data-bind="text: reason"></span></li>
|
||||
<ul class="text-danger" v-for="image in imagesFailed">
|
||||
<li><span v-text="image.name"></span>: <span v-text="image.reason"></span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-toolbar btn-group-sm pull-right">
|
||||
<a class="btn btn-default" href="{{ $album->url() }}">View album</a>
|
||||
<a class="btn btn-primary" href="{{ route('albums.show', ['id' => $album->id]) }}">Back to album settings</a>
|
||||
<div class="text-right">
|
||||
<a class="btn btn-link" href="{{ $album->url() }}">View album</a>
|
||||
<a class="btn btn-primary" href="{{ route('albums.show', ['id' => $album->id]) }}"><i class="fa fa-fw fa-chevron-left"></i> Back to album settings</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -59,16 +62,15 @@
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
var viewModel = new AnalyseAlbumViewModel();
|
||||
var app = new Vue(viewModel);
|
||||
|
||||
{{-- For each photo to analyse, push an instance of AnalyseImageViewModel to our master view model --}}
|
||||
@foreach ($photos as $photo)
|
||||
viewModel.imagesToAnalyse.push(new AnalyseImageViewModel({
|
||||
app.analyseImage(new AnalyseImageViewModel({
|
||||
'id': '{{ $photo->id }}',
|
||||
'name': '{!! addslashes($photo->name) !!}',
|
||||
'url': '{{ route('photos.analyse', ['id' => $photo->id, 'queue_token' => $queue_token]) }}'
|
||||
}));
|
||||
@endforeach
|
||||
|
||||
ko.applyBindings(viewModel);
|
||||
</script>
|
||||
@endpush
|
@ -1,7 +1,7 @@
|
||||
@php ($field_prefix = sprintf('photo[%d]', $photo->id))
|
||||
<hr/>
|
||||
<div class="photo row" data-photo-id="{{ $photo->id }}">
|
||||
<div class="col-xs-12 col-sm-2">
|
||||
<div class="col-sm-2">
|
||||
<div class="loading"><img src="{{ asset('ripple.svg') }}" /></div>
|
||||
|
||||
<a href="{{ $photo->thumbnailUrl() }}" target="_blank">
|
||||
@ -43,8 +43,8 @@
|
||||
<div class="col-xs-12 col-sm-10">
|
||||
@php($validation_field_name = ('photo.' . $photo->id . '.name'))
|
||||
<div class="form-group{{ $errors->has($validation_field_name) ? ' has-error' : '' }}">
|
||||
{!! Form::label($field_prefix . '[name]', trans('forms.name_label'), ['class' => 'control-label']) !!}
|
||||
{!! Form::text($field_prefix . '[name]', old('name', $photo->name), ['class' => 'form-control']) !!}
|
||||
<label class="control-label" name="{{ $field_prefix }}[name]">@lang('forms.name_label')</label>
|
||||
<input class="form-control" type="text" name="{{ $field_prefix }}[name]" value="{{ old('name', $photo->name) }}"/>
|
||||
|
||||
@if ($errors->has($validation_field_name))
|
||||
<span class="help-block">
|
||||
@ -54,8 +54,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{!! Form::label($field_prefix . '[description]', trans('forms.description_label'), ['class' => 'control-label']) !!}
|
||||
{!! Form::textarea($field_prefix . '[description]', old('name', $photo->description), ['class' => 'form-control', 'rows' => 4]) !!}
|
||||
<label class="control-label" name="{{ $field_prefix }}[description]">@lang('forms.description_label')</label>
|
||||
<textarea name="{{ $field_prefix }}[description]" class="form-control" rows="4">{{ old('name', $photo->description) }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user