Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 7d1992b

Browse files
committed
v2.5.0
- image editor https://github.com/ctf0/Laravel-Media-Manager/wiki/Optimize-Edited-Images-On-Save - update readme - update wiki - update resources
1 parent d02d501 commit 7d1992b

File tree

20 files changed

+1089
-154
lines changed

20 files changed

+1089
-154
lines changed

README.md

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
The only media manager with this number of features & flexibility.
66

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

1111
- 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)
@@ -31,15 +31,15 @@ The only media manager with this number of features & flexibility.
3131
`php artisan vendor:publish --provider="ctf0\MediaManager\MediaManagerServiceProvider"`
3232

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

3737
- install dependencies
3838

3939
```bash
40-
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
40+
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
4141
# or
42-
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
42+
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
4343
```
4444

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

5858
## Features
5959

60+
- [image editor](https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor)
6061
- multi
6162
+ upload
6263
+ move/copy
6364
+ delete
65+
- upload an image from a url
6466
- bulk selection
65-
- restrict access to [folders](https://github.com/ctf0/Laravel-Media-Manager/wiki/Folder-Restriction)
6667
- dynamically hide [files](https://github.com/ctf0/Laravel-Media-Manager/wiki/Hide-Files-With-Extension)
6768
- dynamically hide [folders](https://github.com/ctf0/Laravel-Media-Manager/wiki/Hide-Folders)
6869
- toggle between `random names` & `original names` for uploaded files
@@ -100,8 +101,9 @@ new Vue({
100101
| navigation | button | keyboard | click / tap | touch |
101102
|----------------|--------------------------------------------|---------------|--------------------------|-------------------------|
102103
| | upload *(toolbar)* | u | * | |
103-
| | refresh *(toolbar)* | r | * / hold *"clear cache"* | |
104+
| | refresh *(toolbar)* | r | * / hold *(clear cache)* | |
104105
| | move *(toolbar)* | m | * | swipe up |
106+
| | editor *(toolbar)* | e | * | |
105107
| | delete *(toolbar)* | d/del | * | swipe down |
106108
| | lock/unlock *(toolbar)* | l | * | |
107109
| | (reset) bulk select *(toolbar)* | b | * | |
@@ -120,6 +122,7 @@ new Vue({
120122
| | &nbsp; | | | |
121123
| | limit bulk select *(files container)* | shift + click | | |
122124
| | preview image/pdf/text *(files container)* | space | ** | |
125+
| | image editor *(files container)* | | hold | |
123126
| | hide *(preview)* | space/esc | * | |
124127
| select next | | right / down | * | swipe left *(preview)* |
125128
| select prev | | left / up | * | swipe right *(preview)* |
@@ -130,17 +133,23 @@ new Vue({
130133

131134
- events
132135

133-
| type | event-name | description |
134-
|---------|---------------------------------------|------------------------------------------|
135-
| [JS](https://github.com/gocanto/vuemit) |
136-
| | modal-show | when modal is showen |
137-
| | modal-hide | when modal is hidden |
138-
| | file_selected *(when inside modal)* | get selected file url |
139-
| [Laravel](https://laravel.com/docs/5.5/events#manually-registering-events) |
140-
| | MMFileUploaded($file_path) | get uploaded file full path |
141-
| | MMFileDeleted($file_path, $is_folder) | get deleted file/folder full path |
142-
| | MMFileRenamed($old_path, $new_path) | get renamed file/folder "old & new" path |
143-
| | MMFileMoved($old_path, $new_path) | get moved file/folder "old & new" path |
136+
| type | event-name | description |
137+
|-----------------|---------------------------------------|--------------------------------------------------|
138+
| [JS][js] | | |
139+
| | modal-show | when modal is showen |
140+
| | modal-hide | when modal is hidden |
141+
| | file_selected *(when inside modal)* | get selected file url |
142+
| [Laravel][lara] | | |
143+
| | MMFileUploaded($file_path) | get uploaded file full [path][path] |
144+
| | [MMFileSaved][event]($file_path) | get saved(edited/link) image full [path][path] |
145+
| | MMFileDeleted($file_path, $is_folder) | get deleted file/folder full [path][path] |
146+
| | MMFileRenamed($old_path, $new_path) | get renamed file/folder "old & new" [path][path] |
147+
| | MMFileMoved($old_path, $new_path) | get moved file/folder "old & new" [path][path] |
148+
149+
[js]: https://github.com/gocanto/vuemit
150+
[lara]: https://laravel.com/docs/5.5/events#manually-registering-events
151+
[event]: https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor#optimize-edited-images-on-save
152+
[path]: https://gist.github.com/ctf0/9fa6013954654384052d2e2e809b9bf6
144153

145154
<br>
146155

logs/v2.4.1.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

logs/v2.5.0.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- added full image editor https://github.com/ctf0/Laravel-Media-Manager/wiki/Image-Editor
2+
- you can now save images from url too, it follows the same flow as the normal upload (random names, upload to current folder, events)
3+
- added new event "MMFileSaved" for both of the above features.
4+
- fix setting selected file twice
5+
- fix clearing cache twice
6+
7+
- update readme
8+
- update wiki
9+
- update resources

src/Controllers/MediaController.php

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public function upload(Request $request)
127127
$original = $one->getClientOriginalName();
128128
$name_only = pathinfo($original, PATHINFO_FILENAME);
129129
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
130-
$file_name = $random_name ? uniqid() . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
130+
$file_name = $random_name ? $this->sanitizedText . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
131131
$file_type = $one->getMimeType();
132132
$destination = "$upload_path/$file_name";
133133

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

151151
$result[] = [
152-
'path' => preg_replace('/^public\//', '', $saved_name),
153152
'success' => true,
154153
'message' => $file_name,
155154
];
156155
} catch (Exception $e) {
157156
$result[] = [
158-
'path' => '',
159157
'success' => false,
160158
'message' => "\"$file_name\" " . $e->getMessage(),
161159
];
@@ -165,6 +163,101 @@ public function upload(Request $request)
165163
return response()->json(['data'=>$result]);
166164
}
167165

166+
/**
167+
* save cropped image.
168+
*
169+
* @param Request $request [description]
170+
*
171+
* @return [type] [description]
172+
*/
173+
public function uploadCropped(Request $request)
174+
{
175+
$path = $request->path;
176+
$data = explode(',', $request->data)[1];
177+
$original = $request->name;
178+
179+
$name_only = pathinfo($original, PATHINFO_FILENAME) . '_' . $this->sanitizedText;
180+
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
181+
$file_name = "$name_only.$ext_only";
182+
$destination = "$path/$file_name";
183+
184+
try {
185+
// check existence
186+
if ($this->storageDisk->exists($destination)) {
187+
throw new Exception(trans('MediaManager::messages.error_already_exists'));
188+
}
189+
190+
// save file
191+
$this->storageDisk->put($destination, base64_decode($data));
192+
193+
// fire event
194+
event('MMFileSaved', $this->getFilePath($destination));
195+
196+
$result = [
197+
'success' => true,
198+
'message' => $file_name,
199+
];
200+
} catch (Exception $e) {
201+
$result = [
202+
'success' => false,
203+
'message' => "\"$file_name\" " . $e->getMessage(),
204+
];
205+
}
206+
207+
return response()->json($result);
208+
}
209+
210+
/**
211+
* save image from link.
212+
*
213+
* @param Request $request [description]
214+
*
215+
* @return [type] [description]
216+
*/
217+
public function uploadLink(Request $request)
218+
{
219+
$url = $request->url;
220+
$path = $request->path;
221+
$random_name = $request->random_names;
222+
223+
$original = substr($url, strrpos($url, '/') + 1);
224+
$name_only = pathinfo($original, PATHINFO_FILENAME);
225+
$ext_only = pathinfo($original, PATHINFO_EXTENSION);
226+
$file_name = $random_name ? $this->sanitizedText . ".$ext_only" : $this->cleanName($name_only, null) . ".$ext_only";
227+
$destination = "$path/$file_name";
228+
$file_type = image_type_to_mime_type(exif_imagetype($url));
229+
230+
try {
231+
// check for mime type
232+
if (str_contains($file_type, $this->unallowedMimes)) {
233+
throw new Exception(trans('MediaManager::messages.not_allowed_file_ext', ['attr'=>$file_type]));
234+
}
235+
236+
// check existence
237+
if ($this->storageDisk->exists($destination)) {
238+
throw new Exception(trans('MediaManager::messages.error_already_exists'));
239+
}
240+
241+
// save file
242+
$this->storageDisk->put($destination, file_get_contents($url));
243+
244+
// fire event
245+
event('MMFileSaved', $this->getFilePath($destination));
246+
247+
$result = [
248+
'success' => true,
249+
'message' => $file_name,
250+
];
251+
} catch (Exception $e) {
252+
$result = [
253+
'success' => false,
254+
'message' => "\"$file_name\" " . $e->getMessage(),
255+
];
256+
}
257+
258+
return response()->json($result);
259+
}
260+
168261
/**
169262
* create new folder.
170263
*

src/MediaRoutes.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static function routes()
1616
], function () use ($controller) {
1717
Route::get('/', ['uses' => "$controller@index", 'as' => 'index']);
1818
Route::post('upload', ['uses' => "$controller@upload", 'as' => 'upload']);
19+
Route::post('upload-cropped', ['uses' => "$controller@uploadCropped", 'as' => 'uploadCropped']);
20+
Route::post('upload-link', ['uses' => "$controller@uploadLink", 'as' => 'uploadLink']);
21+
1922
Route::post('files', ['uses' => "$controller@get_files", 'as' => 'files']);
2023
Route::post('directories', ['uses' => "$controller@get_dirs", 'as' => 'directories']);
2124
Route::post('new_folder', ['uses' => "$controller@new_folder", 'as' => 'new_folder']);
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<template>
2+
<div class="__caman">
3+
<button class="btn-plain" @click="toggleControls()"
4+
:class="{'is-active': controls}"
5+
:disabled="processing"
6+
v-tippy :title="filterName">
7+
<span class="icon"><icon :name="processing ? 'spinner' : icon" :pulse="processing"/></span>
8+
</button>
9+
10+
<transition name="list">
11+
<div v-show="controls" class="__caman-controls">
12+
<button class="btn-plain" :disabled="incLimit() || processing" @click="inc()">
13+
<span class="icon"><icon :name="processing ? 'spinner' : 'plus'" :pulse="processing"/></span>
14+
</button>
15+
<button class="btn-plain" :disabled="decLimit() || processing" @click="dec()">
16+
<span class="icon"><icon :name="processing ? 'spinner' : 'minus'" :pulse="processing"/></span>
17+
</button>
18+
</div>
19+
</transition>
20+
</div>
21+
</template>
22+
23+
<script>
24+
export default {
25+
props: [
26+
'filterName',
27+
'icon',
28+
'step',
29+
'max',
30+
'min',
31+
'processing',
32+
'reset'
33+
],
34+
data() {
35+
return {
36+
controls: false,
37+
noController: [
38+
'greyscale',
39+
'invert'
40+
],
41+
range: 0
42+
}
43+
},
44+
beforeMount() {
45+
this.$options.name = `${this.filterName}-filter`
46+
},
47+
methods: {
48+
toggleControls() {
49+
if (this.noController.includes(this.filterName)) {
50+
return this.update()
51+
}
52+
53+
this.controls = !this.controls
54+
},
55+
56+
inc() {
57+
this.range += this.step
58+
this.update(this.range)
59+
},
60+
dec() {
61+
this.range -= this.step
62+
this.update(this.range)
63+
},
64+
incLimit() {
65+
return this.range == this.max
66+
},
67+
decLimit() {
68+
return this.range == this.min
69+
},
70+
71+
update(val = null) {
72+
this.$parent.updateFilter(this.filterName, val)
73+
}
74+
},
75+
watch: {
76+
reset(val) {
77+
if (val) {
78+
this.controls = false
79+
this.range = 0
80+
}
81+
}
82+
}
83+
}
84+
</script>

0 commit comments

Comments
 (0)