aboutsummaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-13 23:32:26 +0530
committerGitHub <noreply@github.com>2026-07-13 23:32:26 +0530
commitce401d03e75bcbfd1cdfa963954e0807219fb80d (patch)
tree52a813c1705a952312c20c328b00fa845a3453f9 /src/shared
parent98e7019c61ea0ffe344ef7ce809d38d62254a9fc (diff)
parentdfba7ff6fff7bde33b40a343a2318b35c429b40f (diff)
downloadbanglar-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.ts17
-rw-r--r--src/shared/intercept-jquery-ajax.ts99
-rw-r--r--src/shared/modify-dom.ts36
-rw-r--r--src/shared/observe-dom.ts27
-rw-r--r--src/shared/ocr-request.ts13
-rw-r--r--src/shared/script-injector.ts19
-rw-r--r--src/shared/styling.ts13
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]);
}
}
};