ZDDC — Zero Day Document Control. A file-naming convention plus five single-file HTML tools (archive, transmittal, classifier, mdedit, landing) and an optional Go HTTP server (zddc-server) with ACL and a virtual archive index. Self-contained, offline-capable, dependency-free. See README.md for an overview, AGENTS.md and ARCHITECTURE.md for the build/release/architecture detail, bootstrap/README.md for the two-level deployment install pattern, and zddc/README.md for the HTTP server.
188 lines
6.7 KiB
JavaScript
188 lines
6.7 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
// Directory selection and scanning functionality
|
|
|
|
// Add directory
|
|
async function addDirectory() {
|
|
try {
|
|
const dirHandle = await window.showDirectoryPicker();
|
|
|
|
// Check if already added
|
|
const exists = window.app.directories.some(d => d.name === dirHandle.name);
|
|
if (exists) {
|
|
alert('This directory has already been added.');
|
|
return;
|
|
}
|
|
|
|
// Add to directories
|
|
window.app.directories.push({
|
|
handle: dirHandle,
|
|
name: dirHandle.name,
|
|
path: dirHandle.name // Root path
|
|
});
|
|
|
|
// Hide empty state if this is the first directory
|
|
if (window.app.directories.length === 1) {
|
|
window.app.modules.app.hideEmptyState();
|
|
}
|
|
|
|
// Scan the new directory
|
|
await scanDirectory(dirHandle, dirHandle.name);
|
|
|
|
window.app.modules.app.updateUI();
|
|
} catch (err) {
|
|
if (err.name !== 'AbortError') {
|
|
console.error('Error selecting directory:', err);
|
|
alert('Error selecting directory: ' + err.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Scan directory recursively (local mode — delegates to local source in source.js)
|
|
async function scanDirectory(dirHandle, path) {
|
|
window.app.isScanning = true;
|
|
window.app.scanProgress = 'Scanning ' + path + '...';
|
|
window.app.modules.app.updateStatusBar();
|
|
|
|
const source = window.app.modules.source.createSource('local', {});
|
|
|
|
const callbacks = {
|
|
onGroupingFolder: function(folder) {
|
|
window.app.groupingFolders.push(folder);
|
|
},
|
|
onTransmittalFolder: function(folder) {
|
|
window.app.transmittalFolders.push(folder);
|
|
},
|
|
onFile: function(file) {
|
|
window.app.files.push(file);
|
|
},
|
|
onProgress: function(message) {
|
|
window.app.scanProgress = message;
|
|
window.app.modules.app.updateStatusBar();
|
|
}
|
|
};
|
|
|
|
try {
|
|
await source.scan(dirHandle, callbacks);
|
|
|
|
// Only auto-select top-level party folders (shallowest depth)
|
|
const groupingDepths = window.app.groupingFolders.map(f => f.path.split('/').length);
|
|
const minGroupingDepth = groupingDepths.length > 0 ? Math.min(...groupingDepths) : 1;
|
|
window.app.groupingFolders.forEach(folder => {
|
|
if (folder.path.split('/').length === minGroupingDepth) {
|
|
window.app.selectedGroupingFolders.add(folder.path);
|
|
}
|
|
});
|
|
|
|
window.app.transmittalFolders.forEach(folder => {
|
|
if (!window.app.modules.app.isUnderHiddenFolderType(folder.path)) {
|
|
window.app.selectedTransmittalFolders.add(folder.path);
|
|
}
|
|
});
|
|
|
|
window.app.modules.app.ensureOutstandingTransmittal();
|
|
// Auto-select Outstanding if selectAllTransmittals is active
|
|
if (window.app.selectAllTransmittals) {
|
|
window.app.selectedTransmittalFolders.add('__outstanding__');
|
|
}
|
|
|
|
window.app.modules.app.collectModifiers();
|
|
window.app.modules.app.updateUI();
|
|
window.app.modules.filtering.applyFilters();
|
|
if (window.app.modules.presets) {
|
|
window.app.modules.presets.init();
|
|
}
|
|
} catch (err) {
|
|
console.error('Error scanning directory:', err);
|
|
alert('Error scanning directory: ' + err.message);
|
|
} finally {
|
|
window.app.isScanning = false;
|
|
window.app.scanProgress = '';
|
|
window.app.modules.app.updateStatusBar();
|
|
}
|
|
}
|
|
|
|
// Refresh all directories
|
|
async function refreshDirectories() {
|
|
// Clear existing data
|
|
window.app.groupingFolders = [];
|
|
window.app.transmittalFolders = [];
|
|
window.app.files = [];
|
|
window.app.filteredFiles = [];
|
|
|
|
if (window.app.sourceMode === 'http') {
|
|
// Re-scan all HTTP sources
|
|
const dirs = window.app.directories.slice();
|
|
window.app.directories = [];
|
|
for (const dir of dirs) {
|
|
await window.app.modules.app.addHttpSource(dir.url);
|
|
}
|
|
} else {
|
|
// Re-scan all local directories
|
|
for (const dir of window.app.directories) {
|
|
await scanDirectory(dir.handle, dir.name);
|
|
}
|
|
}
|
|
|
|
window.app.modules.app.updateUI();
|
|
}
|
|
|
|
// Remove directory
|
|
function removeDirectory(dirName) {
|
|
const index = window.app.directories.findIndex(d => d.name === dirName);
|
|
if (index !== -1) {
|
|
window.app.directories.splice(index, 1);
|
|
|
|
// Remove associated folders and files
|
|
window.app.groupingFolders = window.app.groupingFolders.filter(f =>
|
|
!f.path.startsWith(dirName)
|
|
);
|
|
window.app.transmittalFolders = window.app.transmittalFolders.filter(f =>
|
|
!f.path.startsWith(dirName)
|
|
);
|
|
window.app.files = window.app.files.filter(f =>
|
|
!f.path.startsWith(dirName)
|
|
);
|
|
|
|
// Clean up the Outstanding virtual transmittal if no outstanding files remain
|
|
const hasAnyOutstanding = window.app.files.some(f => f.folderPath === '__outstanding__');
|
|
if (!hasAnyOutstanding) {
|
|
window.app.transmittalFolders = window.app.transmittalFolders.filter(f => f.path !== '__outstanding__');
|
|
window.app.selectedTransmittalFolders.delete('__outstanding__');
|
|
}
|
|
|
|
// Show empty state if no directories left
|
|
if (window.app.directories.length === 0) {
|
|
window.app.modules.app.showEmptyState();
|
|
}
|
|
|
|
window.app.modules.app.updateUI();
|
|
}
|
|
}
|
|
|
|
// Request permission for directory
|
|
async function requestPermission(dirHandle) {
|
|
const options = { mode: 'read' };
|
|
|
|
// Check current permission state
|
|
if ((await dirHandle.queryPermission(options)) === 'granted') {
|
|
return true;
|
|
}
|
|
|
|
// Request permission
|
|
if ((await dirHandle.requestPermission(options)) === 'granted') {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
window.app.modules.directory = {
|
|
addDirectory,
|
|
scanDirectory,
|
|
refreshDirectories,
|
|
removeDirectory,
|
|
requestPermission
|
|
};
|
|
|
|
})();
|