From 6f6c263a072c9df4e826d8ebb2035c82a87be7e0 Mon Sep 17 00:00:00 2001 From: Arpit Chakladar Date: Mon, 13 Jul 2026 20:49:57 +0530 Subject: refactor: organised the scripts into a more well defined structure now all scripts that are common to all pages lie in src/scripts/common each page gets its own folder in src/pages and different parts of the page's configuration are separated in separated folders which are all finally imported in src/pages/*/index.ts --- src/scripts/pages/application-receipt/captcha.ts | 9 + src/scripts/pages/application-receipt/index.ts | 1 + src/scripts/pages/know-your-property/captcha.ts | 9 + src/scripts/pages/know-your-property/index.ts | 1 + .../pages/mutation-application/download-button.ts | 60 +++++ src/scripts/pages/mutation-application/index.ts | 1 + .../sheet-map/download-map-pdf-page-content.html | 87 ++++++++ src/scripts/pages/sheet-map/index.ts | 185 ++++++++++++++++ .../map-plot-number-label-text-element.html | 3 + .../sheet-map/map-plot-polygon-path-element.html | 1 + .../pages/sheet-map/plot-information-element.html | 6 + .../download-information-pdf-page-content.html | 241 +++++++++++++++++++++ src/scripts/pages/view-khatian/index.ts | 95 ++++++++ 13 files changed, 699 insertions(+) create mode 100644 src/scripts/pages/application-receipt/captcha.ts create mode 100644 src/scripts/pages/application-receipt/index.ts create mode 100644 src/scripts/pages/know-your-property/captcha.ts create mode 100644 src/scripts/pages/know-your-property/index.ts create mode 100644 src/scripts/pages/mutation-application/download-button.ts create mode 100644 src/scripts/pages/mutation-application/index.ts create mode 100644 src/scripts/pages/sheet-map/download-map-pdf-page-content.html create mode 100644 src/scripts/pages/sheet-map/index.ts create mode 100644 src/scripts/pages/sheet-map/map-plot-number-label-text-element.html create mode 100644 src/scripts/pages/sheet-map/map-plot-polygon-path-element.html create mode 100644 src/scripts/pages/sheet-map/plot-information-element.html create mode 100644 src/scripts/pages/view-khatian/download-information-pdf-page-content.html create mode 100644 src/scripts/pages/view-khatian/index.ts (limited to 'src/scripts/pages') diff --git a/src/scripts/pages/application-receipt/captcha.ts b/src/scripts/pages/application-receipt/captcha.ts new file mode 100644 index 0000000..c5bb657 --- /dev/null +++ b/src/scripts/pages/application-receipt/captcha.ts @@ -0,0 +1,9 @@ +/** + * Hides the CAPTCHA section on the application-receipt page and + * stubs the form validation so the user can proceed without + * solving a CAPTCHA. + */ +document.addEventListener("DOMContentLoaded", () => { + $("#werter > div > form > div:nth-child(4)").hide(); + (window as any).validateForm = () => true; +}); diff --git a/src/scripts/pages/application-receipt/index.ts b/src/scripts/pages/application-receipt/index.ts new file mode 100644 index 0000000..5a8d0a6 --- /dev/null +++ b/src/scripts/pages/application-receipt/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/application-receipt/captcha"; diff --git a/src/scripts/pages/know-your-property/captcha.ts b/src/scripts/pages/know-your-property/captcha.ts new file mode 100644 index 0000000..3abdf08 --- /dev/null +++ b/src/scripts/pages/know-your-property/captcha.ts @@ -0,0 +1,9 @@ +/** + * Hides the CAPTCHA section on the Know-Your-Property page and + * stubs the captcha validation so the user can proceed without + * solving a CAPTCHA. + */ +document.addEventListener("DOMContentLoaded", () => { + $("#khatianPlotDiv > div:nth-child(6) > div").hide(); + (window as any).validateCaptcha = () => true; +}); diff --git a/src/scripts/pages/know-your-property/index.ts b/src/scripts/pages/know-your-property/index.ts new file mode 100644 index 0000000..d4d7f63 --- /dev/null +++ b/src/scripts/pages/know-your-property/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/know-your-property/captcha"; diff --git a/src/scripts/pages/mutation-application/download-button.ts b/src/scripts/pages/mutation-application/download-button.ts new file mode 100644 index 0000000..9503e00 --- /dev/null +++ b/src/scripts/pages/mutation-application/download-button.ts @@ -0,0 +1,60 @@ +import { PDFDocument, StandardFonts } from "pdf-lib"; +import { observeDOM } from "@/shared/observe-dom"; + +const sanghaFacilitationCentreBannerUrl = "$l{ /assets/sangha-facilitation-centre-banner.jpg }l$"; + +/** + * On the Mutation Application form, removes the form action (to prevent + * the default server-side submit) and attaches a custom click handler + * that fetches the declaration PDF, overlays a banner image and date + * stamp on the last page, then triggers a download. + */ +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); + + 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) + }); + + 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; + } +}); diff --git a/src/scripts/pages/mutation-application/index.ts b/src/scripts/pages/mutation-application/index.ts new file mode 100644 index 0000000..93e07ad --- /dev/null +++ b/src/scripts/pages/mutation-application/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/mutation-application/download-button"; diff --git a/src/scripts/pages/sheet-map/download-map-pdf-page-content.html b/src/scripts/pages/sheet-map/download-map-pdf-page-content.html new file mode 100644 index 0000000..da765ec --- /dev/null +++ b/src/scripts/pages/sheet-map/download-map-pdf-page-content.html @@ -0,0 +1,87 @@ + +
+
+ DISTRICT: $district$ +
+
+ BLOCK: $block$ +
+
+ MOUZA: $mouza$ +
+
+ + $mapContent$ + + diff --git a/src/scripts/pages/sheet-map/index.ts b/src/scripts/pages/sheet-map/index.ts new file mode 100644 index 0000000..a4e45b0 --- /dev/null +++ b/src/scripts/pages/sheet-map/index.ts @@ -0,0 +1,185 @@ +import { generateWebPage } from "@/shared/generate-web-page"; +import getDownloadMapPDFPageContent from "@/scripts/pages/sheet-map/download-map-pdf-page-content.html"; +import getMapPlotPolygonPathElement from "@/scripts/pages/sheet-map/map-plot-polygon-path-element.html"; +import getMapPlotNumberLabelTextElement from "@/scripts/pages/sheet-map/map-plot-number-label-text-element.html"; +import getPlotInformationElement from "@/scripts/pages/sheet-map/plot-information-element.html"; + +interface PlotPolygon { + plotArea: number; + plotno: string; + polygon: string; +}; + +interface PlotNumberLabel { + plotno: string; + point: string; +} + +const headerElement = document.querySelector("#headerTable > tbody > tr")!; +const plotNumberInput = document.querySelector("#txtPlotNo")!; +const plotInformation = document.createElement("div") as HTMLDivElement; +let plotPolygonPathElements = ""; +let plotNumberLabelTextElements = ""; + +document.body.appendChild(plotInformation); + +/** + * Creates a header toolbar button and appends it to the page header. + * The button starts hidden and is shown when data is ready. + * + * @param text - The button label text. + * @returns The created button element. + */ +const createHeaderButton = (text: string) => { + const buttonContainer = document.createElement("td"); + const button = document.createElement("button"); + button.innerHTML = text; + button.style.display = "none"; + buttonContainer.appendChild(button); + headerElement.appendChild(buttonContainer); + return button; +}; + +/** + * Displays the area and plot number for the given polygon in a floating + * info panel, or shows "0.000" / empty if no polygon is selected. + * + * @param plotPolygon - The selected plot's data, or `null`/`undefined` to clear. + */ +const setPlotInformation = (plotPolygon: PlotPolygon | null | undefined = null) => { + plotInformation.innerHTML = plotPolygon ? getPlotInformationElement({ + area: (plotPolygon.plotArea/1000).toFixed(3), + plotNumber: plotPolygon.plotno + }) : getPlotInformationElement({ + area: "0.000", + plotNumber: "" + }); +}; + +/** + * Opens a new window with a printable PDF view of the map, optionally + * including plot-number labels. + * + * @param labelPoints - Whether to include plot number text labels. + */ +const downloadPDF = (labelPoints: boolean = true) => { + /** Extracts a detail value (district/block/mouza) from the header table by column index. */ + const _getMapDetail = (i: number) => { + const detail = document.querySelector(`#headerTable > tbody > tr > td:nth-child(${i})`)! + .innerHTML + .split("[")[1] + .trim(); + return detail.substring(0, detail.length - 1); + }; + generateWebPage( + getDownloadMapPDFPageContent({ + district: _getMapDetail(1), + block: _getMapDetail(2), + mouza: _getMapDetail(3), + mapContent: plotPolygonPathElements + (labelPoints ? plotNumberLabelTextElements : "") + }), + "map" + ); +}; + +const downloadPDFButton = createHeaderButton("SAVE PDF"); +const downloadPDFNoLabelButton = createHeaderButton("SAVE PDF (NO LABEL)"); + +downloadPDFButton.addEventListener("click", e => { + e.preventDefault(); + downloadPDF(); +}); + +downloadPDFNoLabelButton.addEventListener("click", e => { + e.preventDefault(); + downloadPDF(false); +}); + +setPlotInformation(); + +(async () => { + const searchParams = new URLSearchParams(window.location.search); + const response1 = await fetch( + "/BanglarBhumi/sheetMap_populateLayerData?lstSheetNo=" + searchParams.get("lstSheetNo"), + { + method: "POST" + }); + const plotPolygonList: PlotPolygon[] = (await response1.json()).features; + const response2 = await fetch( + "/BanglarBhumi/sheetMap_populateCentroidData?lstSheetNo=" + searchParams.get("lstSheetNo"), + { + method: "POST" + }); + const plotNumberLabelList: PlotNumberLabel[] = (await response2.json()).features; + let plotPolygons: { [key: string]: PlotPolygon } = {}; + + for (const plotPolygon of plotPolygonList) { + const plotPolygonPoints = plotPolygon.polygon.split("(((")[1].split(")))")[0]; + plotPolygonPathElements += getMapPlotPolygonPathElement({ + polygonVertices: plotPolygonPoints + }); + } + + for (const plotNumberLabel of plotNumberLabelList) { + const plotNumberLabelPoint = plotNumberLabel.point.split("(")[1].split(")")[0].split(" "); + plotNumberLabelTextElements += getMapPlotNumberLabelTextElement({ + x: plotNumberLabelPoint[0], + y: plotNumberLabelPoint[1], + plotNumber: plotNumberLabel.plotno + }); + } + + downloadPDFButton.style.display = "inherit"; + downloadPDFNoLabelButton.style.display = "inherit"; + + document.querySelector("#btnSearch")!.addEventListener("click", () => { + let plotPolygon; + for (const p of plotPolygonList) { + if (p.plotno === plotNumberInput.value) { + plotPolygon = p; + break; + } + } + setPlotInformation(plotPolygon); + }); + + await new Promise((resolve, _reject) => { + const plotElementIdsControl = setInterval(() => { + let plotElements = document.querySelector("#OpenLayers_Layer_Vector_25_vroot")?.children || []; + if (plotElements.length) { + clearInterval(plotElementIdsControl); + for (let i = 0; i < plotElements.length; i++) { + plotPolygons[plotElements[i].id] = plotPolygonList[i]; + } + resolve(); + } + }, 50); + }); + + setInterval(() => { + for (const plotElementId in plotPolygons) { + const e = document.getElementById(plotElementId); + if (e) { + e.removeEventListener("click", handlePlotClick); + e.addEventListener("click", handlePlotClick); + } + } + }, 300); + + /** + * Highlights the clicked plot on the SVG map and shows its + * information in the info panel. + * + * @param e - The mouse click event. + */ + const handlePlotClick = (e: MouseEvent) => { + document.querySelectorAll("path").forEach(e => { + e.setAttribute("fill", "#ffcc66"); + }); + + const target = e.target as SVGPathElement; + + target.setAttribute("fill", "#8aeeef"); + setPlotInformation(plotPolygons[target.id]); + }; +})(); diff --git a/src/scripts/pages/sheet-map/map-plot-number-label-text-element.html b/src/scripts/pages/sheet-map/map-plot-number-label-text-element.html new file mode 100644 index 0000000..d220367 --- /dev/null +++ b/src/scripts/pages/sheet-map/map-plot-number-label-text-element.html @@ -0,0 +1,3 @@ + + $plotNumber$ + diff --git a/src/scripts/pages/sheet-map/map-plot-polygon-path-element.html b/src/scripts/pages/sheet-map/map-plot-polygon-path-element.html new file mode 100644 index 0000000..d4d38a6 --- /dev/null +++ b/src/scripts/pages/sheet-map/map-plot-polygon-path-element.html @@ -0,0 +1 @@ + diff --git a/src/scripts/pages/sheet-map/plot-information-element.html b/src/scripts/pages/sheet-map/plot-information-element.html new file mode 100644 index 0000000..fd740a8 --- /dev/null +++ b/src/scripts/pages/sheet-map/plot-information-element.html @@ -0,0 +1,6 @@ +
+ Plot Number: $plotNumber$ +
+
+ Area: $area$ acres +
diff --git a/src/scripts/pages/view-khatian/download-information-pdf-page-content.html b/src/scripts/pages/view-khatian/download-information-pdf-page-content.html new file mode 100644 index 0000000..129608e --- /dev/null +++ b/src/scripts/pages/view-khatian/download-information-pdf-page-content.html @@ -0,0 +1,241 @@ +
+ + + +
$details$
+ +
diff --git a/src/scripts/pages/view-khatian/index.ts b/src/scripts/pages/view-khatian/index.ts new file mode 100644 index 0000000..0be0c52 --- /dev/null +++ b/src/scripts/pages/view-khatian/index.ts @@ -0,0 +1,95 @@ +import { generateWebPage } from "@/shared/generate-web-page"; +import { interceptPost } from "@/shared/intercept-jquery-ajax"; +import getDownloadInformationPDFPageContent from "@/scripts/pages/view-khatian/download-information-pdf-page-content.html"; + +const submitButtonElement = $("#khbutton"); +const separatorElement = $("#bodycover > div > form > hr:nth-child(2)"); +const formElement = $("#bodycover > div > form"); +let downloadPDFButton: JQuery | null = null; + +const submitButtonElementComputedStyles = window.getComputedStyle(submitButtonElement[0]); +const styles = Array.from(submitButtonElementComputedStyles) + .reduce( + (str, property) => `${str}${property}:${submitButtonElementComputedStyles.getPropertyValue(property)};`, + "" + ); + +/** + * Reads the currently selected text from a `