diff --git a/script.js b/script.js index 0e7f957..1e9c4c1 100644 --- a/script.js +++ b/script.js @@ -1,359 +1,373 @@ // Configuration globale let config = { - baseUrl: '', - currentPath: '' + baseUrl: "", + currentPath: "", }; // Initialisation de l'application -document.addEventListener('DOMContentLoaded', function() { - initializeApp(); - setupEventListeners(); +document.addEventListener("DOMContentLoaded", function () { + initializeApp(); + setupEventListeners(); }); function initializeApp() { - // Tentative de configuration automatique depuis l'URL courante - autoConfigureFromURL(); - - // Affichage du formulaire de développement - showDevForm(); - + // Tentative de configuration automatique depuis l'URL courante + autoConfigureFromURL(); + + // Affichage du formulaire de développement + showDevForm(); } function setupEventListeners() { - // Formulaire de développement - const urlForm = document.getElementById('url-form'); - if (urlForm) { - urlForm.addEventListener('submit', handleUrlFormSubmit); - } - - // Gestion de la navigation arrière/avant du navigateur - window.addEventListener('popstate', handlePopState); - - // Gestionnaires pour la prévisualisation - const closePreview = document.getElementById('close-preview'); - if (closePreview) { - closePreview.addEventListener('click', hidePreview); - } - - const downloadFile = document.getElementById('download-file'); - if (downloadFile) { - downloadFile.addEventListener('click', downloadCurrentFile); - } + // Formulaire de développement + const urlForm = document.getElementById("url-form"); + if (urlForm) { + urlForm.addEventListener("submit", handleUrlFormSubmit); + } + + // Gestion de la navigation arrière/avant du navigateur + window.addEventListener("popstate", handlePopState); + + // Gestionnaires pour la prévisualisation + const closePreview = document.getElementById("close-preview"); + if (closePreview) { + closePreview.addEventListener("click", hidePreview); + } + + const downloadFile = document.getElementById("download-file"); + if (downloadFile) { + downloadFile.addEventListener("click", downloadCurrentFile); + } } function handlePopState(event) { - console.log('Navigation arrière/avant détectée:', event.state); - - if (event.state && event.state.baseUrl) { - // Restaurer la configuration - config.baseUrl = event.state.baseUrl; - config.currentPath = event.state.path || ''; - - updateConfigDisplay(); - - // Charger le contenu sans ajouter à l'historique (pour éviter les boucles) - loadBucketContents(config.currentPath, false); - } + console.log("Navigation arrière/avant détectée:", event.state); + + if (event.state && event.state.baseUrl) { + // Restaurer la configuration + config.baseUrl = event.state.baseUrl; + config.currentPath = event.state.path || ""; + + updateConfigDisplay(); + + // Charger le contenu sans ajouter à l'historique (pour éviter les boucles) + loadBucketContents(config.currentPath, false); + } } function autoConfigureFromURL() { - const currentUrl = window.location.href; - const url = new URL(currentUrl); - - // Configuration simplifiée : on prend juste le base URL sans le bucket - config.baseUrl = `${url.protocol}//${url.host}${url.pathname.replace('/index.html', '')}`; - - // Vérifier s'il y a un fragment d'URL pour définir le chemin initial - if (url.hash) { - const hashPath = url.hash.replace('#/', ''); - config.currentPath = hashPath; - } - - updateConfigDisplay(); - console.log('Configuration automatique:', config); - - // Charger automatiquement le contenu si on a une config valide - if (config.baseUrl) { - loadBucketContents(config.currentPath, false); - } + const currentUrl = window.location.href; + const url = new URL(currentUrl); + + // Configuration simplifiée : on prend juste le base URL sans le bucket + config.baseUrl = `${url.protocol}//${url.host}${url.pathname.replace("/index.html", "")}`; + + // Vérifier s'il y a un fragment d'URL pour définir le chemin initial + if (url.hash) { + const hashPath = url.hash.replace("#/", ""); + config.currentPath = hashPath; + } + + updateConfigDisplay(); + console.log("Configuration automatique:", config); + + // Charger automatiquement le contenu si on a une config valide + if (config.baseUrl) { + loadBucketContents(config.currentPath, false); + } } function handleUrlFormSubmit(event) { - event.preventDefault(); - - const urlInput = document.getElementById('minio-url'); - if (!urlInput) return; - - const minioUrl = urlInput.value.trim(); - - if (!minioUrl) { - showError('Veuillez saisir une URL MinIO'); - return; - } - - parseMinioURL(minioUrl); + event.preventDefault(); + + const urlInput = document.getElementById("minio-url"); + if (!urlInput) return; + + const minioUrl = urlInput.value.trim(); + + if (!minioUrl) { + showError("Veuillez saisir une URL MinIO"); + return; + } + + parseMinioURL(minioUrl); } function parseMinioURL(url) { - try { - const urlObj = new URL(url); - - // Configuration simplifiée : on prend l'URL complète comme base - config.baseUrl = url.replace(/\/$/, ''); // Supprimer le slash final si présent - config.currentPath = ''; - - updateConfigDisplay(); - - // Ajouter l'état initial à l'historique - const initialState = { path: '', baseUrl: config.baseUrl }; - history.replaceState(initialState, '', window.location.href); - - loadBucketContents(); - - } catch (error) { - showError('URL invalide: ' + error.message); - console.error('Erreur de parsing URL:', error); - } + try { + const urlObj = new URL(url); + + // Configuration simplifiée : on prend l'URL complète comme base + config.baseUrl = url.replace(/\/$/, ""); // Supprimer le slash final si présent + config.currentPath = ""; + + updateConfigDisplay(); + + // Ajouter l'état initial à l'historique + const initialState = { path: "", baseUrl: config.baseUrl }; + history.replaceState(initialState, "", window.location.href); + + loadBucketContents(); + } catch (error) { + showError("URL invalide: " + error.message); + console.error("Erreur de parsing URL:", error); + } } function updateConfigDisplay() { - const configInfo = document.getElementById('config-info'); - if (configInfo) { - configInfo.innerHTML = ` + const configInfo = document.getElementById("config-info"); + if (configInfo) { + configInfo.innerHTML = ` Configuration actuelle:
URL de base: ${config.baseUrl}
Chemin actuel: /${config.currentPath} `; - } + } } function showDevForm() { - const devForm = document.getElementById('dev-form'); - if (devForm) { - devForm.style.display = 'block'; - } + const devForm = document.getElementById("dev-form"); + if (devForm) { + devForm.style.display = "block"; + } } - function showError(message) { - const errorSection = document.getElementById('error-section'); - const errorMessage = document.getElementById('error-message'); - - if (errorMessage) { - errorMessage.textContent = message; - } - - if (errorSection) { - errorSection.style.display = 'block'; - - // Masquer l'erreur après 5 secondes - setTimeout(() => { - errorSection.style.display = 'none'; - }, 5000); - } + const errorSection = document.getElementById("error-section"); + const errorMessage = document.getElementById("error-message"); + + if (errorMessage) { + errorMessage.textContent = message; + } + + if (errorSection) { + errorSection.style.display = "block"; + + // Masquer l'erreur après 5 secondes + setTimeout(() => { + errorSection.style.display = "none"; + }, 5000); + } } function showLoading(show = true) { - const loading = document.getElementById('loading'); - const table = document.getElementById('files-table'); - - if (loading) { - loading.style.display = show ? 'block' : 'none'; - } - - if (table) { - table.style.display = show ? 'none' : 'table'; - } + const loading = document.getElementById("loading"); + const table = document.getElementById("files-table"); + + if (loading) { + loading.style.display = show ? "block" : "none"; + } + + if (table) { + table.style.display = show ? "none" : "table"; + } } function updateCurrentPathDisplay() { - const pathDisplay = document.getElementById('current-path'); - if (pathDisplay) { - pathDisplay.textContent = '/' + config.currentPath; - } + const pathDisplay = document.getElementById("current-path"); + if (pathDisplay) { + pathDisplay.textContent = "/" + config.currentPath; + } } -async function loadBucketContents(path = '', pushToHistory = true) { - console.log('Debug loadBucketContents - path received:', JSON.stringify(path)); - - if (!config.baseUrl) { - showError('Configuration URL manquante'); - return; +async function loadBucketContents(path = "", pushToHistory = true) { + console.log( + "Debug loadBucketContents - path received:", + JSON.stringify(path), + ); + + if (!config.baseUrl) { + showError("Configuration URL manquante"); + return; + } + + showLoading(true); + config.currentPath = path; + updateCurrentPathDisplay(); + + // Ajouter à l'historique du navigateur si demandé + if (pushToHistory) { + const state = { path: path, baseUrl: config.baseUrl }; + const url = path ? `#/${path}` : "#/"; + history.pushState(state, "", url); + } + + try { + // Construction de l'URL API avec delimiter + let apiUrl = `${config.baseUrl}?list-type=2&delimiter=/`; + + // Construire le prefix pour l'API MinIO + if (path) { + // Pour un sous-dossier + const cleanPath = path.startsWith("/") ? path.substring(1) : path; + const fullPrefix = cleanPath + "/"; + apiUrl += `&prefix=${encodeURIComponent(fullPrefix)}`; } - - showLoading(true); - config.currentPath = path; - updateCurrentPathDisplay(); - - // Ajouter à l'historique du navigateur si demandé - if (pushToHistory) { - const state = { path: path, baseUrl: config.baseUrl }; - const url = path ? `#/${path}` : '#/'; - history.pushState(state, '', url); - } - - try { - // Construction de l'URL API avec delimiter - let apiUrl = `${config.baseUrl}?list-type=2&delimiter=/`; - - // Construire le prefix pour l'API MinIO - if (path) { - // Pour un sous-dossier - const cleanPath = path.startsWith('/') ? path.substring(1) : path; - const fullPrefix = cleanPath + '/'; - apiUrl += `&prefix=${encodeURIComponent(fullPrefix)}`; - } - - console.log('Appel API MinIO:', apiUrl); - - const response = await fetch(apiUrl); - - if (!response.ok) { - throw new Error(`Erreur HTTP: ${response.status}`); - } - - const xmlText = await response.text(); - console.log('Réponse XML reçue:', xmlText); - - const contents = parseMinioXML(xmlText); - displayContents(contents); - - } catch (error) { - console.error('Erreur lors du chargement:', error); - showError('Erreur de chargement: ' + error.message); - } finally { - showLoading(false); + + console.log("Appel API MinIO:", apiUrl); + + const response = await fetch(apiUrl); + + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); } + + const xmlText = await response.text(); + console.log("Réponse XML reçue:", xmlText); + + const contents = parseMinioXML(xmlText); + displayContents(contents); + } catch (error) { + console.error("Erreur lors du chargement:", error); + showError("Erreur de chargement: " + error.message); + } finally { + showLoading(false); + } } function parseMinioXML(xmlText) { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(xmlText, 'text/xml'); - - const contents = { - folders: [], - files: [] - }; - - // Déterminer le préfixe attendu basé sur la navigation actuelle - let expectedPrefix = ''; - if (config.currentPath) { - expectedPrefix = config.currentPath + '/'; - } - - // Parse CommonPrefixes (dossiers) - const prefixes = xmlDoc.getElementsByTagName('CommonPrefixes'); - for (let prefix of prefixes) { - const prefixElement = prefix.getElementsByTagName('Prefix')[0]; - if (prefixElement) { - const fullPrefix = prefixElement.textContent; - - // Extraire le nom du dossier (dernière partie avant le /) - const folderName = fullPrefix.replace(/\/$/, '').split('/').pop(); - - if (folderName) { - // Construire le chemin pour la navigation - let folderPath; - if (config.currentPath) { - folderPath = config.currentPath + '/' + folderName; - } else { - folderPath = folderName; - } - - console.log('Debug parsing - fullPrefix:', fullPrefix, 'folderName:', folderName, 'currentPath:', config.currentPath, 'folderPath:', folderPath); - - contents.folders.push({ - name: folderName, - path: folderPath - }); - } + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(xmlText, "text/xml"); + + const contents = { + folders: [], + files: [], + }; + + // Déterminer le préfixe attendu basé sur la navigation actuelle + let expectedPrefix = ""; + if (config.currentPath) { + expectedPrefix = config.currentPath + "/"; + } + + // Parse CommonPrefixes (dossiers) + const prefixes = xmlDoc.getElementsByTagName("CommonPrefixes"); + for (let prefix of prefixes) { + const prefixElement = prefix.getElementsByTagName("Prefix")[0]; + if (prefixElement) { + const fullPrefix = prefixElement.textContent; + + // Extraire le nom du dossier (dernière partie avant le /) + const folderName = fullPrefix.replace(/\/$/, "").split("/").pop(); + + if (folderName) { + // Construire le chemin pour la navigation + let folderPath; + if (config.currentPath) { + folderPath = config.currentPath + "/" + folderName; + } else { + folderPath = folderName; } + + console.log( + "Debug parsing - fullPrefix:", + fullPrefix, + "folderName:", + folderName, + "currentPath:", + config.currentPath, + "folderPath:", + folderPath, + ); + + contents.folders.push({ + name: folderName, + path: folderPath, + }); + } } - - // Parse Contents (fichiers) - const objects = xmlDoc.getElementsByTagName('Contents'); - for (let obj of objects) { - const keyElement = obj.getElementsByTagName('Key')[0]; - const sizeElement = obj.getElementsByTagName('Size')[0]; - const modifiedElement = obj.getElementsByTagName('LastModified')[0]; - - if (keyElement) { - const fullKey = keyElement.textContent; - const fileName = fullKey.split('/').pop(); - - // Vérifier que le fichier correspond au niveau de navigation actuel - let shouldInclude = false; - - if (config.currentPath) { - // Dans un sous-dossier : vérifier que la clé commence par le bon préfixe - const currentPrefix = config.currentPath + '/'; - if (fullKey.startsWith(currentPrefix)) { - // S'assurer qu'on n'affiche que les fichiers directs (pas dans des sous-sous-dossiers) - const relativePath = fullKey.replace(currentPrefix, ''); - if (!relativePath.includes('/')) { - shouldInclude = true; - } - } - } else { - // À la racine : afficher tous les fichiers qui ne sont pas dans des dossiers - if (!fullKey.includes('/')) { - shouldInclude = true; - } - } - - // Exclure les fichiers de l'application - if (shouldInclude && fileName && !['index.html', 'style.css', 'script.js'].includes(fileName)) { - contents.files.push({ - name: fileName, - size: sizeElement ? parseInt(sizeElement.textContent) : 0, - modified: modifiedElement ? new Date(modifiedElement.textContent) : new Date(), - fullKey: fullKey - }); - } + } + + // Parse Contents (fichiers) + const objects = xmlDoc.getElementsByTagName("Contents"); + for (let obj of objects) { + const keyElement = obj.getElementsByTagName("Key")[0]; + const sizeElement = obj.getElementsByTagName("Size")[0]; + const modifiedElement = obj.getElementsByTagName("LastModified")[0]; + + if (keyElement) { + const fullKey = keyElement.textContent; + const fileName = fullKey.split("/").pop(); + + // Vérifier que le fichier correspond au niveau de navigation actuel + let shouldInclude = false; + + if (config.currentPath) { + // Dans un sous-dossier : vérifier que la clé commence par le bon préfixe + const currentPrefix = config.currentPath + "/"; + if (fullKey.startsWith(currentPrefix)) { + // S'assurer qu'on n'affiche que les fichiers directs (pas dans des sous-sous-dossiers) + const relativePath = fullKey.replace(currentPrefix, ""); + if (!relativePath.includes("/")) { + shouldInclude = true; + } } + } else { + // À la racine : afficher tous les fichiers qui ne sont pas dans des dossiers + if (!fullKey.includes("/")) { + shouldInclude = true; + } + } + + // Exclure les fichiers de l'application + if ( + shouldInclude && + fileName && + !["index.html", "style.css", "script.js"].includes(fileName) + ) { + contents.files.push({ + name: fileName, + size: sizeElement ? parseInt(sizeElement.textContent) : 0, + modified: modifiedElement + ? new Date(modifiedElement.textContent) + : new Date(), + fullKey: fullKey, + }); + } } - - return contents; + } + + return contents; } function displayContents(contents) { - const tbody = document.getElementById('files-tbody'); - if (!tbody) return; - - tbody.innerHTML = ''; - - // Bouton parent directory si on n'est pas à la racine - if (config.currentPath) { - const parentPath = config.currentPath.split('/').slice(0, -1).join('/'); - const parentRow = createParentRow(parentPath); - tbody.appendChild(parentRow); - } - - // Afficher les dossiers - contents.folders.forEach(folder => { - const row = createFolderRow(folder); - tbody.appendChild(row); - }); - - // Afficher les fichiers - contents.files.forEach(file => { - const row = createFileRow(file); - tbody.appendChild(row); - }); - - // Afficher le tableau - const filesTable = document.getElementById('files-table'); - if (filesTable) { - filesTable.style.display = 'table'; - } - - // Chercher et ouvrir automatiquement index.rst s'il existe - autoOpenIndexRst(contents.files); + const tbody = document.getElementById("files-tbody"); + if (!tbody) return; + + tbody.innerHTML = ""; + + // Bouton parent directory si on n'est pas à la racine + if (config.currentPath) { + const parentPath = config.currentPath.split("/").slice(0, -1).join("/"); + const parentRow = createParentRow(parentPath); + tbody.appendChild(parentRow); + } + + // Afficher les dossiers + contents.folders.forEach((folder) => { + const row = createFolderRow(folder); + tbody.appendChild(row); + }); + + // Afficher les fichiers + contents.files.forEach((file) => { + const row = createFileRow(file); + tbody.appendChild(row); + }); + + // Afficher le tableau + const filesTable = document.getElementById("files-table"); + if (filesTable) { + filesTable.style.display = "table"; + } + + // Chercher et ouvrir automatiquement index.rst s'il existe + autoOpenIndexRst(contents.files); } function createParentRow(parentPath) { - const row = document.createElement('tr'); - row.innerHTML = ` + const row = document.createElement("tr"); + row.innerHTML = ` .. @@ -362,19 +376,19 @@ function createParentRow(parentPath) { - - `; - - const link = row.querySelector('.folder-link'); - link.addEventListener('click', (e) => { - e.preventDefault(); - loadBucketContents(parentPath, true); - }); - - return row; + + const link = row.querySelector(".folder-link"); + link.addEventListener("click", (e) => { + e.preventDefault(); + loadBucketContents(parentPath, true); + }); + + return row; } function createFolderRow(folder) { - const row = document.createElement('tr'); - row.innerHTML = ` + const row = document.createElement("tr"); + row.innerHTML = ` ${folder.name}/ @@ -383,21 +397,21 @@ function createFolderRow(folder) { - - `; - - const link = row.querySelector('.folder-link'); - link.addEventListener('click', (e) => { - e.preventDefault(); - loadBucketContents(folder.path, true); - }); - - return row; + + const link = row.querySelector(".folder-link"); + link.addEventListener("click", (e) => { + e.preventDefault(); + loadBucketContents(folder.path, true); + }); + + return row; } function createFileRow(file) { - const row = document.createElement('tr'); - const fileUrl = `${config.baseUrl}/${file.fullKey}`; - - row.innerHTML = ` + const row = document.createElement("tr"); + const fileUrl = `${config.baseUrl}/${file.fullKey}`; + + row.innerHTML = ` ${file.name} @@ -408,310 +422,333 @@ function createFileRow(file) { `; - - const fileLink = row.querySelector('.file-link'); - fileLink.addEventListener('click', (e) => { - e.preventDefault(); - showPreview(fileUrl, file.name); - }); - - const copyBtn = row.querySelector('.copy-btn'); - copyBtn.addEventListener('click', () => copyToClipboard(fileUrl)); - - return row; + + const fileLink = row.querySelector(".file-link"); + fileLink.addEventListener("click", (e) => { + e.preventDefault(); + showPreview(fileUrl, file.name); + }); + + const copyBtn = row.querySelector(".copy-btn"); + copyBtn.addEventListener("click", () => copyToClipboard(fileUrl)); + + return row; } function formatFileSize(bytes) { - if (bytes === 0) return '0 B'; - - const k = 1024; - const sizes = ['B', 'KB', 'MB', 'GB']; - const i = Math.floor(Math.log(bytes) / Math.log(k)); - - return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; + if (bytes === 0) return "0 B"; + + const k = 1024; + const sizes = ["B", "KB", "MB", "GB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i]; } function formatDate(date) { - return date.toLocaleString('fr-FR', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit' - }); + return date.toLocaleString("fr-FR", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }); } async function copyToClipboard(text) { - try { - await navigator.clipboard.writeText(text); - console.log('Lien copié:', text); - - // Feedback visuel temporaire - const btn = event.target; - const originalText = btn.textContent; - btn.textContent = 'Copié !'; - setTimeout(() => { - btn.textContent = originalText; - }, 1000); - - } catch (error) { - console.error('Erreur copie clipboard:', error); - - // Fallback pour les navigateurs plus anciens - const textArea = document.createElement('textarea'); - textArea.value = text; - document.body.appendChild(textArea); - textArea.select(); - document.execCommand('copy'); - document.body.removeChild(textArea); - } + try { + await navigator.clipboard.writeText(text); + console.log("Lien copié:", text); + + // Feedback visuel temporaire + const btn = event.target; + const originalText = btn.textContent; + btn.textContent = "Copié !"; + setTimeout(() => { + btn.textContent = originalText; + }, 1000); + } catch (error) { + console.error("Erreur copie clipboard:", error); + + // Fallback pour les navigateurs plus anciens + const textArea = document.createElement("textarea"); + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand("copy"); + document.body.removeChild(textArea); + } } // Variables globales pour la prévisualisation let currentPreviewFile = { - url: '', - name: '' + url: "", + name: "", }; function detectFileType(fileName) { - const extension = fileName.toLowerCase().split('.').pop(); - - const fileTypes = { - images: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'], - text: ['txt', 'json', 'xml', 'csv', 'log'], - code: ['js', 'css', 'html', 'htm', 'py', 'java', 'cpp', 'c', 'php', 'rb', 'go', 'rs', 'ts', 'jsx', 'tsx', 'vue', 'svelte', 'tex', 'latex'], - markdown: ['md', 'markdown'], - rst: ['rst', 'rest'], - pdf: ['pdf'], - video: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'], - audio: ['mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a'], - archive: ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'] - }; - - for (const [type, extensions] of Object.entries(fileTypes)) { - if (extensions.includes(extension)) { - return type; - } + const extension = fileName.toLowerCase().split(".").pop(); + + const fileTypes = { + images: ["jpg", "jpeg", "png", "gif", "bmp", "svg", "webp"], + text: ["txt", "json", "xml", "csv", "log"], + code: [ + "js", + "css", + "html", + "htm", + "py", + "java", + "cpp", + "c", + "php", + "rb", + "go", + "rs", + "ts", + "jsx", + "tsx", + "vue", + "svelte", + "tex", + "latex", + ], + markdown: ["md", "markdown"], + rst: ["rst", "rest"], + pdf: ["pdf"], + video: ["mp4", "avi", "mov", "wmv", "flv", "webm", "mkv"], + audio: ["mp3", "wav", "ogg", "aac", "flac", "m4a"], + archive: ["zip", "rar", "7z", "tar", "gz", "bz2"], + }; + + for (const [type, extensions] of Object.entries(fileTypes)) { + if (extensions.includes(extension)) { + return type; } - - return 'unknown'; + } + + return "unknown"; } function showPreview(fileUrl, fileName) { - currentPreviewFile = { url: fileUrl, name: fileName }; - - const previewSection = document.getElementById('preview-section'); - const previewTitle = document.getElementById('preview-title'); - const previewContent = document.getElementById('preview-content'); - - if (!previewSection || !previewTitle || !previewContent) { - console.error('Éléments de prévisualisation non trouvés'); - return; - } - - previewTitle.textContent = `Prévisualisation: ${fileName}`; - previewContent.innerHTML = '
Chargement...
'; - - previewSection.style.display = 'flex'; - - const fileType = detectFileType(fileName); - - switch (fileType) { - case 'images': - showImagePreview(fileUrl, previewContent); - break; - case 'text': - showTextPreview(fileUrl, previewContent); - break; - case 'code': - showCodePreview(fileUrl, fileName, previewContent); - break; - case 'markdown': - showMarkdownPreview(fileUrl, previewContent); - break; - case 'rst': - showRstPreview(fileUrl, previewContent); - break; - case 'pdf': - showPdfPreview(fileUrl, previewContent); - break; - case 'video': - showVideoPreview(fileUrl, previewContent); - break; - case 'audio': - showAudioPreview(fileUrl, previewContent); - break; - default: - showUnsupportedPreview(fileName, previewContent); - } + currentPreviewFile = { url: fileUrl, name: fileName }; + + const previewSection = document.getElementById("preview-section"); + const previewTitle = document.getElementById("preview-title"); + const previewContent = document.getElementById("preview-content"); + + if (!previewSection || !previewTitle || !previewContent) { + console.error("Éléments de prévisualisation non trouvés"); + return; + } + + previewTitle.textContent = `Prévisualisation: ${fileName}`; + previewContent.innerHTML = + '
Chargement...
'; + + previewSection.style.display = "flex"; + + const fileType = detectFileType(fileName); + + switch (fileType) { + case "images": + showImagePreview(fileUrl, previewContent); + break; + case "text": + showTextPreview(fileUrl, previewContent); + break; + case "code": + showCodePreview(fileUrl, fileName, previewContent); + break; + case "markdown": + showMarkdownPreview(fileUrl, previewContent); + break; + case "rst": + showRstPreview(fileUrl, previewContent); + break; + case "pdf": + showPdfPreview(fileUrl, previewContent); + break; + case "video": + showVideoPreview(fileUrl, previewContent); + break; + case "audio": + showAudioPreview(fileUrl, previewContent); + break; + default: + showUnsupportedPreview(fileName, previewContent); + } } function showImagePreview(fileUrl, container) { - const img = document.createElement('img'); - img.src = fileUrl; - img.alt = 'Prévisualisation image'; - - img.onload = () => { - container.innerHTML = ''; - container.appendChild(img); - }; - - img.onerror = () => { - container.innerHTML = '
Erreur: Impossible de charger l\'image
'; - }; + const img = document.createElement("img"); + img.src = fileUrl; + img.alt = "Prévisualisation image"; + + img.onload = () => { + container.innerHTML = ""; + container.appendChild(img); + }; + + img.onerror = () => { + container.innerHTML = + '
Erreur: Impossible de charger l\'image
'; + }; } function showTextPreview(fileUrl, container) { - fetch(fileUrl) - .then(response => { - if (!response.ok) { - throw new Error(`Erreur HTTP: ${response.status}`); - } - return response.text(); - }) - .then(text => { - const pre = document.createElement('pre'); - pre.textContent = text; - container.innerHTML = ''; - container.appendChild(pre); - }) - .catch(error => { - console.error('Erreur chargement texte:', error); - container.innerHTML = '
Erreur: Impossible de charger le fichier texte
'; - }); + fetch(fileUrl) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + return response.text(); + }) + .then((text) => { + const pre = document.createElement("pre"); + pre.textContent = text; + container.innerHTML = ""; + container.appendChild(pre); + }) + .catch((error) => { + console.error("Erreur chargement texte:", error); + container.innerHTML = + '
Erreur: Impossible de charger le fichier texte
'; + }); } function detectLanguageFromExtension(fileName) { - const extension = fileName.toLowerCase().split('.').pop(); - - const languageMap = { - 'js': 'javascript', - 'jsx': 'jsx', - 'ts': 'typescript', - 'tsx': 'tsx', - 'py': 'python', - 'java': 'java', - 'c': 'c', - 'cpp': 'cpp', - 'cxx': 'cpp', - 'cc': 'cpp', - 'php': 'php', - 'rb': 'ruby', - 'go': 'go', - 'rs': 'rust', - 'html': 'html', - 'htm': 'html', - 'css': 'css', - 'scss': 'scss', - 'sass': 'sass', - 'less': 'less', - 'json': 'json', - 'xml': 'xml', - 'vue': 'vue', - 'svelte': 'svelte', - 'sh': 'bash', - 'bash': 'bash', - 'zsh': 'bash', - 'fish': 'bash', - 'ps1': 'powershell', - 'sql': 'sql', - 'r': 'r', - 'matlab': 'matlab', - 'm': 'matlab', - 'swift': 'swift', - 'kt': 'kotlin', - 'scala': 'scala', - 'clj': 'clojure', - 'hs': 'haskell', - 'lua': 'lua', - 'pl': 'perl', - 'tex': 'latex', - 'latex': 'latex', - 'md': 'markdown', - 'markdown': 'markdown', - 'yml': 'yaml', - 'yaml': 'yaml', - 'toml': 'toml', - 'ini': 'ini', - 'conf': 'bash', - 'config': 'bash' - }; - - return languageMap[extension] || 'text'; + const extension = fileName.toLowerCase().split(".").pop(); + + const languageMap = { + js: "javascript", + jsx: "jsx", + ts: "typescript", + tsx: "tsx", + py: "python", + java: "java", + c: "c", + cpp: "cpp", + cxx: "cpp", + cc: "cpp", + php: "php", + rb: "ruby", + go: "go", + rs: "rust", + html: "html", + htm: "html", + css: "css", + scss: "scss", + sass: "sass", + less: "less", + json: "json", + xml: "xml", + vue: "vue", + svelte: "svelte", + sh: "bash", + bash: "bash", + zsh: "bash", + fish: "bash", + ps1: "powershell", + sql: "sql", + r: "r", + matlab: "matlab", + m: "matlab", + swift: "swift", + kt: "kotlin", + scala: "scala", + clj: "clojure", + hs: "haskell", + lua: "lua", + pl: "perl", + tex: "latex", + latex: "latex", + md: "markdown", + markdown: "markdown", + yml: "yaml", + yaml: "yaml", + toml: "toml", + ini: "ini", + conf: "bash", + config: "bash", + }; + + return languageMap[extension] || "text"; } function showCodePreview(fileUrl, fileName, container) { - fetch(fileUrl) - .then(response => { - if (!response.ok) { - throw new Error(`Erreur HTTP: ${response.status}`); - } - return response.text(); - }) - .then(text => { - const language = detectLanguageFromExtension(fileName); - - const pre = document.createElement('pre'); - const code = document.createElement('code'); - - if (language !== 'text') { - code.className = `language-${language}`; - } - - code.textContent = text; - pre.appendChild(code); - - container.innerHTML = ''; - container.appendChild(pre); - - // Appliquer la coloration syntaxique si Prism est disponible - if (window.Prism && language !== 'text') { - try { - Prism.highlightElement(code); - } catch (error) { - console.warn('Erreur coloration syntaxique:', error); - } - } - }) - .catch(error => { - console.error('Erreur chargement code:', error); - container.innerHTML = '
Erreur: Impossible de charger le fichier
'; - }); + fetch(fileUrl) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + return response.text(); + }) + .then((text) => { + const language = detectLanguageFromExtension(fileName); + + const pre = document.createElement("pre"); + const code = document.createElement("code"); + + if (language !== "text") { + code.className = `language-${language}`; + } + + code.textContent = text; + pre.appendChild(code); + + container.innerHTML = ""; + container.appendChild(pre); + + // Appliquer la coloration syntaxique si Prism est disponible + if (window.Prism && language !== "text") { + try { + Prism.highlightElement(code); + } catch (error) { + console.warn("Erreur coloration syntaxique:", error); + } + } + }) + .catch((error) => { + console.error("Erreur chargement code:", error); + container.innerHTML = + '
Erreur: Impossible de charger le fichier
'; + }); } function showPdfPreview(fileUrl, container) { - const iframe = document.createElement('iframe'); - iframe.src = fileUrl; - iframe.style.width = '100%'; - iframe.style.height = '500px'; - - container.innerHTML = ''; - container.appendChild(iframe); + const iframe = document.createElement("iframe"); + iframe.src = fileUrl; + iframe.style.width = "100%"; + iframe.style.height = "100%"; + + container.innerHTML = ""; + container.appendChild(iframe); } function showVideoPreview(fileUrl, container) { - const video = document.createElement('video'); - video.src = fileUrl; - video.controls = true; - video.style.maxWidth = '100%'; - - container.innerHTML = ''; - container.appendChild(video); + const video = document.createElement("video"); + video.src = fileUrl; + video.controls = true; + video.style.maxWidth = "100%"; + + container.innerHTML = ""; + container.appendChild(video); } function showAudioPreview(fileUrl, container) { - const audio = document.createElement('audio'); - audio.src = fileUrl; - audio.controls = true; - audio.style.width = '100%'; - - container.innerHTML = ''; - container.appendChild(audio); + const audio = document.createElement("audio"); + audio.src = fileUrl; + audio.controls = true; + audio.style.width = "100%"; + + container.innerHTML = ""; + container.appendChild(audio); } function showUnsupportedPreview(fileName, container) { - const extension = fileName.toLowerCase().split('.').pop(); - container.innerHTML = ` + const extension = fileName.toLowerCase().split(".").pop(); + container.innerHTML = `

Prévisualisation non disponible pour ce type de fichier (.${extension})

Utilisez le bouton "Télécharger" ci-dessous pour obtenir le fichier.

@@ -720,323 +757,354 @@ function showUnsupportedPreview(fileName, container) { } function hidePreview() { - const previewSection = document.getElementById('preview-section'); - if (previewSection) { - previewSection.style.display = 'none'; - } - - currentPreviewFile = { url: '', name: '' }; + const previewSection = document.getElementById("preview-section"); + if (previewSection) { + previewSection.style.display = "none"; + } + + currentPreviewFile = { url: "", name: "" }; } function downloadCurrentFile() { - if (currentPreviewFile.url) { - const link = document.createElement('a'); - link.href = currentPreviewFile.url; - link.download = currentPreviewFile.name; - link.target = '_blank'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } + if (currentPreviewFile.url) { + const link = document.createElement("a"); + link.href = currentPreviewFile.url; + link.download = currentPreviewFile.name; + link.target = "_blank"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } } // Fonction pour ouvrir automatiquement index.rst s'il existe function autoOpenIndexRst(files) { - // Chercher un fichier index.rst dans la liste - const indexRstFile = files.find(file => - file.name.toLowerCase() === 'index.rst' - ); - - if (indexRstFile) { - // Construire l'URL complète du fichier - const fileUrl = `${config.baseUrl}/${indexRstFile.fullKey}`; - - // Ouvrir automatiquement la prévisualisation - console.log('Auto-ouverture de index.rst trouvé:', indexRstFile.name); - showPreview(fileUrl, indexRstFile.name); - } else { - // Pas d'index.rst trouvé, fermer le preview s'il est ouvert - console.log('Aucun index.rst trouvé, fermeture du preview'); - hidePreview(); - } + // Chercher un fichier index.rst dans la liste + const indexRstFile = files.find( + (file) => file.name.toLowerCase() === "index.rst", + ); + + if (indexRstFile) { + // Construire l'URL complète du fichier + const fileUrl = `${config.baseUrl}/${indexRstFile.fullKey}`; + + // Ouvrir automatiquement la prévisualisation + console.log("Auto-ouverture de index.rst trouvé:", indexRstFile.name); + showPreview(fileUrl, indexRstFile.name); + } else { + // Pas d'index.rst trouvé, fermer le preview s'il est ouvert + console.log("Aucun index.rst trouvé, fermeture du preview"); + hidePreview(); + } } // Fonction simple de parsing Markdown vers HTML function parseMarkdown(text) { - let html = text; - - // Headers - html = html.replace(/^### (.*$)/gim, '

$1

'); - html = html.replace(/^## (.*$)/gim, '

$1

'); - html = html.replace(/^# (.*$)/gim, '

$1

'); - - // Bold - html = html.replace(/\*\*(.*?)\*\*/g, '$1'); - html = html.replace(/__(.*?)__/g, '$1'); - - // Italic - html = html.replace(/\*(.*?)\*/g, '$1'); - html = html.replace(/_(.*?)_/g, '$1'); - - // Code inline - html = html.replace(/`(.*?)`/g, '$1'); - - // Code blocks - html = html.replace(/```([\s\S]*?)```/g, '
$1
'); - - // Links - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - - // Images - html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$1'); - - // Lists - html = html.replace(/^\* (.*$)/gim, '
  • $1
  • '); - html = html.replace(/^- (.*$)/gim, '
  • $1
  • '); - html = html.replace(/^\d+\. (.*$)/gim, '
  • $1
  • '); - - // Wrap consecutive
  • items in