New search function et drag and drop clean
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user