add comments
This commit is contained in:
parent
f0ecfb466b
commit
2b727e1755
1 changed files with 10 additions and 2 deletions
12
content.js
12
content.js
|
|
@ -19,6 +19,7 @@ async function getXSRFToken() {
|
||||||
return decodeURIComponent(tokenCookie.split("=").slice(1).join("="))
|
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) {
|
async function fetchApplicantDetails(applicant, token) {
|
||||||
return fetch(`https://personal.uni-graz.at/api/erec/job-applications/${applicant.id}`,
|
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 = () => { }) {
|
async function downloadApplicantFilesWithProgress(applicantDetails, token, onProgress = () => { }) {
|
||||||
const files = applicantDetails.application_files ?? []
|
const files = applicantDetails.application_files ?? []
|
||||||
let completedDownloads = 0
|
let completedDownloads = 0
|
||||||
|
|
@ -67,6 +69,7 @@ async function getApplicant(applicant, token, onProgress = () => { }) {
|
||||||
return downloadApplicantFilesWithProgress(applicantDetails, 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) {
|
async function runWithConcurrencyLimit(items, limit, worker) {
|
||||||
const results = new Array(items.length)
|
const results = new Array(items.length)
|
||||||
let nextIndex = 0
|
let nextIndex = 0
|
||||||
|
|
@ -192,6 +195,7 @@ function getApplicantArchiveFileName(afile) {
|
||||||
return `${baseName}`
|
return `${baseName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the CSV viewer metadata aligned with the actual archive paths written into the ZIP.
|
||||||
function getApplicantArchiveFiles(applicantDetails) {
|
function getApplicantArchiveFiles(applicantDetails) {
|
||||||
const dirName = getApplicantDirectoryName(applicantDetails)
|
const dirName = getApplicantDirectoryName(applicantDetails)
|
||||||
const files = applicantDetails.application_files ?? []
|
const files = applicantDetails.application_files ?? []
|
||||||
|
|
@ -252,6 +256,7 @@ function createApplicantsCsv(applicantDetailsList) {
|
||||||
return rows.join("\n")
|
return rows.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the standalone viewer HTML into the generated archive.
|
||||||
async function getArchiveViewerHtmlSource() {
|
async function getArchiveViewerHtmlSource() {
|
||||||
const response = await fetch(chrome.runtime.getURL("archive-viewer/index.html"))
|
const response = await fetch(chrome.runtime.getURL("archive-viewer/index.html"))
|
||||||
|
|
||||||
|
|
@ -262,6 +267,7 @@ async function getArchiveViewerHtmlSource() {
|
||||||
return response.text()
|
return response.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundle the viewer's JSZip runtime so the exported archive can be browsed offline.
|
||||||
async function getArchiveViewerJsZipSource() {
|
async function getArchiveViewerJsZipSource() {
|
||||||
const candidates = [
|
const candidates = [
|
||||||
"lib/jszip.min.js"
|
"lib/jszip.min.js"
|
||||||
|
|
@ -315,6 +321,7 @@ function formatMegabytes(totalBytes) {
|
||||||
return `${(totalBytes / (1024 * 1024)).toFixed(1)} MB`
|
return `${(totalBytes / (1024 * 1024)).toFixed(1)} MB`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modal progress UI shown while applicants, files, and the final archive are prepared.
|
||||||
function createProgressDialog() {
|
function createProgressDialog() {
|
||||||
const dialog = document.createElement("dialog")
|
const dialog = document.createElement("dialog")
|
||||||
const title = document.createElement("h4")
|
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) {
|
function rip(event) {
|
||||||
const btn = event.target;
|
const btn = event.target;
|
||||||
const progressDialog = createProgressDialog()
|
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() {
|
function install() {
|
||||||
const titleTag = document.querySelector("scrm-module-title")
|
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) => {
|
const contentObserver = new MutationObserver((mutations) => {
|
||||||
mutations.forEach(mu => {
|
mutations.forEach(mu => {
|
||||||
for (const node of mu.removedNodes) {
|
for (const node of mu.removedNodes) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue