Skip to content

Commit

Permalink
v2.5.0
Browse files Browse the repository at this point in the history
- image editor https://github.com/ctf0/Laravel-Media-Manager/wiki/Optimize-Edited-Images-On-Save

- update readme
- update wiki
- update resources
  • Loading branch information
ctf0 committed Jan 16, 2018
1 parent d02d501 commit 7d1992b
Show file tree
Hide file tree
Showing 20 changed files with 1,089 additions and 154 deletions.
45 changes: 27 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The only media manager with this number of features & flexibility.

<p align="center">
<img src="https://user-images.githubusercontent.com/7388088/34068133-75687998-e23f-11e7-98a8-cd7ded43d209.png">
<img src="https://user-images.githubusercontent.com/7388088/34976419-40c1bc90-fa9f-11e7-921f-f311e3099dcc.png">
</p>

- to optimize uploaded files on the fly try [approached](https://github.com/approached/laravel-image-optimizer) or [spatie](https://github.com/spatie/laravel-image-optimizer)
Expand All @@ -31,15 +31,15 @@ The only media manager with this number of features & flexibility.
`php artisan vendor:publish --provider="ctf0\MediaManager\MediaManagerServiceProvider"`

- after installation, package will auto-add
+ package routes to `routes/web.php`
+ package assets compiling to `webpack.mix.js`
+ package routes to `routes/web.php`
+ package assets compiling to `webpack.mix.js`

- install dependencies

```bash
yarn add vue vue-ls vue-multi-ref vue-tippy@v1 vue2-filters vue-bounty vue-notif vue-clipboard2 vue-awesome vue-touch@next axios dropzone keycode babel-preset-es2015-node6 babel-preset-stage-2
yarn add vue vue-ls vue-multi-ref vue-tippy@v1 vue2-filters vue-bounty vue-notif vue-clipboard2 vue-awesome vue-touch@next axios dropzone cropperjs keycode babel-preset-es2015-node6 babel-preset-stage-2
# or
npm install vue vue-ls vue-multi-ref vue-tippy@v1 vue2-filters vue-bounty vue-notif vue-clipboard2 vue-awesome vue-touch@next axios dropzone keycode babel-preset-es2015-node6 babel-preset-stage-2 --save
npm install vue vue-ls vue-multi-ref vue-tippy@v1 vue2-filters vue-bounty vue-notif vue-clipboard2 vue-awesome vue-touch@next axios dropzone cropperjs keycode babel-preset-es2015-node6 babel-preset-stage-2 --save
```

- add this one liner to your main js file and run `npm run watch` to compile your `js/css` files.
Expand All @@ -57,12 +57,13 @@ new Vue({

## Features

- [image editor](https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor)
- multi
+ upload
+ move/copy
+ delete
- upload an image from a url
- bulk selection
- restrict access to [folders](https://github.com/ctf0/Laravel-Media-Manager/wiki/Folder-Restriction)
- dynamically hide [files](https://github.com/ctf0/Laravel-Media-Manager/wiki/Hide-Files-With-Extension)
- dynamically hide [folders](https://github.com/ctf0/Laravel-Media-Manager/wiki/Hide-Folders)
- toggle between `random names` & `original names` for uploaded files
Expand Down Expand Up @@ -100,8 +101,9 @@ new Vue({
| navigation | button | keyboard | click / tap | touch |
|----------------|--------------------------------------------|---------------|--------------------------|-------------------------|
| | upload *(toolbar)* | u | * | |
| | refresh *(toolbar)* | r | * / hold *"clear cache"* | |
| | refresh *(toolbar)* | r | * / hold *(clear cache)* | |
| | move *(toolbar)* | m | * | swipe up |
| | editor *(toolbar)* | e | * | |
| | delete *(toolbar)* | d/del | * | swipe down |
| | lock/unlock *(toolbar)* | l | * | |
| | (reset) bulk select *(toolbar)* | b | * | |
Expand All @@ -120,6 +122,7 @@ new Vue({
| | &nbsp; | | | |
| | limit bulk select *(files container)* | shift + click | | |
| | preview image/pdf/text *(files container)* | space | ** | |
| | image editor *(files container)* | | hold | |
| | hide *(preview)* | space/esc | * | |
| select next | | right / down | * | swipe left *(preview)* |
| select prev | | left / up | * | swipe right *(preview)* |
Expand All @@ -130,17 +133,23 @@ new Vue({

- events

| type | event-name | description |
|---------|---------------------------------------|------------------------------------------|
| [JS](https://github.com/gocanto/vuemit) |
| | modal-show | when modal is showen |
| | modal-hide | when modal is hidden |
| | file_selected *(when inside modal)* | get selected file url |
| [Laravel](https://laravel.com/docs/5.5/events#manually-registering-events) |
| | MMFileUploaded($file_path) | get uploaded file full path |
| | MMFileDeleted($file_path, $is_folder) | get deleted file/folder full path |
| | MMFileRenamed($old_path, $new_path) | get renamed file/folder "old & new" path |
| | MMFileMoved($old_path, $new_path) | get moved file/folder "old & new" path |
| type | event-name | description |
|-----------------|---------------------------------------|--------------------------------------------------|
| [JS][js] | | |
| | modal-show | when modal is showen |
| | modal-hide | when modal is hidden |
| | file_selected *(when inside modal)* | get selected file url |
| [Laravel][lara] | | |
| | MMFileUploaded($file_path) | get uploaded file full [path][path] |
| | [MMFileSaved][event]($file_path) | get saved(edited/link) image full [path][path] |
| | MMFileDeleted($file_path, $is_folder) | get deleted file/folder full [path][path] |
| | MMFileRenamed($old_path, $new_path) | get renamed file/folder "old & new" [path][path] |
| | MMFileMoved($old_path, $new_path) | get moved file/folder "old & new" [path][path] |

[js]: https://github.com/gocanto/vuemit
[lara]: https://laravel.com/docs/5.5/events#manually-registering-events
[event]: https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor#optimize-edited-images-on-save
[path]: https://gist.github.com/ctf0/9fa6013954654384052d2e2e809b9bf6

<br>

Expand Down
5 changes: 0 additions & 5 deletions logs/v2.4.1.txt

This file was deleted.

9 changes: 9 additions & 0 deletions logs/v2.5.0.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- added full image editor https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor
- you can now save images from url too, it follows the same flow as the normal upload (random names, upload to current folder, events)
- added new event "MMFileSaved" for both of the above features.
- fix setting selected file twice
- fix clearing cache twice

- update readme
- update wiki
- update resources
99 changes: 96 additions & 3 deletions src/Controllers/MediaController.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public function upload(Request $request)
$original = $one->getClientOriginalName();
$name_only = pathinfo($original, PATHINFO_FILENAME);
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
$file_name = $random_name ? uniqid() . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
$file_name = $random_name ? $this->sanitizedText . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
$file_type = $one->getMimeType();
$destination = "$upload_path/$file_name";

Expand All @@ -149,13 +149,11 @@ public function upload(Request $request)
event('MMFileUploaded', $this->getFilePath($saved_name));

$result[] = [
'path' => preg_replace('/^public\//', '', $saved_name),
'success' => true,
'message' => $file_name,
];
} catch (Exception $e) {
$result[] = [
'path' => '',
'success' => false,
'message' => "\"$file_name\" " . $e->getMessage(),
];
Expand All @@ -165,6 +163,101 @@ public function upload(Request $request)
return response()->json(['data'=>$result]);
}

/**
* save cropped image.
*
* @param Request $request [description]
*
* @return [type] [description]
*/
public function uploadCropped(Request $request)
{
$path = $request->path;
$data = explode(',', $request->data)[1];
$original = $request->name;

$name_only = pathinfo($original, PATHINFO_FILENAME) . '_' . $this->sanitizedText;
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
$file_name = "$name_only.$ext_only";
$destination = "$path/$file_name";

try {
// check existence
if ($this->storageDisk->exists($destination)) {
throw new Exception(trans('MediaManager::messages.error_already_exists'));
}

// save file
$this->storageDisk->put($destination, base64_decode($data));

// fire event
event('MMFileSaved', $this->getFilePath($destination));

$result = [
'success' => true,
'message' => $file_name,
];
} catch (Exception $e) {
$result = [
'success' => false,
'message' => "\"$file_name\" " . $e->getMessage(),
];
}

return response()->json($result);
}

/**
* save image from link.
*
* @param Request $request [description]
*
* @return [type] [description]
*/
public function uploadLink(Request $request)
{
$url = $request->url;
$path = $request->path;
$random_name = $request->random_names;

$original = substr($url, strrpos($url, '/') + 1);
$name_only = pathinfo($original, PATHINFO_FILENAME);
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
$file_name = $random_name ? $this->sanitizedText . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
$destination = "$path/$file_name";
$file_type = image_type_to_mime_type(exif_imagetype($url));

try {
// check for mime type
if (str_contains($file_type, $this->unallowedMimes)) {
throw new Exception(trans('MediaManager::messages.not_allowed_file_ext', ['attr'=>$file_type]));
}

// check existence
if ($this->storageDisk->exists($destination)) {
throw new Exception(trans('MediaManager::messages.error_already_exists'));
}

// save file
$this->storageDisk->put($destination, file_get_contents($url));

// fire event
event('MMFileSaved', $this->getFilePath($destination));

$result = [
'success' => true,
'message' => $file_name,
];
} catch (Exception $e) {
$result = [
'success' => false,
'message' => "\"$file_name\" " . $e->getMessage(),
];
}

return response()->json($result);
}

/**
* create new folder.
*
Expand Down
3 changes: 3 additions & 0 deletions src/MediaRoutes.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public static function routes()
], function () use ($controller) {
Route::get('/', ['uses' => "$controller@index", 'as' => 'index']);
Route::post('upload', ['uses' => "$controller@upload", 'as' => 'upload']);
Route::post('upload-cropped', ['uses' => "$controller@uploadCropped", 'as' => 'uploadCropped']);
Route::post('upload-link', ['uses' => "$controller@uploadLink", 'as' => 'uploadLink']);

Route::post('files', ['uses' => "$controller@get_files", 'as' => 'files']);
Route::post('directories', ['uses' => "$controller@get_dirs", 'as' => 'directories']);
Route::post('new_folder', ['uses' => "$controller@new_folder", 'as' => 'new_folder']);
Expand Down
84 changes: 84 additions & 0 deletions src/resources/assets/js/components/ImageEditor/caman.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<template>
<div class="__caman">
<button class="btn-plain" @click="toggleControls()"
:class="{'is-active': controls}"
:disabled="processing"
v-tippy :title="filterName">
<span class="icon"><icon :name="processing ? 'spinner' : icon" :pulse="processing"/></span>
</button>

<transition name="list">
<div v-show="controls" class="__caman-controls">
<button class="btn-plain" :disabled="incLimit() || processing" @click="inc()">
<span class="icon"><icon :name="processing ? 'spinner' : 'plus'" :pulse="processing"/></span>
</button>
<button class="btn-plain" :disabled="decLimit() || processing" @click="dec()">
<span class="icon"><icon :name="processing ? 'spinner' : 'minus'" :pulse="processing"/></span>
</button>
</div>
</transition>
</div>
</template>

<script>
export default {
props: [
'filterName',
'icon',
'step',
'max',
'min',
'processing',
'reset'
],
data() {
return {
controls: false,
noController: [
'greyscale',
'invert'
],
range: 0
}
},
beforeMount() {
this.$options.name = `${this.filterName}-filter`
},
methods: {
toggleControls() {
if (this.noController.includes(this.filterName)) {
return this.update()
}
this.controls = !this.controls
},
inc() {
this.range += this.step
this.update(this.range)
},
dec() {
this.range -= this.step
this.update(this.range)
},
incLimit() {
return this.range == this.max
},
decLimit() {
return this.range == this.min
},
update(val = null) {
this.$parent.updateFilter(this.filterName, val)
}
},
watch: {
reset(val) {
if (val) {
this.controls = false
this.range = 0
}
}
}
}
</script>
Loading

0 comments on commit 7d1992b

Please sign in to comment.