This repository has been archived on 2026-07-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cloud-reader/frontend/src/utils/pdfAnchor.ts
T
2026-06-04 06:42:27 -05:00

55 lines
1.5 KiB
TypeScript

export type PdfRect = [number, number, number, number];
export interface ParsedPdfAnchor {
page: number;
rects: PdfRect[];
}
const PDF_ANCHOR_PREFIX = "pdf:v1:";
export function parsePageHref(href: string): number | null {
const match = href.match(/^pdf:page:(\d+)$/);
if (!match) return null;
const page = Number(match[1]);
return Number.isFinite(page) && page > 0 ? page : null;
}
export function serializePdfAnchor(page: number, rects?: PdfRect[]): string {
const base = `${PDF_ANCHOR_PREFIX}p=${page}`;
if (!rects?.length) return base;
return `${base};rects=${encodeURIComponent(JSON.stringify(rects))}`;
}
export function parsePdfAnchor(anchor: string): ParsedPdfAnchor | null {
if (anchor.startsWith("pdf:page:")) {
const page = parsePageHref(anchor);
return page ? { page, rects: [] } : null;
}
if (!anchor.startsWith(PDF_ANCHOR_PREFIX)) return null;
const pageMatch = anchor.match(/p=(\d+)/);
if (!pageMatch) return null;
const page = Number(pageMatch[1]);
if (!Number.isFinite(page) || page < 1) return null;
const rectsMatch = anchor.match(/rects=([^;]+)/);
let rects: PdfRect[] = [];
if (rectsMatch?.[1]) {
try {
const parsed = JSON.parse(decodeURIComponent(rectsMatch[1])) as unknown;
if (Array.isArray(parsed)) {
rects = parsed.filter(
(r): r is PdfRect =>
Array.isArray(r) &&
r.length === 4 &&
r.every((n) => typeof n === "number" && Number.isFinite(n)),
);
}
} catch {
rects = [];
}
}
return { page, rects };
}