New shared/zip-source.js: a ZipDirectoryHandle / ZipFileHandle pair that exposes a JSZip instance behind the File-System-Access surface (values/entries/keys, getDirectoryHandle/getFileHandle, getFile) — read-only, with a zip-slip guard. Mirrors shared/zddc-source.js's HTTP polyfill. Wired into archive's and browse's build.sh (both already bundle JSZip). archive: a .zip whose name minus ".zip" parses as a transmittal-folder name is now scanned as that transmittal folder. Offline, the zip is opened in the browser (ZipDirectoryHandle) and its members enumerated exactly like an uncompressed folder's files — table/export/hash paths are unchanged (they go through file.handle.getFile()). Online, the scanner recurses into the server's "<…>.zip/" virtual-directory listing, so members come back as "<…>.zip/<member>" URLs the server extracts on demand — no whole-zip download. browse: the offline (file://) zip path is migrated onto the shared adapter — expanding a .zip now opens it as a ZipDirectoryHandle and its members become ordinary dir/file nodes handled by the normal fetchFsChildren path (nested zips fall out by recursion). The bespoke flat-entry walker (loadZipChildren / setZipDirChildren / zipEntries / zipParentId / zipPath / _zipSyntheticDir) is gone — one zip implementation repo-wide. Markdown members inside a zip are flagged read-only (the ZipFileHandle refuses createWritable; server "<…>.zip/" URLs 405 on PUT). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
3.1 KiB
JavaScript
75 lines
3.1 KiB
JavaScript
// Archive grouping/sorting helpers — ZDDC parsing comes from window.zddc directly.
|
|
(function() {
|
|
'use strict';
|
|
|
|
function isTransmittalFolder(name) {
|
|
var parsed = zddc.parseFolder(name);
|
|
return !!(parsed && parsed.valid);
|
|
}
|
|
|
|
// A .zip whose name (minus the .zip extension) parses as a
|
|
// transmittal-folder name is treated as that transmittal folder —
|
|
// its members are scanned the same as an uncompressed folder's
|
|
// files. (A plain `archive.zip` etc. is just a file.)
|
|
function isTransmittalFolderZip(name) {
|
|
var parts = zddc.splitExtension(name);
|
|
return parts.extension === 'zip' && isTransmittalFolder(parts.name);
|
|
}
|
|
|
|
function groupFilesByTrackingNumber(files) {
|
|
const groups = {};
|
|
files.forEach(file => {
|
|
if (!file.trackingNumber) return;
|
|
if (!groups[file.trackingNumber]) {
|
|
groups[file.trackingNumber] = { trackingNumber: file.trackingNumber, title: file.title, revisions: {} };
|
|
}
|
|
if (file.title.length > groups[file.trackingNumber].title.length) {
|
|
groups[file.trackingNumber].title = file.title;
|
|
}
|
|
const revKey = `${file.revision}_${file.status}`;
|
|
if (!groups[file.trackingNumber].revisions[revKey]) {
|
|
groups[file.trackingNumber].revisions[revKey] = {
|
|
revision: file.revision, status: file.status, title: file.title,
|
|
hasModifier: file.revision.includes('+'), files: []
|
|
};
|
|
}
|
|
if (file.title.length > groups[file.trackingNumber].revisions[revKey].title.length) {
|
|
groups[file.trackingNumber].revisions[revKey].title = file.title;
|
|
}
|
|
groups[file.trackingNumber].revisions[revKey].files.push(file);
|
|
});
|
|
return groups;
|
|
}
|
|
|
|
function sortGroupedFiles(groups) {
|
|
const field = window.app.sortField || 'trackingNumber';
|
|
const direction = window.app.sortDirection === 'desc' ? -1 : 1;
|
|
const sorted = Object.values(groups).sort((a, b) => {
|
|
let comparison = 0;
|
|
if (field === 'trackingNumber') comparison = a.trackingNumber.localeCompare(b.trackingNumber);
|
|
else if (field === 'title') comparison = a.title.localeCompare(b.title);
|
|
else if (field === 'revisions') {
|
|
const aRevs = Object.keys(a.revisions), bRevs = Object.keys(b.revisions);
|
|
comparison = zddc.compareRevisions(
|
|
aRevs.length > 0 ? aRevs[aRevs.length - 1] : '',
|
|
bRevs.length > 0 ? bRevs[bRevs.length - 1] : ''
|
|
);
|
|
}
|
|
return comparison * direction;
|
|
});
|
|
sorted.forEach(group => {
|
|
const revisions = Object.values(group.revisions);
|
|
revisions.sort((a, b) => zddc.compareRevisions(b.revision, a.revision));
|
|
group.sortedRevisions = revisions;
|
|
});
|
|
return sorted;
|
|
}
|
|
|
|
window.app.modules.parser = {
|
|
isTransmittalFolder,
|
|
isTransmittalFolderZip,
|
|
groupFilesByTrackingNumber,
|
|
sortGroupedFiles,
|
|
};
|
|
|
|
})();
|