diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php index 2ef5b1228..9fcd5c304 100644 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@ -10,6 +10,9 @@ use Intervention\Image\Facades\Image as ImageTool; use Illuminate\Support\Facades\DB; use Oxbow\Http\Requests; use Oxbow\Image; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; class ImageController extends Controller { @@ -71,7 +74,7 @@ class ImageController extends Controller */ public function getAll($page = 0) { - $pageSize = 25; + $pageSize = 30; $images = DB::table('images')->orderBy('created_at', 'desc') ->skip($page*$pageSize)->take($pageSize)->get(); foreach($images as $image) { @@ -146,5 +149,44 @@ class ImageController extends Controller return response()->json($this->image); } + /** + * Update image details + * @param $imageId + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function update($imageId, Request $request) + { + $this->validate($request, [ + 'name' => 'required|min:2|string' + ]); + $image = $this->image->findOrFail($imageId); + $image->fill($request->all()); + $image->save(); + return response()->json($this->image); + } + + /** + * Deletes an image and all thumbnail/image files + * @param $id + * @return \Illuminate\Http\JsonResponse + */ + public function destroy($id) + { + $image = $this->image->findOrFail($id); + + // Delete files + $folder = public_path() . dirname($image->url); + $pattern = '/' . preg_quote(basename($image->url)). '/'; + $dir = new RecursiveDirectoryIterator($folder); + $ite = new RecursiveIteratorIterator($dir); + $files = new RegexIterator($ite, $pattern, RegexIterator::ALL_MATCHES); + foreach($files as $path => $file) { + unlink($path); + } + $image->delete(); + return response()->json('Image Deleted'); + } + } diff --git a/app/Http/routes.php b/app/Http/routes.php index 0b723b98a..ecda75793 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -68,6 +68,8 @@ Route::group(['middleware' => 'auth'], function() { // Image routes Route::get('/images/all', 'ImageController@getAll'); + Route::put('/images/update/{imageId}', 'ImageController@update'); + Route::delete('/images/{imageId}', 'ImageController@destroy'); Route::get('/images/all/{page}', 'ImageController@getAll'); Route::get('/images/{any}', 'ImageController@getImage')->where('any', '.*'); diff --git a/app/Image.php b/app/Image.php index 9d2835dc3..07db68785 100644 --- a/app/Image.php +++ b/app/Image.php @@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Model; class Image extends Model { + + protected $fillable = ['name']; + public function getFilePath() { return storage_path() . $this->url; diff --git a/resources/assets/js/image-manager.js b/resources/assets/js/image-manager.js index 27deed51e..4f8695ff8 100644 --- a/resources/assets/js/image-manager.js +++ b/resources/assets/js/image-manager.js @@ -1,4 +1,30 @@ +jQuery.fn.showSuccess = function(message) { + var elem = $(this); + var success = $('
'); + elem.after(success); + success.slideDown(400, function() { + setTimeout(function() {success.slideUp(400, function() { + success.remove(); + })}, 2000); + }); +}; + +jQuery.fn.showFailure = function(messageMap) { + var elem = $(this); + $.each(messageMap, function(key, messages) { + var input = elem.find('[name="'+key+'"]').last(); + var fail = $(' '); + input.after(fail); + fail.slideDown(400, function() { + setTimeout(function() {fail.slideUp(400, function() { + fail.remove(); + })}, 2000); + }); + }); + +}; + (function() { var ImageManager = new Vue({ @@ -56,7 +82,7 @@ var dblClickTime = 380; var cTime = (new Date()).getTime(); var timeDiff = cTime - this.cClickTime; - if(this.cClickTime !== 0 && timeDiff < dblClickTime) { + if(this.cClickTime !== 0 && timeDiff < dblClickTime && this.selectedImage === image) { // DoubleClick if(this.callback) { this.callback(image); @@ -68,6 +94,13 @@ this.cClickTime = cTime; }, + selectButtonClick: function() { + if(this.callback) { + this.callback(this.selectedImage); + } + this.hide(); + }, + show: function(callback) { this.callback = callback; this.$$.overlay.style.display = 'block'; @@ -81,6 +114,34 @@ hide: function() { this.$$.overlay.style.display = 'none'; + }, + + saveImageDetails: function(e) { + e.preventDefault(); + var _this = this; + var form = $(_this.$$.imageForm); + $.ajax('/images/update/' + _this.selectedImage.id, { + method: 'PUT', + data: form.serialize() + }).done(function() { + form.showSuccess('Image name updated'); + }).fail(function(jqXHR) { + form.showFailure(jqXHR.responseJSON); + }) + }, + + deleteImage: function(e) { + e.preventDefault(); + var _this = this; + var form = $(_this.$$.imageDeleteForm); + $.ajax('/images/' + _this.selectedImage.id, { + method: 'DELETE', + data: form.serialize() + }).done(function() { + _this.images.splice(_this.images.indexOf(_this.selectedImage), 1); + _this.selectedImage = false; + $(_this.$$.imageTitle).showSuccess('Image Deleted'); + }) } } diff --git a/resources/assets/sass/_animations.scss b/resources/assets/sass/_animations.scss new file mode 100644 index 000000000..147197e1d --- /dev/null +++ b/resources/assets/sass/_animations.scss @@ -0,0 +1,17 @@ + +.anim.fadeIn { + opacity: 0; + animation-name: fadeIn; + animation-duration: 160ms; + animation-timing-function: ease-in-out; + animation-fill-mode: forwards; +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} \ No newline at end of file diff --git a/resources/assets/sass/_forms.scss b/resources/assets/sass/_forms.scss index 5472e3053..f6b4a3d8a 100644 --- a/resources/assets/sass/_forms.scss +++ b/resources/assets/sass/_forms.scss @@ -45,6 +45,12 @@ input[type="text"], input[type="number"], input[type="email"], input[type="searc margin-bottom: $-s; } +.form-group { + .text-pos, .text-neg { + padding: $-xs 0; + } +} + .inline-input-style { border: 2px dotted #BBB; display: block; diff --git a/resources/assets/sass/_text.scss b/resources/assets/sass/_text.scss index f09c57121..a542da8a1 100644 --- a/resources/assets/sass/_text.scss +++ b/resources/assets/sass/_text.scss @@ -82,7 +82,7 @@ hr { &.faded { background-image: linear-gradient(to right, #FFF, #e3e0e0 20%, #e3e0e0 80%, #FFF); } - &.margin-top { + &.margin-top, &.even { margin-top: $-l; } } @@ -227,4 +227,11 @@ ul { .list > * { display: block; +} + +/** + * Icons + */ +i { + padding-right: $-xs; } \ No newline at end of file diff --git a/resources/assets/sass/image-manager.scss b/resources/assets/sass/image-manager.scss index 15976e733..fc2d2f368 100644 --- a/resources/assets/sass/image-manager.scss +++ b/resources/assets/sass/image-manager.scss @@ -1,6 +1,5 @@ .image-manager-body { - background-color: rgb(37, 37, 37); - max-width: 90%; + background-color: #FFF; max-height: 90%; width: 90%; height: 90%; @@ -9,18 +8,7 @@ border-radius: 4px; box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3); overflow: hidden; - .image-manager-list img { - border-radius: 0; - float: left; - margin: 0; - cursor: pointer; - width: 150px; - height: 150px; - border: 1px solid transparent; - &.selected { - border: 3px solid #EEE; - } - } + max-width: 1340px; position: fixed; top: 0; bottom: 0; @@ -28,34 +16,48 @@ z-index: 999; display: flex; p, h1, h2, h3, h4, label, input { - color: #EEE; + color: #444; } h1, h2, h3 { font-weight: 300; } } #image-manager .dropzone-container { - height: 100px; position: relative; + border: 3px dashed #DDD; } -#container { - height: 90vh; +.image-manager-bottom { + position: absolute; + bottom: 0; + right: 0; } +.image-manager-list img { + display: block; + border-radius: 0; + float: left; + margin: 0; + cursor: pointer; + width: (100%/6); + height: auto; + border: 1px solid #FFF; + transition: all cubic-bezier(.4,0,1,1) 160ms; + &.selected { + transform: scale3d(0.92, 0.92, 0.92); + } +} #image-manager .load-more { - width: 150px; - height: 150px; display: block; - float: left; text-align: center; - background-color: #404040; - margin: 1px; - color: #FFF; - line-height: 140px; + background-color: #EEE; + padding: $-s $-m; + color: #AAA; + clear: both; font-size: 20px; cursor: pointer; + font-style: italic; } .image-manager-sidebar { @@ -75,6 +77,7 @@ .image-manager-list { overflow-y: scroll; flex: 1; + border-top: 1px solid #ddd; } .image-manager-content { @@ -93,19 +96,13 @@ * Copyright (c) 2012 Matias Meno