Add drag'n'drop for inner files
This commit is contained in:
parent
205040a599
commit
768d93700e
|
|
@ -1445,56 +1445,142 @@ export class ChatPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Обрабатывает событие сброса внешних файлов (Drag-and-Drop) из ОС
|
* Обрабатывает событие сброса внешних файлов (Drag-and-Drop) из ОС
|
||||||
|
* и внутренних файлов из файлового менеджера Obsidian
|
||||||
*/
|
*/
|
||||||
private async handleDrop(e: DragEvent): Promise<void> {
|
private async handleDrop(e: DragEvent): Promise<void> {
|
||||||
if (!e.dataTransfer?.files || e.dataTransfer.files.length === 0) {
|
if (!e.dataTransfer) {
|
||||||
return; // Оброшен не файл (например, просто выделенный текст)
|
return; // Игнорируем пустые события
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCtrlPressed = e.ctrlKey || e.metaKey;
|
const isCtrlPressed = e.ctrlKey || e.metaKey;
|
||||||
const shouldBePermanent = !isCtrlPressed;
|
const shouldBePermanent = !isCtrlPressed;
|
||||||
|
|
||||||
const files = Array.from(e.dataTransfer.files);
|
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
|
|
||||||
for (const file of files) {
|
// 1. Проверяем перетаскивание внешних файлов из файловой системы ОС
|
||||||
let absolutePath = '';
|
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
||||||
|
const files = Array.from(e.dataTransfer.files);
|
||||||
|
for (const file of files) {
|
||||||
|
let absolutePath = '';
|
||||||
|
|
||||||
// 1. Попытка через скрытое свойство 'path' (иногда оно есть, но не перечисляемо)
|
// 1. Попытка через скрытое свойство 'path' (иногда оно есть, но не перечисляемо)
|
||||||
absolutePath = (file as any).path;
|
absolutePath = (file as any).path;
|
||||||
|
|
||||||
// 2. Попытка через Electron (если доступен window.require)
|
// 2. Попытка через Electron (если доступен window.require)
|
||||||
if (!absolutePath && window.require) {
|
if (!absolutePath && window.require) {
|
||||||
try {
|
try {
|
||||||
const electron = window.require('electron');
|
const electron = window.require('electron');
|
||||||
// В некоторых версиях путь можно достать через webUtils из модуля
|
// В некоторых версиях путь можно достать через webUtils из модуля
|
||||||
if (electron.webUtils) {
|
if (electron.webUtils) {
|
||||||
absolutePath = electron.webUtils.getPathForFile(file);
|
absolutePath = electron.webUtils.getPathForFile(file);
|
||||||
}
|
}
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Кэшируем файл (копируем в папку плагина) и получаем метаинформацию
|
// Кэшируем файл (копируем в папку плагина) и получаем метаинформацию
|
||||||
const cacheResult = await this.cacheManager.cacheExternalFile(absolutePath);
|
const cacheResult = await this.cacheManager.cacheExternalFile(absolutePath);
|
||||||
|
|
||||||
// Формируем Attachment объект
|
// Формируем Attachment объект
|
||||||
const newAttachment: Attachment = {
|
const newAttachment: Attachment = {
|
||||||
type: 'external',
|
type: 'external',
|
||||||
name: cacheResult.name,
|
name: cacheResult.name,
|
||||||
sourcePath: absolutePath,
|
sourcePath: absolutePath,
|
||||||
cachedPath: cacheResult.cachedPath,
|
cachedPath: cacheResult.cachedPath,
|
||||||
uuid: cacheResult.uuid,
|
uuid: cacheResult.uuid,
|
||||||
permanent: shouldBePermanent, // D&D файлы прикрепляем разово (как $файл, а не !$)
|
permanent: shouldBePermanent,
|
||||||
mimeType: cacheResult.mimeType
|
mimeType: cacheResult.mimeType
|
||||||
};
|
};
|
||||||
|
|
||||||
this.currentAttachments.push(newAttachment);
|
this.currentAttachments.push(newAttachment);
|
||||||
addedCount++;
|
addedCount++;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Ошибка обработки D&D файла ${file.name}:`, error);
|
console.error(`Ошибка обработки D&D файла ${file.name}:`, error);
|
||||||
new Notice(`Не удалось прикрепить ${file.name}. ${error.message || error}`);
|
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}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1504,7 +1590,7 @@ export class ChatPanel {
|
||||||
new Notice(`Прикреплено файлов: ${addedCount}`, 2000);
|
new Notice(`Прикреплено файлов: ${addedCount}`, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------- Scroll Observers ---------------------------------------------------------------
|
// ----------------------------------------------- Scroll Observers ---------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user