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/shared | |
| 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/shared')
| -rw-r--r-- | src/shared/generate-web-page.ts | 17 | ||||
| -rw-r--r-- | src/shared/intercept-jquery-ajax.ts | 99 | ||||
| -rw-r--r-- | src/shared/modify-dom.ts | 36 | ||||
| -rw-r--r-- | src/shared/observe-dom.ts | 27 | ||||
| -rw-r--r-- | src/shared/ocr-request.ts | 13 | ||||
| -rw-r--r-- | src/shared/script-injector.ts | 19 | ||||
| -rw-r--r-- | src/shared/styling.ts | 13 |
7 files changed, 166 insertions, 58 deletions
diff --git a/src/shared/generate-web-page.ts b/src/shared/generate-web-page.ts index a07575f..a93e2e2 100644 --- a/src/shared/generate-web-page.ts +++ b/src/shared/generate-web-page.ts @@ -1,11 +1,20 @@ -export function generateWebPage(content: string, title: string = "Banglar Bhumi") { +/** + * Opens a new browser tab and writes the given HTML content into it. + * Used to display dynamically-generated pages (e.g. PDF-printable views). + * + * @param content - The full HTML string to write. + * @param title - The document title (default: `"Banglar Bhumi"`). + */ +export function generateWebPage(content: string, title = "Banglar Bhumi"): void { const tab = window.open("about:blank", "_blank"); if (!tab) { return; } - tab.document.write(content); - tab.document.close(); - tab.document.title = title; + tab.addEventListener("DOMContentLoaded", () => { + tab.document.body.innerHTML = content; + tab.document.title = title; + tab.document.close(); + }); tab.focus(); }; diff --git a/src/shared/intercept-jquery-ajax.ts b/src/shared/intercept-jquery-ajax.ts index a77dd44..b627d0e 100644 --- a/src/shared/intercept-jquery-ajax.ts +++ b/src/shared/intercept-jquery-ajax.ts @@ -1,41 +1,86 @@ -type InterceptJqueryAjaxCallback = (args: any) => void; +export type JQueryAjaxArgs = [ + url: string, + data: string | Record<string, unknown>, + callback: (data: unknown, textStatus: string, jqXHR: JQuery.jqXHR) => void, + dataType?: string +]; -interface InterceptJqueryEntry { - url: string; - callback: InterceptJqueryAjaxCallback; +type JQueryAjaxInterceptor = (args: JQueryAjaxArgs) => void; + +type InterceptorRegistration = { + urlSuffix: string; + interceptor: JQueryAjaxInterceptor }; -const postIntercepts: InterceptJqueryEntry[] = []; -const getIntercepts: InterceptJqueryEntry[] = []; +const postInterceptors: InterceptorRegistration[] = []; +const getInterceptors: InterceptorRegistration[] = []; + +// Define a strict signature to replace the unsafe `Function` type +type OriginalJQueryAjaxMethod = (...args: unknown[]) => JQuery.jqXHR; -document.addEventListener("DOMContentLoaded", () => { - const proxiedPost = $.post; - const proxiedGet = $.get; +/** + * On DOMContentLoaded, proxies jQuery's `$.post` and `$.get` so that + * registered interceptors are called before the real request. + */ +document.addEventListener("DOMContentLoaded", function() { + // 1. Keep the original methods bound to the jQuery ($) object + const originalPost = $.post.bind($); + const originalGet = $.get.bind($); - $.post = function() { - for (const { url, callback } of postIntercepts) { - if (arguments[0].endsWith(url)) { - callback(arguments); + /** Proxied `$.post` that invokes registered interceptors before the real call. */ + $.post = function(this: typeof $, ...args: unknown[]): JQuery.jqXHR { + for (const { urlSuffix, interceptor } of postInterceptors) { + // Safely inspect jQuery settings objects without using "any" + const firstArg = args[0]; + const requestUrl = typeof firstArg === "string" + ? firstArg + : (firstArg && typeof firstArg === "object" && "url" in firstArg && typeof firstArg.url === "string" ? firstArg.url : null); + + if (typeof requestUrl === "string" && requestUrl.endsWith(urlSuffix)) { + // Cast the unknown array to the expected tuple type + interceptor(args as unknown as JQueryAjaxArgs); } } - return proxiedPost.apply(this, Array.from(arguments) as any); - }; - $.get = function() { - for (const { url, callback } of getIntercepts) { - if (arguments[0].endsWith(url)) { - callback(arguments); + // Use our strict signature instead of `Function` to satisfy ESLint + return (originalPost as unknown as OriginalJQueryAjaxMethod)(...args); + } as typeof $.post; // Reassert the original type so external consumers see the normal signature + + /** Proxied `$.get` that invokes registered interceptors before the real call. */ + $.get = function(this: typeof $, ...args: unknown[]): JQuery.jqXHR { + for (const { urlSuffix, interceptor } of getInterceptors) { + const firstArg = args[0]; + const requestUrl = typeof firstArg === "string" + ? firstArg + : (firstArg && typeof firstArg === "object" && "url" in firstArg && typeof firstArg.url === "string" ? firstArg.url : null); + + if (typeof requestUrl === "string" && requestUrl.endsWith(urlSuffix)) { + interceptor(args as unknown as JQueryAjaxArgs); } } - return proxiedGet.apply(this, Array.from(arguments) as any); - }; + return (originalGet as unknown as OriginalJQueryAjaxMethod)(...args); + } as typeof $.get; }); -export function interceptPost(url: string, callback: InterceptJqueryAjaxCallback) { - postIntercepts.push({ url, callback }); -}; +/** + * Registers a callback that fires whenever a jQuery POST request matches + * the given URL suffix. + * + * @param urlSuffix - The URL suffix to match (checked via `endsWith`). + * @param interceptor - Receives the original `arguments` from `$.post`. + */ +export function addPostInterceptor(urlSuffix: string, interceptor: JQueryAjaxInterceptor): void { + postInterceptors.push({ urlSuffix, interceptor }); +} -export function interceptGet(url: string, callback: InterceptJqueryAjaxCallback) { - getIntercepts.push({ url, callback }); -}; +/** + * Registers a callback that fires whenever a jQuery GET request matches + * the given URL suffix. + * + * @param urlSuffix - The URL suffix to match (checked via `endsWith`). + * @param interceptor - Receives the original `arguments` from `$.get`. + */ +export function addGetInterceptor(urlSuffix: string, interceptor: JQueryAjaxInterceptor): void { + getInterceptors.push({ urlSuffix, interceptor }); +} diff --git a/src/shared/modify-dom.ts b/src/shared/modify-dom.ts index 22b8e8e..41e8730 100644 --- a/src/shared/modify-dom.ts +++ b/src/shared/modify-dom.ts @@ -2,7 +2,7 @@ import { observeDOM } from "@/shared/observe-dom"; type DOMReplacements = { innerHTML?: string; - [key: string]: string | undefined | null; + [key: string]: string | undefined | null }; type DOMModificaitonRule = readonly [string, DOMReplacements]; type DOMModificationRules = (DOMModificaitonRule | null)[]; @@ -10,25 +10,32 @@ type DOMModificationRules = (DOMModificaitonRule | null)[]; let domModificationRules: DOMModificationRules = []; let domModificationFinishedCount = 0; +/** + * Runs whenever the DOM mutates. Iterates over pending modification + * rules; when the selector matches, the element's innerHTML and + * attributes are updated and the rule is marked as complete. + */ observeDOM(() => { for (let i = 0; i < domModificationRules.length; i++) { - if (domModificationRules[i]) { - const element = document.querySelector(domModificationRules[i]![0]) as HTMLElement | null; + const rule = domModificationRules[i]; + if (rule?.[0]) { + const element = document.querySelector(rule[0]); if (element) { - const attributes = domModificationRules[i]![1]; + const attributes = rule[1]; if (attributes.innerHTML) { - element.innerHTML = attributes.innerHTML as string; + element.innerHTML = attributes.innerHTML; } delete attributes.innerHTML; - for (const attribute in attributes) { - if (attributes[attribute] === null) { - element.removeAttribute(attribute); + for (const attributeName in attributes) { + const attribute = attributes[attributeName]; + if (attribute) { + element.setAttribute(attributeName, attribute); } else { - element.setAttribute(attribute, attributes[attribute] as string); + element.removeAttribute(attributeName); } } @@ -45,6 +52,15 @@ observeDOM(() => { return false; }); -export function modifyDOM(modificationRules: DOMModificationRules) { +/** + * Registers one or more DOM modification rules. Each rule is a tuple of + * `[selector, attributeMap]`. When an element matching the selector is + * found, its `innerHTML` is replaced (if `attributeMap.innerHTML` is set) + * and all other entries in the map are applied as `setAttribute` calls + * (or `removeAttribute` when the value is `null`). + * + * @param modificationRules - Array of `[selector, attributes]` rules. + */ +export function modifyDOM(modificationRules: DOMModificationRules): void { domModificationRules = domModificationRules.concat(modificationRules); }; diff --git a/src/shared/observe-dom.ts b/src/shared/observe-dom.ts index e82ce1e..ee6a51f 100644 --- a/src/shared/observe-dom.ts +++ b/src/shared/observe-dom.ts @@ -1,17 +1,20 @@ type ObserveDOMCallback = () => boolean; -let callbacks: (ObserveDOMCallback | null)[] = []; -let callbacksCalledCount = 0; +const callbacks: ObserveDOMCallback[] = []; +/** + * Starts a MutationObserver on the document that invokes each + * registered callback. A callback should return `true` when it + * has completed its work; once all callbacks are done the observer + * disconnects. + */ const observer = new MutationObserver(() => { for (let i = 0; i < callbacks.length; i++) { const callback = callbacks[i]; - if (callback && callback()) { - callbacksCalledCount++; - callbacks[i] = null; - } + if (callback()) + callbacks.splice(i, 1); - if (callbacksCalledCount >= callbacks.length) { + if (callbacks.length <= 0) { observer.disconnect(); break; @@ -24,6 +27,14 @@ observer.observe(document, { subtree: true }); -export function observeDOM(callback: ObserveDOMCallback) { +/** + * Registers a callback to run on DOM mutations. + * The callback is invoked on each mutation tick and should return `true` + * when its work is finished. When all callbacks have completed the + * observer stops. + * + * @param callback - Function that returns `true` when done. + */ +export function observeDOM(callback: ObserveDOMCallback): void { callbacks.push(callback); }; diff --git a/src/shared/ocr-request.ts b/src/shared/ocr-request.ts new file mode 100644 index 0000000..3109771 --- /dev/null +++ b/src/shared/ocr-request.ts @@ -0,0 +1,13 @@ +export type OCRRequest = { + type: "OFFSCREEN_OCR_REQUEST" | "OCR"; + dataURL: string +}; + +export type OCRResponse = { + success: true; + text: string; + confidence: number +} | { + success: false; + error: string +}; diff --git a/src/shared/script-injector.ts b/src/shared/script-injector.ts index 697c8d6..3422bab 100644 --- a/src/shared/script-injector.ts +++ b/src/shared/script-injector.ts @@ -1,12 +1,19 @@ -type DataType = { - [key: string]: string -}; +type DataType = Record<string, string>; -export function injectScriptHead(src: string, data: DataType = {}) { - const s = document.createElement("script") as HTMLScriptElement; +/** + * Injects a `<script>` element into the document head (or `<html>`) with + * the given `src` pointing to an extension resource. Optional key/value + * data is attached as `data-*` attributes so the injected script can + * read them via `document.currentScript`. + * + * @param src - The extension-relative script path. + * @param data - Optional key/value pairs to set as `data-*` attributes. + */ +export function injectScriptHead(src: string, data: DataType = {}): void { + const s = document.createElement("script"); s.src = chrome.runtime.getURL(src); for (const i in data) { s.setAttribute(`data-${i}`, data[i]); } - (document.head || document.documentElement).append(s); + document.head.append(s); }; diff --git a/src/shared/styling.ts b/src/shared/styling.ts index 759fecb..57a39f6 100644 --- a/src/shared/styling.ts +++ b/src/shared/styling.ts @@ -1,9 +1,16 @@ -export function styles(selector: string, styles: Record<string, string>) { - const elements = Array.from(document.querySelectorAll(selector)) as HTMLElement[]; +/** + * Applies a set of inline CSS styles to every element matching the + * given CSS selector. + * + * @param selector - CSS selector string. + * @param styles - A map of CSS property names to values. + */ +export function styles(selector: string, styles: Record<string, string>): void { + const elements = Array.from(document.querySelectorAll(selector)); for (const element of elements) { for (const styleType in styles) { - element.style[styleType as any] = styles[styleType]; + (element as HTMLElement).style.setProperty(styleType, styles[styleType]); } } }; |
