v3.0.0/src/site/components/uploader/Uploader.vue

255 lines
5.8 KiB
Vue

<template>
<div
:class="{ 'has-files': alreadyAddedFiles }"
class="uploader-wrapper">
<b-select
v-if="loggedIn"
v-model="selectedAlbum"
placeholder="Upload to album"
size="is-medium"
expanded>
<option
v-for="album in albums"
:key="album.id"
:value="album.id">
{{ album.name }}
</option>
</b-select>
<dropzone
v-if="showDropzone"
id="dropzone"
ref="el"
:options="dropzoneOptions"
:include-styling="false"
@vdropzone-success="dropzoneSuccess"
@vdropzone-error="dropzoneError"
@vdropzone-files-added="dropzoneFilesAdded" />
<label class="add-more">
Add or drop more files
</label>
<div
id="template"
ref="template">
<div class="dz-preview dz-file-preview">
<div class="dz-details">
<div class="dz-filename">
<span data-dz-name />
</div>
<div class="dz-size">
<span data-dz-size />
</div>
</div>
<div class="result">
<div class="openLink">
<a
class="link"
target="_blank">
Link
</a>
</div>
</div>
<div class="error">
<div>
<span>
<span
class="error-message"
data-dz-errormessage />
<i class="icon-web-warning" />
</span>
</div>
</div>
<div class="dz-progress">
<span
class="dz-upload"
data-dz-uploadprogress />
</div>
<!--
<div class="dz-error-message"><span data-dz-errormessage/></div>
<div class="dz-success-mark"><i class="fa fa-check"/></div>
<div class="dz-error-mark"><i class="fa fa-close"/></div>
-->
</div>
</div>
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
import Dropzone from 'nuxt-dropzone';
import '~/assets/styles/dropzone.scss';
export default {
components: { Dropzone },
data() {
return {
alreadyAddedFiles: false,
files: [],
dropzoneOptions: {},
showDropzone: false,
selectedAlbum: null
};
},
computed: {
...mapState({
config: state => state.config,
albums: state => state.albums.tinyDetails
}),
...mapGetters({ loggedIn: 'auth/isLoggedIn', token: 'auth/getToken' })
},
watch: {
loggedIn() {
this.getAlbums();
},
selectedAlbum() {
this.updateDropzoneConfig();
}
},
mounted() {
this.dropzoneOptions = {
url: `${this.config.baseURL}/upload`,
timeout: 600000, // 10 minutes
autoProcessQueue: true,
addRemoveLinks: false,
parallelUploads: 5,
uploadMultiple: false,
maxFiles: 1000,
createImageThumbnails: false,
paramName: 'files[]',
forceChunking: false,
chunking: true,
retryChunks: true,
retryChunksLimit: 3,
parallelChunkUploads: true,
chunkSize: this.config.chunkSize * 1000000,
chunksUploaded: this.dropzoneChunksUploaded,
maxFilesize: this.config.maxFileSize,
previewTemplate: this.$refs.template.innerHTML,
dictDefaultMessage: 'Drag & Drop your files or click to browse',
headers: { Accept: 'application/vnd.chibisafe.json' }
};
this.showDropzone = true;
if (this.loggedIn) this.getAlbums();
},
methods: {
/*
Get all available albums so the user can upload directly to one (or several soon™) of them.
*/
async getAlbums() {
try {
await this.$store.dispatch('albums/getTinyDetails');
} catch (e) {
this.$store.dispatch('alert/set', { text: e.message, error: true }, { root: true });
}
this.updateDropzoneConfig();
},
/*
This method needs to be called after the token or selectedAlbum changes
since dropzone doesn't seem to update the config values unless you force it.
Tch.
*/
updateDropzoneConfig() {
this.$refs.el.setOption('headers', {
Accept: 'application/vnd.chibisafe.json',
Authorization: this.token ? `Bearer ${this.token}` : '',
albumId: this.selectedAlbum ? this.selectedAlbum : null
});
},
/*
Dropzone stuff
*/
dropzoneFilesAdded() {
this.alreadyAddedFiles = true;
},
dropzoneSuccess(file, response) {
this.processResult(file, response);
},
dropzoneError(file, message, xhr) {
this.$store.dispatch('alert', {
text: 'There was an error uploading this file. Check the console.',
error: true
});
// eslint-disable-next-line no-console
console.error(file, message, xhr);
},
async dropzoneChunksUploaded(file, done) {
const { data } = await this.$axios.post(`${this.config.baseURL}/upload/chunks`, {
files: [{
uuid: file.upload.uuid,
original: file.name,
size: file.size,
type: file.type,
count: file.upload.totalChunkCount
}]
});
this.processResult(file, data);
return done();
},
/*
If upload/s was/were successfull we modify the template so that the buttons for
copying the returned url or opening it in a new window appear.
*/
processResult(file, response) {
if (!response.url) return;
file.previewTemplate.querySelector('.link').setAttribute('href', response.url);
/*
file.previewTemplate.querySelector('.copyLink').addEventListener('click', () => {
this.$store.dispatch('alert', {
text: 'Link copied!'
});
this.$clipboard(response.url);
});
*/
}
}
};
</script>
<style lang="scss" scoped>
#template { display: none; }
.uploader-wrapper {
display: block;
width: 400px;
margin: 0 auto;
max-width: 100%;
position: relative;
}
</style>
<style lang="scss">
@import '~/assets/styles/_colors.scss';
div.uploader-wrapper {
&.has-files {
#dropzone {
padding-bottom: 50px;
}
label.add-more {
position: absolute;
bottom: 23px;
width: 100%;
text-align: center;
color: #797979;
display: block;
pointer-events: none;
}
}
div.control {
margin-bottom: 5px;
span.select {
select {
border: 1px solid #00000061;
background: rgba(0, 0, 0, 0.15);
border-radius: .3em;
color: $uploaderDropdownColor;
padding: 0 0 0 1rem;
}
}
}
label.add-more { display: none; }
}
</style>