#9: The progress bar when uploading is now working correctly. The delete album screen has been updated to Bootstrap v4. Alerts are now dismissable.
This commit is contained in:
parent
8b9e8f0229
commit
c1740be802
@ -94,7 +94,7 @@ class AlbumController extends Controller
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
$this->authorizeAccessToAdminPanel();
|
||||
|
||||
@ -111,6 +111,8 @@ class AlbumController extends Controller
|
||||
$album->getAlbumSource()->deleteAlbumContents();
|
||||
$album->delete();
|
||||
|
||||
$request->session()->flash('success', trans('admin.delete_album_success_message', ['album' => $album->name]));
|
||||
|
||||
return redirect(route('albums.index'));
|
||||
}
|
||||
|
||||
@ -134,14 +136,15 @@ class AlbumController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorizeAccessToAdminPanel();
|
||||
|
||||
$albums = DbHelper::getAlbumsForCurrentUser();
|
||||
|
||||
return Theme::render('admin.list_albums', [
|
||||
'albums' => $albums
|
||||
'albums' => $albums,
|
||||
'success' => $request->session()->get('success'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,148 @@
|
||||
/**
|
||||
* 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
|
||||
* @param queue_token Unique token of the upload queue to save the photos to
|
||||
* @param language Array containing language strings
|
||||
* @param urls Array containing URLs
|
||||
* @constructor
|
||||
*/
|
||||
function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
this.el = '#upload-tab';
|
||||
this.data = {
|
||||
currentStatus: '',
|
||||
imagesFailed: 0,
|
||||
imagesTotal: 0,
|
||||
imagesUploaded: 0,
|
||||
isBulkUploadInProgress: false,
|
||||
isUploadInProgress: false,
|
||||
statusMessages: []
|
||||
};
|
||||
this.computed = {
|
||||
failedPercentage: function () {
|
||||
var result = 0;
|
||||
|
||||
if (this.imagesTotal > 0)
|
||||
{
|
||||
result = (this.imagesFailed / this.imagesTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
},
|
||||
successfulPercentage: function () {
|
||||
var result = 0;
|
||||
|
||||
if (this.imagesTotal > 0)
|
||||
{
|
||||
result = (this.imagesUploaded / this.imagesTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
}
|
||||
};
|
||||
this.methods = {
|
||||
// This method is called when an image is uploaded - regardless if it fails or not
|
||||
onUploadCompleted: function () {
|
||||
this.currentStatus = language.upload_status
|
||||
.replace(':current', (this.imagesUploaded + this.imagesFailed))
|
||||
.replace(':total', this.imagesTotal);
|
||||
|
||||
if ((this.imagesFailed + this.imagesUploaded) >= this.imagesTotal) {
|
||||
this.isUploadInProgress = false;
|
||||
|
||||
if (this.imagesFailed === 0 && this.imagesUploaded > 0) {
|
||||
window.location = urls.analyse;
|
||||
}
|
||||
}
|
||||
},
|
||||
// This method is called when an uploaded image fails
|
||||
onUploadFailed: function (data, file_name) {
|
||||
this.imagesFailed++;
|
||||
this.statusMessages.push({
|
||||
'message_class': 'text-danger',
|
||||
'message_text': language.image_failed.replace(':file_name', file_name)
|
||||
});
|
||||
this.onUploadCompleted();
|
||||
},
|
||||
// This method is called when an uploaded image succeeds
|
||||
onUploadSuccessful: function (data, file_name) {
|
||||
if (data.is_successful) {
|
||||
this.imagesUploaded++;
|
||||
// Don't add to statusMessages() array so user only sees errors
|
||||
/*self.statusMessages.push({
|
||||
'message_class': 'text-success',
|
||||
'message_text': language.image_uploaded.replace(':file_name', file_name)
|
||||
});*/
|
||||
this.onUploadCompleted();
|
||||
}
|
||||
else {
|
||||
this.onUploadFailed(data, file_name);
|
||||
}
|
||||
},
|
||||
uploadFile: function uploadImageFile(formObject, imageFile) {
|
||||
var self = this;
|
||||
var formData = new FormData();
|
||||
formData.append('album_id', album_id);
|
||||
formData.append('queue_token', queue_token);
|
||||
formData.append('photo[]', imageFile, imageFile.name);
|
||||
|
||||
$.ajax(
|
||||
{
|
||||
contentType: false,
|
||||
data: formData,
|
||||
error: function (data) {
|
||||
self.onUploadFailed(data, imageFile.name);
|
||||
},
|
||||
method: $(formObject).attr('method'),
|
||||
processData: false,
|
||||
success: function (data) {
|
||||
self.onUploadSuccessful(data, imageFile.name);
|
||||
},
|
||||
url: $(formObject).attr('action')
|
||||
}
|
||||
);
|
||||
this.isUploadInProgress = true;
|
||||
|
||||
this.currentStatus = language.upload_status
|
||||
.replace(':current', 0)
|
||||
.replace(':total', this.imagesTotal);
|
||||
},
|
||||
uploadIndividualFiles: function(event) {
|
||||
var fileSelect = $('input[type=file]', event.target);
|
||||
|
||||
// Get the selected files
|
||||
var files = fileSelect[0].files;
|
||||
|
||||
// Reset statistics
|
||||
this.currentStatus = '';
|
||||
this.statusMessages = [];
|
||||
this.imagesUploaded = 0;
|
||||
this.imagesFailed = 0;
|
||||
this.imagesTotal = files.length;
|
||||
this.isUploadInProgress = true;
|
||||
|
||||
// Loop through each of the selected files and upload them individually
|
||||
for (var i = 0; i < files.length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
|
||||
// We're only interested in image files
|
||||
if (!file.type.match('image.*'))
|
||||
{
|
||||
alert(language.not_an_image_file.replace(':file_name', file.name));
|
||||
this.onUploadFailed(null, file.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Upload the file
|
||||
this.uploadFile(event.target, file);
|
||||
}
|
||||
|
||||
// Prevent standard form upload
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
/*!
|
||||
* jQuery JavaScript Library v3.2.0
|
||||
* https://jquery.com/
|
||||
@ -22961,131 +23106,3 @@ var Popover = function ($) {
|
||||
}(jQuery);
|
||||
|
||||
}();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param queue_token Unique token of the upload queue to save the photos to
|
||||
* @param language Array containing language strings
|
||||
* @param urls Array containing URLs
|
||||
* @constructor
|
||||
*/
|
||||
function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
this.el = '#upload-tab';
|
||||
this.data = {
|
||||
currentStatus: '',
|
||||
imagesFailed: 0,
|
||||
imagesTotal: 0,
|
||||
isBulkUploadInProgress: false,
|
||||
isUploadInProgress: false,
|
||||
statusMessages: []
|
||||
};
|
||||
this.computed = {
|
||||
// a computed getter
|
||||
failedPercentage: function () {
|
||||
return ((this.imagesFailed() / this.imagesTotal()) * 100).toFixed(2) + '%';
|
||||
},
|
||||
successfulPercentage: function () {
|
||||
return ((self.imagesUploaded() / self.imagesTotal()) * 100).toFixed(2) + '%';
|
||||
}
|
||||
};
|
||||
this.methods = {
|
||||
// This method is called when an image is uploaded - regardless if it fails or not
|
||||
onUploadCompleted: function () {
|
||||
this.currentStatus = language.upload_status
|
||||
.replace(':current', (self.imagesUploaded + self.imagesFailed))
|
||||
.replace(':total', self.imagesTotal);
|
||||
|
||||
if ((this.imagesFailed + this.imagesUploaded) >= this.imagesTotal) {
|
||||
this.isUploadInProgress = false;
|
||||
|
||||
if (this.imagesFailed == 0 && this.imagesUploaded > 0) {
|
||||
window.location = urls.analyse;
|
||||
}
|
||||
}
|
||||
},
|
||||
// This method is called when an uploaded image fails
|
||||
onUploadFailed: function (data, file_name) {
|
||||
this.imagesFailed++;
|
||||
this.statusMessages.push({
|
||||
'message_class': 'text-danger',
|
||||
'message_text': language.image_failed.replace(':file_name', file_name)
|
||||
});
|
||||
this.onUploadCompleted();
|
||||
},
|
||||
// This method is called when an uploaded image succeeds
|
||||
onUploadSuccessful: function (data, file_name) {
|
||||
if (data.is_successful) {
|
||||
self.imagesUploaded++;
|
||||
// Don't add to statusMessages() array so user only sees errors
|
||||
/*self.statusMessages.push({
|
||||
'message_class': 'text-success',
|
||||
'message_text': language.image_uploaded.replace(':file_name', file_name)
|
||||
});*/
|
||||
self.onUploadCompleted();
|
||||
}
|
||||
else {
|
||||
self.onUploadFailed(data, file_name);
|
||||
}
|
||||
},
|
||||
uploadFile: function uploadImageFile(formObject, imageFile) {
|
||||
var self = this;
|
||||
var formData = new FormData();
|
||||
formData.append('album_id', album_id);
|
||||
formData.append('queue_token', queue_token);
|
||||
formData.append('photo[]', imageFile, imageFile.name);
|
||||
|
||||
$.ajax(
|
||||
{
|
||||
contentType: false,
|
||||
data: formData,
|
||||
error: function (data) {
|
||||
self.onUploadFailed(data, imageFile.name);
|
||||
},
|
||||
method: $(formObject).attr('method'),
|
||||
processData: false,
|
||||
success: function (data) {
|
||||
self.onUploadSuccessful(data, imageFile.name);
|
||||
},
|
||||
url: $(formObject).attr('action')
|
||||
}
|
||||
);
|
||||
this.isUploadInProgress = true;
|
||||
},
|
||||
uploadIndividualFiles: function(event) {
|
||||
var fileSelect = $('input[type=file]', event.target);
|
||||
|
||||
// Get the selected files
|
||||
var files = fileSelect[0].files;
|
||||
|
||||
// Reset statistics
|
||||
this.currentStatus = '';
|
||||
this.statusMessages = [];
|
||||
this.imagesUploaded = 0;
|
||||
this.imagesFailed = 0;
|
||||
this.imagesTotal = files.length;
|
||||
this.isUploadInProgress = true;
|
||||
|
||||
// Loop through each of the selected files and upload them individually
|
||||
for (var i = 0; i < files.length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
|
||||
// We're only interested in image files
|
||||
if (!file.type.match('image.*'))
|
||||
{
|
||||
alert(language.not_an_image_file.replace(':file_name', file.name));
|
||||
this.onUploadFailed(null, file.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Upload the file
|
||||
this.uploadFile($(this), file);
|
||||
}
|
||||
|
||||
// Prevent standard form upload
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
16
public/js/blue-twilight.min.js
vendored
16
public/js/blue-twilight.min.js
vendored
File diff suppressed because one or more lines are too long
@ -12,17 +12,31 @@ function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
currentStatus: '',
|
||||
imagesFailed: 0,
|
||||
imagesTotal: 0,
|
||||
imagesUploaded: 0,
|
||||
isBulkUploadInProgress: false,
|
||||
isUploadInProgress: false,
|
||||
statusMessages: []
|
||||
};
|
||||
this.computed = {
|
||||
// a computed getter
|
||||
failedPercentage: function () {
|
||||
return ((this.imagesFailed / this.imagesTotal) * 100).toFixed(2) + '%';
|
||||
var result = 0;
|
||||
|
||||
if (this.imagesTotal > 0)
|
||||
{
|
||||
result = (this.imagesFailed / this.imagesTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
},
|
||||
successfulPercentage: function () {
|
||||
return ((self.imagesUploaded / self.imagesTotal) * 100).toFixed(2) + '%';
|
||||
var result = 0;
|
||||
|
||||
if (this.imagesTotal > 0)
|
||||
{
|
||||
result = (this.imagesUploaded / this.imagesTotal) * 100;
|
||||
}
|
||||
|
||||
return result.toFixed(2) + '%';
|
||||
}
|
||||
};
|
||||
this.methods = {
|
||||
@ -35,7 +49,7 @@ function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
if ((this.imagesFailed + this.imagesUploaded) >= this.imagesTotal) {
|
||||
this.isUploadInProgress = false;
|
||||
|
||||
if (this.imagesFailed == 0 && this.imagesUploaded > 0) {
|
||||
if (this.imagesFailed === 0 && this.imagesUploaded > 0) {
|
||||
window.location = urls.analyse;
|
||||
}
|
||||
}
|
||||
@ -87,6 +101,10 @@ function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
||||
}
|
||||
);
|
||||
this.isUploadInProgress = true;
|
||||
|
||||
this.currentStatus = language.upload_status
|
||||
.replace(':current', 0)
|
||||
.replace(':total', this.imagesTotal);
|
||||
},
|
||||
uploadIndividualFiles: function(event) {
|
||||
var fileSelect = $('input[type=file]', event.target);
|
||||
|
@ -43,6 +43,7 @@ return [
|
||||
'default_storage_legend' => 'Default storage location for new albums.',
|
||||
'delete_album' => 'Delete album :name',
|
||||
'delete_album_confirm' => 'Are you sure you want to permanently delete this album and all its contents?',
|
||||
'delete_album_success_message' => 'The album ":album" was deleted successfully.',
|
||||
'delete_album_warning' => 'This is a permanent action that cannot be undone!',
|
||||
'delete_bulk_photos_message' => 'Are you sure you want to delete the selected photos? This action cannot be undone!',
|
||||
'delete_bulk_photos_title' => 'Delete selected photos',
|
||||
|
@ -2,33 +2,32 @@
|
||||
@section('title', trans('admin.delete_album', ['name' => $album->name]))
|
||||
|
||||
@section('breadcrumb')
|
||||
<div class="breadcrumb">
|
||||
<div class="container">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ route('home') }}"><i class="fa fa-fw fa-home"></i></a></li>
|
||||
<li><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li>
|
||||
<li><a href="{{ route('albums.index') }}">@lang('navigation.breadcrumb.albums')</a></li>
|
||||
<li><a href="{{ route('albums.show', ['id' => $album->id]) }}">{{ $album->name }}</a></li>
|
||||
<li class="active">@lang('navigation.breadcrumb.delete_album')</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}"><i class="fa fa-fw fa-home"></i></a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('albums.index') }}">@lang('navigation.breadcrumb.albums')</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('albums.show', ['id' => $album->id]) }}">{{ $album->name }}</a></li>
|
||||
<li class="breadcrumb-item active">@lang('navigation.breadcrumb.delete_album')</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h1>@yield('title')</h1>
|
||||
<p>@lang('admin.delete_album_confirm', ['name' => $album->name])</p>
|
||||
<div class="alert alert-danger">
|
||||
@lang('admin.delete_album_warning')
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
{!! Form::open(['route' => ['albums.destroy', $album->id], 'method' => 'DELETE']) !!}
|
||||
<a href="{{ route('albums.show', ['id' => $album->id]) }}" class="btn btn-default">@lang('forms.cancel_action')</a>
|
||||
<button type="submit" class="btn btn-danger"><i class="fa fa-fw fa-trash"></i> @lang('forms.delete_action')</button>
|
||||
{!! Form::close() !!}
|
||||
<div class="col-md-8 offset-md-2">
|
||||
<div class="card card-outline-danger">
|
||||
<div class="card-header card-danger">@yield('title')</div>
|
||||
<div class="card-block">
|
||||
<p>@lang('admin.delete_album_confirm', ['name' => $album->name])</p>
|
||||
<p class="text-danger"><b>@lang('admin.delete_album_warning')</b></p>
|
||||
|
||||
<div class="text-right">
|
||||
<form action="{{ route('albums.destroy', [$album->id]) }}" method="POST">
|
||||
{{ csrf_field() }}
|
||||
{{ method_field('DELETE') }}
|
||||
<a href="{{ route('albums.show', ['id' => $album->id]) }}" class="btn btn-link">@lang('forms.cancel_action')</a>
|
||||
<button type="submit" class="btn btn-danger"><i class="fa fa-fw fa-trash"></i> @lang('forms.delete_action')</button>
|
||||
</form>
|
||||
</div>
|
||||
</pdiv>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -359,18 +359,26 @@
|
||||
|
||||
// Bind the view models to the relevant tab
|
||||
//ko.applyBindings(editViewModel, document.getElementById('photos-tab'));
|
||||
//ko.applyBindings(viewModel, document.getElementById('upload-tab'));
|
||||
var appUpload = new Vue(viewModel);
|
||||
appUpload.$watch('isUploadInProgress', function(value) {
|
||||
if (value)
|
||||
{
|
||||
$('#upload-progress-modal').modal('show');
|
||||
}
|
||||
else if (this.statusMessages.length == 0)
|
||||
else if (this.statusMessages.length === 0)
|
||||
{
|
||||
$('#upload-progress-modal').modal('hide');
|
||||
}
|
||||
});
|
||||
{{-- Whatever I try, I could not get VueJS to adjust the progress bars automatically --}}
|
||||
/*appUpload.$watch('failedPercentage', function(value) {
|
||||
alert('failed: ' + value);
|
||||
$('.progress-bar.bg-danger', '#upload-progress-modal').width(value);
|
||||
});
|
||||
appUpload.$watch('successfulPercentage', function(value) {
|
||||
alert('success: ' + value);
|
||||
$('.progress-bar.bg-success', '#upload-progress-modal').width(value);
|
||||
});*/
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -39,7 +39,10 @@
|
||||
|
||||
@if (isset($error))
|
||||
<div class="container">
|
||||
<div class="alert alert-danger">
|
||||
<div class="alert alert-danger alert-dismissable fade show" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<strong><i class="fa fa-exclamation-circle fa-fw"></i></strong> {{ $error }}
|
||||
</div>
|
||||
</div>
|
||||
@ -47,7 +50,10 @@
|
||||
|
||||
@if (isset($warning))
|
||||
<div class="container">
|
||||
<div class="alert alert-warning">
|
||||
<div class="alert alert-warning alert-dismissable fade show" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<strong><i class="fa fa-warning fa-fw"></i></strong> {{ $warning }}
|
||||
</div>
|
||||
</div>
|
||||
@ -55,7 +61,10 @@
|
||||
|
||||
@if (isset($success))
|
||||
<div class="container">
|
||||
<div class="alert alert-success">
|
||||
<div class="alert alert-success alert-dismissable fade show" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<strong><i class="fa fa-info-circle fa-fw"></i></strong> {{ $success }}
|
||||
</div>
|
||||
</div>
|
||||
@ -63,7 +72,10 @@
|
||||
|
||||
@if (isset($info))
|
||||
<div class="container">
|
||||
<div class="alert alert-info">
|
||||
<div class="alert alert-info alert-dismissable fade show" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<strong><i class="fa fa-info-circle fa-fw"></i></strong> {{ $info }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -72,11 +72,9 @@
|
||||
<div class="modal-body">
|
||||
<div class="text-center">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" v-bind:style="{ width: successfulPercentage }">
|
||||
<span class="sr-only"><span class="percentage-success" v-text="successfulPercentage"></span></span>
|
||||
<div class="progress-bar bg-success" role="progressbar" v-bind:style="{ width: successfulPercentage }">
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-danger" v-bind:style="{ width: failedPercentage }">
|
||||
<span class="sr-only"><span class="percentage-danger" v-text="failedPercentage"></span></span>
|
||||
<div class="progress-bar bg-danger" role="progressbar" v-bind:style="{ width: failedPercentage }">
|
||||
</div>
|
||||
</div>
|
||||
<p v-text="currentStatus"></p>
|
||||
|
Loading…
Reference in New Issue
Block a user