diff options
| author | Arpit Chakladar <arpitchakladar+git@gmail.com> | 2026-07-13 19:26:52 +0530 |
|---|---|---|
| committer | Arpit Chakladar <arpitchakladar+git@gmail.com> | 2026-07-13 19:26:52 +0530 |
| commit | bc4eb3606afbbc4b54fbb3b4ef81badd06cde525 (patch) | |
| tree | 59358a47a679507e1eed9d1c4aed2cd48da1ca79 | |
| parent | e2a62b68f3a2fc4414ff27a7908f4ee7e93b6142 (diff) | |
| download | banglar-bhumi-utils-bc4eb3606afbbc4b54fbb3b4ef81badd06cde525.tar.gz banglar-bhumi-utils-bc4eb3606afbbc4b54fbb3b4ef81badd06cde525.zip | |
refactor: using observeDOM instead of a separate login MutationObserver
using the observeDOM which serves as a common MutationObserver for all
scripts, mainly to improve performance.
| -rw-r--r-- | src/scripts/functionality/mutation-application.ts | 88 | ||||
| -rw-r--r-- | src/scripts/login/index.ts | 113 | ||||
| -rw-r--r-- | src/shared/observe-dom.ts | 8 |
3 files changed, 102 insertions, 107 deletions
diff --git a/src/scripts/functionality/mutation-application.ts b/src/scripts/functionality/mutation-application.ts index f0de884..9503e00 100644 --- a/src/scripts/functionality/mutation-application.ts +++ b/src/scripts/functionality/mutation-application.ts @@ -9,54 +9,52 @@ const sanghaFacilitationCentreBannerUrl = "$l{ /assets/sangha-facilitation-centr * that fetches the declaration PDF, overlays a banner image and date * stamp on the last page, then triggers a download. */ -document.addEventListener("DOMContentLoaded", () => { - observeDOM(() => { - const formElement = $("#form_MutationApplication > div > div:nth-child(14) > div.col-sm-2.btreset > form"); - const submitButtonElement = $("#btnDeclareForm"); - if (formElement.length > 0 && submitButtonElement.length > 0) { - formElement.removeAttr("action"); - submitButtonElement.on("click", (submitButtonClickEvent) => { - submitButtonClickEvent.preventDefault(); +observeDOM(() => { + const formElement = $("#form_MutationApplication > div > div:nth-child(14) > div.col-sm-2.btreset > form"); + const submitButtonElement = $("#btnDeclareForm"); + if (formElement.length > 0 && submitButtonElement.length > 0) { + formElement.removeAttr("action"); + submitButtonElement.on("click", (submitButtonClickEvent) => { + submitButtonClickEvent.preventDefault(); - (async () => { - const pdfDoc = await PDFDocument.load(await fetch("/BanglarBhumi/MutationDeclarationForm.action", { - method: "post", - credentials: "same-origin", - headers: { - "Content-Type": "application/x-www-form-urlencoded" - }, - body: "hdnAppNo=" - }).then(res => res.arrayBuffer())); - const pages = pdfDoc.getPages(); - const lastPage = pages[pages.length - 1]; - const { width, height: _ } = lastPage.getSize(); - const bannerImage = await pdfDoc.embedJpg(await fetch(sanghaFacilitationCentreBannerUrl).then(res => res.arrayBuffer())); - const bannerImageHeight = width * (bannerImage.height / bannerImage.width); + (async () => { + const pdfDoc = await PDFDocument.load(await fetch("/BanglarBhumi/MutationDeclarationForm.action", { + method: "post", + credentials: "same-origin", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: "hdnAppNo=" + }).then(res => res.arrayBuffer())); + const pages = pdfDoc.getPages(); + const lastPage = pages[pages.length - 1]; + const { width, height: _ } = lastPage.getSize(); + const bannerImage = await pdfDoc.embedJpg(await fetch(sanghaFacilitationCentreBannerUrl).then(res => res.arrayBuffer())); + const bannerImageHeight = width * (bannerImage.height / bannerImage.width); - lastPage.drawImage(bannerImage, { - x: 0, - y: 0, - width: width, - height: bannerImageHeight - }); + lastPage.drawImage(bannerImage, { + x: 0, + y: 0, + width: width, + height: bannerImageHeight + }); - lastPage.drawText(pdfDoc.getCreationDate()!.toLocaleString(), { - x: 10, - y: bannerImageHeight, - size: 12, - font: await pdfDoc.embedFont(StandardFonts.TimesRoman) - }); + lastPage.drawText(pdfDoc.getCreationDate()!.toLocaleString(), { + x: 10, + y: bannerImageHeight, + size: 12, + font: await pdfDoc.embedFont(StandardFonts.TimesRoman) + }); - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(new Blob([new Uint8Array(await pdfDoc.save())], {type: "application/pdf"})); - link.download = "Declaration.pdf"; - link.click(); - })(); - }); + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(new Blob([new Uint8Array(await pdfDoc.save())], {type: "application/pdf"})); + link.download = "Declaration.pdf"; + link.click(); + })(); + }); - return true; - } else { - return false; - } - }); + return true; + } else { + return false; + } }); diff --git a/src/scripts/login/index.ts b/src/scripts/login/index.ts index 80348e2..ebea7ec 100644 --- a/src/scripts/login/index.ts +++ b/src/scripts/login/index.ts @@ -1,3 +1,5 @@ +import { observeDOM } from "@/shared/observe-dom"; + /** * Pre-processes a CAPTCHA image on a canvas by removing grayish * background noise while preserving dark pixels, producing a clean @@ -62,62 +64,59 @@ function prepareCaptcha(ctx: CanvasRenderingContext2D, width: number, height: nu ctx.putImageData(imgData, 0, 0); } -// TODO: use observe dom instead -const observer = new MutationObserver((mutationsList, _obs) => { - for (const mutation of mutationsList) { - for (const node of mutation.addedNodes) { - if ((node as any).nodeType === 1 && (node as any).id === "loginform") { - const img = (node as HTMLFormElement).querySelector("#captchaImg") as HTMLImageElement; - const captchaInput = (node as HTMLFormElement).querySelector("#txtInput") as HTMLInputElement; - - // Wait for image to load to get correct dimensions - img.addEventListener("load", async () => { - const { width, height } = img; - - // 1. Create canvas - const canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - canvas.style.display = "block"; - - // 2. Copy styles (optional) - canvas.style.cssText = getComputedStyle(img).cssText; - canvas.style.display = "none"; - - // 3. Insert canvas before image - img.parentNode!.querySelectorAll("canvas").forEach(c => c.remove()); - img.parentNode!.insertBefore(canvas, img); - - // 4. Hide image - img.style.display = "none"; - - // 5. Draw the image onto the canvas - const ctx = canvas.getContext("2d")!; - ctx.drawImage(img, 0, 0); - prepareCaptcha(ctx, canvas.width, canvas.height); - canvas.style.display = ""; - const dataURL = canvas.toDataURL("image/png"); - - // Perform OCR - chrome.runtime.sendMessage( - { type: "OCR", dataURL }, - ({ success, text, confidence }) => { - if (success) { - const textResult = text.trim(); - if (confidence < 80 || textResult.length !== 6) { - // Reset the captcha if confidence is low - img.src = "generateCaptcha?" + new Date().getTime(); - } else { - captchaInput.value = textResult; - } - } - }, - ); - }); - } - } +observeDOM(() => { + const loginFormElement = document.querySelector("#loginform") as (HTMLFormElement | undefined); + + if (loginFormElement) { + const captchaImg = loginFormElement.querySelector("#captchaImg") as HTMLImageElement; + const captchaInput = loginFormElement.querySelector("#txtInput") as HTMLInputElement; + + // Wait for image to load to get correct dimensions + captchaImg.addEventListener("load", async () => { + const { width, height } = captchaImg; + + // 1. Create canvas + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + canvas.style.display = "block"; + + // 2. Copy styles (optional) + canvas.style.cssText = getComputedStyle(captchaImg).cssText; + canvas.style.display = "none"; + + // 3. Insert canvas before image + captchaImg.parentNode!.querySelectorAll("canvas").forEach(c => c.remove()); + captchaImg.parentNode!.insertBefore(canvas, captchaImg); + + // 4. Hide image + captchaImg.style.display = "none"; + + // 5. Draw the image onto the canvas + const ctx = canvas.getContext("2d")!; + ctx.drawImage(captchaImg, 0, 0); + prepareCaptcha(ctx, canvas.width, canvas.height); + canvas.style.display = ""; + const dataURL = canvas.toDataURL("image/png"); + + // Perform OCR + chrome.runtime.sendMessage( + { type: "OCR", dataURL }, + ({ success, text, confidence }) => { + if (success) { + const textResult = text.trim(); + if (confidence < 80 || textResult.length !== 6) { + // Reset the captcha if confidence is low + captchaImg.src = "generateCaptcha?" + new Date().getTime(); + } else { + captchaInput.value = textResult; + } + } + }, + ); + }); } -}); -// Start observing the body -observer.observe(document.body, { childList: true, subtree: true }); + // This runs forever + return false; +}); diff --git a/src/shared/observe-dom.ts b/src/shared/observe-dom.ts index 90a52ff..6ba1db4 100644 --- a/src/shared/observe-dom.ts +++ b/src/shared/observe-dom.ts @@ -1,7 +1,6 @@ type ObserveDOMCallback = () => boolean; -let callbacks: (ObserveDOMCallback | null)[] = []; -let callbacksCalledCount = 0; +let callbacks: ObserveDOMCallback[] = []; /** * Starts a MutationObserver on the document that invokes each @@ -13,11 +12,10 @@ const observer = new MutationObserver(() => { for (let i = 0; i < callbacks.length; i++) { const callback = callbacks[i]; if (callback && callback()) { - callbacksCalledCount++; - callbacks[i] = null; + callbacks.splice(i, 1); } - if (callbacksCalledCount >= callbacks.length) { + if (callbacks.length <= 0) { observer.disconnect(); break; |
