/** * app_utils.js — Общие утилиты (форматирование, стрелки, модалки). * Вынесены из app.js для облегчения анализа и отладки. * Загружается ДО app.js. */ /** * Форматирует размер файла в человекочитаемый вид. * Используется в модальном окне документа. */ function formatSize(bytes) { if (!bytes || bytes === 0) return '—'; if (bytes < 1024) return bytes + ' B'; if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1048576).toFixed(1) + ' MB'; } /** * Форматирует timestamp в российскую дату + время. * Используется в модальном окне документа. */ function formatDate(ts) { if (!ts) return '—'; var d = new Date(ts); return d.toLocaleDateString('ru-RU') + ' ' + d.toLocaleTimeString('ru-RU', {hour:'2-digit',minute:'2-digit'}); } /** * Удаляет файл из очереди по индексу. * Вызывается по кнопке ✕ в таблице файлов. * * Фаза 0 (state + render): мутирует state.files, затем render(state). * Если очередь опустела — сбрасывает state.contractId. */ function removeFile(i) { var file = state.files[i]; if (file && filePicker) filePicker.remove(file.pickerId); } window.removeFile = removeFile; /** * Переместить файл на одну позицию ВВЕРХ (сохранено для возможного возврата ручной сортировки). * В текущей версии (v1.0.164+) не используется — порядок определяет авто-классификация. * * Фаза 0 (state + render): мутирует state.files, затем render(state). */ function moveUp(i) { if (i <= 0) return; var tmp = state.files[i]; state.files[i] = state.files[i-1]; state.files[i-1] = tmp; render(state); } /** * Переместить файл на одну позицию ВНИЗ (сохранено для возможного возврата ручной сортировки). * В текущей версии (v1.0.164+) не используется — порядок определяет авто-классификация. * * Фаза 0 (state + render): мутирует state.files, затем render(state). */ function moveDown(i) { if (i >= state.files.length - 1) return; var tmp = state.files[i]; state.files[i] = state.files[i+1]; state.files[i+1] = tmp; render(state); } window.moveUp = moveUp; window.moveDown = moveDown; /** * Открыть модальное окно справки. */ function openAbout() { document.getElementById('aboutModalOverlay').classList.add('open'); } /** * Закрыть модальное окно справки по клику на оверлей или кнопку. */ function closeAbout(e) { if (e && e.target !== document.getElementById('aboutModalOverlay')) return; document.getElementById('aboutModalOverlay').classList.remove('open'); } window.openAbout = openAbout; window.closeAbout = closeAbout; /** * Экранировать HTML (для безопасного рендеринга пользовательских данных). * Используется в истории промптов. */ function escHtml(s) { if (s == null) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; } /** * Форматировать дату для истории промптов (YYYY-MM-DD HH:MM). */ function fmtDate(d) { if (!d) return ''; return d.replace('T', ' ').substring(0, 16); }