aboutsummaryrefslogtreecommitdiff
path: root/src/site/components/uploader/Uploader.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/site/components/uploader/Uploader.vue')
-rw-r--r--src/site/components/uploader/Uploader.vue258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/site/components/uploader/Uploader.vue b/src/site/components/uploader/Uploader.vue
new file mode 100644
index 0000000..f180546
--- /dev/null
+++ b/src/site/components/uploader/Uploader.vue
@@ -0,0 +1,258 @@
+<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
+ }]
+ }, {
+ headers: {
+ albumId: this.selectedAlbum ? this.selectedAlbum : null
+ }
+ });
+
+ 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>