diff --git a/content.js b/content.js index 3919889..aa4f6a4 100644 --- a/content.js +++ b/content.js @@ -101,8 +101,7 @@ async function runWithConcurrencyLimit(items, limit, worker) { return results } -async function getApplicants() { - const aid = getApplicationId() +async function getApplicants(aid) { const token = await getXSRFToken() return fetch(`https://personal.uni-graz.at/api/erec/job-applications/procedure/${aid}`, { @@ -519,14 +518,18 @@ function createProgressDialog() { } // Main export flow: fetch applicant data, download files, then assemble the ZIP. -function rip(event) { +function rip(event, aid) { Notification.requestPermission() const btn = event.target; const progressDialog = createProgressDialog() btn.textContent = "working ..." btn.classList.add("loading") btn.disabled = true; - getApplicants() + if (aid == null) { + console.error("could not find procedure ID") + return + } + getApplicants(aid) .then(async ({ aid, applicants, token }) => { progressDialog.setStatus("Downloading applicant details (will take several minutes)...") applicants.forEach((applicant) => { @@ -615,22 +618,63 @@ function rip(event) { }) } +function createRipButton(aid) { + const btn = document.createElement("button") + btn.textContent = "rip" + btn.classList.add("ripper-btn") + btn.addEventListener("click", event => rip(event, aid), { + once: true + }) + return btn +} + +function installTable(tableBody) { + if (tableBody == null) { + console.log("could not install button") + return + } + tableBody.querySelectorAll("tr").forEach((tr) => { + if (tr.querySelector(".ripper-btn") != null) return; + const nameTd = tr.querySelector(".column-name") + const link = nameTd?.querySelector("a") + const href = link?.href + if (href == null) { + console.log("could not install button") + return + } + const match = href.match(/^https:\/\/personal\.uni-graz\.at\/#\/job-procedures\/record\/([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})/) + if (match == null) { + console.log("could not install button") + return + } + const aid = match[1] + const actionMenu = tableBody.querySelector("scrm-line-action-menu") + if (actionMenu == null) { + console.log("could not install button") + return + } + actionMenu.append(createRipButton(aid)) + }) +} + // Inject the entrypoint button into the SPA header when we are on a procedure page. function install() { const titleTag = document.querySelector("scrm-module-title") if (titleTag != null && window.location.hash.startsWith("#/job-procedures/record")) { + /* procedure specific page, add the button to the title */ + + /* prevent double install */ if (titleTag.querySelector(".ripper-btn") != null) { return } - - const a = document.createElement("button") - a.textContent = "rip" - a.classList.add("ripper-btn") - a.addEventListener("click", rip, { - once: true - }) - titleTag.append(" (", a, ")") + titleTag.append(" (", createRipButton(getApplicationId()), ")") + } else if (window.location.hash === "#/job-procedures/list") { + /* procedure list page, add the button to each row */ + setTimeout(() => { + const tableBody = document.querySelector("scrm-table")?.querySelector("tbody") + installTable(tableBody) + }, 1000) } else { console.log("could not install button") }