Skip to content

Commit

Permalink
file upload: refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
Mogge committed Feb 8, 2021
1 parent c304b74 commit 650e83f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 35 deletions.
78 changes: 46 additions & 32 deletions webapp/components/ImageUploader/ImageUploader.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
<template>
<div class="image-uploader">
<vue-dropzone
v-show="!showCropper"
v-show="!showCropper && !hasImage"
id="postdropzone"
:options="dropzoneOptions"
:use-custom-slot="true"
@vdropzone-error="onDropzoneError"
@vdropzone-file-added="fileAdded"
>
<loading-spinner v-if="isLoadingImage" />
<base-icon v-else-if="!hasImage" name="image" />
<div v-if="!hasImage" class="supported-formats">
{{ $t('contribution.teaserImage.supportedFormats') }}
</div>
</vue-dropzone>
<div v-show="!showCropper && hasImage">
<base-button
v-if="hasImage"
class="delete-image-button"
icon="trash"
circle
danger
Expand All @@ -20,10 +24,7 @@
:title="$t('actions.delete')"
@click.stop="deleteImage"
/>
<div v-if="!hasImage" class="supported-formats">
{{ $t('contribution.teaserImage.supportedFormats') }}
</div>
</vue-dropzone>
</div>
<div v-show="!showCropper && imageCanBeCropped" class="crop-overlay">
<base-button class="crop-confirm" filled @click="initCropper">
{{ $t('contribution.teaserImage.cropImage') }}
Expand Down Expand Up @@ -53,6 +54,8 @@ import Cropper from 'cropperjs'
import LoadingSpinner from '~/components/_new/generic/LoadingSpinner/LoadingSpinner'
import 'cropperjs/dist/cropper.css'
const minAspectRatio = 0.3
export default {
components: {
LoadingSpinner,
Expand Down Expand Up @@ -80,12 +83,8 @@ export default {
}
},
methods: {
onDropzoneError(file, message) {
this.$toast.error(file.status, message)
},
onUnSupportedFormat(status, message) {
this.$toast.error(status, message)
onUnSupportedFormat(message) {
this.$toast.error(message)
},
addImageProcess(src) {
return new Promise((resolve, reject) => {
Expand All @@ -96,46 +95,45 @@ export default {
})
},
async fileAdded(file) {
const supportedFormats = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
if (supportedFormats.indexOf(file.type) < 0) {
this.onUnSupportedFormat(this.$t('contribution.teaserImage.errors.unSupported-file-format'))
this.$nextTick((this.isLoadingImage = false))
return null
}
const imageURL = URL.createObjectURL(file)
const image = await this.addImageProcess(imageURL)
this.$emit('addImageAspectRatio', image.width / image.height || 1.0)
this.$emit('addHeroImage', file)
this.$emit('addImageType', file.type)
const aspectRatio = image.width / image.height
if (aspectRatio < minAspectRatio) {
this.aspectRatioError()
return null
}
this.saveImage(aspectRatio, file, file.type)
this.file = file
if (this.file.type === 'image/jpeg') this.imageCanBeCropped = true
this.$nextTick((this.isLoadingImage = false))
},
initCropper() {
const supportedFormats = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
if (supportedFormats.indexOf(this.file.type) < 0) {
this.onUnSupportedFormat(
'error',
this.$t('contribution.teaserImage.errors.unSupported-file-format'),
)
return
}
this.showCropper = true
const imageElement = document.querySelector('#cropping-image')
imageElement.src = URL.createObjectURL(this.file)
this.cropper = new Cropper(imageElement, { zoomable: false, autoCropArea: 0.9 })
},
cropImage() {
this.isLoadingImage = true
const onCropComplete = (aspectRatio, imageFile, imageType) => {
this.$emit('addImageAspectRatio', aspectRatio)
this.$emit('addHeroImage', imageFile)
this.$emit('addImageType', imageType)
this.saveImage(aspectRatio, imageFile, imageType)
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
if (imageAspectRatio < minAspectRatio) {
this.aspectRatioError()
return
}
const croppedImageFile = new File([blob], this.file.name, { type: this.file.type })
onCropComplete(imageAspectRatio, croppedImageFile, 'image/jpeg')
}, 'image/jpeg')
Expand All @@ -149,6 +147,14 @@ export default {
this.showCropper = false
this.cropper.destroy()
},
aspectRatioError() {
this.$toast.error(this.$t('contribution.teaserImage.errors.aspect-ratio-too-small'))
},
saveImage(aspectRatio = 1.0, file, fileType) {
this.$emit('addImageAspectRatio', aspectRatio)
this.$emit('addHeroImage', file)
this.$emit('addImageType', fileType)
},
deleteImage() {
this.$emit('addHeroImage', null)
this.$emit('addImageAspectRatio', null)
Expand All @@ -161,7 +167,6 @@ export default {
.image-uploader {
position: relative;
min-height: $size-image-uploader-min-height;
cursor: pointer;
.image + & {
position: absolute;
Expand Down Expand Up @@ -206,6 +211,14 @@ export default {
}
}
.delete-image-button {
position: absolute;
top: $space-small;
right: $space-small;
z-index: $z-index-surface;
cursor: pointer;
}
.dz-message {
position: absolute;
display: flex;
Expand All @@ -214,6 +227,7 @@ export default {
width: 100%;
height: 100%;
z-index: $z-index-surface;
cursor: pointer;
&:hover {
> .base-icon {
Expand Down
1 change: 1 addition & 0 deletions webapp/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
"cropImage": "Bild zuschneiden",
"cropperConfirm": "Bestätigen",
"errors": {
"aspect-ratio-too-small": "Dieses Bild ist zu hoch.",
"unSupported-file-format": "Bitte lade ein Bild in den folgenden Formaten hoch: JPG, JPEG, PNG or GIF!"
},
"supportedFormats": "Füge ein Bild im Dateiformat JPG, PNG oder GIF ein"
Expand Down
1 change: 1 addition & 0 deletions webapp/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
"cropImage": "Crop image",
"cropperConfirm": "Confirm",
"errors": {
"aspect-ratio-too-small": "This image is too high.",
"unSupported-file-format": "Please upload an image of file format: JPG, JPEG, PNG or GIF!"
},
"supportedFormats": "Insert a picture of file format JPG, PNG or GIF"
Expand Down
4 changes: 1 addition & 3 deletions webapp/pages/post/_id/_slug/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,9 @@ export default {
if (!this.post.image || typeof this.post.image.aspectRatio !== 'number') return false
/* Return the aspect ratio as a css variable. Later to be used when calculating
the height with respect to the width.
Why is this correction necessary?
*/
return {
'--hero-image-aspect-ratio': 1.0 / this.post.image.aspectRatio,
'--hero-image-correction': 1.0 / this.post.image.aspectRatio * 48.0 + 'px',
}
},
},
Expand Down Expand Up @@ -261,7 +259,7 @@ export default {
the autoscroll works correctly when following a comment link.
*/
padding-top: calc(var(--hero-image-aspect-ratio) * 100% + var(--hero-image-correction));
padding-top: calc(var(--hero-image-aspect-ratio) * (100% + 48px));
/* Letting the image fill the container, since the container
is the one determining height
*/
Expand Down

0 comments on commit 650e83f

Please sign in to comment.