Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue')
-rw-r--r--app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue172
1 files changed, 172 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
new file mode 100644
index 00000000000..b645758d891
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
@@ -0,0 +1,172 @@
+<script>
+import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { isValidImage } from './utils';
+import { VALID_DATA_TRANSFER_TYPE, VALID_IMAGE_FILE_MIMETYPE } from './constants';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ },
+ props: {
+ displayAsCard: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ enableDragBehavior: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ dropToStartMessage: {
+ type: String,
+ required: false,
+ default: __('Drop your files to start your upload.'),
+ },
+ isFileValid: {
+ type: Function,
+ required: false,
+ default: isValidImage,
+ },
+ validFileMimetypes: {
+ type: Array,
+ required: false,
+ default: () => [VALID_IMAGE_FILE_MIMETYPE.mimetype],
+ },
+ },
+ data() {
+ return {
+ dragCounter: 0,
+ isDragDataValid: false,
+ };
+ },
+ computed: {
+ dragging() {
+ return this.dragCounter !== 0;
+ },
+ iconStyles() {
+ return {
+ size: this.displayAsCard ? 24 : 16,
+ class: this.displayAsCard ? 'gl-mb-2' : 'gl-mr-3 gl-text-gray-500',
+ };
+ },
+ validMimeTypeString() {
+ return this.validFileMimetypes.join();
+ },
+ },
+ methods: {
+ isValidUpload(files) {
+ return files.every(this.isFileValid);
+ },
+ isValidDragDataType({ dataTransfer }) {
+ return Boolean(dataTransfer && dataTransfer.types.some(t => t === VALID_DATA_TRANSFER_TYPE));
+ },
+ ondrop({ dataTransfer = {} }) {
+ this.dragCounter = 0;
+ // User already had feedback when dropzone was active, so bail here
+ if (!this.isDragDataValid) {
+ return;
+ }
+
+ const { files } = dataTransfer;
+ if (!this.isValidUpload(Array.from(files))) {
+ this.$emit('error');
+ return;
+ }
+
+ this.$emit('change', files);
+ },
+ ondragenter(e) {
+ this.dragCounter += 1;
+ this.isDragDataValid = this.isValidDragDataType(e);
+ },
+ ondragleave() {
+ this.dragCounter -= 1;
+ },
+ openFileUpload() {
+ this.$refs.fileUpload.click();
+ },
+ onFileInputChange(e) {
+ this.$emit('change', e.target.files);
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ class="gl-w-full gl-relative"
+ @dragstart.prevent.stop
+ @dragend.prevent.stop
+ @dragover.prevent.stop
+ @dragenter.prevent.stop="ondragenter"
+ @dragleave.prevent.stop="ondragleave"
+ @drop.prevent.stop="ondrop"
+ >
+ <slot>
+ <button
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
+ @click="openFileUpload"
+ >
+ <div
+ :class="{ 'gl-flex-direction-column': displayAsCard }"
+ class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center"
+ data-testid="dropzone-area"
+ >
+ <gl-icon name="upload" :size="iconStyles.size" :class="iconStyles.class" />
+ <p class="gl-mb-0">
+ <slot name="upload-text" :openFileUpload="openFileUpload">
+ <gl-sprintf :message="__('Drop or %{linkStart}upload%{linkEnd} files to attach')">
+ <template #link="{ content }">
+ <gl-link @click.stop="openFileUpload">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </slot>
+ </p>
+ </div>
+ </button>
+
+ <input
+ ref="fileUpload"
+ type="file"
+ name="upload_file"
+ :accept="validFileMimetypes"
+ class="hide"
+ multiple
+ @change="onFileInputChange"
+ />
+ </slot>
+ <transition name="upload-dropzone-fade">
+ <div
+ v-show="dragging && !enableDragBehavior"
+ class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
+ >
+ <div v-show="!isDragDataValid" class="mw-50 gl-text-center">
+ <slot name="invalid-drag-data-slot">
+ <h3 :class="{ 'gl-font-base gl-display-inline': !displayAsCard }">
+ {{ __('Oh no!') }}
+ </h3>
+ <span>{{
+ __(
+ 'You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.',
+ )
+ }}</span>
+ </slot>
+ </div>
+ <div v-show="isDragDataValid" class="mw-50 gl-text-center">
+ <slot name="valid-drag-data-slot">
+ <h3 :class="{ 'gl-font-base gl-display-inline': !displayAsCard }">
+ {{ __('Incoming!') }}
+ </h3>
+ <span>{{ dropToStartMessage }}</span>
+ </slot>
+ </div>
+ </div>
+ </transition>
+ </div>
+</template>