Skip to content

Commit

Permalink
multiple upload/insert , image delete option
Browse files Browse the repository at this point in the history
  • Loading branch information
lahirulhr committed May 24, 2022
1 parent 5eff68c commit fc254c6
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 55 deletions.
2 changes: 1 addition & 1 deletion dist/css/field.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ export default {
editorConfig['setup'] = function(editor){
self.$on('i-have-images',function(images){
editor.insertContent('<img src="'+ images[0].image_url +'">');
images.forEach(img => {
editor.insertContent('<img src="'+ img.image_url +'">');
})
})
editor.ui.registry.addButton('image-gallery', {
text: 'Image Gallary',
text: 'Image Gallery',
onAction: function (_) {
self.handleMediaPicker(true)
}
Expand Down Expand Up @@ -100,7 +102,6 @@ export default {
},
handleImageChoose(imgs){
console.log(imgs)
this.$emit('i-have-images',imgs)
}
},
Expand Down
12 changes: 9 additions & 3 deletions resources/js/components/addons/media/ImageBlock.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
<template>
<div @click="$emit('choose',image)" :title="image.name" class="mb-2 cursor-pointer image-item">
<div @click="choose($event)" :title="image.name" class="mb-2 cursor-pointer image-item">
<div class="rounded-lg shadow-md image-wrapper"
:style=" 'background-image: url(&quot;' + image.preview_url + '&quot;)' ">
<div class="img-text">
{{ image.name }} <br> ({{ image.size }})
</div>
</div>
<!-- <div class="title truncate">{{ image.name }}</div>-->
</div>
</template>

<script>
export default {
props: ['image']
props: ['image'],
methods:{
choose(event){
event.target.classList.toggle('image-selected')
this.$emit('choose', this.image)
}
}
}
</script>

Expand Down
81 changes: 65 additions & 16 deletions resources/js/components/addons/media/ImagePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,39 @@
</div>
</form>

<div v-if="field.upload" class="ml-auto">
<div class="ml-auto flex">

<span class="form-file mr-4">
<input @change="handleFileUpload" ref="file" dusk="photo" type="file" id="file-teams-photo" name="name" accept="image/*" class="form-file-input select-none">
<button v-show="selectedImages.length" @click="deleteSelected()" type="button" class="btn-icon text-70 hover:text-primary mr-3 has-tooltip">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" aria-labelledby="delete" role="presentation" class="fill-current"><path fill-rule="nonzero" d="M6 4V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2h5a1 1 0 0 1 0 2h-1v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6H1a1 1 0 1 1 0-2h5zM4 6v12h12V6H4zm8-2V2H8v2h4zM8 8a1 1 0 0 1 1 1v6a1 1 0 0 1-2 0V9a1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1v6a1 1 0 0 1-2 0V9a1 1 0 0 1 1-1z"></path></svg>
<span>Delete ({{ selectedImages.length }})</span>
</button>

<span v-if="field.upload" class="form-file mr-4">
<input @change="handleFileUpload" ref="file" dusk="photo" multiple type="file" id="file-teams-photo" name="name" accept="image/*" class="form-file-input select-none">
<label
for="file-teams-photo"
class="form-file-btn btn btn-default btn-primary select-none"><span>Upload</span></label>
for="file-teams-photo"
class="form-file-btn btn btn-default btn-primary select-none"><span>Upload</span></label>
</span>

</div>

</div>

<!-- gallary -->
<!-- gallery -->
<loading-view :loading="imagesIsLoading">
<div class="p-4">
<div class="gallery">

<image-block-mt @choose="selectImage(image)" v-for="(image,k) in images" :key="k" :image="image"/>

<p class="p-5" v-if="images == []">Nothing here !</p>
<p class="p-5 text-center" v-if="!images.length">Nothing here !</p>

</div>
</div>
</loading-view>

<!-- end gallary-->

<!-- end gallery-->

<div class="bg-30 px-6 py-3 flex">
<button :disabled="page.url == null || page.active"
Expand All @@ -62,6 +69,8 @@
<button @click="handleClose" type="button" dusk="cancel-general-button"
class="btn text-80 font-normal h-9 px-3 mr-3 btn-link">Cancel
</button>
<button v-show="selectedImages.length" @click="insertSelected()" type="button" class="btn btn-default btn-primary">Insert ({{ selectedImages.length }})</button>

</div>
</div>
</card>
Expand All @@ -81,14 +90,15 @@ export default {
initialLoading: true,
imagesIsLoading:false,
searchQuery: "",
imageToUpload: null,
imagesToUpload: null,
pagination: []
}
},
mounted() {
this.getMedia()
},
methods: {
handleClose() {
this.$emit('close')
},
Expand All @@ -109,9 +119,13 @@ export default {
},
selectImage(img) {
this.selectedImages.push(img)
this.$emit('choose', this.selectedImages)
this.$emit('close')
let has = _.indexOf(this.selectedImages, img)
if(has > -1){
this.selectedImages.splice(has,1)
}else{
this.selectedImages.push(img)
}
},
refreshMedia() {
Expand Down Expand Up @@ -142,18 +156,25 @@ export default {
handleFileUpload(){
this.imagesIsLoading = true
this.imageToUpload = this.$refs.file.files[0]
this.imagesToUpload = this.$refs.file.files
let formData = new FormData()
formData.append('image',this.imageToUpload)
for (let i = 0; i < this.imagesToUpload.length; i++) {
formData.append(`images[]`, this.imagesToUpload[i]);
}
Nova.request().post('/nova-vendor/nova-media-tinymce/upload-image',formData,{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res=>{
this.images.unshift(res.data)
this.$toasted.show("Sucesfuly uploaded !",{type: 'success'})
res.data.forEach(itm => {
this.images.unshift(itm)
})
this.$toasted.show("Successfully uploaded !",{type: 'success'})
this.imagesIsLoading = false
Expand All @@ -163,6 +184,34 @@ export default {
this.imagesIsLoading = false
})
},
deleteSelected(){
if(!window.confirm("Are you sure ?")){
return
}
this.imagesIsLoading = true
Nova.request().post('/nova-vendor/nova-media-tinymce/delete-images/',{
images: this.selectedImages.map((itm) => itm.id)
})
.then(res => {
this.imagesIsLoading = false
this.selectedImages = []
this.refreshMedia()
this.$toasted.show("Successfully deleted !",{type: 'success'})
})
.catch(e=>{
this.$toasted.show("Unable to delete images !",{type: 'error'})
})
},
insertSelected(){
this.$emit('choose', this.selectedImages)
this.$emit('close')
}
}
Expand Down
11 changes: 11 additions & 0 deletions resources/sass/field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,16 @@ button.pagination-active{
}
}
}

.image-selected{
background-color: #4099deb8;
transform: scale(1);
}
}

.btn-icon{
display: inline-flex;
align-items: center;
gap: 6px;
}

3 changes: 2 additions & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@

Route::get('get-images',[ config('nova-tinymce5-editor.options.media_handler'),'getImages']);
Route::get('search-images/{query}',[ config('nova-tinymce5-editor.options.media_handler'),'searchImages']);
Route::post('upload-image',[ config('nova-tinymce5-editor.options.media_handler'),'uploadImage']);
Route::post('upload-image',[ config('nova-tinymce5-editor.options.media_handler'),'uploadImage']);
Route::post('delete-images',[ config('nova-tinymce5-editor.options.media_handler'),'deleteImages']);
99 changes: 69 additions & 30 deletions src/Controller/MediaController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Illuminate\Support\Facades\Storage;

class MediaController implements MediaControllerInterface
{
Expand All @@ -14,53 +14,92 @@ public function getImages(Request $request)

$images = DB::table('tinymce_images')->latest()->paginate();

return $images->through(function($itm){
return $images->through(function ($itm) {
return [
'id' => $itm->id,
'name' => $itm->name,
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path').$itm->file_name),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path').$itm->file_name),
'size' => $itm->file_size
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $itm->file_name),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $itm->file_name),
'size' => $this->sizeFilter($itm->file_size)
];
});
}

public function searchImages($query)
public function searchImages(string $query)
{
$images = DB::table('tinymce_images')->where('name','like' , "$query%")->take(10)->get();
$images = DB::table('tinymce_images')->where('name', 'like', "$query%")->take(10)->get();

return $images->map(function($itm){
return $images->map(function ($itm) {
return [
'id' => $itm->id,
'name' => $itm->name,
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path').$itm->file_name),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path').$itm->file_name),
'size' => $itm->file_size
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $itm->file_name),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $itm->file_name),
'size' => $this->sizeFilter($itm->file_size)
];
});
}

public function uploadImage(Request $request)
{
if($request->hasFile('image')){
$file = $request->file('image');
$fileName = Str::random().".".$file->getClientOriginalExtension();
$file->storeAs(config('nova-tinymce5-editor.options.storage_path'),$fileName);

$rec = DB::table('tinymce_images')->insert([
'name' => $file->getClientOriginalName(),
'file_name' => $fileName,
'file_size' => $file->getSize(),
'disk' => config('filesystems.default'),
'created_at' => now()
]);

return [
'name' => $file->getClientOriginalName(),
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path').$fileName),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path').$fileName),
'size' => $file->getSize()
];
if ($request->hasFile('images')) {
$out = [];
foreach ($request->file('images') as $file){

$fileName = Str::random() . "." . $file->getClientOriginalExtension();
$file->storeAs(config('nova-tinymce5-editor.options.storage_path'), $fileName);

$rec = DB::table('tinymce_images')->insertGetId([
'name' => $file->getClientOriginalName(),
'file_name' => $fileName,
'file_size' => $file->getSize(),
'disk' => config('filesystems.default'),
'created_at' => now()
]);

$rec = DB::table('tinymce_images')->find($rec);

$out[] = [
'id' => $rec->id,
'name' => $file->getClientOriginalName(),
'preview_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $fileName),
'image_url' => url(config('nova-tinymce5-editor.options.image_url_path') . $fileName),
'size' => $this->sizeFilter($file->getSize())
];

}

return $out;
}

return [];
}


public function deleteImages(Request $request)
{
foreach ($request->get('images') as $img) {
$file = DB::table('tinymce_images')->where('id', $img)->first();
// remove file from storage
Storage::delete(config('nova-tinymce5-editor.options.storage_path')."/".$file->file_name);
// remove db entry
DB::table('tinymce_images')->delete($img);
}

return response()->json("Succesfuly deleted !");
}




private function sizeFilter($bytes)
{
$label = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
for (
$i = 0;
$bytes >= 1024 && $i < (count($label) - 1);
$bytes /= 1024, $i++
);
return (round($bytes, 2) . " " . $label[$i]);
}
}
2 changes: 2 additions & 0 deletions src/Controller/MediaControllerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public function searchImages(string $query);

public function uploadImage(Request $request);

public function deleteImages(Request $request);


}

0 comments on commit fc254c6

Please sign in to comment.