move deleteImage logic to ImageUploader

This commit is contained in:
Alina Beck 2020-02-19 15:55:10 +01:00
parent 888051a6ae
commit 4a17cf0e07
3 changed files with 44 additions and 65 deletions

View File

@ -380,9 +380,10 @@ describe('ContributionForm.vue', () => {
it('supports deleting a teaser image', async () => {
expectedParams.variables.image = null
expectedParams.variables.imageAspectRatio = null
propsData.contribution.image = '/uploads/someimage.png'
wrapper = Wrapper()
wrapper.find('.contribution-form .delete-image').trigger('click')
wrapper.find('[data-test="delete-button"]').trigger('click')
await wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})

View File

@ -11,11 +11,11 @@
<template #heroImage>
<img
v-if="formData.image"
:src="contribution.image | proxyApiUrl"
:src="formData.image | proxyApiUrl"
:class="['image', formData.imageBlurred && '--blur-image']"
/>
<image-uploader
:contribution="contribution"
:hasImage="!!formData.image"
:class="[formData.imageBlurred && '--blur-image']"
@addHeroImage="addHeroImage"
@addImageAspectRatio="addImageAspectRatio"
@ -150,6 +150,7 @@ export default {
loading: false,
users: [],
hashtags: [],
imageUpload: null,
}
},
computed: {
@ -162,11 +163,6 @@ export default {
},
methods: {
submit() {
const newImage =
!this.contribution || this.contribution.image !== this.formData.image
? this.formData.image
: null
this.loading = true
this.$apollo
.mutate({
@ -175,8 +171,8 @@ export default {
...this.formData,
id: this.contribution.id || null,
language: this.formData.language.value,
image: newImage ? null : this.formData.image,
imageUpload: newImage,
image: this.imageUpload ? null : this.formData.image,
imageUpload: this.imageUpload,
},
})
.then(({ data }) => {
@ -198,7 +194,8 @@ export default {
this.$refs.contributionForm.update('content', value)
},
addHeroImage(file) {
this.formData.image = file
this.imageUpload = file
this.formData.image = file ? URL.createObjectURL(file) : null
},
addImageAspectRatio(aspectRatio) {
this.formData.imageAspectRatio = aspectRatio
@ -245,6 +242,10 @@ export default {
> .hero-image {
position: relative;
> .image {
max-height: $size-image-max-height;
}
}
.image.--blur-image {

View File

@ -6,17 +6,18 @@
:options="dropzoneOptions"
:use-custom-slot="true"
@vdropzone-error="onDropzoneError"
@vdropzone-thumbnail="initCropper"
@vdropzone-file-added="initCropper"
>
<loading-spinner v-if="isLoadingImage" />
<base-icon v-else name="image" />
<base-button
class="delete-image"
icon="close"
size="small"
v-if="hasImage"
icon="trash"
circle
danger
filled
data-test="delete-button"
:title="$t('actions.delete')"
@click.stop="deleteImage"
/>
</vue-dropzone>
@ -50,14 +51,17 @@ export default {
VueDropzone,
},
props: {
contribution: { type: Object, default: () => {} },
hasImage: {
type: Boolean,
default: false,
},
},
data() {
return {
dropzoneOptions: {
url: () => '',
maxFilesize: 5.0,
previewTemplate: '<img class="preview-image" />',
previewTemplate: '<span class="no-preview" />',
},
cropper: null,
file: null,
@ -69,62 +73,44 @@ export default {
onDropzoneError(file, message) {
this.$toast.error(file.status, message)
},
clearImages() {
const images = document.querySelectorAll('.preview-image')
images.forEach((image, index) => {
if (index === images.length - 1) image.src = ''
else image.remove()
})
},
initCropper(file) {
this.showCropper = true
this.file = file
console.log(file)
this.clearImages()
const imageElement = document.querySelector('#cropping-image')
imageElement.src = URL.createObjectURL(file)
this.cropper = new Cropper(imageElement, { zoomable: false, autoCropArea: 0.9 })
},
deleteImage() {
this.clearImages()
this.$emit('addHeroImage', null) // maybe?
},
cropImage() {
this.isLoadingImage = true
const onCropComplete = (aspectRatio, imageFile) => {
this.$emit('addImageAspectRatio', aspectRatio)
this.$emit('addHeroImage', imageFile)
this.$nextTick((this.isLoadingImage = false))
this.closeCropper()
}
if (this.file.type === 'image/jpeg') {
const canvas = this.cropper.getCroppedCanvas()
canvas.toBlob(blob => {
const imageAspectRatio = canvas.width / canvas.height
const croppedImageFile = new File([blob], this.file.name, { type: this.file.type })
this.$emit('addHeroImage', croppedImageFile)
this.$emit('addImageAspectRatio', imageAspectRatio)
this.$emit('cropInProgress', false)
this.setupPreview(canvas.toDataURL())
onCropComplete(imageAspectRatio, croppedImageFile)
}, 'image/jpeg')
} else {
// TODO: use cropped file instead of original file
const imageAspectRatio = this.file.width / this.file.height || 1.0
const croppedImageFile = this.file
this.setupPreview(this.file.dataURL)
this.$emit('addHeroImage', croppedImageFile)
this.$emit('addImageAspectRatio', imageAspectRatio)
this.$emit('cropInProgress', false)
onCropComplete(imageAspectRatio, this.file)
}
this.closeCropper()
},
setupPreview(url) {
const previewElement = document.querySelector('.image-uploader .preview-image')
previewElement.src = url
this.$nextTick((this.isLoadingImage = false))
},
closeCropper() {
this.showCropper = false
this.cropper.destroy()
},
cancelCrop() {
if (this.oldImage) this.thumbnailElement.appendChild(this.oldImage)
this.showCropper = false
this.$emit('cropInProgress', false)
deleteImage() {
this.$emit('addHeroImage', null)
this.$emit('addImageAspectRatio', null)
},
},
}
@ -151,16 +137,6 @@ export default {
pointer-events: none;
}
&.--blur-image .preview-image {
filter: blur($blur-radius);
}
.preview-image {
width: 100%;
max-height: $size-image-max-height;
object-fit: contain;
}
> .crop-overlay {
width: 100%;
height: 100%;
@ -212,12 +188,13 @@ export default {
font-size: $size-icon-large;
opacity: $opacity-soft;
}
> .base-button {
position: absolute;
top: $space-small;
right: $space-small;
z-index: $z-index-surface;
}
}
}
.delete-image {
position: absolute;
top: $space-small;
right: $space-small;
z-index: $z-index-surface;
}
</style>