- копирую модуль upload/ из drhider (слои 1-2) - blueprint: параметр sink (drhider-сессия по умолчанию, сверка — DB+парсинг) - upload_bp: contracts_upload_sink = _store_and_parse - routes: регистрирую create_upload_refs_blueprint(cfg, sink=...) - app.py: корень репо в sys.path (для import upload) - History: план переиспользования + ревью Соннета
57 lines
2.6 KiB
JavaScript
57 lines
2.6 KiB
JavaScript
// initUploadTable — сборка слоя 1 (выбор файлов/папки/архива).
|
|
// Состояние (files/fileMeta/overNames) живёт внутри модуля.
|
|
|
|
import { addFiles as addFilesToState, makeFilesChangeHandler } from './on_files_change.js';
|
|
import { makeFolderChangeHandler } from './on_folder_change.js';
|
|
import { render } from './render.js';
|
|
import { setStatus } from './set_status.js';
|
|
import { rmFile } from './rm_file.js';
|
|
|
|
// cfg: {allowedExt, maxFileBytes, maxSessionBytes, estMbSec}
|
|
// els: {fileInput, folderInput, tableBody, countEl, uploadBtnEl, onStatus(cls, text)}
|
|
// returns api (см. README.md)
|
|
export function initUploadTable(cfg, els) {
|
|
const state = {
|
|
files: [], // File[]
|
|
fileMeta: new Map(), // имя -> {size, mtime} для дедупа/суффиксов
|
|
overNames: new Set(), // имена файлов сверх лимита (не участвуют)
|
|
busy: false, // идёт загрузка/обработка — список заблокирован
|
|
proc: null, // {phase, procState, procExtractRate} — задаёт слой 3
|
|
};
|
|
|
|
const onFilesChange = makeFilesChangeHandler({ state, cfg, els, onStatus: els.onStatus });
|
|
const onFolderChange = makeFolderChangeHandler({ state, cfg, els, onStatus: els.onStatus });
|
|
|
|
els.fileInput.addEventListener('change', onFilesChange);
|
|
els.folderInput.addEventListener('change', onFolderChange);
|
|
// Делегирование кликов по кнопкам «✕» (удалить строку)
|
|
els.tableBody.addEventListener('click', e => {
|
|
const btn = e.target.closest('.remove-btn');
|
|
if (btn) rmFile(state, els, cfg, Number(btn.dataset.idx));
|
|
});
|
|
|
|
return {
|
|
state, // доступ для слоя 3 (установить state.proc для render)
|
|
addFiles(files) { return addFilesToState(state, cfg, files, els, els.onStatus); },
|
|
getFiles() { // ТОЛЬКО учитываемые (без over): [{name, size, file}]
|
|
return state.files.filter(f => !state.overNames.has(f.name))
|
|
.map(f => ({ name: f.name, size: f.size, file: f }));
|
|
},
|
|
getOverNames() { return state.overNames; },
|
|
setStatus(idx, html) { setStatus(idx, html); },
|
|
render() { render(state, els, cfg); },
|
|
clear() {
|
|
state.files = [];
|
|
state.fileMeta = new Map();
|
|
state.overNames = new Set();
|
|
if (els.fileInput) els.fileInput.value = '';
|
|
render(state, els, cfg);
|
|
},
|
|
setBusy(b) {
|
|
state.busy = b;
|
|
if (els.fileInput) els.fileInput.disabled = b;
|
|
},
|
|
_rm(i) { rmFile(state, els, cfg, i); },
|
|
};
|
|
}
|