webtransfer/src/components/WebContentViewer.vue

278 lines
12 KiB
Vue
Raw Normal View History

2024-11-19 18:22:06 +01:00
<template>
<div class="flex flex-col h-full w-full border">
<div class="flex h-12 items-center border-b border-gray-300">
<div class="w-4/6 px-4 py-2 text-gray-500 font-semibold border-r border-gray-300">Nom</div>
<div class="w-2/6 px-4 py-2 text-gray-500 font-semibold">Taille</div>
</div>
2024-11-26 14:15:26 +01:00
2024-11-26 14:44:25 +01:00
<div class="flex h-16 hover:bg-NcGray items-center pl-4 cursor-pointer rounded-lg border-b last:border-b-0 border-gray-300" v-if="!isLoading"
2024-11-26 14:15:26 +01:00
draggable="true" @dragstart="dragZip()">
<template>
<div class="flex items-center justify-center cursor-pointer">
2024-11-26 14:42:36 +01:00
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-10 h-10 ">
<path fill="#969696" d="M5.12,5H18.87L17.93,4H5.93L5.12,5M20.54,5.23C20.83,5.57 21,6 21,6.5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V6.5C3,6 3.17,5.57 3.46,5.23L4.84,3.55C5.12,3.21 5.53,3 6,3H18C18.47,3 18.88,3.21 19.15,3.55L20.54,5.23M6,18H12V15H6V18Z"/>
2024-11-26 14:15:26 +01:00
</svg>
</div>
</template>
<div class="w-4/6 flex items-center px-4 py-2 cursor-pointer">
2024-11-26 15:07:37 +01:00
<div class="truncate max-sm:max-w-32 max-w-64 cursor-pointer">{{ zipName }}</div>
2024-11-26 14:15:26 +01:00
</div>
<div class="w-2/6 py-2 cursor-pointer">
{{ formatFileSize(zipSize) }}
</div>
</div>
2024-11-22 14:32:31 +01:00
<div v-if="!isLoading && zipContent.length !== 0" class="overflow-y-auto h-full">
2024-11-19 18:22:06 +01:00
<div v-for="(file, index) in sortedFiles" :key="file.fullPath" class="flex flex-col">
2024-11-26 14:15:26 +01:00
<div class="flex h-16 hover:bg-NcGray items-center pl-4 cursor-pointer rounded-lg border-b last:border-b-0 border-gray-300"
@click="toggleFolder(file)" v-if="file.isDirectory" draggable="true" @dragstart="onDragStart(file)">
2024-11-19 18:22:06 +01:00
<div class="w-4/6 flex items-center py-2 border-r border-gray-300 cursor-pointer">
<div class="w-12 h-12 flex items-center justify-center cursor-pointer">
<template>
<svg fill="currentColor" viewBox="0 0 24 24" class="text-NcBlue w-10 h-10 ">
<path
d="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z">
</path>
</svg>
</template>
</div>
<div class="w-4/6 flex items-center py-2 border-r border-gray-300 cursor-pointer">
<!-- Icône dynamique pour plié/déplié -->
<div class="w-12 h-12 flex items-center justify-center cursor-pointer">
2024-11-26 14:15:26 +01:00
<component :is="folderMap[file.fullPath] ? ChevronDownIcon : ChevronRightIcon"
class="text-NcBlue w-6 h-6" />
2024-11-19 18:22:06 +01:00
</div>
2024-11-20 17:12:10 +01:00
<span class="ml-2 truncate cursor-pointer">{{ file.name }}</span>
2024-11-19 18:22:06 +01:00
</div>
</div>
<div class="w-1/6 px-4 py-2 cursor-pointer">-</div>
</div>
2024-11-26 14:15:26 +01:00
<div class="flex h-16 hover:bg-NcGray items-center pl-4 cursor-pointer rounded-lg border-b last:border-b-0 border-gray-300"
v-else draggable="true" @dragstart="onDragStart(file, $event)">
2024-11-19 18:22:06 +01:00
<template>
<div class="flex items-center justify-center cursor-pointer">
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
class="w-10 h-10"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<path
d="M6 22c-.55 0-1.021-.196-1.412-.587A1.927 1.927 0 0 1 4 20V4c0-.55.196-1.021.588-1.413A1.926 1.926 0 0 1 6 2h8l6 6v12a1.93 1.93 0 0 1-.587 1.413A1.93 1.93 0 0 1 18 22H6Z"
style="fill:#969696;fill-rule:nonzero" transform="matrix(.7 0 0 .7 -.43 -.388)" />
</svg>
</div>
</template>
2024-11-20 17:20:16 +01:00
<div class="w-4/6 flex items-center px-4 py-2 cursor-pointer">
2024-11-26 15:07:37 +01:00
<div class="truncate max-sm:max-w-32 max-w-64 cursor-pointer">{{ file.name }}</div>
2024-11-26 14:15:26 +01:00
2024-11-19 18:22:06 +01:00
</div>
<div class="w-2/6 py-2 cursor-pointer">
{{ formatFileSize(file.size) }}
</div>
</div>
</div>
</div>
2024-11-21 14:39:51 +01:00
<div v-if="isLoading" class="flex h-full items-center justify-center">
2024-11-26 14:15:26 +01:00
<component :is="Loading" class="text-white w-24 h-24 animate-spin" :size="40" />
2024-11-21 14:39:51 +01:00
</div>
<div v-if="!isLoading && zipContent.length === 0" class="flex h-full items-center justify-center">
<span class="text-gray-500">Aucun contenu à afficher</span>
</div>
2024-11-19 18:22:06 +01:00
</div>
</template>
<script>
2024-11-20 17:13:09 +01:00
import JSZip from 'jszip';
2024-11-19 18:22:06 +01:00
import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue';
import ChevronDownIcon from 'vue-material-design-icons/ChevronDown.vue';
2024-11-21 14:39:51 +01:00
import Loading from 'vue-material-design-icons/Loading.vue';
import { ref } from 'vue';
2024-11-19 18:22:06 +01:00
export default {
name: 'WebContentViewer',
data() {
return {
zipContent: [],
2024-11-26 14:15:26 +01:00
folderMap: {},
2024-11-19 18:22:06 +01:00
archiveUrl: '',
token: '',
ChevronRightIcon,
2024-11-21 14:39:51 +01:00
ChevronDownIcon,
isLoading: ref(false),
Loading,
2024-11-26 14:15:26 +01:00
zipName: '',
zipSize: 0,
2024-11-19 18:22:06 +01:00
};
},
props: {
zipUrl: {
type: String,
required: true,
},
},
computed: {
sortedFiles() {
const flattenAndSort = (files, parentPath = '') => {
const flatList = [];
files.forEach(file => {
const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
// Toujours ajouter le dossier parent
flatList.push({
...file,
fullPath,
parentPath,
});
// Ajouter les enfants uniquement si le dossier est ouvert
if (file.isDirectory && this.folderMap[fullPath] && file.children) {
flatList.push(...flattenAndSort(file.children, fullPath));
}
});
return flatList.sort((a, b) => a.fullPath.localeCompare(b.fullPath));
};
return flattenAndSort(this.zipContent);
},
},
async mounted() {
2024-11-21 14:39:51 +01:00
this.isLoading = true;
2024-11-19 18:22:06 +01:00
await this.loadZipContent();
const webTransferDiv = document.getElementById('archiveInfos');
if (webTransferDiv) {
this.archiveUrl = webTransferDiv.dataset.archiveUrl;
this.token = webTransferDiv.dataset.token;
} else {
console.error('Pas d\'informations pour recuperer l\'archive');
}
2024-11-21 14:39:51 +01:00
this.isLoading = false;
2024-11-19 18:22:06 +01:00
},
methods: {
async loadZipContent() {
try {
const response = await fetch(this.zipUrl);
const zipData = await response.blob();
2024-11-26 14:15:26 +01:00
this.zipName = this.zipUrl.split('/').pop();
2024-11-19 18:22:06 +01:00
const zip = await JSZip.loadAsync(zipData);
2024-11-26 14:15:26 +01:00
this.zipSize = zipData.size;
2024-11-19 18:22:06 +01:00
const files = [];
2024-11-19 18:22:06 +01:00
zip.forEach((relativePath, file) => {
const pathParts = relativePath.split('/').filter(Boolean);
let currentLevel = files;
2024-11-19 18:22:06 +01:00
for (let i = 0; i < pathParts.length; i++) {
const partName = pathParts[i];
const isDirectory = i < pathParts.length - 1 || file.dir;
let existing = currentLevel.find(f => f.name === partName && f.isDirectory === isDirectory);
2024-11-20 15:23:12 +01:00
let promise;
if (!isDirectory) {
promise = file.async("blob").then(content => {
existing.content = content;
});
}
2024-11-19 18:22:06 +01:00
if (!existing) {
existing = {
2024-11-20 17:12:10 +01:00
name: pathParts[i],
2024-11-19 18:22:06 +01:00
isDirectory,
size: isDirectory ? 0 : file._data.uncompressedSize,
content: isDirectory ? null : '', // Initialiser 'content' pour les fichiers
2024-11-20 15:23:12 +01:00
children: isDirectory ? [] : null,
2024-11-20 17:12:10 +01:00
//remove the name of the file from the path
2024-11-21 15:19:21 +01:00
parentPath: i > 0 ? pathParts[i - 1] : '',
2024-11-20 15:23:12 +01:00
unzip: promise
2024-11-19 18:22:06 +01:00
};
currentLevel.push(existing);
}
if (isDirectory) {
currentLevel = existing.children;
}
}
});
// Attendre que tous les contenus de fichier soient extraits
2024-11-19 18:22:06 +01:00
this.zipContent = files;
// Initialiser folderMap
2024-11-19 18:22:06 +01:00
const initializeFolderMap = (files, parentPath = '') => {
files.forEach(file => {
const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
this.$set(this.folderMap, fullPath, false);
if (file.isDirectory && file.children) {
initializeFolderMap(file.children, fullPath);
}
});
};
initializeFolderMap(this.zipContent);
console.log('Contenu du ZIP chargé avec succès');
2024-11-19 18:22:06 +01:00
} catch (error) {
console.error('Erreur lors du chargement du contenu du ZIP :', error);
}
},
2024-11-19 18:22:06 +01:00
formatFileSize(size) {
if (size < 1024) return `${size} B`;
if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
if (size < 1024 * 1024 * 1024) return `${(size / 1024 / 1024).toFixed(2)} MB`;
return `${(size / 1024 / 1024 / 1024).toFixed(2)} GB`;
},
toggleFolder(file) {
if (!file.isDirectory) return;
const currentState = this.folderMap[file.fullPath];
this.$set(this.folderMap, file.fullPath, !currentState);
},
2024-11-26 14:15:26 +01:00
async dragZip() {
try {
const zip = {name: this.zipName, url: this.zipUrl};
this.$emit('zip-upload', zip);
} catch (error) {
console.error('Erreur lors du drag du ZIP :', error);
}
},
2024-11-20 15:12:59 +01:00
async onDragStart(file) {
2024-11-20 17:12:10 +01:00
const getFilesFromFolder = (folder) => {
const files = [];
if (!folder.children || folder.children.length === 0) return files;
for (let i = 0; i < folder.children.length; i++) {
const child = folder.children[i];
if (child.isDirectory) {
files.push(...getFilesFromFolder(child));
} else {
files.push(child);
}
}
return files;
};
try {
if (file.isDirectory) {
const files = getFilesFromFolder(file);
const filesToUnzip = files.map(file => file.unzip);
await Promise.all(filesToUnzip);
} else {
await file.unzip;
}
this.$emit('file-upload', file);
} catch (error) {
console.error('Erreur lors du drag start :', error);
}
},
2024-11-19 18:22:06 +01:00
},
};
</script>
<style scoped>
/* Ajoutez ici des styles si nécessaire */
2024-11-21 15:19:21 +01:00
</style>