diff options
| author | Arpit Chakladar <arpitchakladar+git@gmail.com> | 2026-07-13 23:32:26 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-13 23:32:26 +0530 |
| commit | ce401d03e75bcbfd1cdfa963954e0807219fb80d (patch) | |
| tree | 52a813c1705a952312c20c328b00fa845a3453f9 /src/scripts/pages | |
| parent | 98e7019c61ea0ffe344ef7ce809d38d62254a9fc (diff) | |
| parent | dfba7ff6fff7bde33b40a343a2318b35c429b40f (diff) | |
| download | banglar-bhumi-utils-ce401d03e75bcbfd1cdfa963954e0807219fb80d.tar.gz banglar-bhumi-utils-ce401d03e75bcbfd1cdfa963954e0807219fb80d.zip | |
Merge pull request #6 from arpitchakladar/adding-documentation-comments
Adding documentation comments
Diffstat (limited to 'src/scripts/pages')
13 files changed, 722 insertions, 0 deletions
diff --git a/src/scripts/pages/application-receipt/captcha.ts b/src/scripts/pages/application-receipt/captcha.ts new file mode 100644 index 0000000..94e6b0e --- /dev/null +++ b/src/scripts/pages/application-receipt/captcha.ts @@ -0,0 +1,13 @@ +/** + * Hides the CAPTCHA section on the application-receipt page and + * stubs the form validation so the user can proceed without + * solving a CAPTCHA. + */ +type WindowApplicationReceipt = { + validateForm?: () => boolean +} & Window; + +document.addEventListener("DOMContentLoaded", () => { + $("#werter > div > form > div:nth-child(4)").hide(); + (window as WindowApplicationReceipt).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..e304342 --- /dev/null +++ b/src/scripts/pages/know-your-property/captcha.ts @@ -0,0 +1,13 @@ +/** + * Hides the CAPTCHA section on the Know-Your-Property page and + * stubs the captcha validation so the user can proceed without + * solving a CAPTCHA. + */ +type WindowKnowYourProperty = { + validateCaptcha?: () => boolean +} & Window; + +document.addEventListener("DOMContentLoaded", () => { + $("#khatianPlotDiv > div:nth-child(6) > div").hide(); + (window as WindowKnowYourProperty).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..6463079 --- /dev/null +++ b/src/scripts/pages/mutation-application/download-button.ts @@ -0,0 +1,63 @@ +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(); + + void (async function(): Promise<void> { + 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 } = 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 @@ +<style> + body { + margin: 0; + padding: 0; + } + svg { + display: block; + max-width: 100%; + max-height: 100%; + } + text { + font-family: "BNB-TTBidisha", sans-serif; + font-weight: bold; + font-size: 2; + fill: blue; + text-anchor: middle; + } + path { + fill-rule: evenodd; + fill: #ffcc66; + fill-opacity: 0.8; + stroke: #cc6633; + stroke-opacity: 0.8; + stroke-width: 0.2; + stroke-linecap: round; + stroke-linejoin: round; + } + .details { + font-size: 1.3rem; + display: flex; + width: 100%; + padding: 0 1rem 1rem 1rem; + border-bottom: 2px solid black; + justify-content: space-around; + margin-bottom: 0.2rem; + } +</style> +<div class="details"> + <div> + DISTRICT: $district$ + </div> + <div> + BLOCK: $block$ + </div> + <div> + MOUZA: $mouza$ + </div> +</div> +<svg> + $mapContent$ +</svg> +<script> + let minx = Infinity; + let miny = Infinity; + let maxx = 0; + let maxy = 0; + const paths = document.querySelectorAll("path"); + + for (const p of paths) { + const b = p.getBBox(); + minx = b.x < minx ? b.x : minx; + miny = b.y < miny ? b.y : miny; + maxx = maxx < b.x + b.width ? b.x + b.width : maxx; + maxy = maxy < b.y + b.height ? b.y + b.height : maxy; + } + + for (const p of paths) { + const m = "M " + p.getAttribute("d").substr(2).split(",").map(cood => { + cood = cood.trim().split(" "); + return cood[0] + " " + (miny + maxy - parseFloat(cood[1])).toString(); + }).join(", "); + p.setAttribute("d", m); + } + + for (const t of document.querySelectorAll("text")) { + t.setAttribute("y", (miny + maxy - parseFloat(t.getAttribute("y"))).toString()); + } + + document.querySelector("svg") + .setAttribute( + "viewBox", + [minx, miny, maxx - minx, maxy - miny] + .map(e => e.toString()).join(" ") + ); + window.addEventListener("afterprint", window.close); + window.print(); +</script> diff --git a/src/scripts/pages/sheet-map/index.ts b/src/scripts/pages/sheet-map/index.ts new file mode 100644 index 0000000..c16a2ae --- /dev/null +++ b/src/scripts/pages/sheet-map/index.ts @@ -0,0 +1,197 @@ +import getDownloadMapPDFPageContent from "@/scripts/pages/sheet-map/download-map-pdf-page-content.html"; +import getMapPlotNumberLabelTextElement from "@/scripts/pages/sheet-map/map-plot-number-label-text-element.html"; +import getMapPlotPolygonPathElement from "@/scripts/pages/sheet-map/map-plot-polygon-path-element.html"; +import getPlotInformationElement from "@/scripts/pages/sheet-map/plot-information-element.html"; +import { generateWebPage } from "@/shared/generate-web-page"; + +type PlotPolygon = { + plotArea: number; + plotno: string; + polygon: string +}; + +type PlotNumberLabel = { + plotno: string; + point: string +}; + +const headerElement = document.querySelector<HTMLTableRowElement>("#headerTable > tbody > tr"); +const plotNumberInput = document.querySelector<HTMLInputElement>("#txtPlotNo"); +const plotInformation = document.createElement("div"); +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. + */ +function createHeaderButton(text: string): HTMLButtonElement { + const buttonContainer = document.createElement("td"); + const button = document.createElement("button"); + button.innerHTML = text; + button.style.display = "none"; + buttonContainer.appendChild(button); + if (headerElement) + 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. + */ +function setPlotInformation(plotPolygon: PlotPolygon | null | undefined = null): void { + 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. + */ +function downloadPDF(labelPoints = true): void { + /** Extracts a detail value (district/block/mouza) from the header table by column index. */ + function _getMapDetail(i: number): string { + const detail = (document.querySelector<HTMLTableCellElement>(`#headerTable > tbody > tr > td:nth-child(${i.toString()})`)?.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(); + +void (async function(): Promise<void> { + const searchParams = new URLSearchParams(window.location.search); + const sheetMapLayerDataResponse = await fetch( + `/BanglarBhumi/sheetMap_populateLayerData?lstSheetNo=${searchParams.get("lstSheetNo")?.toString() ?? ""}`, + { + method: "POST" + }); + type SheetMapLayerDataResponseType = { + features: PlotPolygon[] + }; + const sheetMapLayerDataResponseJson + = await sheetMapLayerDataResponse.json() as SheetMapLayerDataResponseType; + const plotPolygonList: PlotPolygon[] = sheetMapLayerDataResponseJson.features; + const sheetMapCentroidDataResponse = await fetch( + `/BanglarBhumi/sheetMap_populateCentroidData?lstSheetNo=${searchParams.get("lstSheetNo")?.toString() ?? ""}`, + { + method: "POST" + }); + type SheetMapCentroidDataResponseType = { + features: PlotNumberLabel[] + }; + const sheetMapCentroidDataResponseJson + = await sheetMapCentroidDataResponse.json() as SheetMapCentroidDataResponseType; + const plotNumberLabelList: PlotNumberLabel[] = sheetMapCentroidDataResponseJson.features; + const plotPolygons: Record<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<HTMLButtonElement>("#btnSearch")?.addEventListener("click", () => { + let plotPolygon; + for (const p of plotPolygonList) { + if (p.plotno === plotNumberInput?.value) { + plotPolygon = p; + break; + } + } + setPlotInformation(plotPolygon); + }); + + await new Promise<void>((resolve, _reject) => { + const plotElementIdsControl = setInterval(() => { + const 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. + */ + function handlePlotClick(e: MouseEvent): void { + 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 @@ +<text x="$x$" y="$y$"> + <tspan baseline-shift="-35%" x="$x$" dy="0em">$plotNumber$</tspan> +</text> 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 @@ +<path d="M $polygonVertices$"></path> 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 @@ +<div> + Plot Number: $plotNumber$ +</div> +<div> + Area: $area$ acres +</div> 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 @@ +<div id="content"> + <style type="text/css" media="print"> + @page { + size: A4; + margin: 0; + } + </style> + <style> + * { + box-sizing: border-box !important; + text-decoration: none; + margin: 0; + padding: 0; + font-size: 16px !important; + } + + #content { + width: 100%; + margin: 0; + padding: 0; + } + + .banner { + width: 100%; + } + + .details { + padding: 1rem; + } + + #locater-information { + width: 100%; + margin-bottom: 1rem; + } + + #locater-information, + .details#plot-information > div:nth-child(1) > div:nth-child(5) > table { + border-collapse: collapse; + } + + .details#khatian-information > table, + .details#plot-information > div:nth-child(1) { + width: 100% !important; + border-spacing: 0; + } + + .details#plot-information > div:nth-child(1) > div:nth-child(1) { + text-align: center !important; + } + + .details#plot-information > div:nth-child(1) > div:nth-child(1) { + margin: 0 !important; + } + + .details#plot-information > div > div > table tr, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div > table > tbody > tr, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(5) > table > tbody > tr:last-child, + #locater-information > tbody > tr { + border-bottom: 1px solid black; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div > table > tbody > tr > th:nth-child(1), + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div > table > tbody > tr > td:nth-child(1), + .details#khatian-information #headertitle > tr > th:nth-child(1), + #locater-information > tbody > tr > td:nth-child(1), + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table > tbody > tr > td:nth-child(1), + #headertitle > tr > th:nth-child(1), + #plot-information > div:nth-child(1) > div:nth-child(5) > table > tbody > tr > td:nth-child(1) { + border-left: 1px solid black !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody > tr:nth-child(1), + #headertitle > tr, + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table > tbody > tr.table-text.knwurprpty_tbl_head_txt.ng-scope, + #headertitle, + #locater-information tr:nth-child(1) { + border-top: 1px solid black !important; + border-color: black !important; + } + + .details td { + white-space: normal; + } + + .details#plot-information #headertitle > tr > th, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div > table > tbody > tr > th, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div > table > tbody > tr > td, + .details#khatian-information #headertitle > tr > th, + #locater-information > tbody > tr > td, + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table > tbody > tr > td, + .details#plot-information > div:nth-child(1) > div:nth-child(5) > table > tbody > tr > td, + .details#plot-information > div:nth-child(1) > div:nth-child(5) > table > tbody { + border-right: 1px solid black !important; + } + + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table { + border: none !important; + } + + .details#plot-information > div:nth-child(1) > div { + position: initial !important; + left: 0 !important; + width: 100% !important; + border-left: none !important; + border-right: none !important; + } + + .details#plot-information > div:nth-child(2), + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table > tbody > tr > td:nth-child(4), + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table > tbody > tr > th:nth-child(4), + .details#khatian-information > table > tbody > tr > td:nth-child(1) > p:nth-child(3), + .details#khatian-information > table > tbody > tr > td:nth-child(2) { + display: none !important; + } + + .details#plot-information > div:nth-child(1) > div:nth-child(5) > table > tbody > tr { + background-color: transparent !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1), + .details#plot-information > div:nth-child(1) > div:nth-child(3) > table { + width: 100% !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(1), + .details#khatian-information > table > tbody > tr > td:nth-child(1) > p:nth-child(4) { + text-align: center; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) { + width: 100% !important; + position: initial !important; + left: 0 !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(5) > table { + width: 100% !important; + border: none !important; + } + + .details table tbody tr tr, + .details table tbody tr th, + .details table tbody tr td { + background-color: transparent; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) td, + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) th { + text-align: left; + } + + .details#khatian-information > table > tbody > tr > td > div > table > tbody > tr > th, + .details#khatian-information > table > tbody > tr > td > div > table > tbody > tr > td, + .details#plot-information td { + padding: 0 0.2rem 0 0.2rem; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody > tr:nth-child(1) > th { + font-weight: 500; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody > tr > th:nth-child(1), + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody > tr > td:nth-child(1), + #locater-information > tbody > tr > td:nth-child(1) { + font-weight: bold; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > p:nth-child(4) { + margin-top: 1rem !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(5), + .details#plot-information > div:nth-child(1) > div:nth-child(5) { + position: initial !important; + left: 0 !important; + top: 0 !important; + margin: 0 !important; + width: 100% !important; + } + + .details#plot-information > div:nth-child(1), + .details#khatian-information > table, + .details#khatian-information > table > tbody > tr > td:nth-child(1) { + border: none !important; + } + + .details#khatian-information > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody > tr:nth-child(1) > th, + #locater-information > tbody > tr > td { + width: 50%; + } + + body { + width: 210mm !important; + height: 297mm !important; + margin: 0 !important; + padding: 0 !important; + } + </style> + <img class="banner" src="https://banglarbhumi.gov.in/BanglarBhumi/images/bl.png"> + <div class="details">$details$</div> + <script> + let tableBodyElement; + const createTableEntry = (label, value) => { + const tableRowElement = document.createElement("tr"); + const tableLabelColumnElement = document.createElement("td"); + tableLabelColumnElement.innerHTML = label; + const tableValueColumnElement = document.createElement("td"); + tableValueColumnElement.innerHTML = value; + tableRowElement.appendChild(tableLabelColumnElement); + tableRowElement.appendChild(tableValueColumnElement); + tableBodyElement.appendChild(tableRowElement); + }; + + if ($isPlotInformation$) { + document.querySelector(".details").setAttribute("id", "plot-information"); + const tableElement = document.createElement("table"); + tableElement.setAttribute("id", "locater-information"); + tableBodyElement = document.createElement("tbody"); + tableElement.appendChild(tableBodyElement); + const detailsElement = document.querySelector(".details > div:nth-child(1)"); + detailsElement.insertBefore(tableElement, detailsElement.querySelector("div:nth-child(2)")); + } else { + document.querySelector(".details").setAttribute("id", "khatian-information"); + tableBodyElement = document.querySelector(".details > table > tbody > tr > td:nth-child(1) > div:nth-child(2) > table > tbody"); + } + + createTableEntry("\u{99C}\u{9C7}\u{9B2}\u{9BE} (District):", "$district$"); + createTableEntry("\u{9AC}\u{9CD}\u{9B2}\u{995} (Block):", "$block$"); + createTableEntry("\u{9AE}\u{9CC}\u{99C}\u{9BE} (Mouza):", "$mouza$"); + Promise.all( + Array.from(document.images) + .filter(img => !img.complete).map(img => new Promise(resolve => { + img.onload = img.onerror = resolve; + })) + ).then(() => { + window.addEventListener("afterprint", window.close); + window.print(); + }); + </script> +</div> diff --git a/src/scripts/pages/view-khatian/index.ts b/src/scripts/pages/view-khatian/index.ts new file mode 100644 index 0000000..bb44a38 --- /dev/null +++ b/src/scripts/pages/view-khatian/index.ts @@ -0,0 +1,95 @@ +import getDownloadInformationPDFPageContent from "@/scripts/pages/view-khatian/download-information-pdf-page-content.html"; +import { generateWebPage } from "@/shared/generate-web-page"; +import { addPostInterceptor, JQueryAjaxArgs } from "@/shared/intercept-jquery-ajax"; + +const submitButtonElement = $("#khbutton"); +const separatorElement = $("#bodycover > div > form > hr:nth-child(2)"); +const formElement = $("#bodycover > div > form"); +let downloadPDFButton: JQuery<HTMLButtonElement> | 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 `<select>` element. + * + * @param selector - CSS selector for the select element. + * @returns The text of the selected option. + */ +function getValueOfSelectElement(selector: string): string { + const element = document.querySelector<HTMLSelectElement>(selector); + return element?.options[element.selectedIndex].text ?? ""; +}; + +let isPlotInformation: boolean | null = null; + +/** + * Opens a new window with a printable PDF view of the current khatian + * or plot details, including district/block/mouza info. + */ +function downloadInformationPDF(): void { + generateWebPage( + getDownloadInformationPDFPageContent({ + isPlotInformation: !!isPlotInformation, + details: $(isPlotInformation ? "#plotdetails" : "#khdetails").html() || "", + district: getValueOfSelectElement("#lstDistrictCode1"), + block: getValueOfSelectElement("#lstBlockCode1"), + mouza: getValueOfSelectElement("#lstMouzaList") + }), + isPlotInformation + ? "Plot Details" + : "Khatian Details" + ); +}; + +/** + * Intercepts the success callback of a jQuery AJAX call. When a valid + * details table is returned, it inserts a "Download PDF" button; + * otherwise it removes an existing button. + * + * @param args - The `arguments` object from the intercepted `$.post` call. + */ +function showDownloadButton(args: JQueryAjaxArgs): void { + if (isPlotInformation !== null) { + const callback = args[2]; + args[2] = (...data) => { + callback(...data); + const tableElement = $(isPlotInformation + ? "#plotdetails > div:nth-child(1) > div:nth-child(4) > table > tbody" + : "#khdetails > table > tbody > tr > td:nth-child(1) > div:nth-child(5) > table > tbody" + ); + + if (tableElement.length) { + tableElement.css("height", "auto"); + tableElement.css("width", "100%"); + + if (!downloadPDFButton) { + downloadPDFButton = $(document.createElement("button")); + downloadPDFButton.html("Download PDF"); + downloadPDFButton[0].style.cssText = styles; + downloadPDFButton.css("width", "auto"); + downloadPDFButton.css("margin-bottom", "1rem"); + downloadPDFButton.on("click", downloadInformationPDF); + formElement[0].insertBefore(downloadPDFButton[0], separatorElement[0]); + } + } else if (downloadPDFButton) { + ($(downloadPDFButton)).remove(); + isPlotInformation = null; + downloadPDFButton = null; + } + }; + } +}; + +addPostInterceptor("plotDetailsAction_LandInfo.action", (args: JQueryAjaxArgs) => { + isPlotInformation = true; + showDownloadButton(args); +}); +addPostInterceptor("khDetailsAction_LandInfo.action", (args: JQueryAjaxArgs) => { + isPlotInformation = false; + showDownloadButton(args); +}); |
