Implemented a Javascript viewmodel for analysing an album, added checks for if uploads cannot be completed. Implemented handling if POST request is over the max size configured in php.ini
This commit is contained in:
parent
6be14d385a
commit
fde988e359
@ -4,6 +4,39 @@ namespace App\Helpers;
|
|||||||
|
|
||||||
class MiscHelper
|
class MiscHelper
|
||||||
{
|
{
|
||||||
|
public static function convertToBytes($val)
|
||||||
|
{
|
||||||
|
if(empty($val))return 0;
|
||||||
|
|
||||||
|
$val = trim($val);
|
||||||
|
|
||||||
|
preg_match('#([0-9]+)[\s]*([a-z]+)#i', $val, $matches);
|
||||||
|
|
||||||
|
$last = '';
|
||||||
|
if(isset($matches[2])){
|
||||||
|
$last = $matches[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($matches[1])){
|
||||||
|
$val = (int) $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (strtolower($last))
|
||||||
|
{
|
||||||
|
case 'g':
|
||||||
|
case 'gb':
|
||||||
|
$val *= 1024;
|
||||||
|
case 'm':
|
||||||
|
case 'mb':
|
||||||
|
$val *= 1024;
|
||||||
|
case 'k':
|
||||||
|
case 'kb':
|
||||||
|
$val *= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $val;
|
||||||
|
}
|
||||||
|
|
||||||
public static function gravatarUrl($emailAddress, $size = 48, $default = 'identicon')
|
public static function gravatarUrl($emailAddress, $size = 48, $default = 'identicon')
|
||||||
{
|
{
|
||||||
$hash = md5(strtolower(trim($emailAddress)));
|
$hash = md5(strtolower(trim($emailAddress)));
|
||||||
|
@ -5,6 +5,7 @@ namespace app\Http\Controllers\Admin;
|
|||||||
use App\Album;
|
use App\Album;
|
||||||
use App\Facade\Theme;
|
use App\Facade\Theme;
|
||||||
use App\Facade\UserConfig;
|
use App\Facade\UserConfig;
|
||||||
|
use App\Helpers\MiscHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests;
|
use App\Http\Requests;
|
||||||
use App\Photo;
|
use App\Photo;
|
||||||
@ -32,7 +33,7 @@ class AlbumController extends Controller
|
|||||||
->orderBy('created_at')
|
->orderBy('created_at')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
return Theme::render('admin.album_analyse_progress', ['album' => $album, 'photos' => $photos]);
|
return Theme::render('admin.analyse_album', ['album' => $album, 'photos' => $photos]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,6 +131,12 @@ class AlbumController extends Controller
|
|||||||
->orderBy(DB::raw('COALESCE(taken_at, created_at)'))
|
->orderBy(DB::raw('COALESCE(taken_at, created_at)'))
|
||||||
->paginate(UserConfig::get('items_per_page_admin'));
|
->paginate(UserConfig::get('items_per_page_admin'));
|
||||||
|
|
||||||
|
// See if we can upload (need the GD extension)
|
||||||
|
$isUploadEnabled = extension_loaded('gd');
|
||||||
|
$fileUploadLimit = MiscHelper::convertToBytes(ini_get('upload_max_filesize')) / (1024*1024);
|
||||||
|
$postLimit = MiscHelper::convertToBytes(ini_get('post_max_size')) / (1024*1024);
|
||||||
|
$fileUploadOrPostLowerLimit = ($postLimit < $fileUploadLimit) ? $postLimit : $fileUploadLimit;
|
||||||
|
|
||||||
return Theme::render('admin.show_album', [
|
return Theme::render('admin.show_album', [
|
||||||
'album' => $album,
|
'album' => $album,
|
||||||
'bulk_actions' => [
|
'bulk_actions' => [
|
||||||
@ -140,6 +147,10 @@ class AlbumController extends Controller
|
|||||||
'delete' => trans('admin.photo_actions.delete')
|
'delete' => trans('admin.photo_actions.delete')
|
||||||
],
|
],
|
||||||
'error' => $request->session()->get('error'),
|
'error' => $request->session()->get('error'),
|
||||||
|
'file_upload_limit' => $fileUploadLimit,
|
||||||
|
'is_upload_enabled' => $isUploadEnabled,
|
||||||
|
'max_post_limit' => $postLimit,
|
||||||
|
'max_post_limit_bulk' => $fileUploadOrPostLowerLimit,
|
||||||
'photos' => $photos
|
'photos' => $photos
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class PhotoController extends Controller
|
|||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('auth');
|
$this->middleware(['auth', 'max_post_size_exceeded']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function analyse($photoId)
|
public function analyse($photoId)
|
||||||
@ -215,11 +215,17 @@ class PhotoController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('admin-access');
|
$this->authorize('admin-access');
|
||||||
|
|
||||||
$archiveFile = UploadedFile::createFromBase($request->files->get('archive'));
|
|
||||||
|
|
||||||
// Load the linked album
|
// Load the linked album
|
||||||
$album = $this->loadAlbum($request->get('album_id'));
|
$album = $this->loadAlbum($request->get('album_id'));
|
||||||
|
|
||||||
|
$archiveFile = UploadedFile::createFromBase($request->files->get('archive'));
|
||||||
|
if ($archiveFile->getError() != UPLOAD_ERR_OK)
|
||||||
|
{
|
||||||
|
Log::error('Bulk image upload failed.', ['error' => $archiveFile->getError(), 'reason' => $archiveFile->getErrorMessage()]);
|
||||||
|
$request->session()->flash('error', $archiveFile->getErrorMessage());
|
||||||
|
return redirect(route('albums.show', ['id' => $album->id]));
|
||||||
|
}
|
||||||
|
|
||||||
// Create a temporary folder to hold the extracted files
|
// Create a temporary folder to hold the extracted files
|
||||||
$tempFolder = sprintf('%s/btw_upload_%s', env('TEMP_FOLDER', '/tmp'), MiscHelper::randomString());
|
$tempFolder = sprintf('%s/btw_upload_%s', env('TEMP_FOLDER', '/tmp'), MiscHelper::randomString());
|
||||||
mkdir($tempFolder);
|
mkdir($tempFolder);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http;
|
namespace App\Http;
|
||||||
|
|
||||||
|
use App\Http\Middleware\CheckMaxPostSizeExceeded;
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
class Kernel extends HttpKernel
|
||||||
@ -51,6 +52,7 @@ class Kernel extends HttpKernel
|
|||||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
'max_post_size_exceeded' => CheckMaxPostSizeExceeded::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
51
app/Http/Middleware/CheckMaxPostSizeExceeded.php
Normal file
51
app/Http/Middleware/CheckMaxPostSizeExceeded.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Helpers\MiscHelper;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CheckMaxPostSizeExceeded
|
||||||
|
{
|
||||||
|
protected $exclude = [
|
||||||
|
'/admin/photos/analyse/*',
|
||||||
|
'/admin/photos/regenerate-thumbnails/*'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($request->method() == 'POST' && !$this->shouldExclude($request))
|
||||||
|
{
|
||||||
|
// Check post limit and see if it may have been exceeded
|
||||||
|
$postLimit = MiscHelper::convertToBytes(ini_get('post_max_size'));
|
||||||
|
|
||||||
|
if (
|
||||||
|
(isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > $postLimit) ||
|
||||||
|
(empty($_POST) && empty($_REQUEST))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$request->session()->flash('error', trans('global.post_max_exceeded'));
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shouldExclude(Request $request)
|
||||||
|
{
|
||||||
|
foreach ($this->exclude as $exclude)
|
||||||
|
{
|
||||||
|
if ($exclude !== '/') {
|
||||||
|
$exclude = trim($exclude, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->is($exclude)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ class VerifyCsrfToken extends BaseVerifier
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $except = [
|
protected $except = [
|
||||||
//
|
'/admin/photos',
|
||||||
|
'/admin/photos/store-bulk'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,103 @@
|
|||||||
|
function AnalyseAlbumViewModel()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.imagesFailed = ko.observableArray();
|
||||||
|
self.imagesToAnalyse = ko.observableArray();
|
||||||
|
self.numberSuccessful = ko.observable(0);
|
||||||
|
self.numberFailed = ko.observable(0);
|
||||||
|
|
||||||
|
self.numberTotal = ko.computed(function() {
|
||||||
|
return self.imagesToAnalyse().length;
|
||||||
|
});
|
||||||
|
|
||||||
|
self.failedPercentage = ko.computed(function()
|
||||||
|
{
|
||||||
|
return ((self.numberFailed() / self.numberTotal()) * 100).toFixed(2) + '%';
|
||||||
|
});
|
||||||
|
self.successfulPercentage = ko.computed(function()
|
||||||
|
{
|
||||||
|
return ((self.numberSuccessful() / self.numberTotal()) * 100).toFixed(2) + '%';
|
||||||
|
});
|
||||||
|
|
||||||
|
self.isCompleted = ko.computed(function()
|
||||||
|
{
|
||||||
|
return self.numberTotal() > 0 && (self.numberSuccessful() + self.numberFailed() >= self.numberTotal());
|
||||||
|
});
|
||||||
|
|
||||||
|
// When an image is added to the array, automatically issue it for analysis
|
||||||
|
self.imagesToAnalyse.subscribe(function(changes)
|
||||||
|
{
|
||||||
|
// changes[0].value is an instance of AnalyseImageViewModel
|
||||||
|
var item = changes[0].value;
|
||||||
|
$.ajax(
|
||||||
|
item.url(),
|
||||||
|
{
|
||||||
|
dataType: 'json',
|
||||||
|
error: function (xhr, textStatus, errorThrown)
|
||||||
|
{
|
||||||
|
self.numberFailed(self.numberFailed() + 1);
|
||||||
|
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(self.numberSuccessful() + 1);
|
||||||
|
item.isSuccessful(true);
|
||||||
|
item.isPending(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.numberFailed(self.numberFailed() + 1);
|
||||||
|
self.imagesFailed.push({
|
||||||
|
'name': item.name(),
|
||||||
|
'reason': data.message
|
||||||
|
});
|
||||||
|
item.isSuccessful(false);
|
||||||
|
item.isPending(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, null, 'arrayChange');
|
||||||
|
}
|
||||||
|
|
||||||
|
function AnalyseImageViewModel(image_info)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.isPending = ko.observable(true);
|
||||||
|
self.isSuccessful = ko.observable(false);
|
||||||
|
self.name = ko.observable(image_info.name);
|
||||||
|
self.photoID = ko.observable(image_info.photo_id);
|
||||||
|
self.url = ko.observable(image_info.url);
|
||||||
|
|
||||||
|
self.iconClass = ko.computed(function() {
|
||||||
|
var string = 'fa fa-fw ';
|
||||||
|
|
||||||
|
if (!self.isPending())
|
||||||
|
{
|
||||||
|
string += (self.isSuccessful() ? 'check text-success' : 'times text-danger')
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file 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 language Array containing language strings
|
||||||
|
* @param urls Array containing URLs
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
function UploadPhotosViewModel(album_id, language, urls)
|
function UploadPhotosViewModel(album_id, language, urls)
|
||||||
{
|
{
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -6,6 +106,7 @@ function UploadPhotosViewModel(album_id, language, urls)
|
|||||||
self.imagesFailed = ko.observable(0);
|
self.imagesFailed = ko.observable(0);
|
||||||
self.imagesUploaded = ko.observable(0);
|
self.imagesUploaded = ko.observable(0);
|
||||||
self.imagesTotal = ko.observable(0);
|
self.imagesTotal = ko.observable(0);
|
||||||
|
self.isBulkUploadInProgress = ko.observable(false);
|
||||||
self.isUploadInProgress = ko.observable(false);
|
self.isUploadInProgress = ko.observable(false);
|
||||||
self.statusMessages = ko.observableArray();
|
self.statusMessages = ko.observableArray();
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ return [
|
|||||||
'album_photos_tab' => 'Photos',
|
'album_photos_tab' => 'Photos',
|
||||||
'album_settings_tab' => 'Settings',
|
'album_settings_tab' => 'Settings',
|
||||||
'album_upload_tab' => 'Upload',
|
'album_upload_tab' => 'Upload',
|
||||||
|
'analyse_photos_failed' => 'The following items could not be analysed and were removed:',
|
||||||
'create_album' => 'Create a photo album',
|
'create_album' => 'Create a photo album',
|
||||||
'create_album_intro' => 'Photo albums contain individual photographs together in the same way as a physical photo album or memory book.',
|
'create_album_intro' => 'Photo albums contain individual photographs together in the same way as a physical photo album or memory book.',
|
||||||
'create_album_intro2' => 'Complete the form below to create a photo album.',
|
'create_album_intro2' => 'Complete the form below to create a photo album.',
|
||||||
@ -57,10 +58,18 @@ return [
|
|||||||
'upload_max_limit' => 'Upload limit (maximum size):'
|
'upload_max_limit' => 'Upload limit (maximum size):'
|
||||||
],
|
],
|
||||||
'title' => 'Gallery Admin',
|
'title' => 'Gallery Admin',
|
||||||
|
'upload_bulk_heading' => 'Upload a zip archive',
|
||||||
|
'upload_bulk_text' => 'You can use the form below to upload a zip archive that contains your photographs. Any valid image files in the zip archive will be imported. Common hidden folders used by operating systems will be ignored.',
|
||||||
|
'upload_bulk_text2' => 'Your web server is configured to allow files up to :max_upload_size to be uploaded.',
|
||||||
|
'upload_disabled_heading' => 'Uploading is not supported on this system.',
|
||||||
|
'upload_disabled_text' => 'This system does not have the GD extension installed, so images cannot be processed. Please ensure this extension is installed and refresh this page to try again.',
|
||||||
'upload_file_failed_continue' => 'Click the "Continue" button to analyse the file(s) that were uploaded.',
|
'upload_file_failed_continue' => 'Click the "Continue" button to analyse the file(s) that were uploaded.',
|
||||||
'upload_file_not_image_messages' => 'The file ":file_name" is not recognised as an image and won\'t be uploaded.',
|
'upload_file_not_image_messages' => 'The file ":file_name" is not recognised as an image and won\'t be uploaded.',
|
||||||
'upload_file_number_failed' => 'file(s) failed to upload.',
|
'upload_file_number_failed' => 'file(s) failed to upload.',
|
||||||
'upload_file_status_failed' => ':file_name failed to upload',
|
'upload_file_status_failed' => ':file_name failed to upload',
|
||||||
'upload_file_status_progress' => ':current of :total files completed',
|
'upload_file_status_progress' => ':current of :total files completed',
|
||||||
'upload_file_status_success' => ':file_name uploaded successfully',
|
'upload_file_status_success' => ':file_name uploaded successfully',
|
||||||
|
'upload_single_file_heading' => 'Upload photos individually',
|
||||||
|
'upload_single_file_text' => 'You can use the form below to upload individual files. To upload multiple files at once, hold down CTRL in the file browser.',
|
||||||
|
'upload_single_file_text2' => 'Your web server is configured to allow files up to :file_size. If you browser does not support HTML 5 (most modern browsers do), the combined size of all selected files must be less than :max_upload_size.'
|
||||||
];
|
];
|
@ -1,4 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
'app_name' => 'Blue Twilight'
|
'app_name' => 'Blue Twilight',
|
||||||
|
'post_max_exceeded' => 'Your upload exceeded the maximum size the web server is configured to allow. Please check the value of the "post_max_size" parameter in php.ini.',
|
||||||
|
'units' => [
|
||||||
|
'megabytes' => 'MB'
|
||||||
|
]
|
||||||
];
|
];
|
@ -5,26 +5,37 @@
|
|||||||
<div class="container" style="margin-top: 40px;">
|
<div class="container" style="margin-top: 40px;">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 col-sm-8 col-sm-offset-2">
|
<div class="col-xs-12 col-sm-8 col-sm-offset-2">
|
||||||
<div class="panel panel-default" id="status-panel">
|
<div class="panel panel-default" data-bind="visible: !isCompleted()">
|
||||||
<div class="panel-heading">Analysing...</div>
|
<div class="panel-heading">Analysing...</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>Your uploaded photos are now being analysed.</p>
|
<p>Your uploaded photos are now being analysed.</p>
|
||||||
<div id="progress-bar-container">
|
|
||||||
<div class="progress"></div>
|
<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>
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="file-list" style="margin-top: 20px;">
|
<div data-bind="foreach: imagesToAnalyse" style="margin-top: 20px;">
|
||||||
@foreach ($photos as $photo)
|
<p><span data-bind="text: name"></span> ... <i data-bind="css: iconClass"></i></p>
|
||||||
<p data-photo-id="{{ $photo->id }}">{{ $photo->name }} ... <i class="fa fa-fw"></i></p>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default" id="complete-panel" style="display: none;">
|
<div class="panel panel-default" data-bind="visible: isCompleted">
|
||||||
<div class="panel-heading">Upload completed</div>
|
<div class="panel-heading">Upload completed</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>Your upload has completed.</p>
|
<p>Your upload has completed.</p>
|
||||||
|
<div data-bind="visible: 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>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="btn-toolbar btn-group-sm pull-right">
|
<div class="btn-toolbar btn-group-sm pull-right">
|
||||||
<a class="btn btn-default" href="{{ $album->url() }}">View album</a>
|
<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>
|
<a class="btn btn-primary" href="{{ route('albums.show', ['id' => $album->id]) }}">Back to album settings</a>
|
||||||
@ -38,37 +49,20 @@
|
|||||||
|
|
||||||
@push('scripts')
|
@push('scripts')
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var number_successful = 0;
|
var viewModel = new AnalyseAlbumViewModel();
|
||||||
var number_error = 0;
|
|
||||||
var number_total = 0;
|
|
||||||
|
|
||||||
function redrawProgressBar()
|
{{-- For each photo to analyse, push an instance of AnalyseImageViewModel to our master view model --}}
|
||||||
{
|
@foreach ($photos as $photo)
|
||||||
var successPercentage = (number_successful / number_total) * 100;
|
viewModel.imagesToAnalyse.push(new AnalyseImageViewModel({
|
||||||
var failedPercentage = (number_error / number_total) * 100;
|
'id': '{{ $photo->id }}',
|
||||||
|
'name': '{!! addslashes($photo->name) !!}',
|
||||||
|
'url': '{{ route('photos.analyse', ['id' => $photo->id]) }}'
|
||||||
|
}));
|
||||||
|
@endforeach
|
||||||
|
|
||||||
{{-- Render a Bootstrap-3 compatible progress bar --}}
|
ko.applyBindings(viewModel);
|
||||||
var progressBar = $('<div/>').addClass('progress');
|
|
||||||
|
|
||||||
{{-- Successful --}}
|
/*
|
||||||
var progressBarSuccess = $('<div/>')
|
|
||||||
.addClass('progress-bar')
|
|
||||||
.addClass('progress-bar-success')
|
|
||||||
.css('width', parseInt(successPercentage) + '%')
|
|
||||||
.appendTo(progressBar);
|
|
||||||
var progressBarSuccessSpan = $('<span/>').addClass('sr-only').html(parseInt(successPercentage) + '% successful').appendTo(progressBarSuccess);
|
|
||||||
|
|
||||||
{{-- Failed --}}
|
|
||||||
var progressBarError = $('<div/>')
|
|
||||||
.addClass('progress-bar')
|
|
||||||
.addClass('progress-bar-warning')
|
|
||||||
.css('width', parseInt(failedPercentage) + '%')
|
|
||||||
.appendTo(progressBar);
|
|
||||||
var progressBarErrorSpan = $('<span/>').addClass('sr-only').html(parseInt(failedPercentage) + '% failed').appendTo(progressBarError);
|
|
||||||
|
|
||||||
{{-- Add to DOM --}}
|
|
||||||
$('#progress-bar-container').html(progressBar[0].outerHTML);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
number_total = $('#file-list p').length;
|
number_total = $('#file-list p').length;
|
||||||
@ -121,6 +115,6 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
@ -67,67 +67,89 @@
|
|||||||
|
|
||||||
{{-- Upload --}}
|
{{-- Upload --}}
|
||||||
<div role="tabpanel" class="tab-pane" id="upload-tab">
|
<div role="tabpanel" class="tab-pane" id="upload-tab">
|
||||||
<h4>Upload images</h4>
|
@if (!$is_upload_enabled)
|
||||||
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col-xs-12">
|
||||||
<div class="col-sm-5" style="margin-bottom: 20px;">
|
<p class="text-danger" style="font-weight: bold">@lang('admin.upload_disabled_heading')</p>
|
||||||
{!! Form::open(['route' => 'photos.store', 'method' => 'POST', 'files' => true, 'id' => 'single-upload-form']) !!}
|
<p>@lang('admin.upload_disabled_text')</p>
|
||||||
{!! Form::hidden('album_id', $album->id) !!}
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
{!! Form::file('photo[]', ['class' => 'control-label', 'multiple' => 'multiple', 'id' => 'single-upload-files']) !!}
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
@else
|
||||||
<button type="submit" class="btn btn-success" data-bind="disable: isUploadInProgress, text: isUploadInProgress() ? '@lang('admin.is_uploading')' : '@lang('forms.upload_action')'">@lang('forms.upload_action')</button>
|
<h4>@lang('admin.upload_single_file_heading')</h4>
|
||||||
</div>
|
<p>@lang('admin.upload_single_file_text')</p>
|
||||||
{!! Form::close() !!}
|
<div class="alert alert-info">
|
||||||
|
<p>@lang('admin.upload_single_file_text2', [
|
||||||
|
'file_size' => sprintf('<b>%s%s</b>', round($file_upload_limit, 2), trans('global.units.megabytes')),
|
||||||
|
'max_upload_size' => sprintf('<b>%s%s</b>', round($max_post_limit, 2), trans('global.units.megabytes'))
|
||||||
|
])</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-5">
|
<div class="row">
|
||||||
<div class="text-center" data-bind="visible: isUploadInProgress">
|
<div class="col-sm-5" style="margin-bottom: 20px;">
|
||||||
<p><b>@lang('admin.is_uploading')</b></p>
|
{!! Form::open(['route' => 'photos.store', 'method' => 'POST', 'files' => true, 'id' => 'single-upload-form']) !!}
|
||||||
<div class="progress">
|
{!! Form::hidden('album_id', $album->id) !!}
|
||||||
<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="form-group">
|
||||||
</div>
|
{!! Form::file('photo[]', ['class' => 'control-label', 'multiple' => 'multiple', 'id' => 'single-upload-files']) !!}
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
<p data-bind="text: currentStatus"></p>
|
|
||||||
|
<div>
|
||||||
|
<button type="submit" class="btn btn-success" data-bind="disable: (isUploadInProgress() || isBulkUploadInProgress()), text: isUploadInProgress() ? '@lang('admin.is_uploading')' : '@lang('forms.upload_action')'">@lang('forms.upload_action')</button>
|
||||||
|
</div>
|
||||||
|
{!! Form::close() !!}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-bind="visible: statusMessages().length > 0">
|
<div class="col-sm-5">
|
||||||
<p data-bind="visible: !isUploadInProgress()" class="text-danger" style="font-weight: bold">
|
<div class="text-center" data-bind="visible: isUploadInProgress">
|
||||||
<span data-bind="text: imagesFailed"></span> @lang('admin.upload_file_number_failed')
|
<p><b>@lang('admin.is_uploading')</b></p>
|
||||||
</p>
|
<div class="progress">
|
||||||
<p data-bind="visible: imagesUploaded() > 0">
|
<div class="progress-bar progress-bar-success" data-bind="style: { width: successfulPercentage() }">
|
||||||
@lang('admin.upload_file_failed_continue')<br /><br/>
|
<span class="sr-only"><span class="percentage-success" data-bind="text: successfulPercentage"></span></span>
|
||||||
<a href="{{ route('albums.analyse', ['id' => $album->id]) }}" class="btn btn-primary">@lang('forms.continue_action')</a>
|
</div>
|
||||||
</p>
|
<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>
|
||||||
|
</div>
|
||||||
|
<p data-bind="text: currentStatus"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ul data-bind="foreach: statusMessages">
|
<div data-bind="visible: statusMessages().length > 0">
|
||||||
<li data-bind="css: message_class, text: message_text"></li>
|
<p data-bind="visible: !isUploadInProgress()" class="text-danger" style="font-weight: bold">
|
||||||
</ul>
|
<span data-bind="text: imagesFailed"></span> @lang('admin.upload_file_number_failed')
|
||||||
|
</p>
|
||||||
|
<p data-bind="visible: imagesUploaded() > 0">
|
||||||
|
@lang('admin.upload_file_failed_continue')<br /><br/>
|
||||||
|
<a href="{{ route('albums.analyse', ['id' => $album->id]) }}" class="btn btn-primary">@lang('forms.continue_action')</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul data-bind="foreach: statusMessages">
|
||||||
|
<li data-bind="css: message_class, text: message_text"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<h4>Bulk upload</h4>
|
<h4>@lang('admin.upload_bulk_heading')</h4>
|
||||||
|
<p>@lang('admin.upload_bulk_text')</p>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<p>@lang('admin.upload_bulk_text2', [
|
||||||
|
'max_upload_size' => sprintf('<b>%s%s</b>', round($max_post_limit_bulk, 2), trans('global.units.megabytes'))
|
||||||
|
])</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{!! Form::open(['route' => 'photos.storeBulk', 'method' => 'POST', 'files' => true]) !!}
|
{!! Form::open(['route' => 'photos.storeBulk', 'method' => 'POST', 'files' => true, 'id' => 'bulk-upload-form']) !!}
|
||||||
{!! Form::hidden('album_id', $album->id) !!}
|
{!! Form::hidden('album_id', $album->id) !!}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{!! Form::file('archive', ['class' => 'control-label']) !!}
|
{!! Form::file('archive', ['class' => 'control-label']) !!}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{!! Form::submit(trans('forms.upload_action'), ['class' => 'btn btn-success']) !!}
|
<button type="submit" class="btn btn-success" data-bind="disable: (isUploadInProgress() || isBulkUploadInProgress()), text: isBulkUploadInProgress() ? '@lang('admin.is_uploading')' : '@lang('forms.upload_action')'">@lang('forms.upload_action')</button>
|
||||||
</div>
|
</div>
|
||||||
{!! Form::close() !!}
|
{!! Form::close() !!}
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Settings --}}
|
{{-- Settings --}}
|
||||||
@ -282,7 +304,7 @@
|
|||||||
if (!file.type.match('image.*'))
|
if (!file.type.match('image.*'))
|
||||||
{
|
{
|
||||||
alert(notImageString.replace(':file_name', file.name));
|
alert(notImageString.replace(':file_name', file.name));
|
||||||
viewModel.onUploadFailed();
|
viewModel.onUploadFailed(null, file.name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,6 +316,13 @@
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#bulk-upload-form').submit(function(event) {
|
||||||
|
// Set the in progress flag - no need to unset it as this is a synchronous process so the browser
|
||||||
|
// will reload the page in some way after completion
|
||||||
|
viewModel.isBulkUploadInProgress(true);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ko.applyBindings(viewModel);
|
ko.applyBindings(viewModel);
|
||||||
|
Loading…
Reference in New Issue
Block a user