New search function et drag and drop clean

This commit is contained in:
2025-11-10 19:40:14 +01:00
parent d969b05ead
commit cd9a96c760
42 changed files with 2164 additions and 34 deletions

View File

@ -69,7 +69,7 @@ class FileTree {
// Setup drag events pour les fichiers
fileItems.forEach(file => {
file.addEventListener('dragstart', (e) => this.handleDragStart(e));
file.addEventListener('dragstart', (e) => this.handleDragStart(e, 'file'));
file.addEventListener('dragend', (e) => this.handleDragEnd(e));
// Empêcher htmx de gérer le clic pendant le drag
file.addEventListener('click', (e) => {
@ -79,49 +79,106 @@ class FileTree {
}, true);
});
// Setup drop zones pour les dossiers
// Setup drag events pour les dossiers (headers)
folderItems.forEach(folder => {
const header = folder.querySelector('.folder-header');
const isRoot = folder.dataset.isRoot === 'true';
// La racine ne doit pas être draggable
if (!isRoot) {
header.setAttribute('draggable', 'true');
header.addEventListener('dragstart', (e) => this.handleDragStart(e, 'folder'));
header.addEventListener('dragend', (e) => this.handleDragEnd(e));
}
// Tous les dossiers (y compris la racine) sont des drop zones
header.addEventListener('dragover', (e) => this.handleDragOver(e));
header.addEventListener('dragleave', (e) => this.handleDragLeave(e));
header.addEventListener('drop', (e) => this.handleDrop(e));
});
}
handleDragStart(e) {
const item = e.target;
handleDragStart(e, type) {
const item = e.currentTarget;
item.classList.add('dragging');
const path = item.dataset.path;
let path, name;
if (type === 'file') {
path = item.dataset.path;
name = path.split('/').pop();
} else if (type === 'folder') {
const folderItem = item.closest('.folder-item');
path = folderItem.dataset.path;
name = folderItem.querySelector('.folder-name').textContent.trim();
}
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', path);
e.dataTransfer.setData('application/note-path', path);
e.dataTransfer.setData('application/note-type', type);
e.dataTransfer.setData('application/note-name', name);
// Stocker le chemin source pour validation
this.draggedPath = path;
this.draggedType = type;
console.log('Drag start:', { type, path, name });
}
handleDragEnd(e) {
const item = e.target;
const item = e.currentTarget;
item.classList.remove('dragging');
// Supprimer les highlights de tous les dossiers
document.querySelectorAll('.folder-item.drag-over').forEach(f => {
f.classList.remove('drag-over');
});
// Supprimer l'indicateur de destination
const indicator = document.getElementById('drag-destination-indicator');
if (indicator) {
indicator.remove();
}
this.draggedPath = null;
this.draggedType = null;
}
handleDragOver(e) {
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'move';
const folderHeader = e.currentTarget;
const folderItem = folderHeader.closest('.folder-item');
const targetPath = folderItem.dataset.path;
// Empêcher de déplacer un dossier dans lui-même ou dans ses enfants
if (this.draggedType === 'folder' && this.draggedPath) {
if (targetPath === this.draggedPath || targetPath.startsWith(this.draggedPath + '/')) {
e.dataTransfer.dropEffect = 'none';
folderItem.classList.remove('drag-over');
this.removeDestinationIndicator();
return;
}
}
e.dataTransfer.dropEffect = 'move';
if (folderItem && !folderItem.classList.contains('drag-over')) {
// Retirer la classe des autres dossiers
document.querySelectorAll('.folder-item.drag-over').forEach(f => {
if (f !== folderItem) {
f.classList.remove('drag-over');
}
});
folderItem.classList.add('drag-over');
// Afficher l'indicateur de destination
this.showDestinationIndicator(folderItem, targetPath);
}
}
handleDragLeave(e) {
e.stopPropagation();
const folderHeader = e.currentTarget;
const folderItem = folderHeader.closest('.folder-item');
@ -131,10 +188,39 @@ class FileTree {
e.clientY < rect.top || e.clientY >= rect.bottom) {
if (folderItem) {
folderItem.classList.remove('drag-over');
this.removeDestinationIndicator();
}
}
}
showDestinationIndicator(folderItem, targetPath) {
let indicator = document.getElementById('drag-destination-indicator');
if (!indicator) {
indicator = document.createElement('div');
indicator.id = 'drag-destination-indicator';
indicator.className = 'drag-destination-indicator';
document.body.appendChild(indicator);
}
const folderName = folderItem.querySelector('.folder-name').textContent.trim();
const isRoot = folderItem.dataset.isRoot === 'true';
const displayPath = isRoot ? 'notes/' : targetPath;
indicator.innerHTML = `
<span class="indicator-icon">📥</span>
<span class="indicator-text">Déplacer vers: <strong>${folderName}</strong></span>
<span class="indicator-path">${displayPath}</span>
`;
indicator.style.display = 'flex';
}
removeDestinationIndicator() {
const indicator = document.getElementById('drag-destination-indicator');
if (indicator) {
indicator.style.display = 'none';
}
}
handleDrop(e) {
e.preventDefault();
e.stopPropagation();
@ -143,40 +229,57 @@ class FileTree {
const folderItem = folderHeader.closest('.folder-item');
folderItem.classList.remove('drag-over');
// Supprimer l'indicateur de destination
this.removeDestinationIndicator();
const sourcePath = e.dataTransfer.getData('application/note-path') ||
e.dataTransfer.getData('text/plain');
const sourceType = e.dataTransfer.getData('application/note-type');
const targetFolderPath = folderItem.dataset.path;
console.log('Drop event:', {
sourcePath,
sourceType,
targetFolderPath,
dataTransfer: e.dataTransfer.types,
folderItem: folderItem
dataTransfer: e.dataTransfer.types
});
if (!sourcePath || !targetFolderPath) {
// Validation : sourcePath doit exister, targetFolderPath peut être vide (racine)
if (!sourcePath || targetFolderPath === undefined || targetFolderPath === null) {
console.error('Chemins invalides pour le drag & drop', {
sourcePath,
targetFolderPath,
folderItemDataset: folderItem.dataset
targetFolderPath
});
alert(`Erreur: source='${sourcePath}', destination='${targetFolderPath}'`);
return;
}
// Ne pas déplacer si c'est le même dossier
// Empêcher de déplacer un dossier dans lui-même ou dans ses enfants
if (sourceType === 'folder') {
if (targetFolderPath === sourcePath || targetFolderPath.startsWith(sourcePath + '/')) {
alert('Impossible de déplacer un dossier dans lui-même ou dans un de ses sous-dossiers');
return;
}
}
// Ne pas déplacer si c'est déjà dans le même dossier parent
const sourceDir = sourcePath.includes('/') ?
sourcePath.substring(0, sourcePath.lastIndexOf('/')) : '';
if (sourceDir === targetFolderPath) {
console.log('Déjà dans le même dossier parent, rien à faire');
return;
}
// Extraire le nom du fichier
const fileName = sourcePath.includes('/') ?
// Extraire le nom du fichier/dossier
const itemName = sourcePath.includes('/') ?
sourcePath.substring(sourcePath.lastIndexOf('/') + 1) :
sourcePath;
const destinationPath = targetFolderPath + '/' + fileName;
// Construire le chemin de destination
// Si targetFolderPath est vide (racine), ne pas ajouter de slash
const destinationPath = targetFolderPath === '' ? itemName : targetFolderPath + '/' + itemName;
console.log(`Déplacement: ${sourcePath}${destinationPath}`);
this.moveFile(sourcePath, destinationPath);
}