Add drag'n'drop for inner files

This commit is contained in:
dimitrievgs 2026-05-28 00:32:22 +03:00
parent 205040a599
commit 768d93700e

View File

@ -1446,18 +1446,21 @@ export class ChatPanel {
/**
* Обрабатывает событие сброса внешних файлов (Drag-and-Drop) из ОС
* и внутренних файлов из файлового менеджера Obsidian
*/
private async handleDrop(e: DragEvent): Promise<void> {
if (!e.dataTransfer?.files || e.dataTransfer.files.length === 0) {
return; // Оброшен не файл (например, просто выделенный текст)
if (!e.dataTransfer) {
return; // Игнорируем пустые события
}
const isCtrlPressed = e.ctrlKey || e.metaKey;
const shouldBePermanent = !isCtrlPressed;
const files = Array.from(e.dataTransfer.files);
let addedCount = 0;
// 1. Проверяем перетаскивание внешних файлов из файловой системы ОС
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
const files = Array.from(e.dataTransfer.files);
for (const file of files) {
let absolutePath = '';
@ -1486,7 +1489,7 @@ export class ChatPanel {
sourcePath: absolutePath,
cachedPath: cacheResult.cachedPath,
uuid: cacheResult.uuid,
permanent: shouldBePermanent, // D&D файлы прикрепляем разово (как $файл, а не !$)
permanent: shouldBePermanent,
mimeType: cacheResult.mimeType
};
@ -1497,6 +1500,89 @@ export class ChatPanel {
new Notice(`Не удалось прикрепить ${file.name}. ${error.message || error}`);
}
}
}
// TODO: эту ветку не разбирал, некогда было
// 2. Проверяем перетаскивание внутренних файлов Obsidian
else {
const textData = e.dataTransfer.getData('text/plain');
if (textData) {
const pathsToProcess: string[] = [];
// А) Извлекаем пути, если перетянута системная ссылка Obsidian (из Проводника файлов)
const lines = textData.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith('obsidian://open')) {
try {
const url = new URL(trimmed);
const filePath = url.searchParams.get('file'); // Попутно автоматически декодирует %D0...
if (filePath) {
pathsToProcess.push(filePath);
}
} catch (error) {
console.warn("Не удалось распарсить ссылку Obsidian:", trimmed);
}
}
}
// Б) Оставляем поддержку, если перетащили текст, содержащий [[вики-ссылки]]
const linkRegex = /\[\[(.*?)\]\]/g;
let match;
while ((match = linkRegex.exec(textData)) !== null) {
let linkText = match[1];
if (linkText.includes('|')) linkText = linkText.split('|')[0];
pathsToProcess.push(linkText);
}
// Убираем дубликаты
const uniquePaths = [...new Set(pathsToProcess)];
for (const targetPath of uniquePaths) {
// Ищем файл. Если это был obsidian:// URL, у нас сразу есть точный путь
let file = this.props.plugin.app.vault.getAbstractFileByPath(targetPath);
// Если точный путь не найден (например, это просто имя из вики-ссылки), ищем по кэшу
if (!file) {
file = this.props.plugin.app.metadataCache.getFirstLinkpathDest(targetPath, '');
}
if (file instanceof TFile) {
try {
// Отправляем найденный в Vault файл на кеширование
const cacheResult = await this.cacheManager.cacheVaultFile(file);
const promptsFolder = this.props.plugin.settings.promptsFolder;
const normalizedPromptsPath = promptsFolder ? promptsFolder.replace(/^\/+|\/+$/g, '') : null;
const isPrompt = normalizedPromptsPath && (file.path.startsWith(normalizedPromptsPath + '/') || file.path === normalizedPromptsPath);
const ext = file.extension.toLowerCase();
let mimeType = 'application/octet-stream';
if (['md', 'txt', 'csv'].includes(ext)) mimeType = ext === 'md' ? 'text/markdown' : 'text/plain';
else if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext)) mimeType = `image/${ext === 'svg' ? 'svg+xml' : ext === 'jpg' ? 'jpeg' : ext}`;
else if (ext === 'pdf') mimeType = 'application/pdf';
else if (ext === 'json') mimeType = 'application/json';
// Формируем Attachment объект
const newAttachment: Attachment = {
type: isPrompt ? 'prompt' : 'file',
name: file.name,
sourcePath: file.path,
cachedPath: cacheResult.cachedPath,
uuid: cacheResult.uuid,
permanent: shouldBePermanent,
mimeType: mimeType
};
this.currentAttachments.push(newAttachment);
addedCount++;
} catch (error: any) {
console.error(`Ошибка обработки внутреннего D&D файла ${file.name}:`, error);
new Notice(`Не удалось прикрепить ${file.name}.`);
}
}
}
}
}
if (addedCount > 0) {
// Перерисовываем UI "Скрепки" над полем ввода