Add hierarchical file picker
This commit is contained in:
@@ -2,35 +2,58 @@ import { listZipFiles } from '../zip/list_zip_files.js';
|
||||
import { addFileWithDedup } from './add_file_with_dedup.js';
|
||||
import { render } from './render.js';
|
||||
|
||||
function rebaseTree(root, prefix) {
|
||||
root.path = `${prefix}/${root.path}`;
|
||||
if (root.file) root.file = new File([root.file], root.path, { lastModified: root.file.lastModified });
|
||||
root.children.forEach((child) => rebaseTree(child, prefix));
|
||||
return root;
|
||||
}
|
||||
|
||||
export function onFolderChange(state, cfg, elements) {
|
||||
return async () => {
|
||||
if (state.busy) return;
|
||||
const roots = new Map();
|
||||
for (const file of Array.from(elements.folderInputEl.files)) {
|
||||
const parts = (file.webkitRelativePath || file.name).split('/');
|
||||
const relativePath = parts.slice(1).join('/') || file.name;
|
||||
const lowerPath = relativePath.toLowerCase();
|
||||
const directory = relativePath.includes('/')
|
||||
? relativePath.slice(0, relativePath.lastIndexOf('/')) : '';
|
||||
const rootName = parts[0] || file.name;
|
||||
if (!roots.has(rootName)) {
|
||||
roots.set(rootName, { id: crypto.randomUUID(), kind: 'folder', name: rootName,
|
||||
path: rootName, children: [], expanded: true });
|
||||
}
|
||||
const root = roots.get(rootName);
|
||||
const addToFolder = (node) => {
|
||||
let current = root;
|
||||
const nodeParts = node.path.split('/').slice(1);
|
||||
nodeParts.forEach((part, index) => {
|
||||
const last = index === nodeParts.length - 1;
|
||||
let child = current.children.find((item) => item.name === part);
|
||||
if (!child) {
|
||||
child = last ? node : { id: crypto.randomUUID(), kind: 'folder', name: part,
|
||||
path: `${rootName}/${nodeParts.slice(0, index + 1).join('/')}`,
|
||||
children: [], expanded: true };
|
||||
current.children.push(child);
|
||||
}
|
||||
current = child;
|
||||
});
|
||||
};
|
||||
if (lowerPath.endsWith('.zip')) {
|
||||
try {
|
||||
const extracted = await listZipFiles(file, cfg.allowedExt);
|
||||
if (extracted.length) {
|
||||
extracted.forEach((item) => addFileWithDedup(state, new File([item],
|
||||
directory ? `${directory}/${item.name}` : item.name,
|
||||
{ lastModified: item.lastModified }), cfg));
|
||||
} else {
|
||||
addFileWithDedup(state, new File([file], relativePath,
|
||||
{ lastModified: file.lastModified }), cfg);
|
||||
}
|
||||
const zip = await listZipFiles(file, cfg.allowedExt);
|
||||
rebaseTree(zip, rootName);
|
||||
addToFolder(zip);
|
||||
} catch (error) {
|
||||
addFileWithDedup(state, new File([file], relativePath,
|
||||
{ lastModified: file.lastModified }), cfg);
|
||||
addToFolder({ id: crypto.randomUUID(), kind: 'zip', name: parts.at(-1),
|
||||
path: relativePath, file, children: [], expanded: true,
|
||||
error: 'Не удалось раскрыть ZIP' });
|
||||
}
|
||||
} else if (cfg.allowedExt.some((extension) => lowerPath.endsWith(extension))) {
|
||||
addFileWithDedup(state, new File([file], relativePath,
|
||||
{ lastModified: file.lastModified }), cfg);
|
||||
addToFolder({ id: crypto.randomUUID(), kind: 'file', name: parts.at(-1),
|
||||
path: `${rootName}/${relativePath}`, file, children: [], expanded: true });
|
||||
}
|
||||
}
|
||||
roots.forEach((root) => addFileWithDedup(state, root));
|
||||
elements.folderInputEl.value = '';
|
||||
render(state, elements);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user