From 2b727e1755f414d2834fc9d44deda6e24b0a30b7 Mon Sep 17 00:00:00 2001 From: Gaspard Jankowiak Date: Fri, 5 Jun 2026 14:38:44 +0200 Subject: [PATCH] add comments --- content.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index c01faa2..6b1aa9c 100644 --- a/content.js +++ b/content.js @@ -19,6 +19,7 @@ async function getXSRFToken() { return decodeURIComponent(tokenCookie.split("=").slice(1).join("=")) } +// Fetch the applicant record first so we know which file_ids belong to it. async function fetchApplicantDetails(applicant, token) { return fetch(`https://personal.uni-graz.at/api/erec/job-applications/${applicant.id}`, { @@ -33,6 +34,7 @@ async function fetchApplicantDetails(applicant, token) { }) } +// Download a single applicant's files in parallel and report aggregate progress to the dialog. async function downloadApplicantFilesWithProgress(applicantDetails, token, onProgress = () => { }) { const files = applicantDetails.application_files ?? [] let completedDownloads = 0 @@ -67,6 +69,7 @@ async function getApplicant(applicant, token, onProgress = () => { }) { return downloadApplicantFilesWithProgress(applicantDetails, token, onProgress) } +// Small worker pool used to limit how many applicant pipelines run at once. async function runWithConcurrencyLimit(items, limit, worker) { const results = new Array(items.length) let nextIndex = 0 @@ -192,6 +195,7 @@ function getApplicantArchiveFileName(afile) { return `${baseName}` } +// Keep the CSV viewer metadata aligned with the actual archive paths written into the ZIP. function getApplicantArchiveFiles(applicantDetails) { const dirName = getApplicantDirectoryName(applicantDetails) const files = applicantDetails.application_files ?? [] @@ -252,6 +256,7 @@ function createApplicantsCsv(applicantDetailsList) { return rows.join("\n") } +// Copy the standalone viewer HTML into the generated archive. async function getArchiveViewerHtmlSource() { const response = await fetch(chrome.runtime.getURL("archive-viewer/index.html")) @@ -262,6 +267,7 @@ async function getArchiveViewerHtmlSource() { return response.text() } +// Bundle the viewer's JSZip runtime so the exported archive can be browsed offline. async function getArchiveViewerJsZipSource() { const candidates = [ "lib/jszip.min.js" @@ -315,6 +321,7 @@ function formatMegabytes(totalBytes) { return `${(totalBytes / (1024 * 1024)).toFixed(1)} MB` } +// Modal progress UI shown while applicants, files, and the final archive are prepared. function createProgressDialog() { const dialog = document.createElement("dialog") const title = document.createElement("h4") @@ -434,6 +441,7 @@ function createProgressDialog() { } } +// Main export flow: fetch applicant data, download files, then assemble the ZIP. function rip(event) { const btn = event.target; const progressDialog = createProgressDialog() @@ -514,7 +522,7 @@ function rip(event) { }) } -// injection of rip button +// Inject the entrypoint button into the SPA header when we are on a procedure page. function install() { const titleTag = document.querySelector("scrm-module-title") @@ -535,7 +543,7 @@ function install() { } } -// we need the observer to restore the button after each page load +// The app re-renders after client-side navigation, so we re-install after the spinner disappears. const contentObserver = new MutationObserver((mutations) => { mutations.forEach(mu => { for (const node of mu.removedNodes) {