// ==UserScript== // @name Connect Card Upload Viewer // @namespace https://github.com/nate-kean/ // @version 2025.11.24 // @description Add a pop-up next to the Form view modals for Connect Cards, that lets you zoom into the photos. // @author Nate Kean // @match https://jamesriver.fellowshiponego.com/forms // @icon https://www.google.com/s2/favicons?sz=64&domain=fellowshiponego.com // @grant none // @license MIT // @require https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.7/viewer.min.js // @downloadURL https://update.greasyfork.icu/scripts/556779/Connect%20Card%20Upload%20Viewer.user.js // @updateURL https://update.greasyfork.icu/scripts/556779/Connect%20Card%20Upload%20Viewer.meta.js // ==/UserScript== (async function() { function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function waitForElement(selector, pollingRateMs=100, parent=document) { let el; while (true) { el = parent.querySelector(selector); if (el) return el; await delay(pollingRateMs); } } async function elementGone(selector, pollingRateMs=100, parent=document) { let el; while (true) { el = parent.querySelector(selector); if (!el) return; await delay(pollingRateMs); } } document.head.insertAdjacentHTML("beforeend", ` `); while (true) { const modal = await waitForElement(".modal-dialog"); const detail = modal.querySelector("h3.modal-title > span > span.info"); while (detail.textContent === "") { await delay(10); } let popup = null; if (detail.textContent === "Connect Card Upload") { // Gather information const firstName = modal.querySelector("input[data-qa='field-person-name-input-first-name']").value; const lastName = modal.querySelector("input[data-qa='field-person-name-input-last-name']").value; const fileURLs = modal.querySelectorAll("a.file-upload-link"); const memos = modal.querySelectorAll("textarea[data-qa='field-memo-textarea']"); // Add popup popup = document.createElement("div"); popup.id = "nates-connect-card-viewer"; const closeBtn = document.createElement("button"); closeBtn.textContent = "X"; closeBtn.addEventListener("click", () => { popup.remove(); }); popup.appendChild(closeBtn); for (let i = 0; i < fileURLs.length; i++) { const img = document.createElement("img"); img.src = fileURLs[i].href; new Viewer(img); popup.appendChild(img); const desc = document.createElement("p"); desc.textContent = `${firstName} ${lastName} - ${memos[i].textContent || "(no desc)"}`; popup.appendChild(desc); } document.body.appendChild(popup); } await elementGone(".modal-dialog"); popup?.remove(); } })();