aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-13 19:26:52 +0530
committerArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-13 19:26:52 +0530
commitbc4eb3606afbbc4b54fbb3b4ef81badd06cde525 (patch)
tree59358a47a679507e1eed9d1c4aed2cd48da1ca79
parente2a62b68f3a2fc4414ff27a7908f4ee7e93b6142 (diff)
downloadbanglar-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.ts88
-rw-r--r--src/scripts/login/index.ts113
-rw-r--r--src/shared/observe-dom.ts8
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;