mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-23 08:03:49 +00:00
207 lines
4.5 KiB
Vue
207 lines
4.5 KiB
Vue
<script setup lang="ts">
|
|
import { StoredObject, StoredObjectVersionCreated } from "../../types";
|
|
import {
|
|
encryptFile,
|
|
fetchNewStoredObject,
|
|
uploadVersion,
|
|
} from "../../js/async-upload/uploader";
|
|
import { computed, ref, Ref } from "vue";
|
|
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
|
|
|
|
interface DropFileConfig {
|
|
existingDoc?: StoredObject;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<DropFileConfig>(), {
|
|
existingDoc: null,
|
|
});
|
|
|
|
const emit =
|
|
defineEmits<
|
|
(
|
|
e: "addDocument",
|
|
{
|
|
stored_object_version: StoredObjectVersionCreated,
|
|
stored_object: StoredObject,
|
|
file_name: string,
|
|
},
|
|
) => void
|
|
>();
|
|
|
|
const is_dragging: Ref<boolean> = ref(false);
|
|
const uploading: Ref<boolean> = ref(false);
|
|
const display_filename: Ref<string | null> = ref(null);
|
|
|
|
const has_existing_doc = computed<boolean>(() => {
|
|
return props.existingDoc !== undefined && props.existingDoc !== null;
|
|
});
|
|
|
|
const onDragOver = (e: Event) => {
|
|
e.preventDefault();
|
|
|
|
is_dragging.value = true;
|
|
};
|
|
|
|
const onDragLeave = (e: Event) => {
|
|
e.preventDefault();
|
|
|
|
is_dragging.value = false;
|
|
};
|
|
|
|
const onDrop = (e: DragEvent) => {
|
|
e.preventDefault();
|
|
|
|
const files = e.dataTransfer?.files;
|
|
|
|
if (null === files || undefined === files) {
|
|
console.error("no files transferred", e.dataTransfer);
|
|
return;
|
|
}
|
|
if (files.length === 0) {
|
|
console.error("no files given");
|
|
return;
|
|
}
|
|
|
|
handleFile(files[0]);
|
|
};
|
|
|
|
const onZoneClick = (e: Event) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
const input = document.createElement("input");
|
|
input.type = "file";
|
|
input.addEventListener("change", onFileChange);
|
|
|
|
input.click();
|
|
};
|
|
|
|
const onFileChange = async (event: Event): Promise<void> => {
|
|
const input = event.target as HTMLInputElement;
|
|
|
|
if (input.files && input.files[0]) {
|
|
console.log("file added", input.files[0]);
|
|
const file = input.files[0];
|
|
await handleFile(file);
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
throw "No file given";
|
|
};
|
|
|
|
const handleFile = async (file: File): Promise<void> => {
|
|
uploading.value = true;
|
|
display_filename.value = file.name;
|
|
const type = file.type;
|
|
|
|
// create a stored_object if not exists
|
|
let stored_object;
|
|
if (null === props.existingDoc) {
|
|
stored_object = await fetchNewStoredObject();
|
|
} else {
|
|
stored_object = props.existingDoc;
|
|
}
|
|
|
|
const buffer = await file.arrayBuffer();
|
|
const [encrypted, iv, jsonWebKey] = await encryptFile(buffer);
|
|
const filename = await uploadVersion(encrypted, stored_object);
|
|
|
|
const stored_object_version: StoredObjectVersionCreated = {
|
|
filename: filename,
|
|
iv: Array.from(iv),
|
|
keyInfos: jsonWebKey,
|
|
type: type,
|
|
persisted: false,
|
|
};
|
|
|
|
const fileName = file.name;
|
|
let file_name = "Nouveau document";
|
|
const file_name_split = fileName.split(".");
|
|
if (file_name_split.length > 1) {
|
|
const extension = file_name_split
|
|
? file_name_split[file_name_split.length - 1]
|
|
: "";
|
|
file_name = fileName.replace(extension, "").slice(0, -1);
|
|
}
|
|
|
|
emit("addDocument", {
|
|
stored_object,
|
|
stored_object_version,
|
|
file_name: file_name,
|
|
});
|
|
uploading.value = false;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="drop-file">
|
|
<div
|
|
v-if="!uploading"
|
|
:class="{ area: true, dragging: is_dragging }"
|
|
@click="onZoneClick"
|
|
@dragover="onDragOver"
|
|
@dragleave="onDragLeave"
|
|
@drop="onDrop"
|
|
>
|
|
<p v-if="has_existing_doc" class="file-icon">
|
|
<file-icon :type="props.existingDoc?.type"></file-icon>
|
|
</p>
|
|
|
|
<p v-if="display_filename !== null" class="display-filename">
|
|
{{ display_filename }}
|
|
</p>
|
|
<!-- todo i18n -->
|
|
<p v-if="has_existing_doc">
|
|
Déposez un document ou cliquez ici pour remplacer le document existant
|
|
</p>
|
|
<p v-else>
|
|
Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier
|
|
</p>
|
|
</div>
|
|
<div v-else class="waiting">
|
|
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
|
|
<span class="sr-only">Loading...</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.drop-file {
|
|
width: 100%;
|
|
|
|
.file-icon {
|
|
font-size: xx-large;
|
|
}
|
|
|
|
.display-filename {
|
|
font-variant: small-caps;
|
|
font-weight: 200;
|
|
}
|
|
|
|
& > .area,
|
|
& > .waiting {
|
|
width: 100%;
|
|
height: 10rem;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
p {
|
|
// require for display in DropFileModal
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
& > .area {
|
|
border: 4px dashed #ccc;
|
|
|
|
&.dragging {
|
|
border: 4px dashed blue;
|
|
}
|
|
}
|
|
}
|
|
</style>
|