diff --git a/.codegraph/.gitignore b/.codegraph/.gitignore
new file mode 100644
index 000000000..9de0f1690
--- /dev/null
+++ b/.codegraph/.gitignore
@@ -0,0 +1,16 @@
+# CodeGraph data files
+# These are local to each machine and should not be committed
+
+# Database
+*.db
+*.db-wal
+*.db-shm
+
+# Cache
+cache/
+
+# Logs
+*.log
+
+# Hook markers
+.dirty
diff --git a/.env.example b/.env.example
new file mode 100644
index 000000000..818378be4
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,24 @@
+# PDFCraft Environment Variables
+# Copy this file to .env.local and fill in the values
+
+# -----------------------------------------------------------------------------
+# Core
+# -----------------------------------------------------------------------------
+NEXT_PUBLIC_APP_URL=https://pdfcraft.com
+
+# -----------------------------------------------------------------------------
+# Ads (Google AdSense) — Single switch for entire project
+# -----------------------------------------------------------------------------
+# Set your AdSense client ID to enable ads on ALL pages:
+# pdfcraft.com (homepage, tools, blog, docs...)
+# All tool detail pages
+# Leave empty to hide ads everywhere.
+NEXT_PUBLIC_ADSENSE_CLIENT=
+
+# -----------------------------------------------------------------------------
+# Deployment (Cloudflare Pages)
+# -----------------------------------------------------------------------------
+# For Cloudflare Pages deployment, set NEXT_PUBLIC_ADSENSE_CLIENT
+# in the Cloudflare Pages dashboard under:
+# Settings → Variables and Secrets → Add variable
+# (Build-time environment variables are injected during `npm run build`)
diff --git a/.gitignore b/.gitignore
index 92899281b..9e9b212f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -80,3 +80,7 @@ public/libreoffice-wasm/soffice.data
# Tauri / Cargo (local build output)
src-tauri/target/
+scripts/
+*.translate.ts
+*.bak
+*.sh
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 000000000..6c59086d8
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+enable-pre-post-scripts=true
diff --git a/.trigger-deploy b/.trigger-deploy
new file mode 100644
index 000000000..e69de29bb
diff --git a/.vercelignore b/.vercelignore
new file mode 100644
index 000000000..d50d499c1
--- /dev/null
+++ b/.vercelignore
@@ -0,0 +1,14 @@
+node_modules
+.next
+.git
+*.md
+.DS_Store
+.idea
+.vscode
+coverage
+dist
+build
+.src-tauri
+bentopdf-main
+public/libreoffice-wasm/soffice.wasm
+public/libreoffice-wasm/soffice.data
diff --git a/ADS_CONFIG.md b/ADS_CONFIG.md
new file mode 100644
index 000000000..6c789d3a1
--- /dev/null
+++ b/ADS_CONFIG.md
@@ -0,0 +1,85 @@
+# Ads Configuration Guide
+
+## Overview
+
+This document explains how to enable/disable ads in the PDFCraft project. Ads are controlled via **build-time environment variables** that get baked into the static build output.
+
+## Current Configuration
+
+Ads are controlled by two environment variables:
+
+| Variable | Purpose | Example Value |
+|----------|---------|---------------|
+| `NEXT_PUBLIC_ADVER_ENABLE` | Master switch for all ads | `true` / `false` |
+| `NEXT_PUBLIC_ADSENSE_CLIENT` | Google AdSense client ID | `ca-pub-xxxxxxxxxxxxxxx` |
+
+## How to Enable/Disable Ads
+
+The build command in `package.json` has `NEXT_PUBLIC_ADVER_ENABLE=true` hardcoded:
+
+```json
+"build": "NEXT_PUBLIC_APP_URL=https://pdf.craftisle.com NEXT_PUBLIC_ADVER_ENABLE=true NODE_ENV=production next build"
+```
+
+**To disable ads:**
+1. Open `package.json`
+2. Change `NEXT_PUBLIC_ADVER_ENABLE=true` to `NEXT_PUBLIC_ADVER_ENABLE=false`
+3. Commit and push → Cloudflare Pages will auto-redeploy
+
+**To enable ads:**
+1. Open `package.json`
+2. Ensure `NEXT_PUBLIC_ADVER_ENABLE=true` is set
+3. Commit and push → Cloudflare Pages will auto-redeploy
+
+---
+
+## Ad Components Location
+
+### Monetag Vignette Banner
+- **File**: `src/app/layout.tsx` (lines 76-83)
+- **Condition**: `process.env.NEXT_PUBLIC_ADVER_ENABLE === 'true'`
+- **Script**: `/monetag-vignette.js` (placed in `public/`)
+
+### Google AdSense
+- **File**: `src/app/layout.tsx` (lines 65-72)
+- **Condition**: `process.env.NEXT_PUBLIC_ADSENSE_CLIENT` is truthy
+- **Script**: Google AdSense auto-loads via `adsbygoogle.js`
+
+---
+
+## How to Verify Ads Are Working
+
+After deployment, verify ads are injected:
+
+```bash
+# Check for Monetag script
+curl -s https://pdf.craftisle.com | grep -i "monetag-vignette"
+
+# Check for AdSense script
+curl -s https://pdf.craftisle.com | grep -i "adsbygoogle"
+```
+
+Or manually:
+1. Open `https://pdf.craftisle.com`
+2. Right-click → **View Page Source**
+3. Search for `monetag-vignette` and `adsbygoogle`
+
+---
+
+## Important Notes
+
+1. **Static export limitation**: Since this project uses `output: 'export'`, environment variables are baked in at build time. Changing them requires a **rebuild**.
+2. **No runtime config**: You cannot change ad settings without rebuilding and redeploying.
+3. **Cloudflare cache**: After redeployment, wait ~30 seconds for cache to clear, or do a hard refresh (Cmd+Shift+R).
+
+---
+
+## Quick Reference
+
+| Task | Action |
+|------|--------|
+| Disable all ads | Set `NEXT_PUBLIC_ADVER_ENABLE=false` in `package.json` → commit → push |
+| Enable Monetag ads | Set `NEXT_PUBLIC_ADVER_ENABLE=true` in `package.json` → commit → push |
+| Enable AdSense | Ensure `NEXT_PUBLIC_ADSENSE_CLIENT` is set in build env |
+| Verify ads injected | `curl https://pdf.craftisle.com \| grep monetag` |
+| Force rebuild on Cloudflare | Dashboard → Deployments → Retry latest deployment |
diff --git a/public/libreoffice-wasm/browser.worker.global.js b/browser.worker.global.js
similarity index 53%
rename from public/libreoffice-wasm/browser.worker.global.js
rename to browser.worker.global.js
index 85dd4c415..0cec78113 100644
--- a/public/libreoffice-wasm/browser.worker.global.js
+++ b/browser.worker.global.js
@@ -1,4 +1,4 @@
(function () {
- 'use strict'; var S = class extends Error { code; details; constructor(e, t, r) { super(t), this.name = "ConversionError", this.code = e, this.details = r; } }, te = { pdf: "writer_pdf_Export", docx: "MS Word 2007 XML", doc: "MS Word 97", odt: "writer8", rtf: "Rich Text Format", txt: "Text", html: "HTML (StarWriter)", xlsx: "Calc MS Excel 2007 XML", xls: "MS Excel 97", ods: "calc8", csv: "Text - txt - csv (StarCalc)", pptx: "Impress MS PowerPoint 2007 XML", ppt: "MS PowerPoint 97", odp: "impress8", png: "writer_png_Export", jpg: "writer_jpg_Export", svg: "writer_svg_Export" }; var oe = { pdf: "application/pdf", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", doc: "application/msword", odt: "application/vnd.oasis.opendocument.text", rtf: "application/rtf", txt: "text/plain", html: "text/html", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xls: "application/vnd.ms-excel", ods: "application/vnd.oasis.opendocument.spreadsheet", csv: "text/csv", pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation", ppt: "application/vnd.ms-powerpoint", odp: "application/vnd.oasis.opendocument.presentation", png: "image/png", jpg: "image/jpeg", svg: "image/svg+xml" }, ne = { doc: "doc", docx: "docx", xls: "xls", xlsx: "xlsx", ppt: "ppt", pptx: "pptx", odt: "odt", ods: "ods", odp: "odp", odg: "odg", odf: "odf", rtf: "rtf", txt: "txt", html: "html", htm: "html", csv: "csv", xml: "xml", epub: "epub", pdf: "pdf" }, ye = { 0: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png"], 1: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png"], 2: ["pdf", "pptx", "ppt", "odp", "png", "svg", "html"], 3: ["pdf", "png", "svg", "html"], 4: ["pdf"] }; function ie(l) { return ye[l] || ["pdf"] } var K = { pdf: "pdf", docx: "docx", doc: "doc", odt: "odt", rtf: "rtf", txt: "txt", html: "html", xlsx: "xlsx", xls: "xls", ods: "ods", csv: "csv", pptx: "pptx", ppt: "ppt", odp: "odp", png: "png", jpg: "jpg", svg: "svg" }, $ = { pdf: "", csv: "44,34,76,1,,0,false,true,false,false,false,-1", txt: "UTF8" }, Se = "FilterName=Text - txt - csv (StarCalc),FilterOptions=44,34,76,1,,1033,false,true,false,false,false,0,true,false,true"; function M(l, e) { let t = []; return l?.toLowerCase() === "csv" && t.push(Se), e && t.push(`Password=${e}`), t.join(",") } var se = { doc: "text", docx: "text", odt: "text", rtf: "text", txt: "text", html: "text", htm: "text", epub: "text", xml: "text", xls: "spreadsheet", xlsx: "spreadsheet", ods: "spreadsheet", csv: "spreadsheet", ppt: "presentation", pptx: "presentation", odp: "presentation", odg: "drawing", odf: "drawing", pdf: "drawing" }, Ee = { text: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png"], spreadsheet: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png"], presentation: ["pdf", "pptx", "ppt", "odp", "png", "svg", "html"], drawing: ["pdf", "png", "svg", "html"], other: ["pdf"] }; function G(l) { let e = l.toLowerCase(), t = se[e]; return t ? Ee[t] : ["pdf"] } function re(l, e) { return G(l).includes(e.toLowerCase()) } function ae(l, e) { let t = l.toLowerCase(), r = e.toLowerCase(), n = G(t), o = se[t] || "unknown", s = ""; return o === "drawing" && ["docx", "doc", "xlsx", "xls", "pptx", "ppt"].includes(r) ? s = "PDF files are imported as Draw documents and cannot be exported to Office formats. " : o === "spreadsheet" && ["docx", "doc", "pptx", "ppt"].includes(r) ? s = "Spreadsheet documents cannot be converted to word processing or presentation formats. " : o === "presentation" && ["docx", "doc", "xlsx", "xls"].includes(r) ? s = "Presentation documents cannot be converted to word processing or spreadsheet formats. " : o === "text" && ["xlsx", "xls", "pptx", "ppt"].includes(r) && (s = "Text documents cannot be converted to spreadsheet or presentation formats. "), `Cannot convert ${t.toUpperCase()} to ${r.toUpperCase()}. ${s}Valid output formats for ${t.toUpperCase()}: ${n.join(", ")}` } var I = class { lok; docPtr; options; inputPath = ""; constructor(e, t, r = {}) { this.lok = e, this.docPtr = t, this.options = { maxResponseChars: r.maxResponseChars ?? 8e3, ...r }; } getDocPtr() { return this.docPtr } getLokBindings() { return this.lok } save() { try { return this.inputPath ? (this.lok.postUnoCommand(this.docPtr, ".uno:Save"), this.createResult({ path: this.inputPath })) : this.createErrorResult("No input path set", "Use saveAs() to specify a path") } catch (e) { return this.createErrorResult(`Save failed: ${String(e)}`) } } saveAs(e, t) { try { return this.lok.documentSaveAs(this.docPtr, e, t, ""), this.createResult({ path: e }) } catch (r) { return this.createErrorResult(`SaveAs failed: ${String(r)}`) } } close() { try { return this.lok.documentDestroy(this.docPtr), this.docPtr = 0, this.createResult(void 0) } catch (e) { return this.createErrorResult(`Close failed: ${String(e)}`) } } getEditMode() { return this.lok.getEditMode(this.docPtr) } enableEditMode() { try { if (this.lok.getEditMode(this.docPtr) === 1) return this.createResult({ editMode: 1 }); this.lok.postUnoCommand(this.docPtr, ".uno:Edit"); let t = this.lok.getEditMode(this.docPtr); return { success: !0, verified: t === 1, data: { editMode: t } } } catch (e) { return this.createErrorResult(`Failed to enable edit mode: ${String(e)}`) } } undo() { try { return this.lok.postUnoCommand(this.docPtr, ".uno:Undo"), this.createResult(void 0) } catch (e) { return this.createErrorResult(`Undo failed: ${String(e)}`) } } redo() { try { return this.lok.postUnoCommand(this.docPtr, ".uno:Redo"), this.createResult(void 0) } catch (e) { return this.createErrorResult(`Redo failed: ${String(e)}`) } } find(e, t) { try { let r = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.Backward": { type: "boolean", value: !1 }, "SearchItem.SearchAll": { type: "boolean", value: !0 }, "SearchItem.MatchCase": { type: "boolean", value: t?.caseSensitive ?? !1 }, "SearchItem.WordOnly": { type: "boolean", value: t?.wholeWord ?? !1 } }); this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", r); let n = this.lok.getTextSelection(this.docPtr, "text/plain"), o = n !== null && n.length > 0; return this.createResult({ matches: o ? 1 : 0, firstMatch: o ? { x: 0, y: 0 } : void 0 }) } catch (r) { return this.createErrorResult(`Find failed: ${String(r)}`) } } findAndReplaceAll(e, t, r) { try { let n = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: 3 }, "SearchItem.MatchCase": { type: "boolean", value: r?.caseSensitive ?? !1 }, "SearchItem.WordOnly": { type: "boolean", value: r?.wholeWord ?? !1 } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", n), this.createResult({ replacements: -1 }) } catch (n) { return this.createErrorResult(`Replace failed: ${String(n)}`) } } getStateChanges() { try { let e = this.lok.pollStateChanges(); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to poll state changes: ${String(e)}`) } } flushAndPollState() { try { this.lok.flushCallbacks(this.docPtr); let e = this.lok.pollStateChanges(); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to flush and poll state: ${String(e)}`) } } clearCallbackQueue() { this.lok.clearCallbackQueue(); } select(e) { try { let t = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.createResult({ selected: t || "" }) } catch (t) { return this.createErrorResult(`Select failed: ${String(t)}`) } } getSelection() { try { let e = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.createResult({ text: e || "", range: { type: "text", start: { paragraph: 0, character: 0 } } }) } catch (e) { return this.createErrorResult(`GetSelection failed: ${String(e)}`) } } clearSelection() { try { return this.lok.resetSelection(this.docPtr), this.createResult(void 0) } catch (e) { return this.createErrorResult(`ClearSelection failed: ${String(e)}`) } } createResult(e) { return { success: true, verified: true, data: e } } createErrorResult(e, t) { return { success: false, verified: false, error: e, suggestion: t } } createResultWithTruncation(e, t) { return { success: true, verified: true, data: e, truncated: t } } truncateContent(e, t) { let r = t ?? this.options.maxResponseChars, n = e.length; if (n <= r) return { content: e, truncated: false, original: n, returned: n }; let o = e.slice(0, r), s = o.lastIndexOf(" "); return s > r * .8 && (o = o.slice(0, s)), { content: o, truncated: true, original: n, returned: o.length } } truncateArray(e, t, r) { let n = e.length, o = 0, s = 0; for (let i of e) { let a = r(i); if (o + a.length > t) break; o += a.length, s++; } return { items: e.slice(0, s), truncated: s < n, original: n, returned: s } } a1ToRowCol(e) { let t = e.match(/^([A-Z]+)(\d+)$/i); if (!t) throw new Error(`Invalid A1 notation: ${e}`); let r = t[1].toUpperCase(), n = t[2], o = 0; for (let i = 0; i < r.length; i++)o = o * 26 + (r.charCodeAt(i) - 64); return o -= 1, { row: parseInt(n, 10) - 1, col: o } } rowColToA1(e, t) { let r = "", n = t + 1; for (; n > 0;) { let o = (n - 1) % 26; r = String.fromCharCode(65 + o) + r, n = Math.floor((n - 1) / 26); } return `${r}${e + 1}` } normalizeCellRef(e) { return typeof e == "string" ? this.a1ToRowCol(e) : e } setInputPath(e) { this.inputPath = e; } isOpen() { return this.docPtr !== 0 } }; var H = class extends I { cachedParagraphs = null; getDocumentType() { return "writer" } getStructure(e) { try { let t = this.getParagraphsInternal(), r = e?.maxResponseChars ?? this.options.maxResponseChars, n = t.map((i, a) => ({ index: a, preview: i.slice(0, 100) + (i.length > 100 ? "..." : ""), style: "Normal", charCount: i.length })), o = this.truncateArray(n, r, i => JSON.stringify(i)), s = { type: "writer", paragraphs: o.items, pageCount: this.lok.documentGetParts(this.docPtr), wordCount: t.join(" ").split(/\s+/).filter(i => i.length > 0).length }; return o.truncated ? this.createResultWithTruncation(s, { original: o.original, returned: o.returned, message: `Showing ${o.returned} of ${o.original} paragraphs. Use getParagraphs(start, count) to paginate.` }) : this.createResult(s) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getParagraph(e) { try { let t = this.getParagraphsInternal(); if (e < 0 || e >= t.length) return this.createErrorResult(`Paragraph index ${e} out of range (0-${t.length - 1})`, "Use getStructure() to see available paragraphs"); let r = t[e]; return this.createResult({ index: e, text: r, style: "Normal", charCount: r.length }) } catch (t) { return this.createErrorResult(`Failed to get paragraph: ${String(t)}`) } } getParagraphs(e, t) { try { let r = this.getParagraphsInternal(); if (e < 0 || e >= r.length) return this.createErrorResult(`Start index ${e} out of range`, `Valid range: 0-${r.length - 1}`); let n = Math.min(e + t, r.length), o = r.slice(e, n).map((s, i) => ({ index: e + i, text: s, style: "Normal", charCount: s.length })); return this.createResult(o) } catch (r) { return this.createErrorResult(`Failed to get paragraphs: ${String(r)}`) } } insertParagraph(e, t) { try { let r = this.getParagraphsInternal(), n = t?.afterIndex !== void 0 ? t.afterIndex + 1 : r.length; n > 0 && n <= r.length && this.lok.postUnoCommand(this.docPtr, ".uno:GoToEndOfDoc"), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPara"); let o = JSON.stringify({ Text: { type: "string", value: e } }); if (this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", o), t?.style && t.style !== "Normal") { let d = { "Heading 1": "Heading 1", "Heading 2": "Heading 2", "Heading 3": "Heading 3", List: "List" }[t.style]; if (d) { let h = JSON.stringify({ Template: { type: "string", value: d }, Family: { type: "short", value: 2 } }); this.lok.postUnoCommand(this.docPtr, ".uno:StyleApply", h); } } return this.cachedParagraphs = null, { success: !0, verified: this.getParagraphsInternal().length > r.length, data: { index: n } } } catch (r) { return this.createErrorResult(`Failed to insert paragraph: ${String(r)}`) } } replaceParagraph(e, t) { try { let r = this.getParagraphsInternal(); if (e < 0 || e >= r.length) return this.createErrorResult(`Paragraph index ${e} out of range`, `Valid range: 0-${r.length - 1}`); let n = r[e], o = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: n }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: 2 } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", o), this.cachedParagraphs = null, this.createResult({ oldText: n }) } catch (r) { return this.createErrorResult(`Failed to replace paragraph: ${String(r)}`) } } deleteParagraph(e) { try { let t = this.getParagraphsInternal(); if (e < 0 || e >= t.length) return this.createErrorResult(`Paragraph index ${e} out of range`, `Valid range: 0-${t.length - 1}`); let r = t[e], n = this.replaceParagraph(e, ""); return n.success ? this.createResult({ deletedText: r }) : this.createErrorResult(n.error || "Failed to delete") } catch (t) { return this.createErrorResult(`Failed to delete paragraph: ${String(t)}`) } } insertText(e, t) { try { let r = JSON.stringify({ Text: { type: "string", value: e } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", r), this.cachedParagraphs = null, this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert text: ${String(r)}`) } } deleteText(e, t) { try { let r = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.lok.postUnoCommand(this.docPtr, ".uno:Delete"), this.cachedParagraphs = null, this.createResult({ deleted: r || "" }) } catch (r) { return this.createErrorResult(`Failed to delete text: ${String(r)}`) } } replaceText(e, t, r) { try { let n = r?.all ? 3 : 2, o = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: n } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", o), this.cachedParagraphs = null, this.createResult({ replacements: -1 }) } catch (n) { return this.createErrorResult(`Failed to replace text: ${String(n)}`) } } formatText(e, t) { try { if (t.bold !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Bold"), t.italic !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Italic"), t.underline !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Underline"), t.fontSize !== void 0) { let r = JSON.stringify({ FontHeight: { type: "float", value: t.fontSize } }); this.lok.postUnoCommand(this.docPtr, ".uno:FontHeight", r); } if (t.fontName !== void 0) { let r = JSON.stringify({ CharFontName: { type: "string", value: t.fontName } }); this.lok.postUnoCommand(this.docPtr, ".uno:CharFontName", r); } return this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to format text: ${String(r)}`) } } getFormat(e) { try { this.lok.clearCallbackQueue(), this.lok.postUnoCommand(this.docPtr, ".uno:CharRightSel"), this.lok.flushCallbacks(this.docPtr), this.lok.postUnoCommand(this.docPtr, ".uno:CharLeft"), this.lok.flushCallbacks(this.docPtr); let t = this.lok.pollStateChanges(), r = {}, n = t.get(".uno:Bold"); n !== void 0 && (r.bold = n === "true"); let o = t.get(".uno:Italic"); o !== void 0 && (r.italic = o === "true"); let s = t.get(".uno:Underline"); s !== void 0 && (r.underline = s === "true"); let i = t.get(".uno:FontHeight"); if (i !== void 0) { let d = parseFloat(i); isNaN(d) || (r.fontSize = d); } let a = t.get(".uno:CharFontName"); return a !== void 0 && a.length > 0 && (r.fontName = a), this.createResult(r) } catch (t) { return this.createErrorResult(`Failed to get format: ${String(t)}`) } } getSelectionFormat() { try { let e = this.lok.pollStateChanges(); if (e.size === 0) { this.lok.clearCallbackQueue(), this.lok.postUnoCommand(this.docPtr, ".uno:SelectWord"), this.lok.flushCallbacks(this.docPtr); let t = this.lok.pollStateChanges(); return this.createResult(t) } return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get selection format: ${String(e)}`) } } getParagraphsInternal() { if (this.cachedParagraphs) return this.cachedParagraphs; let e = this.lok.getAllText(this.docPtr); return e ? (this.cachedParagraphs = e.split(/\n\n|\r\n\r\n/).map(t => t.trim()).filter(t => t.length > 0), this.cachedParagraphs) : [] } }; var j = class extends I { getDocumentType() { return "calc" } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.lok.getPartName(this.docPtr, o) || `Sheet${o + 1}`, i = this.lok.getDataArea(this.docPtr, o); r.push({ index: o, name: s, usedRange: i.col > 0 && i.row > 0 ? `A1:${this.rowColToA1(i.row - 1, i.col - 1)}` : "A1", rowCount: i.row, colCount: i.col }); } let n = { type: "calc", sheets: r }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getSheetNames() { try { let e = this.lok.documentGetParts(this.docPtr), t = []; for (let r = 0; r < e; r++) { let n = this.lok.getPartName(this.docPtr, r) || `Sheet${r + 1}`; t.push(n); } return this.createResult(t) } catch (e) { return this.createErrorResult(`Failed to get sheet names: ${String(e)}`) } } getCell(e, t) { try { this.selectSheet(t); let { row: r, col: n } = this.normalizeCellRef(e), o = this.rowColToA1(r, n); this.goToCell(o); let s = this.getCellValueInternal(), i = this.getCellFormulaInternal(); return this.createResult({ address: o, value: s, formula: i || void 0 }) } catch (r) { return this.createErrorResult(`Failed to get cell: ${String(r)}`) } } getCells(e, t, r) { try { this.selectSheet(t); let { startRow: n, startCol: o, endRow: s, endCol: i } = this.normalizeRangeRef(e), a = r?.maxResponseChars ?? this.options.maxResponseChars, d = [], h = 0, m = !1; for (let u = n; u <= s && !m; u++) { let g = []; for (let f = o; f <= i && !m; f++) { let P = this.rowColToA1(u, f); this.goToCell(P); let p = this.getCellValueInternal(), O = { address: P, value: p }, _ = JSON.stringify(O); if (h + _.length > a) { m = !0; break } h += _.length, g.push(O); } g.length > 0 && d.push(g); } return m ? this.createResultWithTruncation(d, { original: (s - n + 1) * (i - o + 1), returned: d.reduce((u, g) => u + g.length, 0), message: "Range truncated due to size. Use smaller ranges to paginate." }) : this.createResult(d) } catch (n) { return this.createErrorResult(`Failed to get cells: ${String(n)}`) } } setCellValue(e, t, r) { try { this.selectSheet(r); let { row: n, col: o } = this.normalizeCellRef(e), s = this.rowColToA1(n, o); this.goToCell(s); let i = this.getCellValueInternal(), a = typeof t == "number" ? t.toString() : t, d = JSON.stringify({ StringName: { type: "string", value: a } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", d); let h = this.getCellValueInternal(), m = typeof t == "number" ? t.toString() : t; return { success: !0, verified: h === m || h === t, data: { oldValue: i, newValue: h } } } catch (n) { return this.createErrorResult(`Failed to set cell value: ${String(n)}`) } } setCellFormula(e, t, r) { try { this.selectSheet(r); let { row: n, col: o } = this.normalizeCellRef(e), s = this.rowColToA1(n, o); this.goToCell(s); let i = JSON.stringify({ StringName: { type: "string", value: t } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", i); let a = this.getCellValueInternal(); return this.createResult({ calculatedValue: a }) } catch (n) { return this.createErrorResult(`Failed to set formula: ${String(n)}`) } } setCells(e, t, r) { try { this.selectSheet(r); let { startRow: n, startCol: o } = this.normalizeRangeRef(e), s = 0; for (let i = 0; i < t.length; i++) { let a = t[i]; if (a) for (let d = 0; d < a.length; d++) { let h = a[d]; if (h == null) continue; let m = this.rowColToA1(n + i, o + d); this.goToCell(m); let u = typeof h == "number" ? h.toString() : String(h), g = JSON.stringify({ StringName: { type: "string", value: u } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", g), s++; } } return this.createResult({ cellsUpdated: s }) } catch (n) { return this.createErrorResult(`Failed to set cells: ${String(n)}`) } } clearCell(e, t) { try { this.selectSheet(t); let { row: r, col: n } = this.normalizeCellRef(e), o = this.rowColToA1(r, n); this.goToCell(o); let s = this.getCellValueInternal(); return this.lok.postUnoCommand(this.docPtr, ".uno:ClearContents"), this.createResult({ oldValue: s }) } catch (r) { return this.createErrorResult(`Failed to clear cell: ${String(r)}`) } } clearRange(e, t) { try { this.selectSheet(t); let r = this.normalizeRangeToString(e); this.goToCell(r), this.lok.postUnoCommand(this.docPtr, ".uno:ClearContents"); let { startRow: n, startCol: o, endRow: s, endCol: i } = this.normalizeRangeRef(e), a = (s - n + 1) * (i - o + 1); return this.createResult({ cellsCleared: a }) } catch (r) { return this.createErrorResult(`Failed to clear range: ${String(r)}`) } } insertRow(e, t) { try { return this.selectSheet(t), this.goToCell(this.rowColToA1(e + 1, 0)), this.lok.postUnoCommand(this.docPtr, ".uno:InsertRows"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert row: ${String(r)}`) } } insertColumn(e, t) { try { this.selectSheet(t); let r = typeof e == "string" ? this.a1ToRowCol(e + "1").col + 1 : e + 1; return this.goToCell(this.rowColToA1(0, r)), this.lok.postUnoCommand(this.docPtr, ".uno:InsertColumns"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert column: ${String(r)}`) } } deleteRow(e, t) { try { return this.selectSheet(t), this.goToCell(this.rowColToA1(e, 0)), this.lok.postUnoCommand(this.docPtr, ".uno:DeleteRows"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete row: ${String(r)}`) } } deleteColumn(e, t) { try { this.selectSheet(t); let r = typeof e == "string" ? this.a1ToRowCol(e + "1").col : e; return this.goToCell(this.rowColToA1(0, r)), this.lok.postUnoCommand(this.docPtr, ".uno:DeleteColumns"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete column: ${String(r)}`) } } formatCells(e, t, r) { try { this.selectSheet(r); let n = this.normalizeRangeToString(e); if (this.goToCell(n), t.bold !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Bold"), t.numberFormat !== void 0) { let o = JSON.stringify({ NumberFormatValue: { type: "string", value: t.numberFormat } }); this.lok.postUnoCommand(this.docPtr, ".uno:NumberFormatValue", o); } if (t.backgroundColor !== void 0) { let o = JSON.stringify({ BackgroundColor: { type: "long", value: this.hexToNumber(t.backgroundColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:BackgroundColor", o); } return this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to format cells: ${String(n)}`) } } addSheet(e) { try { let t = JSON.stringify({ Name: { type: "string", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:Insert", t); let r = this.lok.documentGetParts(this.docPtr); return this.createResult({ index: r - 1 }) } catch (t) { return this.createErrorResult(`Failed to add sheet: ${String(t)}`) } } renameSheet(e, t) { try { this.selectSheet(e); let r = JSON.stringify({ Name: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:RenameTable", r), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to rename sheet: ${String(r)}`) } } deleteSheet(e) { try { return this.selectSheet(e), this.lok.postUnoCommand(this.docPtr, ".uno:Remove"), this.createResult(void 0) } catch (t) { return this.createErrorResult(`Failed to delete sheet: ${String(t)}`) } } selectSheet(e) { if (e === void 0) return; let t = typeof e == "number" ? e : this.getSheetIndexByName(e); t >= 0 && this.lok.documentSetPart(this.docPtr, t); } getSheetIndexByName(e) { let t = this.lok.documentGetParts(this.docPtr); for (let r = 0; r < t; r++)if (this.lok.getPartName(this.docPtr, r) === e) return r; return -1 } goToCell(e) { let t = JSON.stringify({ ToPoint: { type: "string", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:GoToCell", t); } getCellValueInternal() { let e = this.lok.getTextSelection(this.docPtr, "text/plain"); if (!e) return null; let t = parseFloat(e); return !isNaN(t) && e.trim() === t.toString() ? t : e.toLowerCase() === "true" ? true : e.toLowerCase() === "false" ? false : e } getCellFormulaInternal() { let e = this.lok.getCommandValues(this.docPtr, ".uno:GetFormulaBarText"); if (!e) return null; try { return JSON.parse(e).value ?? null } catch { return null } } normalizeRangeRef(e) { if (typeof e == "string") { let n = e.split(":"), o = this.a1ToRowCol(n[0]), s = n[1] ? this.a1ToRowCol(n[1]) : o; return { startRow: o.row, startCol: o.col, endRow: s.row, endCol: s.col } } let t = this.normalizeCellRef(e.start), r = this.normalizeCellRef(e.end); return { startRow: t.row, startCol: t.col, endRow: r.row, endCol: r.col } } normalizeRangeToString(e) { if (typeof e == "string") return e; let t = this.normalizeCellRef(e.start), r = this.normalizeCellRef(e.end); return `${this.rowColToA1(t.row, t.col)}:${this.rowColToA1(r.row, r.col)}` } hexToNumber(e) { return parseInt(e.replace("#", ""), 16) } }; var J = class extends I { getDocumentType() { return "impress" } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.getSlideInfoInternal(o); r.push(s); } let n = { type: "impress", slides: r, slideCount: t }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= t) return this.createErrorResult(`Invalid slide index: ${e}. Valid range: 0-${t - 1}`, "Use getStructure() to see available slides"); this.lok.documentSetPart(this.docPtr, e); let r = this.lok.getAllText(this.docPtr) || "", n = this.parseTextFrames(r), o = { index: e, title: n.find(s => s.type === "title")?.text, textFrames: n, hasNotes: !1 }; return this.createResult(o) } catch (t) { return this.createErrorResult(`Failed to get slide: ${String(t)}`) } } getSlideCount() { try { let e = this.lok.documentGetParts(this.docPtr); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get slide count: ${String(e)}`) } } addSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); e?.afterSlide !== void 0 ? this.lok.documentSetPart(this.docPtr, e.afterSlide) : this.lok.documentSetPart(this.docPtr, t - 1), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPage"), e?.layout && this.applySlideLayout(e.layout); let r = e?.afterSlide !== void 0 ? e.afterSlide + 1 : t; return { success: !0, verified: this.lok.documentGetParts(this.docPtr) > t, data: { index: r } } } catch (t) { return this.createErrorResult(`Failed to add slide: ${String(t)}`) } } deleteSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); return t <= 1 ? this.createErrorResult("Cannot delete the last slide", "A presentation must have at least one slide") : e < 0 || e >= t ? this.createErrorResult(`Invalid slide index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DeletePage"), this.createResult(void 0)) } catch (t) { return this.createErrorResult(`Failed to delete slide: ${String(t)}`) } } duplicateSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= t ? this.createErrorResult(`Invalid slide index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DuplicatePage"), this.createResult({ newIndex: e + 1 })) } catch (t) { return this.createErrorResult(`Failed to duplicate slide: ${String(t)}`) } } moveSlide(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r || t < 0 || t >= r) return this.createErrorResult(`Invalid slide indices. Valid range: 0-${r - 1}`, "Check slide indices are within bounds"); if (e === t) return this.createErrorResult("Source and destination are the same", "Provide different indices to move"); this.lok.documentSetPart(this.docPtr, e); let n = JSON.stringify({ Position: { type: "long", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:MovePageFirst", n), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to move slide: ${String(r)}`) } } setSlideTitle(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let n = this.lok.getAllText(this.docPtr) || "", s = this.parseTextFrames(n).find(a => a.type === "title")?.text; this.lok.postUnoCommand(this.docPtr, ".uno:SelectAll"); let i = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", i), this.createResult({ oldTitle: s }) } catch (r) { return this.createErrorResult(`Failed to set slide title: ${String(r)}`) } } setSlideBody(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let n = this.lok.getAllText(this.docPtr) || "", s = this.parseTextFrames(n).find(a => a.type === "body")?.text; this.lok.postUnoCommand(this.docPtr, ".uno:NextObject"); let i = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", i), this.createResult({ oldBody: s }) } catch (r) { return this.createErrorResult(`Failed to set slide body: ${String(r)}`) } } setSlideNotes(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:NotesMode"); let n = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", n), this.lok.postUnoCommand(this.docPtr, ".uno:NormalViewMode"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to set slide notes: ${String(r)}`) } } setSlideLayout(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= r ? this.createErrorResult(`Invalid slide index: ${e}`) : (this.lok.documentSetPart(this.docPtr, e), this.applySlideLayout(t), this.createResult(void 0)) } catch (r) { return this.createErrorResult(`Failed to set slide layout: ${String(r)}`) } } getSlideInfoInternal(e) { this.lok.documentSetPart(this.docPtr, e); let t = this.lok.getAllText(this.docPtr) || "", r = this.parseTextFrames(t), n = r.find(o => o.type === "title"); return { index: e, title: n?.text, layout: this.detectLayout(r), textFrameCount: r.length } } parseTextFrames(e) { let t = e.split(/\n\n+/).filter(n => n.trim()), r = []; return t.forEach((n, o) => { let s = o === 0 ? "title" : o === 1 ? "body" : "other"; r.push({ index: o, type: s, text: n.trim(), bounds: { x: 0, y: 0, width: 0, height: 0 } }); }), r } detectLayout(e) { return e.length === 0 ? "blank" : e.length === 1 && e[0]?.type === "title" ? "title" : e.length >= 2 ? "titleContent" : "blank" } applySlideLayout(e) { let r = { blank: 0, title: 1, titleContent: 2, twoColumn: 3 }[e] ?? 0, n = JSON.stringify({ WhatLayout: { type: "long", value: r } }); this.lok.postUnoCommand(this.docPtr, ".uno:AssignLayout", n); } }; var X = class extends I { isImportedPdf = false; getDocumentType() { return "draw" } setImportedPdf(e) { this.isImportedPdf = e; } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.getPageInfoInternal(o); r.push(s); } let n = { type: "draw", pages: r, pageCount: t, isImportedPdf: this.isImportedPdf }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getPage(e) { try { let t = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= t) return this.createErrorResult(`Invalid page index: ${e}. Valid range: 0-${t - 1}`, "Use getStructure() to see available pages"); this.lok.documentSetPart(this.docPtr, e); let r = this.lok.documentGetDocumentSize(this.docPtr), n = this.getShapesOnPage(), o = { index: e, shapes: n, size: { width: r.width, height: r.height } }; return this.createResult(o) } catch (t) { return this.createErrorResult(`Failed to get page: ${String(t)}`) } } getPageCount() { try { let e = this.lok.documentGetParts(this.docPtr); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get page count: ${String(e)}`) } } addPage(e) { try { let t = this.lok.documentGetParts(this.docPtr); e?.afterPage !== void 0 ? this.lok.documentSetPart(this.docPtr, e.afterPage) : this.lok.documentSetPart(this.docPtr, t - 1), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPage"); let r = e?.afterPage !== void 0 ? e.afterPage + 1 : t; return this.createResult({ index: r }) } catch (t) { return this.createErrorResult(`Failed to add page: ${String(t)}`) } } deletePage(e) { try { let t = this.lok.documentGetParts(this.docPtr); return t <= 1 ? this.createErrorResult("Cannot delete the last page", "A drawing document must have at least one page") : e < 0 || e >= t ? this.createErrorResult(`Invalid page index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DeletePage"), this.createResult(void 0)) } catch (t) { return this.createErrorResult(`Failed to delete page: ${String(t)}`) } } duplicatePage(e) { try { let t = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= t ? this.createErrorResult(`Invalid page index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DuplicatePage"), this.createResult({ newIndex: e + 1 })) } catch (t) { return this.createErrorResult(`Failed to duplicate page: ${String(t)}`) } } addShape(e, t, r, n) { try { let o = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= o) return this.createErrorResult(`Invalid page index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let s = this.getShapeCommand(t), i = JSON.stringify({ X: { type: "long", value: r.x }, Y: { type: "long", value: r.y }, Width: { type: "long", value: r.width }, Height: { type: "long", value: r.height } }); if (this.lok.postUnoCommand(this.docPtr, s, i), n?.text) { let a = JSON.stringify({ Text: { type: "string", value: n.text } }); this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", a); } if (n?.fillColor) { let a = JSON.stringify({ FillColor: { type: "long", value: this.hexToNumber(n.fillColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:FillColor", a); } if (n?.lineColor) { let a = JSON.stringify({ LineColor: { type: "long", value: this.hexToNumber(n.lineColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:XLineColor", a); } return this.createResult({ shapeIndex: 0 }) } catch (o) { return this.createErrorResult(`Failed to add shape: ${String(o)}`) } } addLine(e, t, r, n) { try { let o = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= o) return this.createErrorResult(`Invalid page index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let s = JSON.stringify({ StartX: { type: "long", value: t.x }, StartY: { type: "long", value: t.y }, EndX: { type: "long", value: r.x }, EndY: { type: "long", value: r.y } }); if (this.lok.postUnoCommand(this.docPtr, ".uno:Line", s), n?.lineColor) { let i = JSON.stringify({ LineColor: { type: "long", value: this.hexToNumber(n.lineColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:XLineColor", i); } if (n?.lineWidth) { let i = JSON.stringify({ LineWidth: { type: "long", value: n.lineWidth } }); this.lok.postUnoCommand(this.docPtr, ".uno:LineWidth", i); } return this.createResult({ shapeIndex: 0 }) } catch (o) { return this.createErrorResult(`Failed to add line: ${String(o)}`) } } deleteShape(e, t) { try { return this.lok.documentSetPart(this.docPtr, e), this.selectShape(t), this.lok.postUnoCommand(this.docPtr, ".uno:Delete"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete shape: ${String(r)}`) } } setShapeText(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t), this.lok.postUnoCommand(this.docPtr, ".uno:EnterGroup"), this.lok.postUnoCommand(this.docPtr, ".uno:SelectAll"); let n = JSON.stringify({ Text: { type: "string", value: r } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", n), this.lok.postUnoCommand(this.docPtr, ".uno:LeaveGroup"), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to set shape text: ${String(n)}`) } } moveShape(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t); let n = JSON.stringify({ X: { type: "long", value: r.x }, Y: { type: "long", value: r.y } }); return this.lok.postUnoCommand(this.docPtr, ".uno:SetObjectPosition", n), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to move shape: ${String(n)}`) } } resizeShape(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t); let n = JSON.stringify({ Width: { type: "long", value: r.width }, Height: { type: "long", value: r.height } }); return this.lok.postUnoCommand(this.docPtr, ".uno:Size", n), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to resize shape: ${String(n)}`) } } getPageInfoInternal(e) { this.lok.documentSetPart(this.docPtr, e); let t = this.lok.documentGetDocumentSize(this.docPtr), r = this.getShapesOnPage(); return { index: e, shapeCount: r.length, size: { width: t.width, height: t.height } } } getShapesOnPage() { let e = this.lok.getAllText(this.docPtr) || ""; return e.trim() ? [{ index: 0, type: "text", text: e, bounds: { x: 0, y: 0, width: 0, height: 0 } }] : [] } selectShape(e) { let t = JSON.stringify({ Index: { type: "long", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:SelectObject", t); } getShapeCommand(e) { return { rectangle: ".uno:Rect", ellipse: ".uno:Ellipse", line: ".uno:Line", text: ".uno:Text", image: ".uno:InsertGraphic", group: ".uno:FormatGroup", other: ".uno:Rect" }[e] } hexToNumber(e) { return parseInt(e.replace("#", ""), 16) } }; var Pe = 0, Oe = 1, _e = 2, ke = 3; function le(l, e, t) { let r = l.documentGetDocumentType(e); switch (r) { case Pe: return new H(l, e, t); case Oe: return new j(l, e, t); case _e: return new J(l, e, t); case ke: return new X(l, e, t); default: throw new Error(`Unsupported document type: ${r}`) } } function be(l) { return { 0: "INVALIDATE_TILES", 1: "INVALIDATE_VISIBLE_CURSOR", 2: "TEXT_SELECTION", 3: "TEXT_SELECTION_START", 4: "TEXT_SELECTION_END", 5: "CURSOR_VISIBLE", 6: "GRAPHIC_SELECTION", 7: "HYPERLINK_CLICKED", 8: "STATE_CHANGED", 9: "STATUS_INDICATOR_START", 10: "STATUS_INDICATOR_SET_VALUE", 11: "STATUS_INDICATOR_FINISH", 12: "SEARCH_NOT_FOUND", 13: "DOCUMENT_SIZE_CHANGED", 14: "SET_PART", 15: "SEARCH_RESULT_SELECTION", 16: "UNO_COMMAND_RESULT", 17: "CELL_CURSOR", 18: "MOUSE_POINTER", 19: "CELL_FORMULA", 20: "DOCUMENT_PASSWORD", 21: "DOCUMENT_PASSWORD_TO_MODIFY", 22: "CONTEXT_MENU", 23: "INVALIDATE_VIEW_CURSOR", 24: "TEXT_VIEW_SELECTION", 25: "CELL_VIEW_CURSOR", 26: "GRAPHIC_VIEW_SELECTION", 27: "VIEW_CURSOR_VISIBLE", 28: "VIEW_LOCK", 29: "REDLINE_TABLE_SIZE_CHANGED", 30: "REDLINE_TABLE_ENTRY_MODIFIED", 31: "COMMENT", 32: "INVALIDATE_HEADER", 33: "CELL_ADDRESS" }[l] || `UNKNOWN(${l})` } var Y = { nSize: 0, destroy: 4, documentLoad: 8, getError: 12, documentLoadWithOptions: 16, freeError: 20 }, ce = { nSize: 0, destroy: 4, saveAs: 8 }, Ce = new TextEncoder, ue = new TextDecoder, Q = class { module; lokPtr = 0; verbose; useShims; constructor(e, t = false) { this.module = e, this.verbose = t, this.useShims = typeof this.module._lok_documentLoad == "function", this.useShims ? this.log("Using direct LOK shim exports") : this.log("Using vtable traversal (shims not available)"); } log(...e) { this.verbose && console.log("[LOK]", ...e); } get HEAPU8() { return this.module.HEAPU8 } get HEAPU32() { return this.module.HEAPU32 } get HEAP32() { return this.module.HEAP32 } allocString(e) { let t = Ce.encode(e + "\0"), r = this.module._malloc(t.length); return this.HEAPU8.set(t, r), r } readString(e) { if (e === 0) return null; let t = this.HEAPU8, r = e; for (; t[r] !== 0;)r++; let n = t.slice(e, r); return ue.decode(n) } readPtr(e) { return this.HEAPU32[e >> 2] || 0 } getFunc(e) { return this.module.wasmTable.get(e) } initialize(e = "/instdir/program") { this.log("Initializing with path:", e); let t = this.allocString(e); try { let r = this.module._libreofficekit_hook; if (typeof r != "function") throw new Error("libreofficekit_hook export not found on module"); if (this.lokPtr = r(t), this.lokPtr === 0) throw new Error("Failed to initialize LibreOfficeKit"); this.log("LOK initialized, ptr:", this.lokPtr); } finally { this.module._free(t); } } getError() { if (this.lokPtr === 0) return null; if (this.useShims && this.module._lok_getError) { let o = this.module._lok_getError(this.lokPtr); return this.readString(o) } let e = this.readPtr(this.lokPtr), t = this.readPtr(e + Y.getError); if (t === 0) return null; let n = this.getFunc(t)(this.lokPtr); return this.readString(n) } getVersionInfo() { return "LibreOffice WASM" } toFileUrl(e) { return e.startsWith("file://") ? e : "file://" + (e.startsWith("/") ? e : "/" + e) } documentLoad(e) { if (this.lokPtr === 0) throw new Error("LOK not initialized"); let t = this.toFileUrl(e); this.log("Loading document:", e, "->", t); let r = this.allocString(t); try { let n = Date.now(), o; if (this.useShims && this.module._lok_documentLoad) o = this.module._lok_documentLoad(this.lokPtr, r); else { let s = this.readPtr(this.lokPtr), i = this.readPtr(s + Y.documentLoad); o = this.getFunc(i)(this.lokPtr, r); } if (this.log("Document loaded in", Date.now() - n, "ms, ptr:", o), o === 0) { let s = this.getError(); throw new Error(`Failed to load document: ${s || "unknown error"}`) } return o } finally { this.module._free(r); } } documentLoadWithOptions(e, t) { if (this.lokPtr === 0) throw new Error("LOK not initialized"); let r = this.toFileUrl(e); this.log("Loading document with options:", e, "->", r, t); let n = this.allocString(r), o = this.allocString(t); try { let s; if (this.useShims && this.module._lok_documentLoadWithOptions) s = this.module._lok_documentLoadWithOptions(this.lokPtr, n, o); else { let i = this.readPtr(this.lokPtr), a = this.readPtr(i + Y.documentLoadWithOptions); if (a === 0) return this.documentLoad(e); s = this.getFunc(a)(this.lokPtr, n, o); } if (s === 0) { let i = this.getError(); throw new Error(`Failed to load document: ${i || "unknown error"}`) } return this.log("Document loaded, ptr:", s), s } finally { this.module._free(n), this.module._free(o); } } documentSaveAs(e, t, r, n = "") { if (e === 0) throw new Error("Invalid document pointer"); let o = this.toFileUrl(t); this.log("Saving document to:", t, "->", o, "format:", r); let s = this.allocString(o), i = this.allocString(r), a = this.allocString(n); try { let d; if (this.useShims && this.module._lok_documentSaveAs) d = this.module._lok_documentSaveAs(e, s, i, a); else { let h = this.readPtr(e), m = this.readPtr(h + ce.saveAs); d = this.getFunc(m)(e, s, i, a); } if (this.log("Save result:", d), d === 0) throw new Error("Failed to save document") } finally { this.module._free(s), this.module._free(i), this.module._free(a); } } documentDestroy(e) { if (e === 0) return; if (this.useShims && this.module._lok_documentDestroy) { this.module._lok_documentDestroy(e), this.log("Document destroyed (via shim)"); return } let t = this.readPtr(e), r = this.readPtr(t + ce.destroy); r !== 0 && (this.getFunc(r)(e), this.log("Document destroyed (via vtable)")); } destroy() { if (this.lokPtr !== 0) { try { if (this.useShims && this.module._lok_destroy) this.module._lok_destroy(this.lokPtr), this.log("LOK destroyed (via shim)"); else { let e = this.readPtr(this.lokPtr), t = this.readPtr(e + Y.destroy); t !== 0 && (this.getFunc(t)(this.lokPtr), this.log("LOK destroyed (via vtable)")); } } catch (e) { this.log("LOK destroy error (ignored):", e); } this.lokPtr = 0; } } isInitialized() { return this.lokPtr !== 0 } isUsingShims() { return this.useShims } documentGetParts(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetParts ? this.module._lok_documentGetParts(e) : (this.log("documentGetParts: shim not available"), 0) } documentGetPart(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetPart ? this.module._lok_documentGetPart(e) : (this.log("documentGetPart: shim not available"), 0) } documentSetPart(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetPart) { this.module._lok_documentSetPart(e, t); return } this.log("documentSetPart: shim not available"); } documentGetDocumentType(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetDocumentType ? this.module._lok_documentGetDocumentType(e) : (this.log("documentGetDocumentType: shim not available"), 0) } documentGetDocumentSize(e) { if (this.log(`documentGetDocumentSize called with docPtr: ${e}`), e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetDocumentSize) { let t = this.module._malloc(8); try { this.module._lok_documentGetDocumentSize(e, t, t + 4); let r = this.HEAP32[t >> 2] ?? 0, n = this.HEAP32[t + 4 >> 2] ?? 0; return this.log(`documentGetDocumentSize: ${r}x${n} twips`), { width: r, height: n } } finally { this.module._free(t); } } return this.log("documentGetDocumentSize: shim not available"), { width: 0, height: 0 } } documentInitializeForRendering(e, t = "") { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentInitializeForRendering) { let r = this.allocString(t); try { this.module._lok_documentInitializeForRendering(e, r); } finally { this.module._free(r); } return } this.log("documentInitializeForRendering: shim not available"); } documentPaintTile(e, t, r, n, o, s, i) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPaintTile) { let a = t * r * 4, d = this.module._malloc(a); if (d === 0) throw new Error(`Failed to allocate ${a} bytes for tile buffer`); try { this.module._lok_documentPaintTile(e, d, t, r, n, o, s, i); let h = new Uint8Array(a); return h.set(this.HEAPU8.subarray(d, d + a)), h } finally { this.module._free(d); } } return this.log("documentPaintTile: shim not available"), new Uint8Array(0) } documentGetTileMode(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetTileMode ? this.module._lok_documentGetTileMode(e) : (this.log("documentGetTileMode: shim not available"), 0) } renderPage(e, t, r, n = 0, o = false) { this.documentInitializeForRendering(e); let s = this.documentGetDocumentType(e); if (s === 2 || s === 3) { console.log(`[LOK] Setting part to ${t} for presentation/drawing`), this.documentSetPart(e, t); let p = this.documentGetPart(e); console.log(`[LOK] Current part after setPart: ${p}`), o || (this.setEditMode(e, 0), console.log("[LOK] Set edit mode to 0 (view mode) for presentation rendering")); } let i = this.documentGetDocumentSize(e); if (this.log("Document size (twips):", i), i.width === 0 || i.height === 0) throw new Error("Failed to get document size"); let a = 0, d = 0, h = i.width, m = i.height; if (s === 0 || s === 1) { let p = this.getPartPageRectangles(e); if (p) { let _ = this.parsePageRectangles(p)[t]; _ && (a = _.x, d = _.y, h = _.width, m = _.height, this.log(`Page ${t} rectangle:`, _)); } } let u = m / h, g = r, f = n > 0 ? n : Math.round(r * u); console.log(`[LOK] Calling paintTile: ${g}x${f} from tile pos (${a}, ${d}) size (${h}x${m})`); let P = this.documentPaintTile(e, g, f, a, d, h, m); return console.log(`[LOK] paintTile returned ${P.length} bytes`), { data: P, width: g, height: f } } renderPageFullQuality(e, t, r = 150, n, o = false) { this.documentInitializeForRendering(e); let s = this.documentGetDocumentType(e); (s === 2 || s === 3) && (this.log(`Setting part to ${t} for presentation/drawing`), this.documentSetPart(e, t), o || (this.setEditMode(e, 0), this.log("Set edit mode to 0 (view mode) for presentation rendering"))); let i = this.documentGetDocumentSize(e); if (this.log("Document size (twips):", i), i.width === 0 || i.height === 0) throw new Error("Failed to get document size"); let a = 0, d = 0, h = i.width, m = i.height; if (s === 0 || s === 1) { let O = this.getPartPageRectangles(e); if (O) { let C = this.parsePageRectangles(O)[t]; C && (a = C.x, d = C.y, h = C.width, m = C.height, this.log(`Page ${t} rectangle:`, C)); } } let u = 1440, g = Math.round(h * r / u), f = Math.round(m * r / u), P = r; if (n && (g > n || f > n)) { let O = n / Math.max(g, f); g = Math.round(g * O), f = Math.round(f * O), P = Math.round(r * O), this.log(`Capped dimensions to ${g}x${f} (effective DPI: ${P})`); } console.log(`[LOK] renderPageFullQuality: ${g}x${f} at ${P} DPI from tile (${a}, ${d}) size (${h}x${m}) twips`); let p = this.documentPaintTile(e, g, f, a, d, h, m); return console.log(`[LOK] renderPageFullQuality returned ${p.length} bytes`), { data: p, width: g, height: f, dpi: P } } getTextSelection(e, t = "text/plain;charset=utf-8") { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetTextSelection) { let r = this.allocString(t), n = this.module._malloc(4); try { let o = this.module._lok_documentGetTextSelection(e, r, n); if (o === 0) return null; let s = this.readString(o); return this.module._free(o), s } finally { this.module._free(r), this.module._free(n); } } return this.log("getTextSelection: shim not available"), null } setTextSelection(e, t, r, n) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetTextSelection) { this.module._lok_documentSetTextSelection(e, t, r, n); return } this.log("setTextSelection: shim not available"); } getSelectionType(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetSelectionType ? this.module._lok_documentGetSelectionType(e) : (this.log("getSelectionType: shim not available"), 0) } resetSelection(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentResetSelection) { this.module._lok_documentResetSelection(e); return } this.log("resetSelection: shim not available"); } postMouseEvent(e, t, r, n, o = 1, s = 1, i = 0) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostMouseEvent) { this.module._lok_documentPostMouseEvent(e, t, r, n, o, s, i); return } this.log("postMouseEvent: shim not available"); } postKeyEvent(e, t, r, n) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostKeyEvent) { this.module._lok_documentPostKeyEvent(e, t, r, n); return } this.log("postKeyEvent: shim not available"); } postUnoCommand(e, t, r = "{}", n = false) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostUnoCommand) { let o = this.allocString(t), s = this.allocString(r); try { this.module._lok_documentPostUnoCommand(e, o, s, n ? 1 : 0); } finally { this.module._free(o), this.module._free(s); } return } this.log("postUnoCommand: shim not available"); } getCommandValues(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetCommandValues) { let r = this.allocString(t); try { let n = this.module._lok_documentGetCommandValues(e, r); if (n === 0) return null; let o = this.readString(n); return this.module._free(n), o } finally { this.module._free(r); } } return this.log("getCommandValues: shim not available"), null } getPartPageRectangles(e) { if (this.log(`getPartPageRectangles called with docPtr: ${e}`), e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartPageRectangles) { this.log("getPartPageRectangles: using shim"); let t = this.module._lok_documentGetPartPageRectangles(e); if (this.log(`getPartPageRectangles: resultPtr=${t}`), t === 0) return null; let r = this.readString(t); return this.log(`getPartPageRectangles: result="${r?.slice(0, 100)}..."`), this.module._free(t), r } return this.log("getPartPageRectangles: shim not available"), null } getPartInfo(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartInfo) { let r = this.module._lok_documentGetPartInfo(e, t); if (r === 0) return null; let n = this.readString(r); return this.module._free(r), n } return this.log("getPartInfo: shim not available"), null } getPartName(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartName) { let r = this.module._lok_documentGetPartName(e, t); if (r === 0) return null; let n = this.readString(r); return this.module._free(r), n } return this.log("getPartName: shim not available"), null } paste(e, t, r) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPaste) { let n = this.allocString(t), o, s; if (typeof r == "string") { let i = new TextEncoder().encode(r); s = i.length, o = this.module._malloc(s), this.HEAPU8.set(i, o); } else s = r.length, o = this.module._malloc(s), this.HEAPU8.set(r, o); try { return this.module._lok_documentPaste(e, n, o, s) !== 0 } finally { this.module._free(n), this.module._free(o); } } return this.log("paste: shim not available"), false } setClientZoom(e, t, r, n, o) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetClientZoom) { this.module._lok_documentSetClientZoom(e, t, r, n, o); return } this.log("setClientZoom: shim not available"); } setClientVisibleArea(e, t, r, n, o) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetClientVisibleArea) { this.module._lok_documentSetClientVisibleArea(e, t, r, n, o); return } this.log("setClientVisibleArea: shim not available"); } getA11yFocusedParagraph(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetA11yFocusedParagraph) { let t = this.module._lok_documentGetA11yFocusedParagraph(e); if (t === 0) return null; let r = this.readString(t); return this.module._free(t), r } return this.log("getA11yFocusedParagraph: shim not available"), null } getA11yCaretPosition(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetA11yCaretPosition ? this.module._lok_documentGetA11yCaretPosition(e) : (this.log("getA11yCaretPosition: shim not available"), -1) } setAccessibilityState(e, t, r) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetAccessibilityState) { this.module._lok_documentSetAccessibilityState(e, t, r ? 1 : 0); return } this.log("setAccessibilityState: shim not available"); } getDataArea(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetDataArea) { let r = this.module._malloc(8), n = this.module._malloc(8); try { this.module._lok_documentGetDataArea(e, t, r, n); let o = this.HEAP32[r >> 2] ?? 0, s = this.HEAP32[n >> 2] ?? 0; return { col: o, row: s } } finally { this.module._free(r), this.module._free(n); } } return this.log("getDataArea: shim not available"), { col: 0, row: 0 } } getEditMode(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetEditMode ? this.module._lok_documentGetEditMode(e) : (this.log("getEditMode: shim not available"), 0) } setEditMode(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetEditMode) { this.log(`setEditMode: setting mode to ${t}`), this.module._lok_documentSetEditMode(e, t); return } this.log("setEditMode: shim not available"); } createView(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentCreateView) { let t = this.module._lok_documentCreateView(e); return this.log(`createView: created view ${t}`), t } return this.log("createView: shim not available"), -1 } createViewWithOptions(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentCreateViewWithOptions) { let r = this.allocString(t); try { let n = this.module._lok_documentCreateViewWithOptions(e, r); return this.log(`createViewWithOptions: created view ${n}`), n } finally { this.module._free(r); } } return this.log("createViewWithOptions: shim not available"), -1 } destroyView(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentDestroyView) { this.log(`destroyView: destroying view ${t}`), this.module._lok_documentDestroyView(e, t); return } this.log("destroyView: shim not available"); } setView(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetView) { this.log(`setView: setting active view to ${t}`), this.module._lok_documentSetView(e, t); return } this.log("setView: shim not available"); } getView(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetView ? this.module._lok_documentGetView(e) : (this.log("getView: shim not available"), -1) } getViewsCount(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetViewsCount ? this.module._lok_documentGetViewsCount(e) : (this.log("getViewsCount: shim not available"), 0) } enableSyncEvents() { this.useShims && this.module._lok_enableSyncEvents ? (this.module._lok_enableSyncEvents(), this.log("enableSyncEvents: Unipoll mode enabled")) : this.log("enableSyncEvents: shim not available"); } disableSyncEvents() { this.useShims && this.module._lok_disableSyncEvents ? (this.module._lok_disableSyncEvents(), this.log("disableSyncEvents: Unipoll mode disabled")) : this.log("disableSyncEvents: shim not available"); } registerCallback(e) { if (e === 0) throw new Error("Invalid document pointer"); this.useShims && this.module._lok_documentRegisterCallback ? (this.module._lok_documentRegisterCallback(e), this.log("registerCallback: callback registered")) : this.log("registerCallback: shim not available"); } unregisterCallback(e) { if (e === 0) throw new Error("Invalid document pointer"); this.useShims && this.module._lok_documentUnregisterCallback ? (this.module._lok_documentUnregisterCallback(e), this.log("unregisterCallback: callback unregistered")) : this.log("unregisterCallback: shim not available"); } hasCallbackEvents() { return this.useShims && this.module._lok_hasCallbackEvents ? this.module._lok_hasCallbackEvents() !== 0 : false } getCallbackEventCount() { return this.useShims && this.module._lok_getCallbackEventCount ? this.module._lok_getCallbackEventCount() : 0 } pollCallback() { if (!this.useShims || !this.module._lok_pollCallback) return null; let e = 4096, t = this.module._malloc(e), r = this.module._malloc(4); try { let n = this.module._lok_pollCallback(t, e, r); if (n === -1) return null; let o = this.module.HEAP32[r >> 2] ?? 0, s = ""; if (o > 0) { let i = Math.min(o, e - 1), a = this.module.HEAPU8.slice(t, t + i); s = ue.decode(a); } return { type: n, typeName: be(n), payload: s } } finally { this.module._free(t), this.module._free(r); } } pollAllCallbacks() { let e = [], t = this.pollCallback(); for (; t !== null;)e.push(t), t = this.pollCallback(); return e } clearCallbackQueue() { this.useShims && this.module._lok_clearCallbackQueue && (this.module._lok_clearCallbackQueue(), this.log("clearCallbackQueue: queue cleared")); } flushCallbacks(e) { if (e === 0) throw new Error("Invalid document pointer"); let t = !!this.module._lok_flushCallbacks; this.log(`flushCallbacks: useShims=${this.useShims}, _lok_flushCallbacks exists=${t}`), this.useShims && this.module._lok_flushCallbacks ? (this.module._lok_flushCallbacks(e), this.log("flushCallbacks: callbacks flushed")) : this.log("flushCallbacks: shim not available"); } pollStateChanges() { let e = new Map, t = this.pollAllCallbacks(); for (let r of t) if (r.type === 8) { let n = r.payload.indexOf("="); if (n !== -1) { let o = r.payload.substring(0, n), s = r.payload.substring(n + 1); e.set(o, s); } else e.set(r.payload, ""); } return e } clickAndGetText(e, t, r) { return this.postMouseEvent(e, 0, t, r, 1, 1, 0), this.postMouseEvent(e, 1, t, r, 1, 1, 0), this.getTextSelection(e, "text/plain;charset=utf-8") } doubleClickAndGetWord(e, t, r) { return this.postMouseEvent(e, 0, t, r, 2, 1, 0), this.postMouseEvent(e, 1, t, r, 2, 1, 0), this.getTextSelection(e, "text/plain;charset=utf-8") } selectAll(e) { this.postUnoCommand(e, ".uno:SelectAll"); } getAllText(e) { this.log(`getAllText called with docPtr: ${e}`), this.selectAll(e); let t = this.getTextSelection(e, "text/plain;charset=utf-8"); return this.log(`getAllText: text="${t?.slice(0, 100)}..."`), this.resetSelection(e), t } parsePageRectangles(e) { return e ? e.split(";").filter(t => t.trim()).map(t => { let r = t.split(",").map(Number); return { x: r[0] ?? 0, y: r[1] ?? 0, width: r[2] ?? 0, height: r[3] ?? 0 } }) : [] } }; var Z = class { module = null; lokBindings = null; initialized = false; initializing = false; options; corrupted = false; fsTracked = false; constructor(e = {}) { this.options = { wasmPath: "./wasm", verbose: false, ...e }; } isCorruptionError(e) { let t = e instanceof Error ? e.message : e; return t.includes("memory access out of bounds") || t.includes("ComponentContext is not avail") || t.includes("unreachable") || t.includes("table index is out of bounds") || t.includes("null function") } async reinitialize() { if (this.options.verbose && console.log("[LibreOfficeConverter] Reinitializing due to corruption..."), this.lokBindings) { try { this.lokBindings.destroy(); } catch { } this.lokBindings = null; } this.module = null, this.initialized = false, this.corrupted = false, await this.initialize(); } async initializeWithModule(e) { if (!this.initialized) { if (this.initializing) { for (; this.initializing;)await new Promise(t => setTimeout(t, 100)); return } this.initializing = true; try { this.module = e, this.setupFileSystem(), this.initializeLibreOfficeKit(), this.initialized = !0, this.options.onReady?.(); } catch (t) { console.error("[LibreOfficeConverter] Initialization error:", t); let r = t instanceof S ? t : new S("WASM_NOT_INITIALIZED", `Failed to initialize with module: ${String(t)}`); throw this.options.onError?.(r), r } finally { this.initializing = false; } } } async initialize() { if (!this.initialized) { if (this.initializing) { for (; this.initializing;)await new Promise(e => setTimeout(e, 100)); return } this.initializing = true, this.emitProgress("loading", 0, "Loading LibreOffice WASM module..."); try { this.module = await this.loadModule(), this.emitProgress("initializing", 50, "Setting up virtual filesystem..."), this.setupFileSystem(), this.emitProgress("initializing", 60, "Initializing LibreOfficeKit..."), this.initializeLibreOfficeKit(), this.emitProgress("initializing", 90, "LibreOfficeKit ready"), this.initialized = !0, this.emitProgress("complete", 100, "LibreOffice ready"), this.options.onReady?.(); } catch (e) { console.error("[LibreOfficeConverter] Initialization error:", e); let t = e instanceof S ? e : new S("WASM_NOT_INITIALIZED", `Failed to initialize WASM module: ${String(e)}`); throw this.options.onError?.(t), t } finally { this.initializing = false; } } } async loadModule() { let e = this.options.wasmPath || "./wasm", t = `${e}/soffice.js`, r = { locateFile: s => s.endsWith(".wasm") ? `${e}/soffice.wasm` : s.endsWith(".data") ? `${e}/soffice.data` : `${e}/${s}`, print: this.options.verbose ? console.log : () => { }, printErr: this.options.verbose ? console.error : () => { } }, n = document.createElement("script"); n.src = t, await new Promise((s, i) => { n.onload = () => s(), n.onerror = () => i(new Error(`Failed to load ${t}`)), document.head.appendChild(n); }); let o = window.createSofficeModule; if (!o) throw new S("WASM_NOT_INITIALIZED", "WASM module factory not found. Make sure soffice.js is loaded."); return new Promise((s, i) => { let a = { ...r, onRuntimeInitialized: () => { s(a); } }; o(a).catch(i); }) } setupFileSystem() { if (!this.module?.FS) throw new S("WASM_NOT_INITIALIZED", "Filesystem not available"); let e = this.module.FS, t = r => { try { e.mkdir(r); } catch { } }; t("/tmp"), t("/tmp/input"), t("/tmp/output"); } initializeLibreOfficeKit() { if (!this.module) throw new S("WASM_NOT_INITIALIZED", "Module not loaded"); if (this.options.verbose && this.module.FS) { let e = this.module.FS; if (!this.fsTracked && (this.fsTracked = true, e.trackingDelegate || (e.trackingDelegate = { onOpen: r => { console.log("[FS OPEN]", r); }, onOpenFile: r => { console.log("[FS OPEN FILE]", r); } }), typeof e.open == "function")) { let r = e.open.bind(e); e.open = ((n, o, s) => { console.log("[FS OPEN CALL]", n); try { return r(n, o, s) } catch (i) { throw i?.code === "ENOENT" && console.log("[FS ENOENT]", n), i } }); } let t = (r, n) => { try { console.log(`[FS] ${r}:`, e.readdir(n)); } catch (o) { console.log(`[FS] ${r}: ERROR -`, o.message); } }; t("ROOT", "/"), t("PROGRAM DIR", "/instdir/program"), t("SHARE DIR", "/instdir/share"), t("REGISTRY DIR", "/instdir/share/registry"), t("FILTER DIR", "/instdir/share/filter"), t("CONFIG DIR", "/instdir/share/config/soffice.cfg"), t("CONFIG FILTER", "/instdir/share/config/soffice.cfg/filter"), t("IMPRESS MODULES", "/instdir/share/config/soffice.cfg/modules/simpress"); } this.lokBindings = new Q(this.module, this.options.verbose); try { if (this.lokBindings.initialize("/instdir/program"), this.options.verbose) { let e = this.lokBindings.getVersionInfo(); e && console.log("[LOK] Version:", e); } } catch (e) { throw new S("WASM_NOT_INITIALIZED", `Failed to initialize LibreOfficeKit: ${String(e)}`) } } async convert(e, t, r = "document") { if (this.corrupted && await this.reinitialize(), !this.initialized || !this.module) throw new S("WASM_NOT_INITIALIZED", "LibreOffice WASM not initialized. Call initialize() first."); let n = Date.now(), o = this.normalizeInput(e); if (o.length === 0) throw new S("INVALID_INPUT", "Empty document provided"); let s = t.inputFormat || this.getExtensionFromFilename(r) || "docx", i = t.outputFormat; if (!te[i]) throw new S("UNSUPPORTED_FORMAT", `Unsupported output format: ${i}`); if (!re(s, i)) throw new S("UNSUPPORTED_FORMAT", ae(s, i)); let a = `/tmp/input/doc.${s}`, d = `/tmp/output/doc.${i}`; try { this.emitProgress("converting", 10, "Writing input document..."), this.module.FS.writeFile(a, o), this.emitProgress("converting", 30, "Converting document..."); let h = await this.performConversion(a, d, t); this.emitProgress("complete", 100, "Conversion complete"); let u = `${this.getBasename(r)}.${i}`; return { data: h, mimeType: oe[i], filename: u, duration: Date.now() - n } } catch (h) { throw h instanceof Error && this.isCorruptionError(h) && (this.corrupted = true, this.options.verbose && console.log("[LibreOfficeConverter] Corruption detected, will reinitialize on next convert")), h } finally { try { this.module?.FS.unlink(a); } catch { } try { this.module?.FS.unlink(d); } catch { } } } async performConversion(e, t, r) { if (!this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Module not loaded"); this.emitProgress("converting", 40, "Loading document..."); let n = 0; try { let o = M(r.inputFormat, r.password); if (this.options.verbose) { try { let a = this.module.FS.stat(e); console.log("[Convert] File exists before LOK load:", e, "size:", a.size); } catch (a) { console.log("[Convert] File NOT found before LOK load:", e, a.message); } o && console.log("[Convert] Using load options:", o); } if (o ? n = this.lokBindings.documentLoadWithOptions(e, o) : n = this.lokBindings.documentLoad(e), n === 0) throw new S("LOAD_FAILED", "Failed to load document"); this.emitProgress("converting", 60, "Converting format..."); let s = K[r.outputFormat], i = $[r.outputFormat] || ""; if (r.outputFormat === "pdf" && r.pdf) { let a = []; if (r.pdf.pdfaLevel) { let d = { "PDF/A-1b": 1, "PDF/A-2b": 2, "PDF/A-3b": 3 }; a.push(`SelectPdfVersion=${d[r.pdf.pdfaLevel] || 0}`); } r.pdf.quality !== void 0 && a.push(`Quality=${r.pdf.quality}`), a.length > 0 && (i = a.join(",")); } if (["png", "jpg", "svg"].includes(r.outputFormat) && r.image?.pageIndex !== void 0) { let a = r.image.pageIndex + 1; i ? i += `;PageRange=${a}-${a}` : i = `PageRange=${a}-${a}`; } this.emitProgress("converting", 70, "Saving document..."), this.lokBindings.documentSaveAs(n, t, s, i), this.emitProgress("converting", 90, "Reading output..."); try { let a = this.module.FS.readFile(t); if (a.length === 0) throw new S("CONVERSION_FAILED", "Conversion produced empty output"); return a } catch (a) { throw new S("CONVERSION_FAILED", `Failed to read converted file: ${String(a)}`) } } catch (o) { throw o instanceof S ? o : new S("CONVERSION_FAILED", `Conversion failed: ${String(o)}`) } finally { if (n !== 0 && this.lokBindings) try { this.lokBindings.documentDestroy(n); } catch { } } } async renderPagePreviews(e, t, r = {}) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let n = this.normalizeInput(e), o = (t.inputFormat || "docx").toLowerCase(), s = r.width ?? 256, i = r.height ?? 0, a = r.pageIndices ?? [], d = `/tmp/preview/doc.${o}`, h = this.module.FS; try { try { h.mkdir("/tmp/preview"); } catch { } h.writeFile(d, n); let m = this.lokBindings.documentLoad(d); if (m === 0) throw new S("LOAD_FAILED", "Failed to load document for preview"); try { let u = this.lokBindings.documentGetParts(m); this.options.verbose && console.log(`[Preview] Document has ${u} pages/parts`); let g = a.length > 0 ? a.filter(p => p >= 0 && p < u) : Array.from({ length: u }, (p, O) => O), f = [], P = r.editMode ?? !1; for (let p of g) { this.options.verbose && console.log(`[Preview] Rendering page ${p + 1}/${u}`); let O = this.lokBindings.renderPage(m, p, s, i, P); f.push({ page: p, data: O.data, width: O.width, height: O.height }); } return f } finally { this.lokBindings.documentDestroy(m); } } finally { try { h.unlink(d); } catch { } try { h.rmdir("/tmp/preview"); } catch { } } } async renderPageFullQuality(e, t, r, n = {}) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let o = this.normalizeInput(e), s = (t.inputFormat || "docx").toLowerCase(), i = n.dpi ?? 150, a = n.maxDimension, d = `/tmp/fullquality/doc.${s}`, h = this.module.FS; try { try { h.mkdir("/tmp/fullquality"); } catch { } h.writeFile(d, o); let m = this.lokBindings.documentLoad(d); if (m === 0) throw new S("LOAD_FAILED", "Failed to load document for full quality render"); try { let u = this.lokBindings.documentGetParts(m); if (r < 0 || r >= u) throw new S("CONVERSION_FAILED", `Page index ${r} out of range (0-${u - 1})`); this.options.verbose && console.log(`[FullQuality] Rendering page ${r + 1}/${u} at ${i} DPI`); let g = n.editMode ?? !1, f = this.lokBindings.renderPageFullQuality(m, r, i, a, g); return { page: r, data: f.data, width: f.width, height: f.height, dpi: f.dpi } } finally { this.lokBindings.documentDestroy(m); } } finally { try { h.unlink(d); } catch { } try { h.rmdir("/tmp/fullquality"); } catch { } } } async getPageCount(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), o = `/tmp/pagecount/doc.${(t.inputFormat || "docx").toLowerCase()}`, s = this.module.FS; try { try { s.mkdir("/tmp/pagecount"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.documentGetParts(i) } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/pagecount"); } catch { } } } async getDocumentInfo(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), o = `/tmp/docinfo/doc.${(t.inputFormat || "docx").toLowerCase()}`, s = this.module.FS; try { try { s.mkdir("/tmp/docinfo"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.documentGetDocumentType(i), d = this.lokBindings.documentGetParts(i), h = ie(a), m = { 0: "Text Document", 1: "Spreadsheet", 2: "Presentation", 3: "Drawing", 4: "Other" }; return { documentType: a, documentTypeName: m[a] || "Unknown", validOutputFormats: h, pageCount: d } } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/docinfo"); } catch { } } } async getDocumentText(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/inspect/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/inspect"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.getAllText(i) } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/inspect"); } catch { } } } async getPageNames(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/names/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/names"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.documentGetParts(i), d = []; for (let h = 0; h < a; h++) { let m = this.lokBindings.getPartName(i, h); d.push(m || `Page ${h + 1}`); } return d } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/names"); } catch { } } } async getPageRectangles(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/rects/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/rects"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.getPartPageRectangles(i); return this.lokBindings.parsePageRectangles(a || "") } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/rects"); } catch { } } } async getSpreadsheetDataArea(e, t, r = 0) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let n = this.normalizeInput(e), o = t.inputFormat?.toLowerCase(); if (!o) throw new S("INVALID_INPUT", "Input format is required"); let s = `/tmp/dataarea/doc.${o}`, i = this.module.FS; try { try { i.mkdir("/tmp/dataarea"); } catch { } i.writeFile(s, n); let a = this.lokBindings.documentLoad(s); if (a === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.getDataArea(a, r) } finally { this.lokBindings.documentDestroy(a); } } finally { try { i.unlink(s); } catch { } try { i.rmdir("/tmp/dataarea"); } catch { } } } async executeUnoCommand(e, t, r, n = "{}") { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let o = this.normalizeInput(e), s = t.inputFormat?.toLowerCase(); if (!s) throw new S("INVALID_INPUT", "Input format is required"); let i = `/tmp/uno/doc.${s}`, a = this.module.FS; try { try { a.mkdir("/tmp/uno"); } catch { } a.writeFile(i, o); let d = this.lokBindings.documentLoad(i); if (d === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { this.lokBindings.postUnoCommand(d, r, n); } finally { this.lokBindings.documentDestroy(d); } } finally { try { a.unlink(i); } catch { } try { a.rmdir("/tmp/uno"); } catch { } } } async renderPage(e, t, r, n, o = 0) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let s = this.normalizeInput(e), a = `/tmp/renderpage/doc.${(t.inputFormat || "docx").toLowerCase()}`, d = this.module.FS; try { try { d.mkdir("/tmp/renderpage"); } catch { } d.writeFile(a, s); let h = this.lokBindings.documentLoad(a); if (h === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let m = this.lokBindings.renderPage(h, r, n, o); return { page: r, data: m.data, width: m.width, height: m.height } } finally { this.lokBindings.documentDestroy(h); } } finally { try { d.unlink(a); } catch { } try { d.rmdir("/tmp/renderpage"); } catch { } } } openDocument(e, t) { return Promise.reject(new S("CONVERSION_FAILED", "Editor sessions not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } editorOperation(e, t, r) { return Promise.reject(new S("CONVERSION_FAILED", "Editor operations not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } closeDocument(e) { return Promise.reject(new S("CONVERSION_FAILED", "Editor sessions not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } getLokBindings() { return this.lokBindings } destroy() { if (this.lokBindings) { try { this.lokBindings.destroy(); } catch { } this.lokBindings = null; } if (this.module) try { let e = this.module; if (e.PThread?.terminateAllThreads && e.PThread.terminateAllThreads(), e.PThread?.runningWorkers) { for (let t of e.PThread.runningWorkers) t?.terminate && t.terminate(); e.PThread.runningWorkers = []; } if (e.PThread?.unusedWorkers) { for (let t of e.PThread.unusedWorkers) t?.terminate && t.terminate(); e.PThread.unusedWorkers = []; } } catch { } return this.module = null, this.initialized = false, Promise.resolve() } isReady() { return this.initialized } getModule() { return this.module } static getSupportedInputFormats() { return Object.keys(ne) } static getSupportedOutputFormats() { return Object.keys(te) } static getValidOutputFormats(e) { return G(e) } static isConversionSupported(e, t) { return re(e, t) } normalizeInput(e) { return e instanceof Uint8Array ? e : e instanceof ArrayBuffer ? new Uint8Array(e) : new Uint8Array(e) } getExtensionFromFilename(e) { let t = e.split("."); return t.length > 1 && t.pop()?.toLowerCase() || null } getBasename(e) { let t = e.lastIndexOf("."); return t > 0 ? e.substring(0, t) : e } emitProgress(e, t, r) { this.options.onProgress?.({ phase: e, percent: t, message: r }); } }; var me = { "download-wasm": 50, "download-data": 30, compile: 5, filesystem: 7, "lok-init": 7, ready: 1, starting: 0, loading: 0, initializing: 0, converting: 0, complete: 0 }, x = { "download-wasm": 0, "download-data": 0, compile: 0, filesystem: 0, "lok-init": 0, ready: 0, starting: 0, loading: 0, initializing: 0, converting: 0, complete: 0 }, pe = 0, ee = 0; function ge() { let l = 0; for (let t of Object.keys(x)) l += x[t]; let e = Math.min(100, Math.round(l)); return e > ee && (ee = e), ee } function q(l) { return `${(l / 1048576).toFixed(1)} MB` } function de(l, e, t) { let r = me[l], n = t > 0 ? e / t : 0, o = r * n; o > x[l] && (x[l] = o); let s = l === "download-wasm" ? `Downloading WebAssembly... ${q(e)} / ${q(t)}` : `Downloading filesystem... ${q(e)} / ${q(t)}`; fe({ percent: ge(), message: s, phase: l, bytesLoaded: e, bytesTotal: t }); } function B(l, e) { let t = me[l]; t > x[l] && (x[l] = t), fe({ percent: ge(), message: e, phase: l }); } function fe(l) { self.postMessage({ type: "progress", id: pe, progress: l }); } function we() { let l = self.fetch; self.fetch = async function (r, n) { let o = typeof r == "string" ? r : r instanceof URL ? r.href : r.url, s = null; o.includes("soffice.wasm") ? (s = "download-wasm", console.log("[Worker] Starting fetch download: soffice.wasm")) : o.includes("soffice.data") && (s = "download-data", console.log("[Worker] Starting fetch download: soffice.data")); let i = await l(r, n); if (!s) return i; if (s === "download-wasm") return console.log("[Worker] Returning original response for soffice.wasm (streaming compile requires raw Response)"), i; let a = i.headers.get("Content-Length"), d = a ? parseInt(a, 10) : 0; if (!d || !i.body) return console.log(`[Worker] No content-length for ${o}, skipping progress tracking`), i; let h = i.body.getReader(), m = 0, u = new ReadableStream({ async start(g) { for (; ;) { let { done: f, value: P } = await h.read(); if (f) { console.log("[Worker] Finished fetch download: soffice.data"), g.close(); break } m += P.length, de(s, m, d), g.enqueue(P); } } }); return new Response(u, { headers: i.headers, status: i.status, statusText: i.statusText }) }, console.log("[Worker] Installed progress-tracking fetch interceptor"); let e = self.XMLHttpRequest, t = function () { let r = new e, n = "", o = r.open.bind(r); r.open = function (i, a, d, h, m) { return n = String(a), o(i, a, d ?? true, h, m) }; let s = r.send.bind(r); return r.send = function (i) { let a = null; if (n.includes("soffice.wasm") ? (a = "download-wasm", console.log("[Worker] Starting XHR download: soffice.wasm")) : n.includes("soffice.data") && (a = "download-data", console.log("[Worker] Starting XHR download: soffice.data")), a) { let d = a; r.addEventListener("progress", h => { h.lengthComputable && de(d, h.loaded, h.total); }), r.addEventListener("load", () => { console.log(`[Worker] Finished XHR download: ${d === "download-wasm" ? "soffice.wasm" : "soffice.data"}`); }); } return s(i) }, r }; Object.defineProperty(t, "prototype", { value: e.prototype, writable: false }), self.XMLHttpRequest = t, console.log("[Worker] Installed progress-tracking XHR interceptor"); } var E = null, c = null, W = null, b = false, v = null, N = new Map, Te = 0; function Le(l) { let e = 0, t = Math.max(1, Math.floor(l.length / 1e3)); for (let r = 0; r < l.length; r += t) { let n = l[r]; n !== void 0 && (e = (e << 5) - e + n | 0); } return `${e}_${l.length}` } function Re(l) { let e = c.documentGetDocumentType(l); if (e === 0) { let r = c.getPartPageRectangles(l); if (r) { let n = c.parsePageRectangles(r); return console.log(`[Worker] getDocumentPageCount: TEXT doc has ${n.length} pages from rectangles`), n.length } return console.log("[Worker] getDocumentPageCount: TEXT doc has no page rectangles, assuming 1 page"), 1 } let t = c.documentGetParts(l); return console.log(`[Worker] getDocumentPageCount: docType=${e} has ${t} parts`), t } function F(l, e) { let t = Le(l); if (v && v.inputHash === t && c) return console.log(`[Worker] getOrLoadDocument: reusing cached doc ptr=${v.docPtr}, pageCount=${v.pageCount}`), { docPtr: v.docPtr, pageCount: v.pageCount }; console.log(`[Worker] getOrLoadDocument: loading new document (hash=${t})`), A(); let r = `/tmp/input/cached_doc.${e || "docx"}`; E.FS.writeFile(r, l); let n = M(e), o; if (n ? o = c.documentLoadWithOptions(r, n) : o = c.documentLoad(r), o === 0) { let i = c.getError(); throw new Error(i || "Failed to load document") } let s = Re(o); return console.log(`[Worker] getOrLoadDocument: loaded doc ptr=${o}, pageCount=${s}`), v = { docPtr: o, inputHash: t, filePath: r, pageCount: s }, { docPtr: o, pageCount: s } } function A() { if (v && c && E) { console.log(`[Worker] closeCachedDocument: closing cached doc ptr=${v.docPtr}`); try { c.documentDestroy(v.docPtr); } catch { } try { E.FS.unlink(v.filePath); } catch { } v = null; } } function y(l) { l.data ? self.postMessage(l, [l.data.buffer]) : self.postMessage(l); } function L(l, e, t) { y({ type: "progress", id: l, progress: { percent: e, message: t } }); } async function ve(l) { if (b) { y({ type: "ready", id: l.id }); return } let { sofficeJs: e, sofficeWasm: t, sofficeData: r, sofficeWorkerJs: n } = l; if (!e || !t || !r || !n) { y({ type: "error", id: l.id, error: "Missing required WASM paths (sofficeJs, sofficeWasm, sofficeData, sofficeWorkerJs)" }); return } let o = l.verbose || false; pe = l.id; for (let s of Object.keys(x)) x[s] = 0; ee = 0, l.enableProgressTracking ? (console.log("[Worker] Progress tracking enabled, installing interceptors..."), we()) : console.log("[Worker] Progress tracking disabled (default)"), B("download-wasm", "Preparing to download WebAssembly..."); try { console.log("[Worker] Setting up Module with explicit paths:", { sofficeJs: e, sofficeWasm: t, sofficeData: r, sofficeWorkerJs: n }), self.Module = { mainScriptUrlOrBlob: e, preRun: [function () { try { var FS = self.Module.FS; function mk(p) { try { FS.mkdir(p) } catch (e) { } } mk("/instdir"); mk("/instdir/share"); mk("/instdir/share/fonts"); mk("/instdir/share/fonts/truetype"); FS.createPreloadedFile("/instdir/share/fonts/truetype", "NotoSansSC-Regular.ttf", "/fonts/NotoSansSC-Regular.ttf", true, true, function () { console.log("CJK Font loaded") }, function () { console.error("CJK Font failed to load") }) } catch (e) { console.error("Font install error", e) } }], locateFile: (i, a) => { let d; return i.endsWith(".wasm") ? d = t : i.endsWith(".data") ? d = r : i.includes(".worker.") ? d = n : d = `${e.substring(0, e.lastIndexOf("/") + 1)}${i}`, console.log("[Worker] locateFile called:", i, "scriptDir:", a, "-> result:", d), d }, print: console.log, printErr: console.error }, importScripts(e), B("compile", "Compiling WebAssembly module..."), await new Promise((i, a) => { let d = () => { if (self.Module && self.Module.calledRun) i(); else if (self.Module?.onRuntimeInitialized) { let h = self.Module.onRuntimeInitialized; self.Module.onRuntimeInitialized = () => { h?.(), i(); }; } else self.Module && (self.Module.onRuntimeInitialized = i); setTimeout(() => a(new Error("WASM initialization timeout")), 12e4); }; self.Module && self.Module.calledRun ? i() : d(); }), E = self.Module, B("filesystem", "Setting up filesystem..."); try { let i = E; i.ENV ? (i.ENV.SAL_LOG = "+ALL", i.ENV.MAX_CONCURRENCY = "1", console.log("[Worker] Set SAL_LOG to +ALL")) : console.log("[Worker] ENV not available"); } catch (i) { console.log("[Worker] Could not set SAL_LOG:", i); } let s = E.FS; if (o) { let i = s.open.bind(s); s.open = (a, d, h) => { console.log("[FS OPEN CALL]", a); try { return i(a, d, h) } catch (m) { throw m?.code === "ENOENT" && console.log("[FS ENOENT]", a), m } }; } try { s.mkdir("/tmp"); } catch { } try { s.mkdir("/tmp/input"); } catch { } try { s.mkdir("/tmp/output"); } catch { } if (B("lok-init", "Initializing LibreOfficeKit..."), W = new Z({ verbose: o }), await W.initializeWithModule(E), c = W.getLokBindings(), !c) throw new Error("Failed to get LOK bindings from converter"); c.enableSyncEvents(), console.log("[LOK Worker] Enabled synchronous event dispatch (Unipoll mode)"), b = !0, B("ready", "Ready"), y({ type: "ready", id: l.id }); } catch (s) { y({ type: "error", id: l.id, error: s instanceof Error ? s.message : String(s) }); } } var Ae = ["png", "jpg", "jpeg", "svg"]; function Ie(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, outputFormat: r, filterOptions: n, password: o } = l; if (!e || !r) { y({ type: "error", id: l.id, error: "Missing input data or output format" }); return } let s = Ae.includes(r.toLowerCase()), i = `/tmp/input/doc.${t || "docx"}`, a = `/tmp/output/doc.${r}`, d = 0, h = []; try { L(l.id, 10, "Writing input file..."), E.FS.writeFile(i, e), L(l.id, 30, "Loading document..."); let m = M(t, o); if (m ? d = c.documentLoadWithOptions(i, m) : d = c.documentLoad(i), d === 0) { let f = c.getError(); throw new Error(f || "Failed to load document") } let u = c.documentGetParts(d), g = c.documentGetDocumentType(d); if (s && u > 1) { L(l.id, 40, `Exporting ${u} pages as ${r.toUpperCase()}...`); let f = K[r], P = n || $[r] || "", p = [], { width: O, height: _ } = c.documentGetDocumentSize(d), C = _ / O, D = 1024, U = Math.round(D * C); for (let k = 0; k < u; k++) { let R = 40 + Math.round(k / u * 40); L(l.id, R, `Exporting page ${k + 1}/${u}...`); let w = `/tmp/output/page_${k + 1}.${r}`; if (h.push(w), g === 2 || g === 3) { c.documentSetPart(d, k); let T = P; (r === "png" || r === "jpg" || r === "jpeg") && (T = `PixelWidth=${D};PixelHeight=${U}`, P && (T = `${P};${T}`)), c.documentSaveAs(d, w, f, T), console.log(`[Worker] Page ${k + 1} (presentation) exported with opts: ${T}`); } else { let T = `PageRange=${k + 1}-${k + 1}`; (r === "png" || r === "jpg" || r === "jpeg") && (T += `;PixelWidth=${D};PixelHeight=${U}`), P && (T = `${P};${T}`), c.documentSaveAs(d, w, f, T), console.log(`[Worker] Page ${k + 1} (text) exported with opts: ${T}`); } let z = E.FS.readFile(w); if (console.log(`[Worker] Page ${k + 1} exported: ${z.length} bytes`), z.length > 0) { let T = new Uint8Array(z.length); T.set(z), p.push({ name: `page_${k + 1}.${r}`, data: T }); } else console.warn(`[Worker] Page ${k + 1} export produced empty file`); } L(l.id, 85, "Creating ZIP archive..."); let V = xe(p); L(l.id, 100, "Complete"), y({ type: "result", id: l.id, data: V }); } else { L(l.id, 50, "Converting..."); let f = K[r], P = n || $[r] || ""; L(l.id, 70, "Saving..."), c.documentSaveAs(d, a, f, P), h.push(a), L(l.id, 90, "Reading output..."); let p = E.FS.readFile(a); if (p.length === 0) throw new Error("Conversion produced empty output"); let O = new Uint8Array(p.length); O.set(p), L(l.id, 100, "Complete"), y({ type: "result", id: l.id, data: O }); } } catch (m) { y({ type: "error", id: l.id, error: m instanceof Error ? m.message : String(m) }); } finally { if (d !== 0) try { c.documentDestroy(d); } catch { } try { E.FS.unlink(i); } catch { } for (let m of h) try { E.FS.unlink(m); } catch { } } } function xe(l) { let e = [], t = [], r = 0; for (let m of l) { let u = new TextEncoder().encode(m.name), g = new Uint8Array(30 + u.length), f = new DataView(g.buffer); f.setUint32(0, 67324752, true), f.setUint16(4, 20, true), f.setUint16(6, 0, true), f.setUint16(8, 0, true), f.setUint16(10, 0, true), f.setUint16(12, 0, true), f.setUint32(14, he(m.data), true), f.setUint32(18, m.data.length, true), f.setUint32(22, m.data.length, true), f.setUint16(26, u.length, true), f.setUint16(28, 0, true), g.set(u, 30), e.push(g), e.push(m.data); let P = new Uint8Array(46 + u.length), p = new DataView(P.buffer); p.setUint32(0, 33639248, true), p.setUint16(4, 20, true), p.setUint16(6, 20, true), p.setUint16(8, 0, true), p.setUint16(10, 0, true), p.setUint16(12, 0, true), p.setUint16(14, 0, true), p.setUint32(16, he(m.data), true), p.setUint32(20, m.data.length, true), p.setUint32(24, m.data.length, true), p.setUint16(28, u.length, true), p.setUint16(30, 0, true), p.setUint16(32, 0, true), p.setUint16(34, 0, true), p.setUint16(36, 0, true), p.setUint32(38, 0, true), p.setUint32(42, r, true), P.set(u, 46), t.push(P), r += g.length + m.data.length; } let n = r, o = 0; for (let m of t) e.push(m), o += m.length; let s = new Uint8Array(22), i = new DataView(s.buffer); i.setUint32(0, 101010256, true), i.setUint16(4, 0, true), i.setUint16(6, 0, true), i.setUint16(8, l.length, true), i.setUint16(10, l.length, true), i.setUint32(12, o, true), i.setUint32(16, n, true), i.setUint16(20, 0, true), e.push(s); let a = e.reduce((m, u) => m + u.length, 0), d = new Uint8Array(a), h = 0; for (let m of e) d.set(m, h), h += m.length; return d } function he(l) { let e = 4294967295; for (let t = 0; t < l.length; t++) { let r = l[t]; e ^= r; for (let n = 0; n < 8; n++)e = e >>> 1 ^ (e & 1 ? 3988292384 : 0); } return (e ^ 4294967295) >>> 0 } async function Fe(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { pageCount: r } = F(e, t || "docx"); y({ type: "pageCount", id: l.id, pageCount: r }); } catch (r) { y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function De(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { L(l.id, 10, "Loading document for preview..."); let { docPtr: n, pageCount: o } = F(e, t || "docx"); L(l.id, 20, `Rendering ${o} pages...`); let s = []; for (let a = 0; a < o; a++) { let d = 20 + Math.round(a / o * 70); L(l.id, d, `Rendering page ${a + 1}/${o}...`); let h = c.renderPage(n, a, r), m = new Uint8Array(h.data.length); m.set(h.data), s.push({ page: a + 1, data: m, width: h.width, height: h.height }); } L(l.id, 100, "Preview complete"); let i = s.map(a => a.data.buffer); self.postMessage({ type: "previews", id: l.id, previews: s }, i); } catch (n) { y({ type: "error", id: l.id, error: n instanceof Error ? n.message : String(n) }), A(); } } async function We(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256, pageIndex: n = 0 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let o = -1, s = 0; try { let i = F(e, t || "docx"); s = i.docPtr; let a = i.pageCount; if (n < 0 || n >= a) throw new Error(`Page index ${n} out of range (0-${a - 1})`); let d = c.documentGetDocumentType(s); console.log(`[Worker] handleRenderSinglePage: ${["TEXT", "SPREADSHEET", "PRESENTATION", "DRAWING"][d] || "UNKNOWN"} document - creating view for rendering`), o = c.createView(s), o >= 0 && (c.setView(s, o), console.log(`[Worker] handleRenderSinglePage: Created and set view ${o}`)), console.log(`[Worker] handleRenderSinglePage: calling renderPage for page ${n} at maxWidth=${r}...`); let m = c.renderPage(s, n, r); console.log(`[Worker] handleRenderSinglePage: renderPage returned ${m.data.length} bytes (${m.width}x${m.height})`); let u = new Uint8Array(m.data.length); u.set(m.data); let g = { page: n + 1, data: u, width: m.width, height: m.height }; if (o >= 0 && s !== 0) { try { c.destroyView(s, o); } catch { } console.log(`[Worker] handleRenderSinglePage: Destroyed view ${o}`); } self.postMessage({ type: "singlePagePreview", id: l.id, preview: g }, [u.buffer]); } catch (i) { if (o >= 0 && s !== 0) { try { c.destroyView(s, o); } catch { } console.log(`[Worker] handleRenderSinglePage: Destroyed view ${o} (on error)`); } let a = i instanceof Error ? String(i.message) : String(i); y({ type: "error", id: l.id, error: a }), A(); } } async function Ne(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256, pageIndex: n = 0 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let o = `/tmp/output/page_${n}.png`; try { let { docPtr: s, pageCount: i } = F(e, t || "pdf"), a = c.documentGetDocumentType(s); if (n < 0 || n >= i) throw new Error(`Page index ${n} out of range (0-${i - 1})`); (a === 2 || a === 3) && c.documentSetPart(s, n); let { width: d, height: h } = c.documentGetDocumentSize(s), m = h / d, u = Math.min(r, d), g = Math.round(u * m), f = `PixelWidth=${u};PixelHeight=${g}`; a === 0 && (f += `;PageRange=${n + 1}-${n + 1}`), c.documentSaveAs(s, o, "png", f); let P = E.FS.readFile(o); if (P.length === 0) throw new Error("PNG export produced empty output"); let p = new Uint8Array(P.length); p.set(P); let O = { page: n + 1, data: p, width: u, height: g, format: "png" }; self.postMessage({ type: "singlePagePreview", id: l.id, preview: O, isPng: !0 }, [p.buffer]); try { E.FS.unlink(o); } catch { } } catch (s) { y({ type: "error", id: l.id, error: s instanceof Error ? s.message : String(s) }), A(); try { E.FS.unlink(o); } catch { } } } async function Ue(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, pageIndex: r = 0, dpi: n = 150, maxDimension: o, editMode: s = false } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let i = -1, a = 0; try { let d = F(e, t || "docx"); a = d.docPtr; let h = d.pageCount; if (r < 0 || r >= h) throw new Error(`Page index ${r} out of range (0-${h - 1})`); let m = c.documentGetDocumentType(a); console.log(`[Worker] handleRenderPageFullQuality: ${["TEXT", "SPREADSHEET", "PRESENTATION", "DRAWING"][m] || "UNKNOWN"} document at ${n} DPI, editMode=${s}`), i = c.createView(a), i >= 0 && (c.setView(a, i), console.log(`[Worker] handleRenderPageFullQuality: Created and set view ${i}`)); let g = c.renderPageFullQuality(a, r, n, o, s); console.log(`[Worker] handleRenderPageFullQuality: rendered ${g.data.length} bytes (${g.width}x${g.height} at ${g.dpi} DPI)`); let f = new Uint8Array(g.data.length); f.set(g.data); let P = { page: r + 1, data: f, width: g.width, height: g.height, dpi: g.dpi }; if (i >= 0 && a !== 0) try { c.destroyView(a, i); } catch { } self.postMessage({ type: "fullQualityPagePreview", id: l.id, preview: P }, [f.buffer]); } catch (d) { if (i >= 0 && a !== 0) try { c.destroyView(a, i); } catch { } let h = d instanceof Error ? String(d.message) : String(d); y({ type: "error", id: l.id, error: h }), A(); } } async function Ke(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { docPtr: r, pageCount: n } = F(e, t || "docx"), o = c.documentGetDocumentType(r), s = { 0: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png", "jpg", "svg"], 1: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png", "jpg", "svg"], 2: ["pdf", "pptx", "ppt", "odp", "png", "jpg", "svg", "html"], 3: ["pdf", "png", "jpg", "svg", "html"], 4: ["pdf"] }, a = { documentType: o, documentTypeName: { 0: "Text Document", 1: "Spreadsheet", 2: "Presentation", 3: "Drawing", 4: "Other" }[o] || "Unknown", validOutputFormats: s[o] || ["pdf"], pageCount: n }; y({ type: "documentInfo", id: l.id, documentInfo: a }); } catch (r) { y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function $e(l) { if (console.log("[LOK Worker] handleGetLokInfo called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { console.log("[LOK Worker] Getting or loading document..."); let { docPtr: r } = F(e, t || "docx"); console.log(`[LOK Worker] Got docPtr: ${r}`), console.log("[LOK Worker] Calling LOK methods..."); let n = c.getPartPageRectangles(r); console.log(`[LOK Worker] pageRectangles: ${n}`); let o = c.documentGetDocumentSize(r); console.log(`[LOK Worker] documentSize: ${o.width}x${o.height}`); let s = c.getPartInfo(r, 0); console.log(`[LOK Worker] partInfo: ${s}`); let i = c.getA11yFocusedParagraph(r); console.log(`[LOK Worker] a11yFocusedParagraph: ${i}`); let a = c.getA11yCaretPosition(r); console.log(`[LOK Worker] a11yCaretPosition: ${a}`); let d = c.getEditMode(r); console.log(`[LOK Worker] editMode (initial): ${d}`); let h = null, m = -1; m = c.getView(r), console.log(`[LOK Worker] Got existing view: ${m}`), m >= 0 && (c.setView(r, m), console.log(`[LOK Worker] Set active view to ${m}`)); let u = c.createView(r); console.log(`[LOK Worker] Created new view: ${u}`), u >= 0 && (c.setView(r, u), console.log(`[LOK Worker] Switched to new view: ${u}`)), c.setEditMode(r, 1), d = c.getEditMode(r), console.log(`[LOK Worker] editMode (after setEditMode): ${d}`), h = c.getAllText(r), console.log(`[LOK Worker] allText: ${h?.slice(0, 100) || "null"}`), u >= 0 && (c.destroyView(r, u), console.log(`[LOK Worker] Destroyed view: ${u}`)); let g = null; if (s) try { g = JSON.parse(s); } catch { console.warn("[LOK Worker] Failed to parse partInfo JSON:", s); } let f = null; if (i) try { f = JSON.parse(i); } catch { console.warn("[LOK Worker] Failed to parse a11yFocusedParagraph JSON:", i); } let P = { pageRectangles: n, documentSize: o, partInfo: g, a11yFocusedParagraph: f, a11yCaretPosition: a, editMode: d, allText: h }; console.log("[LOK Worker] Posting lokInfo response"), y({ type: "lokInfo", id: l.id, lokInfo: P }); } catch (r) { console.error("[LOK Worker] Error in handleGetLokInfo:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function Me(l) { if (console.log("[LOK Worker] handleEditText called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, findText: r, replaceText: n, insertText: o } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } A(); let s = `/tmp/input/edit_doc.${t || "docx"}`, i = `/tmp/output/edited_doc.${t || "docx"}`, a = 0, d = -1; try { if (console.log("[LOK Worker] Writing input file..."), E.FS.writeFile(s, e), console.log("[LOK Worker] Loading document for editing..."), a = c.documentLoad(s), a === 0) { let p = c.getError(); throw new Error(p || "Failed to load document") } console.log(`[LOK Worker] Document loaded, docPtr=${a}`), c.documentInitializeForRendering(a), console.log("[LOK Worker] Document initialized for rendering"), d = c.getView(a), console.log(`[LOK Worker] Got existing view: ${d}`), d >= 0 && (c.setView(a, d), console.log(`[LOK Worker] Set active view to ${d}`)); let h = c.createView(a); console.log(`[LOK Worker] Created new view: ${h}`), h >= 0 && (c.setView(a, h), console.log(`[LOK Worker] Switched to new view: ${h}`), d = h), c.setEditMode(a, 1); let m = c.getEditMode(a); console.log(`[LOK Worker] Edit mode after setEditMode(1): ${m}`); let u = ""; if (r && n !== void 0) { console.log(`[LOK Worker] Attempting find/replace: "${r}" -> "${n}"`); let p = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: r }, "SearchItem.ReplaceString": { type: "string", value: n }, "SearchItem.Command": { type: "unsigned short", value: "3" } }); try { c.postUnoCommand(a, ".uno:ExecuteSearch", p), u = `Attempted replace all "${r}" with "${n}"`, console.log(`[LOK Worker] ${u}`); } catch (O) { console.error("[LOK Worker] ExecuteSearch threw:", O), u = `ExecuteSearch failed: ${String(O)}`; } } else if (o) { console.log(`[LOK Worker] Attempting to insert text: "${o}"`); let p = []; try { console.log("[LOK Worker] Clicking in document to establish focus..."), c.postMouseEvent(a, 0, 1e3, 1e3, 1, 1, 0), c.postMouseEvent(a, 1, 1e3, 1e3, 1, 1, 0), console.log("[LOK Worker] Posted mouse events for focus"), p.push("mouseEvents:ok"); } catch (_) { console.error("[LOK Worker] postMouseEvent threw:", _), p.push("mouseEvents:err"); } try { c.postUnoCommand(a, ".uno:GoToEndOfDoc"), console.log("[LOK Worker] Posted GoToEndOfDoc"), p.push("GoToEndOfDoc:ok"); } catch (_) { console.error("[LOK Worker] GoToEndOfDoc threw:", _), p.push("GoToEndOfDoc:err"); } let O = !1; try { console.log("[LOK Worker] Trying paste() with text/plain..."), O = c.paste(a, "text/plain;charset=utf-8", o), console.log(`[LOK Worker] paste() returned: ${O}`), p.push(`paste:${O}`); } catch (_) { console.error("[LOK Worker] paste() threw:", _), p.push("paste:err"); } try { let _ = JSON.stringify({ Text: { type: "string", value: o } }); c.postUnoCommand(a, ".uno:InsertText", _), console.log("[LOK Worker] Posted InsertText"), p.push("InsertText:ok"); } catch (_) { console.error("[LOK Worker] InsertText threw:", _), p.push("InsertText:err"); } try { console.log("[LOK Worker] Now trying postKeyEvent for each character..."); for (let _ = 0; _ < o.length; _++) { let C = o.charCodeAt(_); c.postKeyEvent(a, 0, C, 0), c.postKeyEvent(a, 1, C, 0); } console.log(`[LOK Worker] Posted ${o.length} key events`), p.push(`keyEvents:${o.length}`); } catch (_) { console.error("[LOK Worker] postKeyEvent threw:", _), p.push("keyEvents:err"); } u = `Insert attempts: ${p.join(", ")}`, console.log(`[LOK Worker] ${u}`); } else u = "No edit operation specified (need findText+replaceText or insertText)", console.log(`[LOK Worker] ${u}`); console.log("[LOK Worker] Attempting to save modified document..."); let g = t || "docx", P = { docx: "docx", doc: "doc", odt: "odt", xlsx: "xlsx", xls: "xls", ods: "ods", pptx: "pptx", ppt: "ppt", odp: "odp" }[g] || g; try { c.documentSaveAs(a, i, P, ""), console.log("[LOK Worker] Document saved"); let p = E.FS.readFile(i); console.log(`[LOK Worker] Modified document size: ${p.length} bytes`); let O = new Uint8Array(p.length); O.set(p); let _ = { success: !0, editMode: m, message: u + ` | Document saved (${O.length} bytes)`, modifiedDocument: O }; self.postMessage({ type: "editResult", id: l.id, editResult: _ }, [O.buffer]); } catch (p) { console.error("[LOK Worker] Save error:", p); let O = { success: !1, editMode: m, message: u + ` | Save failed: ${String(p)}` }; y({ type: "editResult", id: l.id, editResult: O }); } } catch (h) { console.error("[LOK Worker] Error in handleEditText:", h), h instanceof Error && (console.error("[LOK Worker] Error name:", h.name), console.error("[LOK Worker] Error message:", h.message), console.error("[LOK Worker] Error stack:", h.stack)); let m = h; if (m && typeof m == "object") { console.error("[LOK Worker] Error keys:", Object.keys(m)); for (let u of Object.keys(m)) try { console.error(`[LOK Worker] Error.${u}:`, m[u]); } catch { } } if (typeof h == "number") { console.error("[LOK Worker] Emscripten exception pointer:", h); let u = E; if (u && typeof u.getExceptionMessage == "function") try { let g = u.getExceptionMessage(h); console.error("[LOK Worker] Emscripten exception message:", g); } catch { } } y({ type: "error", id: l.id, error: h instanceof Error ? h.message : String(h) }); } finally { if (a !== 0 && c) { if (d >= 0) try { c.destroyView(a, d); } catch { } try { c.documentDestroy(a); } catch { } } if (E) { try { E.FS.unlink(s); } catch { } try { E.FS.unlink(i); } catch { } } } } async function Be(l) { if (console.log("[LOK Worker] handleRenderPageRectangles called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { docPtr: n } = F(e, t || "docx"); c.documentInitializeForRendering(n); let o = c.getPartPageRectangles(n); if (console.log(`[LOK Worker] Page rectangles string: ${o?.slice(0, 100) || "null"}...`), !o || o.length === 0) { y({ type: "pageRectangles", id: l.id, pageRectangles: [] }); return } let s = c.parsePageRectangles(o); console.log(`[LOK Worker] Parsed ${s.length} page rectangles`); let i = [], a = []; for (let d = 0; d < s.length; d++) { let h = s[d]; console.log(`[LOK Worker] Rendering page ${d}: x=${h.x}, y=${h.y}, w=${h.width}, h=${h.height}`); let m = h.height / h.width, u = r, g = Math.round(r * m), f = c.documentPaintTile(n, u, g, h.x, h.y, h.width, h.height), P = new Uint8Array(f.length); P.set(f), i.push({ index: d, x: h.x, y: h.y, width: h.width, height: h.height, imageData: P, imageWidth: u, imageHeight: g }), a.push(P.buffer), console.log(`[LOK Worker] Rendered page ${d}: ${u}x${g}, ${P.length} bytes`); } self.postMessage({ type: "pageRectangles", id: l.id, pageRectangles: i }, a); } catch (n) { console.error("[LOK Worker] Error in handleRenderPageRectangles:", n); let o = n instanceof Error ? String(n.message) : String(n); y({ type: "error", id: l.id, error: o }), A(); } } async function Ve(l) { if (console.log("[LOK Worker] handleTestLokOperations called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } A(); let r = `/tmp/input/test_ops_doc.${t || "docx"}`, n = `/tmp/output/test_ops_doc.${t || "docx"}`, o = 0, s = -1, i = []; try { if (console.log("[LOK Worker] Writing input file..."), E.FS.writeFile(r, e), console.log("[LOK Worker] Loading document for LOK operations testing..."), o = c.documentLoad(r), o === 0) { let u = c.getError(); throw new Error(u || "Failed to load document") } console.log(`[LOK Worker] Document loaded, docPtr=${o}`), c.documentInitializeForRendering(o), console.log("[LOK Worker] Document initialized for rendering"), s = c.getView(o), console.log(`[LOK Worker] Got existing view: ${s}`), s >= 0 && c.setView(o, s); let a = c.createView(o); console.log(`[LOK Worker] Created new view: ${a}`), a >= 0 && (c.setView(o, a), s = a), c.setEditMode(o, 1); let d = c.getEditMode(o); console.log(`[LOK Worker] Edit mode: ${d}`), c.registerCallback(o), c.clearCallbackQueue(), console.log("[LOK Worker] Callback registered for STATE_CHANGED events"); try { c.postMouseEvent(o, 0, 1e3, 1e3, 1, 1, 0), c.postMouseEvent(o, 1, 1e3, 1e3, 1, 1, 0), i.push({ operation: "establishFocus", success: !0, result: "Mouse click events sent" }); } catch (u) { i.push({ operation: "establishFocus", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing SelectAll + getTextSelection..."); try { c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"), g = u?.length || 0; console.log(`[LOK Worker] SelectAll result: ${g} chars, preview: "${u?.slice(0, 100)}..."`), i.push({ operation: "SelectAll+getTextSelection", success: g > 0, result: { textLength: g, preview: u?.slice(0, 200) } }); } catch (u) { console.error("[LOK Worker] SelectAll error:", u), i.push({ operation: "SelectAll+getTextSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing getSelectionType..."); try { let u = c.getSelectionType(o); console.log(`[LOK Worker] Selection type: ${u}`), i.push({ operation: "getSelectionType", success: !0, result: { selectionType: u, meaning: u === 0 ? "NONE" : u === 1 ? "TEXT" : u === 2 ? "CELL" : "UNKNOWN" } }); } catch (u) { console.error("[LOK Worker] getSelectionType error:", u), i.push({ operation: "getSelectionType", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing resetSelection..."); try { c.resetSelection(o); let u = c.getSelectionType(o); console.log(`[LOK Worker] Selection type after reset: ${u}`), i.push({ operation: "resetSelection", success: !0, result: { selectionTypeAfterReset: u } }); } catch (u) { console.error("[LOK Worker] resetSelection error:", u), i.push({ operation: "resetSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing GoToStartOfDoc + selection + Delete..."); try { c.postUnoCommand(o, ".uno:GoToStartOfDoc"), console.log("[LOK Worker] Sent GoToStartOfDoc"), c.postUnoCommand(o, ".uno:WordRightSel"), console.log("[LOK Worker] Sent WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected text before delete: "${u}"`), c.postUnoCommand(o, ".uno:Delete"), console.log("[LOK Worker] Sent Delete"), i.push({ operation: "SelectWord+Delete", success: !0, result: { deletedText: u } }); } catch (u) { console.error("[LOK Worker] SelectWord+Delete error:", u), i.push({ operation: "SelectWord+Delete", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Undo..."); try { c.postUnoCommand(o, ".uno:Undo"), console.log("[LOK Worker] Sent Undo"), c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Text after Undo: ${u?.length} chars`), i.push({ operation: "Undo", success: !0, result: { textLengthAfterUndo: u?.length || 0 } }); } catch (u) { console.error("[LOK Worker] Undo error:", u), i.push({ operation: "Undo", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Redo..."); try { c.postUnoCommand(o, ".uno:Redo"), console.log("[LOK Worker] Sent Redo"), c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Text after Redo: ${u?.length} chars`), i.push({ operation: "Redo", success: !0, result: { textLengthAfterRedo: u?.length || 0 } }); } catch (u) { console.error("[LOK Worker] Redo error:", u), i.push({ operation: "Redo", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Bold formatting..."); try { c.postUnoCommand(o, ".uno:Undo"), c.postUnoCommand(o, ".uno:GoToStartOfDoc"), c.postUnoCommand(o, ".uno:WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected for bold: "${u}"`), c.postUnoCommand(o, ".uno:Bold"), console.log("[LOK Worker] Sent Bold"); let g = c.getCommandValues(o, ".uno:Bold"); console.log(`[LOK Worker] Bold state: ${g}`), i.push({ operation: "Bold", success: !0, result: { selectedText: u, boldState: g } }); } catch (u) { console.error("[LOK Worker] Bold error:", u), i.push({ operation: "Bold", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Italic formatting..."); try { c.postUnoCommand(o, ".uno:GoRight"), c.postUnoCommand(o, ".uno:WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected for italic: "${u}"`), c.postUnoCommand(o, ".uno:Italic"), console.log("[LOK Worker] Sent Italic"); let g = c.getCommandValues(o, ".uno:Italic"); console.log(`[LOK Worker] Italic state: ${g}`), i.push({ operation: "Italic", success: !0, result: { selectedText: u, italicState: g } }); } catch (u) { console.error("[LOK Worker] Italic error:", u), i.push({ operation: "Italic", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing getCharacterFormatting via STATE_CHANGED callbacks..."); try { let u = c.getCallbackEventCount(); console.log(`[LOK Worker] Existing events in queue: ${u}`); let g = c.pollStateChanges(); console.log(`[LOK Worker] Existing STATE_CHANGED events: ${g.size}`); for (let [R, w] of g.entries()) console.log(`[LOK Worker] ${R} = ${w}`); c.clearCallbackQueue(), c.postUnoCommand(o, ".uno:GoToStartOfDoc"), c.flushCallbacks(o), c.postUnoCommand(o, ".uno:WordRightSel"), c.flushCallbacks(o); let f = c.getCallbackEventCount(), P = c.hasCallbackEvents(); console.log(`[LOK Worker] Event count after WordRightSel: ${f}, hasEvents: ${P}`); let p = c.pollStateChanges(); console.log(`[LOK Worker] State changes after selection: ${p.size}`); for (let [R, w] of p.entries()) console.log(`[LOK Worker] ${R} = ${w}`); for (let [R, w] of g.entries()) p.has(R) || p.set(R, w); let O = {}; for (let [R, w] of p.entries()) O[R] = w; console.log(`[LOK Worker] Received ${p.size} state changes:`); for (let [R, w] of p.entries()) console.log(` ${R} = ${w}`); let _ = p.get(".uno:Bold") ?? null, C = p.get(".uno:Italic") ?? null, D = p.get(".uno:Underline") ?? null, U = p.get(".uno:CharFontName") ?? null, V = p.get(".uno:FontHeight") ?? null, k = p.get(".uno:Color") ?? p.get(".uno:CharColor") ?? null; console.log("[LOK Worker] Character formatting from STATE_CHANGED:"), console.log(` Bold: ${_}`), console.log(` Italic: ${C}`), console.log(` Underline: ${D}`), console.log(` FontName: ${U}`), console.log(` FontSize: ${V}`), console.log(` Color: ${k}`), i.push({ operation: "getCharacterFormatting", success: !0, result: { stateChangeCount: p.size, note: p.size === 0 ? "Callback queue empty - C++ shims may need to be added to WASM build" : void 0, bold: _, italic: C, underline: D, fontName: U, fontSize: V, color: k, allStates: O } }); } catch (u) { console.error("[LOK Worker] getCharacterFormatting error:", u), i.push({ operation: "getCharacterFormatting", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing setTextSelection..."); try { c.resetSelection(o), c.setTextSelection(o, 0, 500, 500), c.setTextSelection(o, 1, 3e3, 500); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Coordinate-selected text: "${u}"`), i.push({ operation: "setTextSelection", success: !0, result: { selectedText: u } }); } catch (u) { console.error("[LOK Worker] setTextSelection error:", u), i.push({ operation: "setTextSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing document save..."); try { let u = t || "docx", f = { docx: "docx", doc: "doc", odt: "odt", xlsx: "xlsx", xls: "xls", ods: "ods", pptx: "pptx", ppt: "ppt", odp: "odp" }[u] || u; c.documentSaveAs(o, n, f, ""); let P = E.FS.readFile(n); i.push({ operation: "documentSave", success: P.length > 0, result: { savedBytes: P.length, originalBytes: e.length } }); } catch (u) { console.error("[LOK Worker] Save error:", u), i.push({ operation: "documentSave", success: !1, error: String(u) }); } let m = `${i.filter(u => u.success).length}/${i.length} operations succeeded`; console.log(`[LOK Worker] Test results summary: ${m}`), y({ type: "testLokOperations", id: l.id, testLokOperationsResult: { operations: i, summary: m } }); } catch (a) { console.error("[LOK Worker] Error in handleTestLokOperations:", a), y({ type: "error", id: l.id, error: a instanceof Error ? a.message : String(a) }); } finally { if (o !== 0 && c) { try { c.unregisterCallback(o); } catch { } if (s >= 0) try { c.destroyView(o, s); } catch { } try { c.documentDestroy(o); } catch { } } if (E) { try { E.FS.unlink(r); } catch { } try { E.FS.unlink(n); } catch { } } } } async function ze(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let e = l.inputData, t = l.inputExt || "docx"; if (!e || e.length === 0) { y({ type: "error", id: l.id, error: "No input data provided" }); return } try { let r = `session_${++Te}_${Date.now()}`, n = `/tmp/edit_${r}.${t}`; E.FS.writeFile(n, e); let o = c.documentLoad(n); if (o === 0) { let h = c.getError(); E.FS.unlink(n), y({ type: "error", id: l.id, error: `Failed to load document: ${String(h)}` }); return } c.documentInitializeForRendering(o); let s = c.createView(o); c.setView(o, s), c.registerCallback(o), c.postUnoCommand(o, ".uno:Edit"); let i = le(c, o), a = i.getDocumentType(), d = c.documentGetParts(o); N.set(r, { sessionId: r, docPtr: o, filePath: n, editor: i, documentType: a }), console.log(`[LOK Worker] Opened document session: ${r}, type: ${a}, pages: ${d}`), y({ type: "editorSession", id: l.id, editorSession: { sessionId: r, documentType: a, pageCount: d } }); } catch (r) { console.error("[LOK Worker] Error in handleOpenDocument:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }); } } async function Ge(l) { let { sessionId: e, editorMethod: t, editorArgs: r } = l; if (!e || !t) { y({ type: "error", id: l.id, error: "Missing sessionId or editorMethod" }); return } let n = N.get(e); if (!n) { y({ type: "error", id: l.id, error: `Session not found: ${e}` }); return } try { let { editor: o } = n, s = r || [], i = o[t]; if (typeof i != "function") { y({ type: "error", id: l.id, error: `Unknown editor method: ${t}` }); return } let a = i.apply(o, s), d = a.data; a.data instanceof Map && (d = Object.fromEntries(a.data)), y({ type: "editorOperationResult", id: l.id, editorOperationResult: { success: a.success, verified: a.verified, data: d, error: a.error, suggestion: a.suggestion } }); } catch (o) { console.error(`[LOK Worker] Error in handleEditorOperation (${t}):`, o), y({ type: "error", id: l.id, error: o instanceof Error ? o.message : String(o) }); } } async function He(l) { let { sessionId: e } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing sessionId" }); return } let t = N.get(e); if (!t) { y({ type: "error", id: l.id, error: `Session not found: ${e}` }); return } try { let { docPtr: r, filePath: n } = t, o; if (E) try { let s = n.split(".").pop() || "docx"; c?.documentSaveAs(r, n, s, ""), o = E.FS.readFile(n); } catch (s) { console.warn("[LOK Worker] Could not save document:", s); } if (c && r !== 0) { try { c.unregisterCallback(r); } catch { } try { c.documentDestroy(r); } catch { } } if (E) try { E.FS.unlink(n); } catch { } N.delete(e), console.log(`[LOK Worker] Closed document session: ${e}`), y({ type: "documentClosed", id: l.id, data: o }); } catch (r) { console.error("[LOK Worker] Error in handleCloseDocument:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }); } } function je(l) { console.log("handleDestroy"); for (let [, e] of N) try { if (c && e.docPtr !== 0) { try { c.unregisterCallback(e.docPtr); } catch { } try { c.documentDestroy(e.docPtr); } catch { } } if (E) try { E.FS.unlink(e.filePath); } catch { } } catch { } if (N.clear(), A(), W) { try { W.destroy(); } catch { } W = null, c = null; } else if (c) { try { c.destroy(); } catch { } c = null; } if (E && E.PThread?.terminateAllThreads) try { E.PThread.terminateAllThreads(); } catch { } E = null, b = false, y({ type: "ready", id: l.id }), setTimeout(() => self.close(), 100); } self.onmessage = async l => { let e = l.data; switch (e.type) { case "init": await ve(e); break; case "convert": await Ie(e); break; case "getPageCount": await Fe(e); break; case "renderPreviews": await De(e); break; case "renderSinglePage": await We(e); break; case "renderPageViaConvert": await Ne(e); break; case "renderPageFullQuality": await Ue(e); break; case "getDocumentInfo": await Ke(e); break; case "getLokInfo": await $e(e); break; case "editText": await Me(e); break; case "renderPageRectangles": await Be(e); break; case "testLokOperations": await Ve(e); break; case "openDocument": await ze(e); break; case "editorOperation": await Ge(e); break; case "closeDocument": await He(e); break; case "destroy": je(e); break } }; self.postMessage({ type: "loaded" });
+ 'use strict'; var S = class extends Error { code; details; constructor(e, t, r) { super(t), this.name = "ConversionError", this.code = e, this.details = r; } }, te = { pdf: "writer_pdf_Export", docx: "MS Word 2007 XML", doc: "MS Word 97", odt: "writer8", rtf: "Rich Text Format", txt: "Text", html: "HTML (StarWriter)", xlsx: "Calc MS Excel 2007 XML", xls: "MS Excel 97", ods: "calc8", csv: "Text - txt - csv (StarCalc)", pptx: "Impress MS PowerPoint 2007 XML", ppt: "MS PowerPoint 97", odp: "impress8", png: "writer_png_Export", jpg: "writer_jpg_Export", svg: "writer_svg_Export" }; var oe = { pdf: "application/pdf", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", doc: "application/msword", odt: "application/vnd.oasis.opendocument.text", rtf: "application/rtf", txt: "text/plain", html: "text/html", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xls: "application/vnd.ms-excel", ods: "application/vnd.oasis.opendocument.spreadsheet", csv: "text/csv", pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation", ppt: "application/vnd.ms-powerpoint", odp: "application/vnd.oasis.opendocument.presentation", png: "image/png", jpg: "image/jpeg", svg: "image/svg+xml" }, ne = { doc: "doc", docx: "docx", xls: "xls", xlsx: "xlsx", ppt: "ppt", pptx: "pptx", odt: "odt", ods: "ods", odp: "odp", odg: "odg", odf: "odf", rtf: "rtf", txt: "txt", html: "html", htm: "html", csv: "csv", xml: "xml", epub: "epub", pdf: "pdf" }, ye = { 0: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png"], 1: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png"], 2: ["pdf", "pptx", "ppt", "odp", "png", "svg", "html"], 3: ["pdf", "png", "svg", "html"], 4: ["pdf"] }; function ie(l) { return ye[l] || ["pdf"] } var K = { pdf: "pdf", docx: "docx", doc: "doc", odt: "odt", rtf: "rtf", txt: "txt", html: "html", xlsx: "xlsx", xls: "xls", ods: "ods", csv: "csv", pptx: "pptx", ppt: "ppt", odp: "odp", png: "png", jpg: "jpg", svg: "svg" }, $ = { pdf: "", csv: "44,34,76,1,,0,false,true,false,false,false,-1", txt: "UTF8" }, Se = "FilterName=Text - txt - csv (StarCalc),FilterOptions=44,34,76,1,,1033,false,true,false,false,false,0,true,false,true"; function M(l, e) { let t = []; return l?.toLowerCase() === "csv" && t.push(Se), e && t.push(`Password=${e}`), t.join(",") } var se = { doc: "text", docx: "text", odt: "text", rtf: "text", txt: "text", html: "text", htm: "text", epub: "text", xml: "text", xls: "spreadsheet", xlsx: "spreadsheet", ods: "spreadsheet", csv: "spreadsheet", ppt: "presentation", pptx: "presentation", odp: "presentation", odg: "drawing", odf: "drawing", pdf: "drawing" }, Ee = { text: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png"], spreadsheet: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png"], presentation: ["pdf", "pptx", "ppt", "odp", "png", "svg", "html"], drawing: ["pdf", "png", "svg", "html"], other: ["pdf"] }; function G(l) { let e = l.toLowerCase(), t = se[e]; return t ? Ee[t] : ["pdf"] } function re(l, e) { return G(l).includes(e.toLowerCase()) } function ae(l, e) { let t = l.toLowerCase(), r = e.toLowerCase(), n = G(t), o = se[t] || "unknown", s = ""; return o === "drawing" && ["docx", "doc", "xlsx", "xls", "pptx", "ppt"].includes(r) ? s = "PDF files are imported as Draw documents and cannot be exported to Office formats. " : o === "spreadsheet" && ["docx", "doc", "pptx", "ppt"].includes(r) ? s = "Spreadsheet documents cannot be converted to word processing or presentation formats. " : o === "presentation" && ["docx", "doc", "xlsx", "xls"].includes(r) ? s = "Presentation documents cannot be converted to word processing or spreadsheet formats. " : o === "text" && ["xlsx", "xls", "pptx", "ppt"].includes(r) && (s = "Text documents cannot be converted to spreadsheet or presentation formats. "), `Cannot convert ${t.toUpperCase()} to ${r.toUpperCase()}. ${s}Valid output formats for ${t.toUpperCase()}: ${n.join(", ")}` } var I = class { lok; docPtr; options; inputPath = ""; constructor(e, t, r = {}) { this.lok = e, this.docPtr = t, this.options = { maxResponseChars: r.maxResponseChars ?? 8e3, ...r }; } getDocPtr() { return this.docPtr } getLokBindings() { return this.lok } save() { try { return this.inputPath ? (this.lok.postUnoCommand(this.docPtr, ".uno:Save"), this.createResult({ path: this.inputPath })) : this.createErrorResult("No input path set", "Use saveAs() to specify a path") } catch (e) { return this.createErrorResult(`Save failed: ${String(e)}`) } } saveAs(e, t) { try { return this.lok.documentSaveAs(this.docPtr, e, t, ""), this.createResult({ path: e }) } catch (r) { return this.createErrorResult(`SaveAs failed: ${String(r)}`) } } close() { try { return this.lok.documentDestroy(this.docPtr), this.docPtr = 0, this.createResult(void 0) } catch (e) { return this.createErrorResult(`Close failed: ${String(e)}`) } } getEditMode() { return this.lok.getEditMode(this.docPtr) } enableEditMode() { try { if (this.lok.getEditMode(this.docPtr) === 1) return this.createResult({ editMode: 1 }); this.lok.postUnoCommand(this.docPtr, ".uno:Edit"); let t = this.lok.getEditMode(this.docPtr); return { success: !0, verified: t === 1, data: { editMode: t } } } catch (e) { return this.createErrorResult(`Failed to enable edit mode: ${String(e)}`) } } undo() { try { return this.lok.postUnoCommand(this.docPtr, ".uno:Undo"), this.createResult(void 0) } catch (e) { return this.createErrorResult(`Undo failed: ${String(e)}`) } } redo() { try { return this.lok.postUnoCommand(this.docPtr, ".uno:Redo"), this.createResult(void 0) } catch (e) { return this.createErrorResult(`Redo failed: ${String(e)}`) } } find(e, t) { try { let r = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.Backward": { type: "boolean", value: !1 }, "SearchItem.SearchAll": { type: "boolean", value: !0 }, "SearchItem.MatchCase": { type: "boolean", value: t?.caseSensitive ?? !1 }, "SearchItem.WordOnly": { type: "boolean", value: t?.wholeWord ?? !1 } }); this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", r); let n = this.lok.getTextSelection(this.docPtr, "text/plain"), o = n !== null && n.length > 0; return this.createResult({ matches: o ? 1 : 0, firstMatch: o ? { x: 0, y: 0 } : void 0 }) } catch (r) { return this.createErrorResult(`Find failed: ${String(r)}`) } } findAndReplaceAll(e, t, r) { try { let n = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: 3 }, "SearchItem.MatchCase": { type: "boolean", value: r?.caseSensitive ?? !1 }, "SearchItem.WordOnly": { type: "boolean", value: r?.wholeWord ?? !1 } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", n), this.createResult({ replacements: -1 }) } catch (n) { return this.createErrorResult(`Replace failed: ${String(n)}`) } } getStateChanges() { try { let e = this.lok.pollStateChanges(); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to poll state changes: ${String(e)}`) } } flushAndPollState() { try { this.lok.flushCallbacks(this.docPtr); let e = this.lok.pollStateChanges(); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to flush and poll state: ${String(e)}`) } } clearCallbackQueue() { this.lok.clearCallbackQueue(); } select(e) { try { let t = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.createResult({ selected: t || "" }) } catch (t) { return this.createErrorResult(`Select failed: ${String(t)}`) } } getSelection() { try { let e = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.createResult({ text: e || "", range: { type: "text", start: { paragraph: 0, character: 0 } } }) } catch (e) { return this.createErrorResult(`GetSelection failed: ${String(e)}`) } } clearSelection() { try { return this.lok.resetSelection(this.docPtr), this.createResult(void 0) } catch (e) { return this.createErrorResult(`ClearSelection failed: ${String(e)}`) } } createResult(e) { return { success: true, verified: true, data: e } } createErrorResult(e, t) { return { success: false, verified: false, error: e, suggestion: t } } createResultWithTruncation(e, t) { return { success: true, verified: true, data: e, truncated: t } } truncateContent(e, t) { let r = t ?? this.options.maxResponseChars, n = e.length; if (n <= r) return { content: e, truncated: false, original: n, returned: n }; let o = e.slice(0, r), s = o.lastIndexOf(" "); return s > r * .8 && (o = o.slice(0, s)), { content: o, truncated: true, original: n, returned: o.length } } truncateArray(e, t, r) { let n = e.length, o = 0, s = 0; for (let i of e) { let a = r(i); if (o + a.length > t) break; o += a.length, s++; } return { items: e.slice(0, s), truncated: s < n, original: n, returned: s } } a1ToRowCol(e) { let t = e.match(/^([A-Z]+)(\d+)$/i); if (!t) throw new Error(`Invalid A1 notation: ${e}`); let r = t[1].toUpperCase(), n = t[2], o = 0; for (let i = 0; i < r.length; i++)o = o * 26 + (r.charCodeAt(i) - 64); return o -= 1, { row: parseInt(n, 10) - 1, col: o } } rowColToA1(e, t) { let r = "", n = t + 1; for (; n > 0;) { let o = (n - 1) % 26; r = String.fromCharCode(65 + o) + r, n = Math.floor((n - 1) / 26); } return `${r}${e + 1}` } normalizeCellRef(e) { return typeof e == "string" ? this.a1ToRowCol(e) : e } setInputPath(e) { this.inputPath = e; } isOpen() { return this.docPtr !== 0 } }; var H = class extends I { cachedParagraphs = null; getDocumentType() { return "writer" } getStructure(e) { try { let t = this.getParagraphsInternal(), r = e?.maxResponseChars ?? this.options.maxResponseChars, n = t.map((i, a) => ({ index: a, preview: i.slice(0, 100) + (i.length > 100 ? "..." : ""), style: "Normal", charCount: i.length })), o = this.truncateArray(n, r, i => JSON.stringify(i)), s = { type: "writer", paragraphs: o.items, pageCount: this.lok.documentGetParts(this.docPtr), wordCount: t.join(" ").split(/\s+/).filter(i => i.length > 0).length }; return o.truncated ? this.createResultWithTruncation(s, { original: o.original, returned: o.returned, message: `Showing ${o.returned} of ${o.original} paragraphs. Use getParagraphs(start, count) to paginate.` }) : this.createResult(s) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getParagraph(e) { try { let t = this.getParagraphsInternal(); if (e < 0 || e >= t.length) return this.createErrorResult(`Paragraph index ${e} out of range (0-${t.length - 1})`, "Use getStructure() to see available paragraphs"); let r = t[e]; return this.createResult({ index: e, text: r, style: "Normal", charCount: r.length }) } catch (t) { return this.createErrorResult(`Failed to get paragraph: ${String(t)}`) } } getParagraphs(e, t) { try { let r = this.getParagraphsInternal(); if (e < 0 || e >= r.length) return this.createErrorResult(`Start index ${e} out of range`, `Valid range: 0-${r.length - 1}`); let n = Math.min(e + t, r.length), o = r.slice(e, n).map((s, i) => ({ index: e + i, text: s, style: "Normal", charCount: s.length })); return this.createResult(o) } catch (r) { return this.createErrorResult(`Failed to get paragraphs: ${String(r)}`) } } insertParagraph(e, t) { try { let r = this.getParagraphsInternal(), n = t?.afterIndex !== void 0 ? t.afterIndex + 1 : r.length; n > 0 && n <= r.length && this.lok.postUnoCommand(this.docPtr, ".uno:GoToEndOfDoc"), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPara"); let o = JSON.stringify({ Text: { type: "string", value: e } }); if (this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", o), t?.style && t.style !== "Normal") { let d = { "Heading 1": "Heading 1", "Heading 2": "Heading 2", "Heading 3": "Heading 3", List: "List" }[t.style]; if (d) { let h = JSON.stringify({ Template: { type: "string", value: d }, Family: { type: "short", value: 2 } }); this.lok.postUnoCommand(this.docPtr, ".uno:StyleApply", h); } } return this.cachedParagraphs = null, { success: !0, verified: this.getParagraphsInternal().length > r.length, data: { index: n } } } catch (r) { return this.createErrorResult(`Failed to insert paragraph: ${String(r)}`) } } replaceParagraph(e, t) { try { let r = this.getParagraphsInternal(); if (e < 0 || e >= r.length) return this.createErrorResult(`Paragraph index ${e} out of range`, `Valid range: 0-${r.length - 1}`); let n = r[e], o = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: n }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: 2 } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", o), this.cachedParagraphs = null, this.createResult({ oldText: n }) } catch (r) { return this.createErrorResult(`Failed to replace paragraph: ${String(r)}`) } } deleteParagraph(e) { try { let t = this.getParagraphsInternal(); if (e < 0 || e >= t.length) return this.createErrorResult(`Paragraph index ${e} out of range`, `Valid range: 0-${t.length - 1}`); let r = t[e], n = this.replaceParagraph(e, ""); return n.success ? this.createResult({ deletedText: r }) : this.createErrorResult(n.error || "Failed to delete") } catch (t) { return this.createErrorResult(`Failed to delete paragraph: ${String(t)}`) } } insertText(e, t) { try { let r = JSON.stringify({ Text: { type: "string", value: e } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", r), this.cachedParagraphs = null, this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert text: ${String(r)}`) } } deleteText(e, t) { try { let r = this.lok.getTextSelection(this.docPtr, "text/plain"); return this.lok.postUnoCommand(this.docPtr, ".uno:Delete"), this.cachedParagraphs = null, this.createResult({ deleted: r || "" }) } catch (r) { return this.createErrorResult(`Failed to delete text: ${String(r)}`) } } replaceText(e, t, r) { try { let n = r?.all ? 3 : 2, o = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: e }, "SearchItem.ReplaceString": { type: "string", value: t }, "SearchItem.Command": { type: "long", value: n } }); return this.lok.postUnoCommand(this.docPtr, ".uno:ExecuteSearch", o), this.cachedParagraphs = null, this.createResult({ replacements: -1 }) } catch (n) { return this.createErrorResult(`Failed to replace text: ${String(n)}`) } } formatText(e, t) { try { if (t.bold !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Bold"), t.italic !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Italic"), t.underline !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Underline"), t.fontSize !== void 0) { let r = JSON.stringify({ FontHeight: { type: "float", value: t.fontSize } }); this.lok.postUnoCommand(this.docPtr, ".uno:FontHeight", r); } if (t.fontName !== void 0) { let r = JSON.stringify({ CharFontName: { type: "string", value: t.fontName } }); this.lok.postUnoCommand(this.docPtr, ".uno:CharFontName", r); } return this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to format text: ${String(r)}`) } } getFormat(e) { try { this.lok.clearCallbackQueue(), this.lok.postUnoCommand(this.docPtr, ".uno:CharRightSel"), this.lok.flushCallbacks(this.docPtr), this.lok.postUnoCommand(this.docPtr, ".uno:CharLeft"), this.lok.flushCallbacks(this.docPtr); let t = this.lok.pollStateChanges(), r = {}, n = t.get(".uno:Bold"); n !== void 0 && (r.bold = n === "true"); let o = t.get(".uno:Italic"); o !== void 0 && (r.italic = o === "true"); let s = t.get(".uno:Underline"); s !== void 0 && (r.underline = s === "true"); let i = t.get(".uno:FontHeight"); if (i !== void 0) { let d = parseFloat(i); isNaN(d) || (r.fontSize = d); } let a = t.get(".uno:CharFontName"); return a !== void 0 && a.length > 0 && (r.fontName = a), this.createResult(r) } catch (t) { return this.createErrorResult(`Failed to get format: ${String(t)}`) } } getSelectionFormat() { try { let e = this.lok.pollStateChanges(); if (e.size === 0) { this.lok.clearCallbackQueue(), this.lok.postUnoCommand(this.docPtr, ".uno:SelectWord"), this.lok.flushCallbacks(this.docPtr); let t = this.lok.pollStateChanges(); return this.createResult(t) } return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get selection format: ${String(e)}`) } } getParagraphsInternal() { if (this.cachedParagraphs) return this.cachedParagraphs; let e = this.lok.getAllText(this.docPtr); return e ? (this.cachedParagraphs = e.split(/\n\n|\r\n\r\n/).map(t => t.trim()).filter(t => t.length > 0), this.cachedParagraphs) : [] } }; var j = class extends I { getDocumentType() { return "calc" } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.lok.getPartName(this.docPtr, o) || `Sheet${o + 1}`, i = this.lok.getDataArea(this.docPtr, o); r.push({ index: o, name: s, usedRange: i.col > 0 && i.row > 0 ? `A1:${this.rowColToA1(i.row - 1, i.col - 1)}` : "A1", rowCount: i.row, colCount: i.col }); } let n = { type: "calc", sheets: r }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getSheetNames() { try { let e = this.lok.documentGetParts(this.docPtr), t = []; for (let r = 0; r < e; r++) { let n = this.lok.getPartName(this.docPtr, r) || `Sheet${r + 1}`; t.push(n); } return this.createResult(t) } catch (e) { return this.createErrorResult(`Failed to get sheet names: ${String(e)}`) } } getCell(e, t) { try { this.selectSheet(t); let { row: r, col: n } = this.normalizeCellRef(e), o = this.rowColToA1(r, n); this.goToCell(o); let s = this.getCellValueInternal(), i = this.getCellFormulaInternal(); return this.createResult({ address: o, value: s, formula: i || void 0 }) } catch (r) { return this.createErrorResult(`Failed to get cell: ${String(r)}`) } } getCells(e, t, r) { try { this.selectSheet(t); let { startRow: n, startCol: o, endRow: s, endCol: i } = this.normalizeRangeRef(e), a = r?.maxResponseChars ?? this.options.maxResponseChars, d = [], h = 0, m = !1; for (let u = n; u <= s && !m; u++) { let g = []; for (let f = o; f <= i && !m; f++) { let P = this.rowColToA1(u, f); this.goToCell(P); let p = this.getCellValueInternal(), O = { address: P, value: p }, _ = JSON.stringify(O); if (h + _.length > a) { m = !0; break } h += _.length, g.push(O); } g.length > 0 && d.push(g); } return m ? this.createResultWithTruncation(d, { original: (s - n + 1) * (i - o + 1), returned: d.reduce((u, g) => u + g.length, 0), message: "Range truncated due to size. Use smaller ranges to paginate." }) : this.createResult(d) } catch (n) { return this.createErrorResult(`Failed to get cells: ${String(n)}`) } } setCellValue(e, t, r) { try { this.selectSheet(r); let { row: n, col: o } = this.normalizeCellRef(e), s = this.rowColToA1(n, o); this.goToCell(s); let i = this.getCellValueInternal(), a = typeof t == "number" ? t.toString() : t, d = JSON.stringify({ StringName: { type: "string", value: a } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", d); let h = this.getCellValueInternal(), m = typeof t == "number" ? t.toString() : t; return { success: !0, verified: h === m || h === t, data: { oldValue: i, newValue: h } } } catch (n) { return this.createErrorResult(`Failed to set cell value: ${String(n)}`) } } setCellFormula(e, t, r) { try { this.selectSheet(r); let { row: n, col: o } = this.normalizeCellRef(e), s = this.rowColToA1(n, o); this.goToCell(s); let i = JSON.stringify({ StringName: { type: "string", value: t } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", i); let a = this.getCellValueInternal(); return this.createResult({ calculatedValue: a }) } catch (n) { return this.createErrorResult(`Failed to set formula: ${String(n)}`) } } setCells(e, t, r) { try { this.selectSheet(r); let { startRow: n, startCol: o } = this.normalizeRangeRef(e), s = 0; for (let i = 0; i < t.length; i++) { let a = t[i]; if (a) for (let d = 0; d < a.length; d++) { let h = a[d]; if (h == null) continue; let m = this.rowColToA1(n + i, o + d); this.goToCell(m); let u = typeof h == "number" ? h.toString() : String(h), g = JSON.stringify({ StringName: { type: "string", value: u } }); this.lok.postUnoCommand(this.docPtr, ".uno:EnterString", g), s++; } } return this.createResult({ cellsUpdated: s }) } catch (n) { return this.createErrorResult(`Failed to set cells: ${String(n)}`) } } clearCell(e, t) { try { this.selectSheet(t); let { row: r, col: n } = this.normalizeCellRef(e), o = this.rowColToA1(r, n); this.goToCell(o); let s = this.getCellValueInternal(); return this.lok.postUnoCommand(this.docPtr, ".uno:ClearContents"), this.createResult({ oldValue: s }) } catch (r) { return this.createErrorResult(`Failed to clear cell: ${String(r)}`) } } clearRange(e, t) { try { this.selectSheet(t); let r = this.normalizeRangeToString(e); this.goToCell(r), this.lok.postUnoCommand(this.docPtr, ".uno:ClearContents"); let { startRow: n, startCol: o, endRow: s, endCol: i } = this.normalizeRangeRef(e), a = (s - n + 1) * (i - o + 1); return this.createResult({ cellsCleared: a }) } catch (r) { return this.createErrorResult(`Failed to clear range: ${String(r)}`) } } insertRow(e, t) { try { return this.selectSheet(t), this.goToCell(this.rowColToA1(e + 1, 0)), this.lok.postUnoCommand(this.docPtr, ".uno:InsertRows"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert row: ${String(r)}`) } } insertColumn(e, t) { try { this.selectSheet(t); let r = typeof e == "string" ? this.a1ToRowCol(e + "1").col + 1 : e + 1; return this.goToCell(this.rowColToA1(0, r)), this.lok.postUnoCommand(this.docPtr, ".uno:InsertColumns"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to insert column: ${String(r)}`) } } deleteRow(e, t) { try { return this.selectSheet(t), this.goToCell(this.rowColToA1(e, 0)), this.lok.postUnoCommand(this.docPtr, ".uno:DeleteRows"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete row: ${String(r)}`) } } deleteColumn(e, t) { try { this.selectSheet(t); let r = typeof e == "string" ? this.a1ToRowCol(e + "1").col : e; return this.goToCell(this.rowColToA1(0, r)), this.lok.postUnoCommand(this.docPtr, ".uno:DeleteColumns"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete column: ${String(r)}`) } } formatCells(e, t, r) { try { this.selectSheet(r); let n = this.normalizeRangeToString(e); if (this.goToCell(n), t.bold !== void 0 && this.lok.postUnoCommand(this.docPtr, ".uno:Bold"), t.numberFormat !== void 0) { let o = JSON.stringify({ NumberFormatValue: { type: "string", value: t.numberFormat } }); this.lok.postUnoCommand(this.docPtr, ".uno:NumberFormatValue", o); } if (t.backgroundColor !== void 0) { let o = JSON.stringify({ BackgroundColor: { type: "long", value: this.hexToNumber(t.backgroundColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:BackgroundColor", o); } return this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to format cells: ${String(n)}`) } } addSheet(e) { try { let t = JSON.stringify({ Name: { type: "string", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:Insert", t); let r = this.lok.documentGetParts(this.docPtr); return this.createResult({ index: r - 1 }) } catch (t) { return this.createErrorResult(`Failed to add sheet: ${String(t)}`) } } renameSheet(e, t) { try { this.selectSheet(e); let r = JSON.stringify({ Name: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:RenameTable", r), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to rename sheet: ${String(r)}`) } } deleteSheet(e) { try { return this.selectSheet(e), this.lok.postUnoCommand(this.docPtr, ".uno:Remove"), this.createResult(void 0) } catch (t) { return this.createErrorResult(`Failed to delete sheet: ${String(t)}`) } } selectSheet(e) { if (e === void 0) return; let t = typeof e == "number" ? e : this.getSheetIndexByName(e); t >= 0 && this.lok.documentSetPart(this.docPtr, t); } getSheetIndexByName(e) { let t = this.lok.documentGetParts(this.docPtr); for (let r = 0; r < t; r++)if (this.lok.getPartName(this.docPtr, r) === e) return r; return -1 } goToCell(e) { let t = JSON.stringify({ ToPoint: { type: "string", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:GoToCell", t); } getCellValueInternal() { let e = this.lok.getTextSelection(this.docPtr, "text/plain"); if (!e) return null; let t = parseFloat(e); return !isNaN(t) && e.trim() === t.toString() ? t : e.toLowerCase() === "true" ? true : e.toLowerCase() === "false" ? false : e } getCellFormulaInternal() { let e = this.lok.getCommandValues(this.docPtr, ".uno:GetFormulaBarText"); if (!e) return null; try { return JSON.parse(e).value ?? null } catch { return null } } normalizeRangeRef(e) { if (typeof e == "string") { let n = e.split(":"), o = this.a1ToRowCol(n[0]), s = n[1] ? this.a1ToRowCol(n[1]) : o; return { startRow: o.row, startCol: o.col, endRow: s.row, endCol: s.col } } let t = this.normalizeCellRef(e.start), r = this.normalizeCellRef(e.end); return { startRow: t.row, startCol: t.col, endRow: r.row, endCol: r.col } } normalizeRangeToString(e) { if (typeof e == "string") return e; let t = this.normalizeCellRef(e.start), r = this.normalizeCellRef(e.end); return `${this.rowColToA1(t.row, t.col)}:${this.rowColToA1(r.row, r.col)}` } hexToNumber(e) { return parseInt(e.replace("#", ""), 16) } }; var J = class extends I { getDocumentType() { return "impress" } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.getSlideInfoInternal(o); r.push(s); } let n = { type: "impress", slides: r, slideCount: t }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= t) return this.createErrorResult(`Invalid slide index: ${e}. Valid range: 0-${t - 1}`, "Use getStructure() to see available slides"); this.lok.documentSetPart(this.docPtr, e); let r = this.lok.getAllText(this.docPtr) || "", n = this.parseTextFrames(r), o = { index: e, title: n.find(s => s.type === "title")?.text, textFrames: n, hasNotes: !1 }; return this.createResult(o) } catch (t) { return this.createErrorResult(`Failed to get slide: ${String(t)}`) } } getSlideCount() { try { let e = this.lok.documentGetParts(this.docPtr); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get slide count: ${String(e)}`) } } addSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); e?.afterSlide !== void 0 ? this.lok.documentSetPart(this.docPtr, e.afterSlide) : this.lok.documentSetPart(this.docPtr, t - 1), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPage"), e?.layout && this.applySlideLayout(e.layout); let r = e?.afterSlide !== void 0 ? e.afterSlide + 1 : t; return { success: !0, verified: this.lok.documentGetParts(this.docPtr) > t, data: { index: r } } } catch (t) { return this.createErrorResult(`Failed to add slide: ${String(t)}`) } } deleteSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); return t <= 1 ? this.createErrorResult("Cannot delete the last slide", "A presentation must have at least one slide") : e < 0 || e >= t ? this.createErrorResult(`Invalid slide index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DeletePage"), this.createResult(void 0)) } catch (t) { return this.createErrorResult(`Failed to delete slide: ${String(t)}`) } } duplicateSlide(e) { try { let t = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= t ? this.createErrorResult(`Invalid slide index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DuplicatePage"), this.createResult({ newIndex: e + 1 })) } catch (t) { return this.createErrorResult(`Failed to duplicate slide: ${String(t)}`) } } moveSlide(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r || t < 0 || t >= r) return this.createErrorResult(`Invalid slide indices. Valid range: 0-${r - 1}`, "Check slide indices are within bounds"); if (e === t) return this.createErrorResult("Source and destination are the same", "Provide different indices to move"); this.lok.documentSetPart(this.docPtr, e); let n = JSON.stringify({ Position: { type: "long", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:MovePageFirst", n), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to move slide: ${String(r)}`) } } setSlideTitle(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let n = this.lok.getAllText(this.docPtr) || "", s = this.parseTextFrames(n).find(a => a.type === "title")?.text; this.lok.postUnoCommand(this.docPtr, ".uno:SelectAll"); let i = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", i), this.createResult({ oldTitle: s }) } catch (r) { return this.createErrorResult(`Failed to set slide title: ${String(r)}`) } } setSlideBody(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let n = this.lok.getAllText(this.docPtr) || "", s = this.parseTextFrames(n).find(a => a.type === "body")?.text; this.lok.postUnoCommand(this.docPtr, ".uno:NextObject"); let i = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", i), this.createResult({ oldBody: s }) } catch (r) { return this.createErrorResult(`Failed to set slide body: ${String(r)}`) } } setSlideNotes(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= r) return this.createErrorResult(`Invalid slide index: ${e}`); this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:NotesMode"); let n = JSON.stringify({ Text: { type: "string", value: t } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", n), this.lok.postUnoCommand(this.docPtr, ".uno:NormalViewMode"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to set slide notes: ${String(r)}`) } } setSlideLayout(e, t) { try { let r = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= r ? this.createErrorResult(`Invalid slide index: ${e}`) : (this.lok.documentSetPart(this.docPtr, e), this.applySlideLayout(t), this.createResult(void 0)) } catch (r) { return this.createErrorResult(`Failed to set slide layout: ${String(r)}`) } } getSlideInfoInternal(e) { this.lok.documentSetPart(this.docPtr, e); let t = this.lok.getAllText(this.docPtr) || "", r = this.parseTextFrames(t), n = r.find(o => o.type === "title"); return { index: e, title: n?.text, layout: this.detectLayout(r), textFrameCount: r.length } } parseTextFrames(e) { let t = e.split(/\n\n+/).filter(n => n.trim()), r = []; return t.forEach((n, o) => { let s = o === 0 ? "title" : o === 1 ? "body" : "other"; r.push({ index: o, type: s, text: n.trim(), bounds: { x: 0, y: 0, width: 0, height: 0 } }); }), r } detectLayout(e) { return e.length === 0 ? "blank" : e.length === 1 && e[0]?.type === "title" ? "title" : e.length >= 2 ? "titleContent" : "blank" } applySlideLayout(e) { let r = { blank: 0, title: 1, titleContent: 2, twoColumn: 3 }[e] ?? 0, n = JSON.stringify({ WhatLayout: { type: "long", value: r } }); this.lok.postUnoCommand(this.docPtr, ".uno:AssignLayout", n); } }; var X = class extends I { isImportedPdf = false; getDocumentType() { return "draw" } setImportedPdf(e) { this.isImportedPdf = e; } getStructure(e) { try { let t = this.lok.documentGetParts(this.docPtr), r = []; for (let o = 0; o < t; o++) { let s = this.getPageInfoInternal(o); r.push(s); } let n = { type: "draw", pages: r, pageCount: t, isImportedPdf: this.isImportedPdf }; return this.createResult(n) } catch (t) { return this.createErrorResult(`Failed to get structure: ${String(t)}`) } } getPage(e) { try { let t = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= t) return this.createErrorResult(`Invalid page index: ${e}. Valid range: 0-${t - 1}`, "Use getStructure() to see available pages"); this.lok.documentSetPart(this.docPtr, e); let r = this.lok.documentGetDocumentSize(this.docPtr), n = this.getShapesOnPage(), o = { index: e, shapes: n, size: { width: r.width, height: r.height } }; return this.createResult(o) } catch (t) { return this.createErrorResult(`Failed to get page: ${String(t)}`) } } getPageCount() { try { let e = this.lok.documentGetParts(this.docPtr); return this.createResult(e) } catch (e) { return this.createErrorResult(`Failed to get page count: ${String(e)}`) } } addPage(e) { try { let t = this.lok.documentGetParts(this.docPtr); e?.afterPage !== void 0 ? this.lok.documentSetPart(this.docPtr, e.afterPage) : this.lok.documentSetPart(this.docPtr, t - 1), this.lok.postUnoCommand(this.docPtr, ".uno:InsertPage"); let r = e?.afterPage !== void 0 ? e.afterPage + 1 : t; return this.createResult({ index: r }) } catch (t) { return this.createErrorResult(`Failed to add page: ${String(t)}`) } } deletePage(e) { try { let t = this.lok.documentGetParts(this.docPtr); return t <= 1 ? this.createErrorResult("Cannot delete the last page", "A drawing document must have at least one page") : e < 0 || e >= t ? this.createErrorResult(`Invalid page index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DeletePage"), this.createResult(void 0)) } catch (t) { return this.createErrorResult(`Failed to delete page: ${String(t)}`) } } duplicatePage(e) { try { let t = this.lok.documentGetParts(this.docPtr); return e < 0 || e >= t ? this.createErrorResult(`Invalid page index: ${e}`, `Valid range: 0-${t - 1}`) : (this.lok.documentSetPart(this.docPtr, e), this.lok.postUnoCommand(this.docPtr, ".uno:DuplicatePage"), this.createResult({ newIndex: e + 1 })) } catch (t) { return this.createErrorResult(`Failed to duplicate page: ${String(t)}`) } } addShape(e, t, r, n) { try { let o = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= o) return this.createErrorResult(`Invalid page index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let s = this.getShapeCommand(t), i = JSON.stringify({ X: { type: "long", value: r.x }, Y: { type: "long", value: r.y }, Width: { type: "long", value: r.width }, Height: { type: "long", value: r.height } }); if (this.lok.postUnoCommand(this.docPtr, s, i), n?.text) { let a = JSON.stringify({ Text: { type: "string", value: n.text } }); this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", a); } if (n?.fillColor) { let a = JSON.stringify({ FillColor: { type: "long", value: this.hexToNumber(n.fillColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:FillColor", a); } if (n?.lineColor) { let a = JSON.stringify({ LineColor: { type: "long", value: this.hexToNumber(n.lineColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:XLineColor", a); } return this.createResult({ shapeIndex: 0 }) } catch (o) { return this.createErrorResult(`Failed to add shape: ${String(o)}`) } } addLine(e, t, r, n) { try { let o = this.lok.documentGetParts(this.docPtr); if (e < 0 || e >= o) return this.createErrorResult(`Invalid page index: ${e}`); this.lok.documentSetPart(this.docPtr, e); let s = JSON.stringify({ StartX: { type: "long", value: t.x }, StartY: { type: "long", value: t.y }, EndX: { type: "long", value: r.x }, EndY: { type: "long", value: r.y } }); if (this.lok.postUnoCommand(this.docPtr, ".uno:Line", s), n?.lineColor) { let i = JSON.stringify({ LineColor: { type: "long", value: this.hexToNumber(n.lineColor) } }); this.lok.postUnoCommand(this.docPtr, ".uno:XLineColor", i); } if (n?.lineWidth) { let i = JSON.stringify({ LineWidth: { type: "long", value: n.lineWidth } }); this.lok.postUnoCommand(this.docPtr, ".uno:LineWidth", i); } return this.createResult({ shapeIndex: 0 }) } catch (o) { return this.createErrorResult(`Failed to add line: ${String(o)}`) } } deleteShape(e, t) { try { return this.lok.documentSetPart(this.docPtr, e), this.selectShape(t), this.lok.postUnoCommand(this.docPtr, ".uno:Delete"), this.createResult(void 0) } catch (r) { return this.createErrorResult(`Failed to delete shape: ${String(r)}`) } } setShapeText(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t), this.lok.postUnoCommand(this.docPtr, ".uno:EnterGroup"), this.lok.postUnoCommand(this.docPtr, ".uno:SelectAll"); let n = JSON.stringify({ Text: { type: "string", value: r } }); return this.lok.postUnoCommand(this.docPtr, ".uno:InsertText", n), this.lok.postUnoCommand(this.docPtr, ".uno:LeaveGroup"), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to set shape text: ${String(n)}`) } } moveShape(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t); let n = JSON.stringify({ X: { type: "long", value: r.x }, Y: { type: "long", value: r.y } }); return this.lok.postUnoCommand(this.docPtr, ".uno:SetObjectPosition", n), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to move shape: ${String(n)}`) } } resizeShape(e, t, r) { try { this.lok.documentSetPart(this.docPtr, e), this.selectShape(t); let n = JSON.stringify({ Width: { type: "long", value: r.width }, Height: { type: "long", value: r.height } }); return this.lok.postUnoCommand(this.docPtr, ".uno:Size", n), this.createResult(void 0) } catch (n) { return this.createErrorResult(`Failed to resize shape: ${String(n)}`) } } getPageInfoInternal(e) { this.lok.documentSetPart(this.docPtr, e); let t = this.lok.documentGetDocumentSize(this.docPtr), r = this.getShapesOnPage(); return { index: e, shapeCount: r.length, size: { width: t.width, height: t.height } } } getShapesOnPage() { let e = this.lok.getAllText(this.docPtr) || ""; return e.trim() ? [{ index: 0, type: "text", text: e, bounds: { x: 0, y: 0, width: 0, height: 0 } }] : [] } selectShape(e) { let t = JSON.stringify({ Index: { type: "long", value: e } }); this.lok.postUnoCommand(this.docPtr, ".uno:SelectObject", t); } getShapeCommand(e) { return { rectangle: ".uno:Rect", ellipse: ".uno:Ellipse", line: ".uno:Line", text: ".uno:Text", image: ".uno:InsertGraphic", group: ".uno:FormatGroup", other: ".uno:Rect" }[e] } hexToNumber(e) { return parseInt(e.replace("#", ""), 16) } }; var Pe = 0, Oe = 1, _e = 2, ke = 3; function le(l, e, t) { let r = l.documentGetDocumentType(e); switch (r) { case Pe: return new H(l, e, t); case Oe: return new j(l, e, t); case _e: return new J(l, e, t); case ke: return new X(l, e, t); default: throw new Error(`Unsupported document type: ${r}`) } } function be(l) { return { 0: "INVALIDATE_TILES", 1: "INVALIDATE_VISIBLE_CURSOR", 2: "TEXT_SELECTION", 3: "TEXT_SELECTION_START", 4: "TEXT_SELECTION_END", 5: "CURSOR_VISIBLE", 6: "GRAPHIC_SELECTION", 7: "HYPERLINK_CLICKED", 8: "STATE_CHANGED", 9: "STATUS_INDICATOR_START", 10: "STATUS_INDICATOR_SET_VALUE", 11: "STATUS_INDICATOR_FINISH", 12: "SEARCH_NOT_FOUND", 13: "DOCUMENT_SIZE_CHANGED", 14: "SET_PART", 15: "SEARCH_RESULT_SELECTION", 16: "UNO_COMMAND_RESULT", 17: "CELL_CURSOR", 18: "MOUSE_POINTER", 19: "CELL_FORMULA", 20: "DOCUMENT_PASSWORD", 21: "DOCUMENT_PASSWORD_TO_MODIFY", 22: "CONTEXT_MENU", 23: "INVALIDATE_VIEW_CURSOR", 24: "TEXT_VIEW_SELECTION", 25: "CELL_VIEW_CURSOR", 26: "GRAPHIC_VIEW_SELECTION", 27: "VIEW_CURSOR_VISIBLE", 28: "VIEW_LOCK", 29: "REDLINE_TABLE_SIZE_CHANGED", 30: "REDLINE_TABLE_ENTRY_MODIFIED", 31: "COMMENT", 32: "INVALIDATE_HEADER", 33: "CELL_ADDRESS" }[l] || `UNKNOWN(${l})` } var Y = { nSize: 0, destroy: 4, documentLoad: 8, getError: 12, documentLoadWithOptions: 16, freeError: 20 }, ce = { nSize: 0, destroy: 4, saveAs: 8 }, Ce = new TextEncoder, ue = new TextDecoder, Q = class { module; lokPtr = 0; verbose; useShims; constructor(e, t = false) { this.module = e, this.verbose = t, this.useShims = typeof this.module._lok_documentLoad == "function", this.useShims ? this.log("Using direct LOK shim exports") : this.log("Using vtable traversal (shims not available)"); } log(...e) { this.verbose && console.log("[LOK]", ...e); } get HEAPU8() { return this.module.HEAPU8 } get HEAPU32() { return this.module.HEAPU32 } get HEAP32() { return this.module.HEAP32 } allocString(e) { let t = Ce.encode(e + "\0"), r = this.module._malloc(t.length); return this.HEAPU8.set(t, r), r } readString(e) { if (e === 0) return null; let t = this.HEAPU8, r = e; for (; t[r] !== 0;)r++; let n = t.slice(e, r); return ue.decode(n) } readPtr(e) { return this.HEAPU32[e >> 2] || 0 } getFunc(e) { return this.module.wasmTable.get(e) } initialize(e = "/instdir/program") { this.log("Initializing with path:", e); let t = this.allocString(e); try { let r = this.module._libreofficekit_hook; if (typeof r != "function") throw new Error("libreofficekit_hook export not found on module"); if (this.lokPtr = r(t), this.lokPtr === 0) throw new Error("Failed to initialize LibreOfficeKit"); this.log("LOK initialized, ptr:", this.lokPtr); } finally { this.module._free(t); } } getError() { if (this.lokPtr === 0) return null; if (this.useShims && this.module._lok_getError) { let o = this.module._lok_getError(this.lokPtr); return this.readString(o) } let e = this.readPtr(this.lokPtr), t = this.readPtr(e + Y.getError); if (t === 0) return null; let n = this.getFunc(t)(this.lokPtr); return this.readString(n) } getVersionInfo() { return "LibreOffice WASM" } toFileUrl(e) { return e.startsWith("file://") ? e : "file://" + (e.startsWith("/") ? e : "/" + e) } documentLoad(e) { if (this.lokPtr === 0) throw new Error("LOK not initialized"); let t = this.toFileUrl(e); this.log("Loading document:", e, "->", t); let r = this.allocString(t); try { let n = Date.now(), o; if (this.useShims && this.module._lok_documentLoad) o = this.module._lok_documentLoad(this.lokPtr, r); else { let s = this.readPtr(this.lokPtr), i = this.readPtr(s + Y.documentLoad); o = this.getFunc(i)(this.lokPtr, r); } if (this.log("Document loaded in", Date.now() - n, "ms, ptr:", o), o === 0) { let s = this.getError(); throw new Error(`Failed to load document: ${s || "unknown error"}`) } return o } finally { this.module._free(r); } } documentLoadWithOptions(e, t) { if (this.lokPtr === 0) throw new Error("LOK not initialized"); let r = this.toFileUrl(e); this.log("Loading document with options:", e, "->", r, t); let n = this.allocString(r), o = this.allocString(t); try { let s; if (this.useShims && this.module._lok_documentLoadWithOptions) s = this.module._lok_documentLoadWithOptions(this.lokPtr, n, o); else { let i = this.readPtr(this.lokPtr), a = this.readPtr(i + Y.documentLoadWithOptions); if (a === 0) return this.documentLoad(e); s = this.getFunc(a)(this.lokPtr, n, o); } if (s === 0) { let i = this.getError(); throw new Error(`Failed to load document: ${i || "unknown error"}`) } return this.log("Document loaded, ptr:", s), s } finally { this.module._free(n), this.module._free(o); } } documentSaveAs(e, t, r, n = "") { if (e === 0) throw new Error("Invalid document pointer"); let o = this.toFileUrl(t); this.log("Saving document to:", t, "->", o, "format:", r); let s = this.allocString(o), i = this.allocString(r), a = this.allocString(n); try { let d; if (this.useShims && this.module._lok_documentSaveAs) d = this.module._lok_documentSaveAs(e, s, i, a); else { let h = this.readPtr(e), m = this.readPtr(h + ce.saveAs); d = this.getFunc(m)(e, s, i, a); } if (this.log("Save result:", d), d === 0) throw new Error("Failed to save document") } finally { this.module._free(s), this.module._free(i), this.module._free(a); } } documentDestroy(e) { if (e === 0) return; if (this.useShims && this.module._lok_documentDestroy) { this.module._lok_documentDestroy(e), this.log("Document destroyed (via shim)"); return } let t = this.readPtr(e), r = this.readPtr(t + ce.destroy); r !== 0 && (this.getFunc(r)(e), this.log("Document destroyed (via vtable)")); } destroy() { if (this.lokPtr !== 0) { try { if (this.useShims && this.module._lok_destroy) this.module._lok_destroy(this.lokPtr), this.log("LOK destroyed (via shim)"); else { let e = this.readPtr(this.lokPtr), t = this.readPtr(e + Y.destroy); t !== 0 && (this.getFunc(t)(this.lokPtr), this.log("LOK destroyed (via vtable)")); } } catch (e) { this.log("LOK destroy error (ignored):", e); } this.lokPtr = 0; } } isInitialized() { return this.lokPtr !== 0 } isUsingShims() { return this.useShims } documentGetParts(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetParts ? this.module._lok_documentGetParts(e) : (this.log("documentGetParts: shim not available"), 0) } documentGetPart(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetPart ? this.module._lok_documentGetPart(e) : (this.log("documentGetPart: shim not available"), 0) } documentSetPart(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetPart) { this.module._lok_documentSetPart(e, t); return } this.log("documentSetPart: shim not available"); } documentGetDocumentType(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetDocumentType ? this.module._lok_documentGetDocumentType(e) : (this.log("documentGetDocumentType: shim not available"), 0) } documentGetDocumentSize(e) { if (this.log(`documentGetDocumentSize called with docPtr: ${e}`), e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetDocumentSize) { let t = this.module._malloc(8); try { this.module._lok_documentGetDocumentSize(e, t, t + 4); let r = this.HEAP32[t >> 2] ?? 0, n = this.HEAP32[t + 4 >> 2] ?? 0; return this.log(`documentGetDocumentSize: ${r}x${n} twips`), { width: r, height: n } } finally { this.module._free(t); } } return this.log("documentGetDocumentSize: shim not available"), { width: 0, height: 0 } } documentInitializeForRendering(e, t = "") { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentInitializeForRendering) { let r = this.allocString(t); try { this.module._lok_documentInitializeForRendering(e, r); } finally { this.module._free(r); } return } this.log("documentInitializeForRendering: shim not available"); } documentPaintTile(e, t, r, n, o, s, i) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPaintTile) { let a = t * r * 4, d = this.module._malloc(a); if (d === 0) throw new Error(`Failed to allocate ${a} bytes for tile buffer`); try { this.module._lok_documentPaintTile(e, d, t, r, n, o, s, i); let h = new Uint8Array(a); return h.set(this.HEAPU8.subarray(d, d + a)), h } finally { this.module._free(d); } } return this.log("documentPaintTile: shim not available"), new Uint8Array(0) } documentGetTileMode(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetTileMode ? this.module._lok_documentGetTileMode(e) : (this.log("documentGetTileMode: shim not available"), 0) } renderPage(e, t, r, n = 0, o = false) { this.documentInitializeForRendering(e); let s = this.documentGetDocumentType(e); if (s === 2 || s === 3) { console.log(`[LOK] Setting part to ${t} for presentation/drawing`), this.documentSetPart(e, t); let p = this.documentGetPart(e); console.log(`[LOK] Current part after setPart: ${p}`), o || (this.setEditMode(e, 0), console.log("[LOK] Set edit mode to 0 (view mode) for presentation rendering")); } let i = this.documentGetDocumentSize(e); if (this.log("Document size (twips):", i), i.width === 0 || i.height === 0) throw new Error("Failed to get document size"); let a = 0, d = 0, h = i.width, m = i.height; if (s === 0 || s === 1) { let p = this.getPartPageRectangles(e); if (p) { let _ = this.parsePageRectangles(p)[t]; _ && (a = _.x, d = _.y, h = _.width, m = _.height, this.log(`Page ${t} rectangle:`, _)); } } let u = m / h, g = r, f = n > 0 ? n : Math.round(r * u); console.log(`[LOK] Calling paintTile: ${g}x${f} from tile pos (${a}, ${d}) size (${h}x${m})`); let P = this.documentPaintTile(e, g, f, a, d, h, m); return console.log(`[LOK] paintTile returned ${P.length} bytes`), { data: P, width: g, height: f } } renderPageFullQuality(e, t, r = 150, n, o = false) { this.documentInitializeForRendering(e); let s = this.documentGetDocumentType(e); (s === 2 || s === 3) && (this.log(`Setting part to ${t} for presentation/drawing`), this.documentSetPart(e, t), o || (this.setEditMode(e, 0), this.log("Set edit mode to 0 (view mode) for presentation rendering"))); let i = this.documentGetDocumentSize(e); if (this.log("Document size (twips):", i), i.width === 0 || i.height === 0) throw new Error("Failed to get document size"); let a = 0, d = 0, h = i.width, m = i.height; if (s === 0 || s === 1) { let O = this.getPartPageRectangles(e); if (O) { let C = this.parsePageRectangles(O)[t]; C && (a = C.x, d = C.y, h = C.width, m = C.height, this.log(`Page ${t} rectangle:`, C)); } } let u = 1440, g = Math.round(h * r / u), f = Math.round(m * r / u), P = r; if (n && (g > n || f > n)) { let O = n / Math.max(g, f); g = Math.round(g * O), f = Math.round(f * O), P = Math.round(r * O), this.log(`Capped dimensions to ${g}x${f} (effective DPI: ${P})`); } console.log(`[LOK] renderPageFullQuality: ${g}x${f} at ${P} DPI from tile (${a}, ${d}) size (${h}x${m}) twips`); let p = this.documentPaintTile(e, g, f, a, d, h, m); return console.log(`[LOK] renderPageFullQuality returned ${p.length} bytes`), { data: p, width: g, height: f, dpi: P } } getTextSelection(e, t = "text/plain;charset=utf-8") { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetTextSelection) { let r = this.allocString(t), n = this.module._malloc(4); try { let o = this.module._lok_documentGetTextSelection(e, r, n); if (o === 0) return null; let s = this.readString(o); return this.module._free(o), s } finally { this.module._free(r), this.module._free(n); } } return this.log("getTextSelection: shim not available"), null } setTextSelection(e, t, r, n) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetTextSelection) { this.module._lok_documentSetTextSelection(e, t, r, n); return } this.log("setTextSelection: shim not available"); } getSelectionType(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetSelectionType ? this.module._lok_documentGetSelectionType(e) : (this.log("getSelectionType: shim not available"), 0) } resetSelection(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentResetSelection) { this.module._lok_documentResetSelection(e); return } this.log("resetSelection: shim not available"); } postMouseEvent(e, t, r, n, o = 1, s = 1, i = 0) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostMouseEvent) { this.module._lok_documentPostMouseEvent(e, t, r, n, o, s, i); return } this.log("postMouseEvent: shim not available"); } postKeyEvent(e, t, r, n) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostKeyEvent) { this.module._lok_documentPostKeyEvent(e, t, r, n); return } this.log("postKeyEvent: shim not available"); } postUnoCommand(e, t, r = "{}", n = false) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPostUnoCommand) { let o = this.allocString(t), s = this.allocString(r); try { this.module._lok_documentPostUnoCommand(e, o, s, n ? 1 : 0); } finally { this.module._free(o), this.module._free(s); } return } this.log("postUnoCommand: shim not available"); } getCommandValues(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetCommandValues) { let r = this.allocString(t); try { let n = this.module._lok_documentGetCommandValues(e, r); if (n === 0) return null; let o = this.readString(n); return this.module._free(n), o } finally { this.module._free(r); } } return this.log("getCommandValues: shim not available"), null } getPartPageRectangles(e) { if (this.log(`getPartPageRectangles called with docPtr: ${e}`), e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartPageRectangles) { this.log("getPartPageRectangles: using shim"); let t = this.module._lok_documentGetPartPageRectangles(e); if (this.log(`getPartPageRectangles: resultPtr=${t}`), t === 0) return null; let r = this.readString(t); return this.log(`getPartPageRectangles: result="${r?.slice(0, 100)}..."`), this.module._free(t), r } return this.log("getPartPageRectangles: shim not available"), null } getPartInfo(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartInfo) { let r = this.module._lok_documentGetPartInfo(e, t); if (r === 0) return null; let n = this.readString(r); return this.module._free(r), n } return this.log("getPartInfo: shim not available"), null } getPartName(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetPartName) { let r = this.module._lok_documentGetPartName(e, t); if (r === 0) return null; let n = this.readString(r); return this.module._free(r), n } return this.log("getPartName: shim not available"), null } paste(e, t, r) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentPaste) { let n = this.allocString(t), o, s; if (typeof r == "string") { let i = new TextEncoder().encode(r); s = i.length, o = this.module._malloc(s), this.HEAPU8.set(i, o); } else s = r.length, o = this.module._malloc(s), this.HEAPU8.set(r, o); try { return this.module._lok_documentPaste(e, n, o, s) !== 0 } finally { this.module._free(n), this.module._free(o); } } return this.log("paste: shim not available"), false } setClientZoom(e, t, r, n, o) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetClientZoom) { this.module._lok_documentSetClientZoom(e, t, r, n, o); return } this.log("setClientZoom: shim not available"); } setClientVisibleArea(e, t, r, n, o) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetClientVisibleArea) { this.module._lok_documentSetClientVisibleArea(e, t, r, n, o); return } this.log("setClientVisibleArea: shim not available"); } getA11yFocusedParagraph(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetA11yFocusedParagraph) { let t = this.module._lok_documentGetA11yFocusedParagraph(e); if (t === 0) return null; let r = this.readString(t); return this.module._free(t), r } return this.log("getA11yFocusedParagraph: shim not available"), null } getA11yCaretPosition(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetA11yCaretPosition ? this.module._lok_documentGetA11yCaretPosition(e) : (this.log("getA11yCaretPosition: shim not available"), -1) } setAccessibilityState(e, t, r) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetAccessibilityState) { this.module._lok_documentSetAccessibilityState(e, t, r ? 1 : 0); return } this.log("setAccessibilityState: shim not available"); } getDataArea(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentGetDataArea) { let r = this.module._malloc(8), n = this.module._malloc(8); try { this.module._lok_documentGetDataArea(e, t, r, n); let o = this.HEAP32[r >> 2] ?? 0, s = this.HEAP32[n >> 2] ?? 0; return { col: o, row: s } } finally { this.module._free(r), this.module._free(n); } } return this.log("getDataArea: shim not available"), { col: 0, row: 0 } } getEditMode(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetEditMode ? this.module._lok_documentGetEditMode(e) : (this.log("getEditMode: shim not available"), 0) } setEditMode(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetEditMode) { this.log(`setEditMode: setting mode to ${t}`), this.module._lok_documentSetEditMode(e, t); return } this.log("setEditMode: shim not available"); } createView(e) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentCreateView) { let t = this.module._lok_documentCreateView(e); return this.log(`createView: created view ${t}`), t } return this.log("createView: shim not available"), -1 } createViewWithOptions(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentCreateViewWithOptions) { let r = this.allocString(t); try { let n = this.module._lok_documentCreateViewWithOptions(e, r); return this.log(`createViewWithOptions: created view ${n}`), n } finally { this.module._free(r); } } return this.log("createViewWithOptions: shim not available"), -1 } destroyView(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentDestroyView) { this.log(`destroyView: destroying view ${t}`), this.module._lok_documentDestroyView(e, t); return } this.log("destroyView: shim not available"); } setView(e, t) { if (e === 0) throw new Error("Invalid document pointer"); if (this.useShims && this.module._lok_documentSetView) { this.log(`setView: setting active view to ${t}`), this.module._lok_documentSetView(e, t); return } this.log("setView: shim not available"); } getView(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetView ? this.module._lok_documentGetView(e) : (this.log("getView: shim not available"), -1) } getViewsCount(e) { if (e === 0) throw new Error("Invalid document pointer"); return this.useShims && this.module._lok_documentGetViewsCount ? this.module._lok_documentGetViewsCount(e) : (this.log("getViewsCount: shim not available"), 0) } enableSyncEvents() { this.useShims && this.module._lok_enableSyncEvents ? (this.module._lok_enableSyncEvents(), this.log("enableSyncEvents: Unipoll mode enabled")) : this.log("enableSyncEvents: shim not available"); } disableSyncEvents() { this.useShims && this.module._lok_disableSyncEvents ? (this.module._lok_disableSyncEvents(), this.log("disableSyncEvents: Unipoll mode disabled")) : this.log("disableSyncEvents: shim not available"); } registerCallback(e) { if (e === 0) throw new Error("Invalid document pointer"); this.useShims && this.module._lok_documentRegisterCallback ? (this.module._lok_documentRegisterCallback(e), this.log("registerCallback: callback registered")) : this.log("registerCallback: shim not available"); } unregisterCallback(e) { if (e === 0) throw new Error("Invalid document pointer"); this.useShims && this.module._lok_documentUnregisterCallback ? (this.module._lok_documentUnregisterCallback(e), this.log("unregisterCallback: callback unregistered")) : this.log("unregisterCallback: shim not available"); } hasCallbackEvents() { return this.useShims && this.module._lok_hasCallbackEvents ? this.module._lok_hasCallbackEvents() !== 0 : false } getCallbackEventCount() { return this.useShims && this.module._lok_getCallbackEventCount ? this.module._lok_getCallbackEventCount() : 0 } pollCallback() { if (!this.useShims || !this.module._lok_pollCallback) return null; let e = 4096, t = this.module._malloc(e), r = this.module._malloc(4); try { let n = this.module._lok_pollCallback(t, e, r); if (n === -1) return null; let o = this.module.HEAP32[r >> 2] ?? 0, s = ""; if (o > 0) { let i = Math.min(o, e - 1), a = this.module.HEAPU8.slice(t, t + i); s = ue.decode(a); } return { type: n, typeName: be(n), payload: s } } finally { this.module._free(t), this.module._free(r); } } pollAllCallbacks() { let e = [], t = this.pollCallback(); for (; t !== null;)e.push(t), t = this.pollCallback(); return e } clearCallbackQueue() { this.useShims && this.module._lok_clearCallbackQueue && (this.module._lok_clearCallbackQueue(), this.log("clearCallbackQueue: queue cleared")); } flushCallbacks(e) { if (e === 0) throw new Error("Invalid document pointer"); let t = !!this.module._lok_flushCallbacks; this.log(`flushCallbacks: useShims=${this.useShims}, _lok_flushCallbacks exists=${t}`), this.useShims && this.module._lok_flushCallbacks ? (this.module._lok_flushCallbacks(e), this.log("flushCallbacks: callbacks flushed")) : this.log("flushCallbacks: shim not available"); } pollStateChanges() { let e = new Map, t = this.pollAllCallbacks(); for (let r of t) if (r.type === 8) { let n = r.payload.indexOf("="); if (n !== -1) { let o = r.payload.substring(0, n), s = r.payload.substring(n + 1); e.set(o, s); } else e.set(r.payload, ""); } return e } clickAndGetText(e, t, r) { return this.postMouseEvent(e, 0, t, r, 1, 1, 0), this.postMouseEvent(e, 1, t, r, 1, 1, 0), this.getTextSelection(e, "text/plain;charset=utf-8") } doubleClickAndGetWord(e, t, r) { return this.postMouseEvent(e, 0, t, r, 2, 1, 0), this.postMouseEvent(e, 1, t, r, 2, 1, 0), this.getTextSelection(e, "text/plain;charset=utf-8") } selectAll(e) { this.postUnoCommand(e, ".uno:SelectAll"); } getAllText(e) { this.log(`getAllText called with docPtr: ${e}`), this.selectAll(e); let t = this.getTextSelection(e, "text/plain;charset=utf-8"); return this.log(`getAllText: text="${t?.slice(0, 100)}..."`), this.resetSelection(e), t } parsePageRectangles(e) { return e ? e.split(";").filter(t => t.trim()).map(t => { let r = t.split(",").map(Number); return { x: r[0] ?? 0, y: r[1] ?? 0, width: r[2] ?? 0, height: r[3] ?? 0 } }) : [] } }; var Z = class { module = null; lokBindings = null; initialized = false; initializing = false; options; corrupted = false; fsTracked = false; constructor(e = {}) { this.options = { wasmPath: "./wasm", verbose: false, ...e }; } isCorruptionError(e) { let t = e instanceof Error ? e.message : e; return t.includes("memory access out of bounds") || t.includes("ComponentContext is not avail") || t.includes("unreachable") || t.includes("table index is out of bounds") || t.includes("null function") } async reinitialize() { if (this.options.verbose && console.log("[LibreOfficeConverter] Reinitializing due to corruption..."), this.lokBindings) { try { this.lokBindings.destroy(); } catch { } this.lokBindings = null; } this.module = null, this.initialized = false, this.corrupted = false, await this.initialize(); } async initializeWithModule(e) { if (!this.initialized) { if (this.initializing) { for (; this.initializing;)await new Promise(t => setTimeout(t, 100)); return } this.initializing = true; try { this.module = e, this.setupFileSystem(), this.initializeLibreOfficeKit(), this.initialized = !0, this.options.onReady?.(); } catch (t) { console.error("[LibreOfficeConverter] Initialization error:", t); let r = t instanceof S ? t : new S("WASM_NOT_INITIALIZED", `Failed to initialize with module: ${String(t)}`); throw this.options.onError?.(r), r } finally { this.initializing = false; } } } async initialize() { if (!this.initialized) { if (this.initializing) { for (; this.initializing;)await new Promise(e => setTimeout(e, 100)); return } this.initializing = true, this.emitProgress("loading", 0, "Loading LibreOffice WASM module..."); try { this.module = await this.loadModule(), this.emitProgress("initializing", 50, "Setting up virtual filesystem..."), this.setupFileSystem(), this.emitProgress("initializing", 60, "Initializing LibreOfficeKit..."), this.initializeLibreOfficeKit(), this.emitProgress("initializing", 90, "LibreOfficeKit ready"), this.initialized = !0, this.emitProgress("complete", 100, "LibreOffice ready"), this.options.onReady?.(); } catch (e) { console.error("[LibreOfficeConverter] Initialization error:", e); let t = e instanceof S ? e : new S("WASM_NOT_INITIALIZED", `Failed to initialize WASM module: ${String(e)}`); throw this.options.onError?.(t), t } finally { this.initializing = false; } } } async loadModule() { let e = this.options.wasmPath || "./wasm", t = `${e}/soffice.js`, r = { locateFile: s => s.endsWith(".wasm") ? `${e}/soffice.wasm` : s.endsWith(".data") ? `${e}/soffice.data` : `${e}/${s}`, print: this.options.verbose ? console.log : () => { }, printErr: this.options.verbose ? console.error : () => { } }, n = document.createElement("script"); n.src = t, await new Promise((s, i) => { n.onload = () => s(), n.onerror = () => i(new Error(`Failed to load ${t}`)), document.head.appendChild(n); }); let o = window.createSofficeModule; if (!o) throw new S("WASM_NOT_INITIALIZED", "WASM module factory not found. Make sure soffice.js is loaded."); return new Promise((s, i) => { let a = { ...r, onRuntimeInitialized: () => { s(a); } }; a.fonts = this.options.fonts || []; o(a).catch(i); }) } setupFileSystem() { if (!this.module?.FS) throw new S("WASM_NOT_INITIALIZED", "Filesystem not available"); let e = this.module.FS, t = r => { try { e.mkdir(r); } catch { } }; t("/tmp"), t("/tmp/input"), t("/tmp/output"); } initializeLibreOfficeKit() { if (!this.module) throw new S("WASM_NOT_INITIALIZED", "Module not loaded"); if (this.options.verbose && this.module.FS) { let e = this.module.FS; if (!this.fsTracked && (this.fsTracked = true, e.trackingDelegate || (e.trackingDelegate = { onOpen: r => { console.log("[FS OPEN]", r); }, onOpenFile: r => { console.log("[FS OPEN FILE]", r); } }), typeof e.open == "function")) { let r = e.open.bind(e); e.open = ((n, o, s) => { console.log("[FS OPEN CALL]", n); try { return r(n, o, s) } catch (i) { throw i?.code === "ENOENT" && console.log("[FS ENOENT]", n), i } }); } let t = (r, n) => { try { console.log(`[FS] ${r}:`, e.readdir(n)); } catch (o) { console.log(`[FS] ${r}: ERROR -`, o.message); } }; t("ROOT", "/"), t("PROGRAM DIR", "/instdir/program"), t("SHARE DIR", "/instdir/share"), t("REGISTRY DIR", "/instdir/share/registry"), t("FILTER DIR", "/instdir/share/filter"), t("CONFIG DIR", "/instdir/share/config/soffice.cfg"), t("CONFIG FILTER", "/instdir/share/config/soffice.cfg/filter"), t("IMPRESS MODULES", "/instdir/share/config/soffice.cfg/modules/simpress"); } this.lokBindings = new Q(this.module, this.options.verbose); try { if (this.lokBindings.initialize("/instdir/program"), this.options.verbose) { let e = this.lokBindings.getVersionInfo(); e && console.log("[LOK] Version:", e); } } catch (e) { throw new S("WASM_NOT_INITIALIZED", `Failed to initialize LibreOfficeKit: ${String(e)}`) } } async convert(e, t, r = "document") { if (this.corrupted && await this.reinitialize(), !this.initialized || !this.module) throw new S("WASM_NOT_INITIALIZED", "LibreOffice WASM not initialized. Call initialize() first."); let n = Date.now(), o = this.normalizeInput(e); if (o.length === 0) throw new S("INVALID_INPUT", "Empty document provided"); let s = t.inputFormat || this.getExtensionFromFilename(r) || "docx", i = t.outputFormat; if (!te[i]) throw new S("UNSUPPORTED_FORMAT", `Unsupported output format: ${i}`); if (!re(s, i)) throw new S("UNSUPPORTED_FORMAT", ae(s, i)); let a = `/tmp/input/doc.${s}`, d = `/tmp/output/doc.${i}`; try { this.emitProgress("converting", 10, "Writing input document..."), this.module.FS.writeFile(a, o), this.emitProgress("converting", 30, "Converting document..."); let h = await this.performConversion(a, d, t); this.emitProgress("complete", 100, "Conversion complete"); let u = `${this.getBasename(r)}.${i}`; return { data: h, mimeType: oe[i], filename: u, duration: Date.now() - n } } catch (h) { throw h instanceof Error && this.isCorruptionError(h) && (this.corrupted = true, this.options.verbose && console.log("[LibreOfficeConverter] Corruption detected, will reinitialize on next convert")), h } finally { try { this.module?.FS.unlink(a); } catch { } try { this.module?.FS.unlink(d); } catch { } } } async performConversion(e, t, r) { if (!this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Module not loaded"); this.emitProgress("converting", 40, "Loading document..."); let n = 0; try { let o = M(r.inputFormat, r.password); if (this.options.verbose) { try { let a = this.module.FS.stat(e); console.log("[Convert] File exists before LOK load:", e, "size:", a.size); } catch (a) { console.log("[Convert] File NOT found before LOK load:", e, a.message); } o && console.log("[Convert] Using load options:", o); } if (o ? n = this.lokBindings.documentLoadWithOptions(e, o) : n = this.lokBindings.documentLoad(e), n === 0) throw new S("LOAD_FAILED", "Failed to load document"); this.emitProgress("converting", 60, "Converting format..."); let s = K[r.outputFormat], i = $[r.outputFormat] || ""; if (r.outputFormat === "pdf" && r.pdf) { let a = []; if (r.pdf.pdfaLevel) { let d = { "PDF/A-1b": 1, "PDF/A-2b": 2, "PDF/A-3b": 3 }; a.push(`SelectPdfVersion=${d[r.pdf.pdfaLevel] || 0}`); } r.pdf.quality !== void 0 && a.push(`Quality=${r.pdf.quality}`), a.length > 0 && (i = a.join(",")); } if (["png", "jpg", "svg"].includes(r.outputFormat) && r.image?.pageIndex !== void 0) { let a = r.image.pageIndex + 1; i ? i += `;PageRange=${a}-${a}` : i = `PageRange=${a}-${a}`; } this.emitProgress("converting", 70, "Saving document..."), this.lokBindings.documentSaveAs(n, t, s, i), this.emitProgress("converting", 90, "Reading output..."); try { let a = this.module.FS.readFile(t); if (a.length === 0) throw new S("CONVERSION_FAILED", "Conversion produced empty output"); return a } catch (a) { throw new S("CONVERSION_FAILED", `Failed to read converted file: ${String(a)}`) } } catch (o) { throw o instanceof S ? o : new S("CONVERSION_FAILED", `Conversion failed: ${String(o)}`) } finally { if (n !== 0 && this.lokBindings) try { this.lokBindings.documentDestroy(n); } catch { } } } async renderPagePreviews(e, t, r = {}) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let n = this.normalizeInput(e), o = (t.inputFormat || "docx").toLowerCase(), s = r.width ?? 256, i = r.height ?? 0, a = r.pageIndices ?? [], d = `/tmp/preview/doc.${o}`, h = this.module.FS; try { try { h.mkdir("/tmp/preview"); } catch { } h.writeFile(d, n); let m = this.lokBindings.documentLoad(d); if (m === 0) throw new S("LOAD_FAILED", "Failed to load document for preview"); try { let u = this.lokBindings.documentGetParts(m); this.options.verbose && console.log(`[Preview] Document has ${u} pages/parts`); let g = a.length > 0 ? a.filter(p => p >= 0 && p < u) : Array.from({ length: u }, (p, O) => O), f = [], P = r.editMode ?? !1; for (let p of g) { this.options.verbose && console.log(`[Preview] Rendering page ${p + 1}/${u}`); let O = this.lokBindings.renderPage(m, p, s, i, P); f.push({ page: p, data: O.data, width: O.width, height: O.height }); } return f } finally { this.lokBindings.documentDestroy(m); } } finally { try { h.unlink(d); } catch { } try { h.rmdir("/tmp/preview"); } catch { } } } async renderPageFullQuality(e, t, r, n = {}) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let o = this.normalizeInput(e), s = (t.inputFormat || "docx").toLowerCase(), i = n.dpi ?? 150, a = n.maxDimension, d = `/tmp/fullquality/doc.${s}`, h = this.module.FS; try { try { h.mkdir("/tmp/fullquality"); } catch { } h.writeFile(d, o); let m = this.lokBindings.documentLoad(d); if (m === 0) throw new S("LOAD_FAILED", "Failed to load document for full quality render"); try { let u = this.lokBindings.documentGetParts(m); if (r < 0 || r >= u) throw new S("CONVERSION_FAILED", `Page index ${r} out of range (0-${u - 1})`); this.options.verbose && console.log(`[FullQuality] Rendering page ${r + 1}/${u} at ${i} DPI`); let g = n.editMode ?? !1, f = this.lokBindings.renderPageFullQuality(m, r, i, a, g); return { page: r, data: f.data, width: f.width, height: f.height, dpi: f.dpi } } finally { this.lokBindings.documentDestroy(m); } } finally { try { h.unlink(d); } catch { } try { h.rmdir("/tmp/fullquality"); } catch { } } } async getPageCount(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), o = `/tmp/pagecount/doc.${(t.inputFormat || "docx").toLowerCase()}`, s = this.module.FS; try { try { s.mkdir("/tmp/pagecount"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.documentGetParts(i) } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/pagecount"); } catch { } } } async getDocumentInfo(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), o = `/tmp/docinfo/doc.${(t.inputFormat || "docx").toLowerCase()}`, s = this.module.FS; try { try { s.mkdir("/tmp/docinfo"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.documentGetDocumentType(i), d = this.lokBindings.documentGetParts(i), h = ie(a), m = { 0: "Text Document", 1: "Spreadsheet", 2: "Presentation", 3: "Drawing", 4: "Other" }; return { documentType: a, documentTypeName: m[a] || "Unknown", validOutputFormats: h, pageCount: d } } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/docinfo"); } catch { } } } async getDocumentText(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/inspect/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/inspect"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.getAllText(i) } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/inspect"); } catch { } } } async getPageNames(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/names/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/names"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.documentGetParts(i), d = []; for (let h = 0; h < a; h++) { let m = this.lokBindings.getPartName(i, h); d.push(m || `Page ${h + 1}`); } return d } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/names"); } catch { } } } async getPageRectangles(e, t) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let r = this.normalizeInput(e), n = t.inputFormat?.toLowerCase(); if (!n) throw new S("INVALID_INPUT", "Input format is required"); let o = `/tmp/rects/doc.${n}`, s = this.module.FS; try { try { s.mkdir("/tmp/rects"); } catch { } s.writeFile(o, r); let i = this.lokBindings.documentLoad(o); if (i === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let a = this.lokBindings.getPartPageRectangles(i); return this.lokBindings.parsePageRectangles(a || "") } finally { this.lokBindings.documentDestroy(i); } } finally { try { s.unlink(o); } catch { } try { s.rmdir("/tmp/rects"); } catch { } } } async getSpreadsheetDataArea(e, t, r = 0) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let n = this.normalizeInput(e), o = t.inputFormat?.toLowerCase(); if (!o) throw new S("INVALID_INPUT", "Input format is required"); let s = `/tmp/dataarea/doc.${o}`, i = this.module.FS; try { try { i.mkdir("/tmp/dataarea"); } catch { } i.writeFile(s, n); let a = this.lokBindings.documentLoad(s); if (a === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { return this.lokBindings.getDataArea(a, r) } finally { this.lokBindings.documentDestroy(a); } } finally { try { i.unlink(s); } catch { } try { i.rmdir("/tmp/dataarea"); } catch { } } } async executeUnoCommand(e, t, r, n = "{}") { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let o = this.normalizeInput(e), s = t.inputFormat?.toLowerCase(); if (!s) throw new S("INVALID_INPUT", "Input format is required"); let i = `/tmp/uno/doc.${s}`, a = this.module.FS; try { try { a.mkdir("/tmp/uno"); } catch { } a.writeFile(i, o); let d = this.lokBindings.documentLoad(i); if (d === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { this.lokBindings.postUnoCommand(d, r, n); } finally { this.lokBindings.documentDestroy(d); } } finally { try { a.unlink(i); } catch { } try { a.rmdir("/tmp/uno"); } catch { } } } async renderPage(e, t, r, n, o = 0) { if (!this.initialized || !this.module || !this.lokBindings) throw new S("WASM_NOT_INITIALIZED", "Converter not initialized"); let s = this.normalizeInput(e), a = `/tmp/renderpage/doc.${(t.inputFormat || "docx").toLowerCase()}`, d = this.module.FS; try { try { d.mkdir("/tmp/renderpage"); } catch { } d.writeFile(a, s); let h = this.lokBindings.documentLoad(a); if (h === 0) throw new S("LOAD_FAILED", "Failed to load document"); try { let m = this.lokBindings.renderPage(h, r, n, o); return { page: r, data: m.data, width: m.width, height: m.height } } finally { this.lokBindings.documentDestroy(h); } } finally { try { d.unlink(a); } catch { } try { d.rmdir("/tmp/renderpage"); } catch { } } } openDocument(e, t) { return Promise.reject(new S("CONVERSION_FAILED", "Editor sessions not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } editorOperation(e, t, r) { return Promise.reject(new S("CONVERSION_FAILED", "Editor operations not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } closeDocument(e) { return Promise.reject(new S("CONVERSION_FAILED", "Editor sessions not supported by LibreOfficeConverter. Use WorkerConverter or WorkerBrowserConverter.")) } getLokBindings() { return this.lokBindings } destroy() { if (this.lokBindings) { try { this.lokBindings.destroy(); } catch { } this.lokBindings = null; } if (this.module) try { let e = this.module; if (e.PThread?.terminateAllThreads && e.PThread.terminateAllThreads(), e.PThread?.runningWorkers) { for (let t of e.PThread.runningWorkers) t?.terminate && t.terminate(); e.PThread.runningWorkers = []; } if (e.PThread?.unusedWorkers) { for (let t of e.PThread.unusedWorkers) t?.terminate && t.terminate(); e.PThread.unusedWorkers = []; } } catch { } return this.module = null, this.initialized = false, Promise.resolve() } isReady() { return this.initialized } getModule() { return this.module } static getSupportedInputFormats() { return Object.keys(ne) } static getSupportedOutputFormats() { return Object.keys(te) } static getValidOutputFormats(e) { return G(e) } static isConversionSupported(e, t) { return re(e, t) } normalizeInput(e) { return e instanceof Uint8Array ? e : e instanceof ArrayBuffer ? new Uint8Array(e) : new Uint8Array(e) } getExtensionFromFilename(e) { let t = e.split("."); return t.length > 1 && t.pop()?.toLowerCase() || null } getBasename(e) { let t = e.lastIndexOf("."); return t > 0 ? e.substring(0, t) : e } emitProgress(e, t, r) { this.options.onProgress?.({ phase: e, percent: t, message: r }); } }; var me = { "download-wasm": 50, "download-data": 30, compile: 5, filesystem: 7, "lok-init": 7, ready: 1, starting: 0, loading: 0, initializing: 0, converting: 0, complete: 0 }, x = { "download-wasm": 0, "download-data": 0, compile: 0, filesystem: 0, "lok-init": 0, ready: 0, starting: 0, loading: 0, initializing: 0, converting: 0, complete: 0 }, pe = 0, ee = 0; function ge() { let l = 0; for (let t of Object.keys(x)) l += x[t]; let e = Math.min(100, Math.round(l)); return e > ee && (ee = e), ee } function q(l) { return `${(l / 1048576).toFixed(1)} MB` } function de(l, e, t) { let r = me[l], n = t > 0 ? e / t : 0, o = r * n; o > x[l] && (x[l] = o); let s = l === "download-wasm" ? `Downloading WebAssembly... ${q(e)} / ${q(t)}` : `Downloading filesystem... ${q(e)} / ${q(t)}`; fe({ percent: ge(), message: s, phase: l, bytesLoaded: e, bytesTotal: t }); } function B(l, e) { let t = me[l]; t > x[l] && (x[l] = t), fe({ percent: ge(), message: e, phase: l }); } function fe(l) { self.postMessage({ type: "progress", id: pe, progress: l }); } function we() { let l = self.fetch; self.fetch = async function (r, n) { let o = typeof r == "string" ? r : r instanceof URL ? r.href : r.url, s = null; o.includes("soffice.wasm") ? (s = "download-wasm", console.log("[Worker] Starting fetch download: soffice.wasm")) : o.includes("soffice.data") && (s = "download-data", console.log("[Worker] Starting fetch download: soffice.data")); let i = await l(r, n); if (!s) return i; if (s === "download-wasm") return console.log("[Worker] Returning original response for soffice.wasm (streaming compile requires raw Response)"), i; let a = i.headers.get("Content-Length"), d = a ? parseInt(a, 10) : 0; if (!d || !i.body) return console.log(`[Worker] No content-length for ${o}, skipping progress tracking`), i; let h = i.body.getReader(), m = 0, u = new ReadableStream({ async start(g) { for (; ;) { let { done: f, value: P } = await h.read(); if (f) { console.log("[Worker] Finished fetch download: soffice.data"), g.close(); break } m += P.length, de(s, m, d), g.enqueue(P); } } }); return new Response(u, { headers: i.headers, status: i.status, statusText: i.statusText }) }, console.log("[Worker] Installed progress-tracking fetch interceptor"); let e = self.XMLHttpRequest, t = function () { let r = new e, n = "", o = r.open.bind(r); r.open = function (i, a, d, h, m) { return n = String(a), o(i, a, d ?? true, h, m) }; let s = r.send.bind(r); return r.send = function (i) { let a = null; if (n.includes("soffice.wasm") ? (a = "download-wasm", console.log("[Worker] Starting XHR download: soffice.wasm")) : n.includes("soffice.data") && (a = "download-data", console.log("[Worker] Starting XHR download: soffice.data")), a) { let d = a; r.addEventListener("progress", h => { h.lengthComputable && de(d, h.loaded, h.total); }), r.addEventListener("load", () => { console.log(`[Worker] Finished XHR download: ${d === "download-wasm" ? "soffice.wasm" : "soffice.data"}`); }); } return s(i) }, r }; Object.defineProperty(t, "prototype", { value: e.prototype, writable: false }), self.XMLHttpRequest = t, console.log("[Worker] Installed progress-tracking XHR interceptor"); } var E = null, c = null, W = null, b = false, v = null, N = new Map, Te = 0; function Le(l) { let e = 0, t = Math.max(1, Math.floor(l.length / 1e3)); for (let r = 0; r < l.length; r += t) { let n = l[r]; n !== void 0 && (e = (e << 5) - e + n | 0); } return `${e}_${l.length}` } function Re(l) { let e = c.documentGetDocumentType(l); if (e === 0) { let r = c.getPartPageRectangles(l); if (r) { let n = c.parsePageRectangles(r); return console.log(`[Worker] getDocumentPageCount: TEXT doc has ${n.length} pages from rectangles`), n.length } return console.log("[Worker] getDocumentPageCount: TEXT doc has no page rectangles, assuming 1 page"), 1 } let t = c.documentGetParts(l); return console.log(`[Worker] getDocumentPageCount: docType=${e} has ${t} parts`), t } function F(l, e) { let t = Le(l); if (v && v.inputHash === t && c) return console.log(`[Worker] getOrLoadDocument: reusing cached doc ptr=${v.docPtr}, pageCount=${v.pageCount}`), { docPtr: v.docPtr, pageCount: v.pageCount }; console.log(`[Worker] getOrLoadDocument: loading new document (hash=${t})`), A(); let r = `/tmp/input/cached_doc.${e || "docx"}`; E.FS.writeFile(r, l); let n = M(e), o; if (n ? o = c.documentLoadWithOptions(r, n) : o = c.documentLoad(r), o === 0) { let i = c.getError(); throw new Error(i || "Failed to load document") } let s = Re(o); return console.log(`[Worker] getOrLoadDocument: loaded doc ptr=${o}, pageCount=${s}`), v = { docPtr: o, inputHash: t, filePath: r, pageCount: s }, { docPtr: o, pageCount: s } } function A() { if (v && c && E) { console.log(`[Worker] closeCachedDocument: closing cached doc ptr=${v.docPtr}`); try { c.documentDestroy(v.docPtr); } catch { } try { E.FS.unlink(v.filePath); } catch { } v = null; } } function y(l) { l.data ? self.postMessage(l, [l.data.buffer]) : self.postMessage(l); } function L(l, e, t) { y({ type: "progress", id: l, progress: { percent: e, message: t } }); } async function ve(l) { if (b) { y({ type: "ready", id: l.id }); return } let { sofficeJs: e, sofficeWasm: t, sofficeData: r, sofficeWorkerJs: n } = l; if (!e || !t || !r || !n) { y({ type: "error", id: l.id, error: "Missing required WASM paths (sofficeJs, sofficeWasm, sofficeData, sofficeWorkerJs)" }); return } let o = l.verbose || false; pe = l.id; for (let s of Object.keys(x)) x[s] = 0; ee = 0, l.enableProgressTracking ? (console.log("[Worker] Progress tracking enabled, installing interceptors..."), we()) : console.log("[Worker] Progress tracking disabled (default)"), B("download-wasm", "Preparing to download WebAssembly..."); try { console.log("[Worker] Setting up Module with explicit paths:", { sofficeJs: e, sofficeWasm: t, sofficeData: r, sofficeWorkerJs: n }), self.Module = { mainScriptUrlOrBlob: e, preRun: [function () { try { var FS = self.Module.FS; function mk(p) { try { FS.mkdir(p) } catch (e) { } } mk("/instdir"); mk("/instdir/share"); mk("/instdir/share/fonts"); mk("/instdir/share/fonts/truetype"); try { FS.symlink("/instdir", "/inst") } catch (e) { } /* Write fonts from Module.fonts (ArrayBuffer) synchronously */ var fonts = self.Module.fonts || []; fonts.forEach(function(f) { var name = f.filename || "font.bin"; var data = f.data; if (!data) return; try { FS.writeFile("/instdir/share/fonts/truetype/" + name, new Uint8Array(data)); console.log("[preRun] Font written to /instdir/: " + name); } catch (e) { console.error("[preRun] Font write /instdir/ failed:", e); } try { FS.writeFile("/inst/share/fonts/truetype/" + name, new Uint8Array(data)); console.log("[preRun] Font written to /inst/: " + name); } catch (e) { console.error("[preRun] Font write /inst/ failed:", e); } }) { console.log("CJK Font loaded") }, function () { console.error("CJK Font failed to load") }) } catch (e) { console.error("Font install error", e) } }], locateFile: (i, a) => { let d; return i.endsWith(".wasm") ? d = t : i.endsWith(".data") ? d = r : i.includes(".worker.") ? d = n : d = `${e.substring(0, e.lastIndexOf("/") + 1)}${i}`, console.log("[Worker] locateFile called:", i, "scriptDir:", a, "-> result:", d), d }, print: console.log, printErr: console.error }, importScripts(e), B("compile", "Compiling WebAssembly module..."), await new Promise((i, a) => { let d = () => { if (self.Module && self.Module.calledRun) i(); else if (self.Module?.onRuntimeInitialized) { let h = self.Module.onRuntimeInitialized; self.Module.onRuntimeInitialized = () => { h?.(), i(); }; } else self.Module && (self.Module.onRuntimeInitialized = i); setTimeout(() => a(new Error("WASM initialization timeout")), 12e4); }; self.Module && self.Module.calledRun ? i() : d(); }), E = self.Module, B("filesystem", "Setting up filesystem..."); try { let i = E; i.ENV ? (i.ENV.SAL_LOG = "+ALL", i.ENV.MAX_CONCURRENCY = "1", console.log("[Worker] Set SAL_LOG to +ALL")) : console.log("[Worker] ENV not available"); } catch (i) { console.log("[Worker] Could not set SAL_LOG:", i); } let s = E.FS; if (o) { let i = s.open.bind(s); s.open = (a, d, h) => { console.log("[FS OPEN CALL]", a); try { return i(a, d, h) } catch (m) { throw m?.code === "ENOENT" && console.log("[FS ENOENT]", a), m } }; } try { s.mkdir("/tmp"); } catch { } try { s.mkdir("/tmp/input"); } catch { } try { s.mkdir("/tmp/output"); } catch { } if (B("lok-init", "Initializing LibreOfficeKit..."), W = new Z({ verbose: o }), await W.initializeWithModule(E), c = W.getLokBindings(), !c) throw new Error("Failed to get LOK bindings from converter"); c.enableSyncEvents(), console.log("[LOK Worker] Enabled synchronous event dispatch (Unipoll mode)"), b = !0, B("ready", "Ready"), y({ type: "ready", id: l.id }); } catch (s) { y({ type: "error", id: l.id, error: s instanceof Error ? s.message : String(s) }); } } var Ae = ["png", "jpg", "jpeg", "svg"]; function Ie(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, outputFormat: r, filterOptions: n, password: o } = l; if (!e || !r) { y({ type: "error", id: l.id, error: "Missing input data or output format" }); return } let s = Ae.includes(r.toLowerCase()), i = `/tmp/input/doc.${t || "docx"}`, a = `/tmp/output/doc.${r}`, d = 0, h = []; try { L(l.id, 10, "Writing input file..."), E.FS.writeFile(i, e), L(l.id, 30, "Loading document..."); let m = M(t, o); if (m ? d = c.documentLoadWithOptions(i, m) : d = c.documentLoad(i), d === 0) { let f = c.getError(); throw new Error(f || "Failed to load document") } let u = c.documentGetParts(d), g = c.documentGetDocumentType(d); if (s && u > 1) { L(l.id, 40, `Exporting ${u} pages as ${r.toUpperCase()}...`); let f = K[r], P = n || $[r] || "", p = [], { width: O, height: _ } = c.documentGetDocumentSize(d), C = _ / O, D = 1024, U = Math.round(D * C); for (let k = 0; k < u; k++) { let R = 40 + Math.round(k / u * 40); L(l.id, R, `Exporting page ${k + 1}/${u}...`); let w = `/tmp/output/page_${k + 1}.${r}`; if (h.push(w), g === 2 || g === 3) { c.documentSetPart(d, k); let T = P; (r === "png" || r === "jpg" || r === "jpeg") && (T = `PixelWidth=${D};PixelHeight=${U}`, P && (T = `${P};${T}`)), c.documentSaveAs(d, w, f, T), console.log(`[Worker] Page ${k + 1} (presentation) exported with opts: ${T}`); } else { let T = `PageRange=${k + 1}-${k + 1}`; (r === "png" || r === "jpg" || r === "jpeg") && (T += `;PixelWidth=${D};PixelHeight=${U}`), P && (T = `${P};${T}`), c.documentSaveAs(d, w, f, T), console.log(`[Worker] Page ${k + 1} (text) exported with opts: ${T}`); } let z = E.FS.readFile(w); if (console.log(`[Worker] Page ${k + 1} exported: ${z.length} bytes`), z.length > 0) { let T = new Uint8Array(z.length); T.set(z), p.push({ name: `page_${k + 1}.${r}`, data: T }); } else console.warn(`[Worker] Page ${k + 1} export produced empty file`); } L(l.id, 85, "Creating ZIP archive..."); let V = xe(p); L(l.id, 100, "Complete"), y({ type: "result", id: l.id, data: V }); } else { L(l.id, 50, "Converting..."); let f = K[r], P = n || $[r] || ""; L(l.id, 70, "Saving..."), c.documentSaveAs(d, a, f, P), h.push(a), L(l.id, 90, "Reading output..."); let p = E.FS.readFile(a); if (p.length === 0) throw new Error("Conversion produced empty output"); let O = new Uint8Array(p.length); O.set(p), L(l.id, 100, "Complete"), y({ type: "result", id: l.id, data: O }); } } catch (m) { y({ type: "error", id: l.id, error: m instanceof Error ? m.message : String(m) }); } finally { if (d !== 0) try { c.documentDestroy(d); } catch { } try { E.FS.unlink(i); } catch { } for (let m of h) try { E.FS.unlink(m); } catch { } } } function xe(l) { let e = [], t = [], r = 0; for (let m of l) { let u = new TextEncoder().encode(m.name), g = new Uint8Array(30 + u.length), f = new DataView(g.buffer); f.setUint32(0, 67324752, true), f.setUint16(4, 20, true), f.setUint16(6, 0, true), f.setUint16(8, 0, true), f.setUint16(10, 0, true), f.setUint16(12, 0, true), f.setUint32(14, he(m.data), true), f.setUint32(18, m.data.length, true), f.setUint32(22, m.data.length, true), f.setUint16(26, u.length, true), f.setUint16(28, 0, true), g.set(u, 30), e.push(g), e.push(m.data); let P = new Uint8Array(46 + u.length), p = new DataView(P.buffer); p.setUint32(0, 33639248, true), p.setUint16(4, 20, true), p.setUint16(6, 20, true), p.setUint16(8, 0, true), p.setUint16(10, 0, true), p.setUint16(12, 0, true), p.setUint16(14, 0, true), p.setUint32(16, he(m.data), true), p.setUint32(20, m.data.length, true), p.setUint32(24, m.data.length, true), p.setUint16(28, u.length, true), p.setUint16(30, 0, true), p.setUint16(32, 0, true), p.setUint16(34, 0, true), p.setUint16(36, 0, true), p.setUint32(38, 0, true), p.setUint32(42, r, true), P.set(u, 46), t.push(P), r += g.length + m.data.length; } let n = r, o = 0; for (let m of t) e.push(m), o += m.length; let s = new Uint8Array(22), i = new DataView(s.buffer); i.setUint32(0, 101010256, true), i.setUint16(4, 0, true), i.setUint16(6, 0, true), i.setUint16(8, l.length, true), i.setUint16(10, l.length, true), i.setUint32(12, o, true), i.setUint32(16, n, true), i.setUint16(20, 0, true), e.push(s); let a = e.reduce((m, u) => m + u.length, 0), d = new Uint8Array(a), h = 0; for (let m of e) d.set(m, h), h += m.length; return d } function he(l) { let e = 4294967295; for (let t = 0; t < l.length; t++) { let r = l[t]; e ^= r; for (let n = 0; n < 8; n++)e = e >>> 1 ^ (e & 1 ? 3988292384 : 0); } return (e ^ 4294967295) >>> 0 } async function Fe(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { pageCount: r } = F(e, t || "docx"); y({ type: "pageCount", id: l.id, pageCount: r }); } catch (r) { y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function De(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { L(l.id, 10, "Loading document for preview..."); let { docPtr: n, pageCount: o } = F(e, t || "docx"); L(l.id, 20, `Rendering ${o} pages...`); let s = []; for (let a = 0; a < o; a++) { let d = 20 + Math.round(a / o * 70); L(l.id, d, `Rendering page ${a + 1}/${o}...`); let h = c.renderPage(n, a, r), m = new Uint8Array(h.data.length); m.set(h.data), s.push({ page: a + 1, data: m, width: h.width, height: h.height }); } L(l.id, 100, "Preview complete"); let i = s.map(a => a.data.buffer); self.postMessage({ type: "previews", id: l.id, previews: s }, i); } catch (n) { y({ type: "error", id: l.id, error: n instanceof Error ? n.message : String(n) }), A(); } } async function We(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256, pageIndex: n = 0 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let o = -1, s = 0; try { let i = F(e, t || "docx"); s = i.docPtr; let a = i.pageCount; if (n < 0 || n >= a) throw new Error(`Page index ${n} out of range (0-${a - 1})`); let d = c.documentGetDocumentType(s); console.log(`[Worker] handleRenderSinglePage: ${["TEXT", "SPREADSHEET", "PRESENTATION", "DRAWING"][d] || "UNKNOWN"} document - creating view for rendering`), o = c.createView(s), o >= 0 && (c.setView(s, o), console.log(`[Worker] handleRenderSinglePage: Created and set view ${o}`)), console.log(`[Worker] handleRenderSinglePage: calling renderPage for page ${n} at maxWidth=${r}...`); let m = c.renderPage(s, n, r); console.log(`[Worker] handleRenderSinglePage: renderPage returned ${m.data.length} bytes (${m.width}x${m.height})`); let u = new Uint8Array(m.data.length); u.set(m.data); let g = { page: n + 1, data: u, width: m.width, height: m.height }; if (o >= 0 && s !== 0) { try { c.destroyView(s, o); } catch { } console.log(`[Worker] handleRenderSinglePage: Destroyed view ${o}`); } self.postMessage({ type: "singlePagePreview", id: l.id, preview: g }, [u.buffer]); } catch (i) { if (o >= 0 && s !== 0) { try { c.destroyView(s, o); } catch { } console.log(`[Worker] handleRenderSinglePage: Destroyed view ${o} (on error)`); } let a = i instanceof Error ? String(i.message) : String(i); y({ type: "error", id: l.id, error: a }), A(); } } async function Ne(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256, pageIndex: n = 0 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let o = `/tmp/output/page_${n}.png`; try { let { docPtr: s, pageCount: i } = F(e, t || "pdf"), a = c.documentGetDocumentType(s); if (n < 0 || n >= i) throw new Error(`Page index ${n} out of range (0-${i - 1})`); (a === 2 || a === 3) && c.documentSetPart(s, n); let { width: d, height: h } = c.documentGetDocumentSize(s), m = h / d, u = Math.min(r, d), g = Math.round(u * m), f = `PixelWidth=${u};PixelHeight=${g}`; a === 0 && (f += `;PageRange=${n + 1}-${n + 1}`), c.documentSaveAs(s, o, "png", f); let P = E.FS.readFile(o); if (P.length === 0) throw new Error("PNG export produced empty output"); let p = new Uint8Array(P.length); p.set(P); let O = { page: n + 1, data: p, width: u, height: g, format: "png" }; self.postMessage({ type: "singlePagePreview", id: l.id, preview: O, isPng: !0 }, [p.buffer]); try { E.FS.unlink(o); } catch { } } catch (s) { y({ type: "error", id: l.id, error: s instanceof Error ? s.message : String(s) }), A(); try { E.FS.unlink(o); } catch { } } } async function Ue(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, pageIndex: r = 0, dpi: n = 150, maxDimension: o, editMode: s = false } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } let i = -1, a = 0; try { let d = F(e, t || "docx"); a = d.docPtr; let h = d.pageCount; if (r < 0 || r >= h) throw new Error(`Page index ${r} out of range (0-${h - 1})`); let m = c.documentGetDocumentType(a); console.log(`[Worker] handleRenderPageFullQuality: ${["TEXT", "SPREADSHEET", "PRESENTATION", "DRAWING"][m] || "UNKNOWN"} document at ${n} DPI, editMode=${s}`), i = c.createView(a), i >= 0 && (c.setView(a, i), console.log(`[Worker] handleRenderPageFullQuality: Created and set view ${i}`)); let g = c.renderPageFullQuality(a, r, n, o, s); console.log(`[Worker] handleRenderPageFullQuality: rendered ${g.data.length} bytes (${g.width}x${g.height} at ${g.dpi} DPI)`); let f = new Uint8Array(g.data.length); f.set(g.data); let P = { page: r + 1, data: f, width: g.width, height: g.height, dpi: g.dpi }; if (i >= 0 && a !== 0) try { c.destroyView(a, i); } catch { } self.postMessage({ type: "fullQualityPagePreview", id: l.id, preview: P }, [f.buffer]); } catch (d) { if (i >= 0 && a !== 0) try { c.destroyView(a, i); } catch { } let h = d instanceof Error ? String(d.message) : String(d); y({ type: "error", id: l.id, error: h }), A(); } } async function Ke(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { docPtr: r, pageCount: n } = F(e, t || "docx"), o = c.documentGetDocumentType(r), s = { 0: ["pdf", "docx", "doc", "odt", "rtf", "txt", "html", "png", "jpg", "svg"], 1: ["pdf", "xlsx", "xls", "ods", "csv", "html", "png", "jpg", "svg"], 2: ["pdf", "pptx", "ppt", "odp", "png", "jpg", "svg", "html"], 3: ["pdf", "png", "jpg", "svg", "html"], 4: ["pdf"] }, a = { documentType: o, documentTypeName: { 0: "Text Document", 1: "Spreadsheet", 2: "Presentation", 3: "Drawing", 4: "Other" }[o] || "Unknown", validOutputFormats: s[o] || ["pdf"], pageCount: n }; y({ type: "documentInfo", id: l.id, documentInfo: a }); } catch (r) { y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function $e(l) { if (console.log("[LOK Worker] handleGetLokInfo called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { console.log("[LOK Worker] Getting or loading document..."); let { docPtr: r } = F(e, t || "docx"); console.log(`[LOK Worker] Got docPtr: ${r}`), console.log("[LOK Worker] Calling LOK methods..."); let n = c.getPartPageRectangles(r); console.log(`[LOK Worker] pageRectangles: ${n}`); let o = c.documentGetDocumentSize(r); console.log(`[LOK Worker] documentSize: ${o.width}x${o.height}`); let s = c.getPartInfo(r, 0); console.log(`[LOK Worker] partInfo: ${s}`); let i = c.getA11yFocusedParagraph(r); console.log(`[LOK Worker] a11yFocusedParagraph: ${i}`); let a = c.getA11yCaretPosition(r); console.log(`[LOK Worker] a11yCaretPosition: ${a}`); let d = c.getEditMode(r); console.log(`[LOK Worker] editMode (initial): ${d}`); let h = null, m = -1; m = c.getView(r), console.log(`[LOK Worker] Got existing view: ${m}`), m >= 0 && (c.setView(r, m), console.log(`[LOK Worker] Set active view to ${m}`)); let u = c.createView(r); console.log(`[LOK Worker] Created new view: ${u}`), u >= 0 && (c.setView(r, u), console.log(`[LOK Worker] Switched to new view: ${u}`)), c.setEditMode(r, 1), d = c.getEditMode(r), console.log(`[LOK Worker] editMode (after setEditMode): ${d}`), h = c.getAllText(r), console.log(`[LOK Worker] allText: ${h?.slice(0, 100) || "null"}`), u >= 0 && (c.destroyView(r, u), console.log(`[LOK Worker] Destroyed view: ${u}`)); let g = null; if (s) try { g = JSON.parse(s); } catch { console.warn("[LOK Worker] Failed to parse partInfo JSON:", s); } let f = null; if (i) try { f = JSON.parse(i); } catch { console.warn("[LOK Worker] Failed to parse a11yFocusedParagraph JSON:", i); } let P = { pageRectangles: n, documentSize: o, partInfo: g, a11yFocusedParagraph: f, a11yCaretPosition: a, editMode: d, allText: h }; console.log("[LOK Worker] Posting lokInfo response"), y({ type: "lokInfo", id: l.id, lokInfo: P }); } catch (r) { console.error("[LOK Worker] Error in handleGetLokInfo:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }), A(); } } async function Me(l) { if (console.log("[LOK Worker] handleEditText called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, findText: r, replaceText: n, insertText: o } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } A(); let s = `/tmp/input/edit_doc.${t || "docx"}`, i = `/tmp/output/edited_doc.${t || "docx"}`, a = 0, d = -1; try { if (console.log("[LOK Worker] Writing input file..."), E.FS.writeFile(s, e), console.log("[LOK Worker] Loading document for editing..."), a = c.documentLoad(s), a === 0) { let p = c.getError(); throw new Error(p || "Failed to load document") } console.log(`[LOK Worker] Document loaded, docPtr=${a}`), c.documentInitializeForRendering(a), console.log("[LOK Worker] Document initialized for rendering"), d = c.getView(a), console.log(`[LOK Worker] Got existing view: ${d}`), d >= 0 && (c.setView(a, d), console.log(`[LOK Worker] Set active view to ${d}`)); let h = c.createView(a); console.log(`[LOK Worker] Created new view: ${h}`), h >= 0 && (c.setView(a, h), console.log(`[LOK Worker] Switched to new view: ${h}`), d = h), c.setEditMode(a, 1); let m = c.getEditMode(a); console.log(`[LOK Worker] Edit mode after setEditMode(1): ${m}`); let u = ""; if (r && n !== void 0) { console.log(`[LOK Worker] Attempting find/replace: "${r}" -> "${n}"`); let p = JSON.stringify({ "SearchItem.SearchString": { type: "string", value: r }, "SearchItem.ReplaceString": { type: "string", value: n }, "SearchItem.Command": { type: "unsigned short", value: "3" } }); try { c.postUnoCommand(a, ".uno:ExecuteSearch", p), u = `Attempted replace all "${r}" with "${n}"`, console.log(`[LOK Worker] ${u}`); } catch (O) { console.error("[LOK Worker] ExecuteSearch threw:", O), u = `ExecuteSearch failed: ${String(O)}`; } } else if (o) { console.log(`[LOK Worker] Attempting to insert text: "${o}"`); let p = []; try { console.log("[LOK Worker] Clicking in document to establish focus..."), c.postMouseEvent(a, 0, 1e3, 1e3, 1, 1, 0), c.postMouseEvent(a, 1, 1e3, 1e3, 1, 1, 0), console.log("[LOK Worker] Posted mouse events for focus"), p.push("mouseEvents:ok"); } catch (_) { console.error("[LOK Worker] postMouseEvent threw:", _), p.push("mouseEvents:err"); } try { c.postUnoCommand(a, ".uno:GoToEndOfDoc"), console.log("[LOK Worker] Posted GoToEndOfDoc"), p.push("GoToEndOfDoc:ok"); } catch (_) { console.error("[LOK Worker] GoToEndOfDoc threw:", _), p.push("GoToEndOfDoc:err"); } let O = !1; try { console.log("[LOK Worker] Trying paste() with text/plain..."), O = c.paste(a, "text/plain;charset=utf-8", o), console.log(`[LOK Worker] paste() returned: ${O}`), p.push(`paste:${O}`); } catch (_) { console.error("[LOK Worker] paste() threw:", _), p.push("paste:err"); } try { let _ = JSON.stringify({ Text: { type: "string", value: o } }); c.postUnoCommand(a, ".uno:InsertText", _), console.log("[LOK Worker] Posted InsertText"), p.push("InsertText:ok"); } catch (_) { console.error("[LOK Worker] InsertText threw:", _), p.push("InsertText:err"); } try { console.log("[LOK Worker] Now trying postKeyEvent for each character..."); for (let _ = 0; _ < o.length; _++) { let C = o.charCodeAt(_); c.postKeyEvent(a, 0, C, 0), c.postKeyEvent(a, 1, C, 0); } console.log(`[LOK Worker] Posted ${o.length} key events`), p.push(`keyEvents:${o.length}`); } catch (_) { console.error("[LOK Worker] postKeyEvent threw:", _), p.push("keyEvents:err"); } u = `Insert attempts: ${p.join(", ")}`, console.log(`[LOK Worker] ${u}`); } else u = "No edit operation specified (need findText+replaceText or insertText)", console.log(`[LOK Worker] ${u}`); console.log("[LOK Worker] Attempting to save modified document..."); let g = t || "docx", P = { docx: "docx", doc: "doc", odt: "odt", xlsx: "xlsx", xls: "xls", ods: "ods", pptx: "pptx", ppt: "ppt", odp: "odp" }[g] || g; try { c.documentSaveAs(a, i, P, ""), console.log("[LOK Worker] Document saved"); let p = E.FS.readFile(i); console.log(`[LOK Worker] Modified document size: ${p.length} bytes`); let O = new Uint8Array(p.length); O.set(p); let _ = { success: !0, editMode: m, message: u + ` | Document saved (${O.length} bytes)`, modifiedDocument: O }; self.postMessage({ type: "editResult", id: l.id, editResult: _ }, [O.buffer]); } catch (p) { console.error("[LOK Worker] Save error:", p); let O = { success: !1, editMode: m, message: u + ` | Save failed: ${String(p)}` }; y({ type: "editResult", id: l.id, editResult: O }); } } catch (h) { console.error("[LOK Worker] Error in handleEditText:", h), h instanceof Error && (console.error("[LOK Worker] Error name:", h.name), console.error("[LOK Worker] Error message:", h.message), console.error("[LOK Worker] Error stack:", h.stack)); let m = h; if (m && typeof m == "object") { console.error("[LOK Worker] Error keys:", Object.keys(m)); for (let u of Object.keys(m)) try { console.error(`[LOK Worker] Error.${u}:`, m[u]); } catch { } } if (typeof h == "number") { console.error("[LOK Worker] Emscripten exception pointer:", h); let u = E; if (u && typeof u.getExceptionMessage == "function") try { let g = u.getExceptionMessage(h); console.error("[LOK Worker] Emscripten exception message:", g); } catch { } } y({ type: "error", id: l.id, error: h instanceof Error ? h.message : String(h) }); } finally { if (a !== 0 && c) { if (d >= 0) try { c.destroyView(a, d); } catch { } try { c.documentDestroy(a); } catch { } } if (E) { try { E.FS.unlink(s); } catch { } try { E.FS.unlink(i); } catch { } } } } async function Be(l) { if (console.log("[LOK Worker] handleRenderPageRectangles called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t, maxWidth: r = 256 } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } try { let { docPtr: n } = F(e, t || "docx"); c.documentInitializeForRendering(n); let o = c.getPartPageRectangles(n); if (console.log(`[LOK Worker] Page rectangles string: ${o?.slice(0, 100) || "null"}...`), !o || o.length === 0) { y({ type: "pageRectangles", id: l.id, pageRectangles: [] }); return } let s = c.parsePageRectangles(o); console.log(`[LOK Worker] Parsed ${s.length} page rectangles`); let i = [], a = []; for (let d = 0; d < s.length; d++) { let h = s[d]; console.log(`[LOK Worker] Rendering page ${d}: x=${h.x}, y=${h.y}, w=${h.width}, h=${h.height}`); let m = h.height / h.width, u = r, g = Math.round(r * m), f = c.documentPaintTile(n, u, g, h.x, h.y, h.width, h.height), P = new Uint8Array(f.length); P.set(f), i.push({ index: d, x: h.x, y: h.y, width: h.width, height: h.height, imageData: P, imageWidth: u, imageHeight: g }), a.push(P.buffer), console.log(`[LOK Worker] Rendered page ${d}: ${u}x${g}, ${P.length} bytes`); } self.postMessage({ type: "pageRectangles", id: l.id, pageRectangles: i }, a); } catch (n) { console.error("[LOK Worker] Error in handleRenderPageRectangles:", n); let o = n instanceof Error ? String(n.message) : String(n); y({ type: "error", id: l.id, error: o }), A(); } } async function Ve(l) { if (console.log("[LOK Worker] handleTestLokOperations called"), !b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let { inputData: e, inputExt: t } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing input data" }); return } A(); let r = `/tmp/input/test_ops_doc.${t || "docx"}`, n = `/tmp/output/test_ops_doc.${t || "docx"}`, o = 0, s = -1, i = []; try { if (console.log("[LOK Worker] Writing input file..."), E.FS.writeFile(r, e), console.log("[LOK Worker] Loading document for LOK operations testing..."), o = c.documentLoad(r), o === 0) { let u = c.getError(); throw new Error(u || "Failed to load document") } console.log(`[LOK Worker] Document loaded, docPtr=${o}`), c.documentInitializeForRendering(o), console.log("[LOK Worker] Document initialized for rendering"), s = c.getView(o), console.log(`[LOK Worker] Got existing view: ${s}`), s >= 0 && c.setView(o, s); let a = c.createView(o); console.log(`[LOK Worker] Created new view: ${a}`), a >= 0 && (c.setView(o, a), s = a), c.setEditMode(o, 1); let d = c.getEditMode(o); console.log(`[LOK Worker] Edit mode: ${d}`), c.registerCallback(o), c.clearCallbackQueue(), console.log("[LOK Worker] Callback registered for STATE_CHANGED events"); try { c.postMouseEvent(o, 0, 1e3, 1e3, 1, 1, 0), c.postMouseEvent(o, 1, 1e3, 1e3, 1, 1, 0), i.push({ operation: "establishFocus", success: !0, result: "Mouse click events sent" }); } catch (u) { i.push({ operation: "establishFocus", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing SelectAll + getTextSelection..."); try { c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"), g = u?.length || 0; console.log(`[LOK Worker] SelectAll result: ${g} chars, preview: "${u?.slice(0, 100)}..."`), i.push({ operation: "SelectAll+getTextSelection", success: g > 0, result: { textLength: g, preview: u?.slice(0, 200) } }); } catch (u) { console.error("[LOK Worker] SelectAll error:", u), i.push({ operation: "SelectAll+getTextSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing getSelectionType..."); try { let u = c.getSelectionType(o); console.log(`[LOK Worker] Selection type: ${u}`), i.push({ operation: "getSelectionType", success: !0, result: { selectionType: u, meaning: u === 0 ? "NONE" : u === 1 ? "TEXT" : u === 2 ? "CELL" : "UNKNOWN" } }); } catch (u) { console.error("[LOK Worker] getSelectionType error:", u), i.push({ operation: "getSelectionType", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing resetSelection..."); try { c.resetSelection(o); let u = c.getSelectionType(o); console.log(`[LOK Worker] Selection type after reset: ${u}`), i.push({ operation: "resetSelection", success: !0, result: { selectionTypeAfterReset: u } }); } catch (u) { console.error("[LOK Worker] resetSelection error:", u), i.push({ operation: "resetSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing GoToStartOfDoc + selection + Delete..."); try { c.postUnoCommand(o, ".uno:GoToStartOfDoc"), console.log("[LOK Worker] Sent GoToStartOfDoc"), c.postUnoCommand(o, ".uno:WordRightSel"), console.log("[LOK Worker] Sent WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected text before delete: "${u}"`), c.postUnoCommand(o, ".uno:Delete"), console.log("[LOK Worker] Sent Delete"), i.push({ operation: "SelectWord+Delete", success: !0, result: { deletedText: u } }); } catch (u) { console.error("[LOK Worker] SelectWord+Delete error:", u), i.push({ operation: "SelectWord+Delete", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Undo..."); try { c.postUnoCommand(o, ".uno:Undo"), console.log("[LOK Worker] Sent Undo"), c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Text after Undo: ${u?.length} chars`), i.push({ operation: "Undo", success: !0, result: { textLengthAfterUndo: u?.length || 0 } }); } catch (u) { console.error("[LOK Worker] Undo error:", u), i.push({ operation: "Undo", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Redo..."); try { c.postUnoCommand(o, ".uno:Redo"), console.log("[LOK Worker] Sent Redo"), c.postUnoCommand(o, ".uno:SelectAll"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Text after Redo: ${u?.length} chars`), i.push({ operation: "Redo", success: !0, result: { textLengthAfterRedo: u?.length || 0 } }); } catch (u) { console.error("[LOK Worker] Redo error:", u), i.push({ operation: "Redo", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Bold formatting..."); try { c.postUnoCommand(o, ".uno:Undo"), c.postUnoCommand(o, ".uno:GoToStartOfDoc"), c.postUnoCommand(o, ".uno:WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected for bold: "${u}"`), c.postUnoCommand(o, ".uno:Bold"), console.log("[LOK Worker] Sent Bold"); let g = c.getCommandValues(o, ".uno:Bold"); console.log(`[LOK Worker] Bold state: ${g}`), i.push({ operation: "Bold", success: !0, result: { selectedText: u, boldState: g } }); } catch (u) { console.error("[LOK Worker] Bold error:", u), i.push({ operation: "Bold", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing Italic formatting..."); try { c.postUnoCommand(o, ".uno:GoRight"), c.postUnoCommand(o, ".uno:WordRightSel"); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Selected for italic: "${u}"`), c.postUnoCommand(o, ".uno:Italic"), console.log("[LOK Worker] Sent Italic"); let g = c.getCommandValues(o, ".uno:Italic"); console.log(`[LOK Worker] Italic state: ${g}`), i.push({ operation: "Italic", success: !0, result: { selectedText: u, italicState: g } }); } catch (u) { console.error("[LOK Worker] Italic error:", u), i.push({ operation: "Italic", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing getCharacterFormatting via STATE_CHANGED callbacks..."); try { let u = c.getCallbackEventCount(); console.log(`[LOK Worker] Existing events in queue: ${u}`); let g = c.pollStateChanges(); console.log(`[LOK Worker] Existing STATE_CHANGED events: ${g.size}`); for (let [R, w] of g.entries()) console.log(`[LOK Worker] ${R} = ${w}`); c.clearCallbackQueue(), c.postUnoCommand(o, ".uno:GoToStartOfDoc"), c.flushCallbacks(o), c.postUnoCommand(o, ".uno:WordRightSel"), c.flushCallbacks(o); let f = c.getCallbackEventCount(), P = c.hasCallbackEvents(); console.log(`[LOK Worker] Event count after WordRightSel: ${f}, hasEvents: ${P}`); let p = c.pollStateChanges(); console.log(`[LOK Worker] State changes after selection: ${p.size}`); for (let [R, w] of p.entries()) console.log(`[LOK Worker] ${R} = ${w}`); for (let [R, w] of g.entries()) p.has(R) || p.set(R, w); let O = {}; for (let [R, w] of p.entries()) O[R] = w; console.log(`[LOK Worker] Received ${p.size} state changes:`); for (let [R, w] of p.entries()) console.log(` ${R} = ${w}`); let _ = p.get(".uno:Bold") ?? null, C = p.get(".uno:Italic") ?? null, D = p.get(".uno:Underline") ?? null, U = p.get(".uno:CharFontName") ?? null, V = p.get(".uno:FontHeight") ?? null, k = p.get(".uno:Color") ?? p.get(".uno:CharColor") ?? null; console.log("[LOK Worker] Character formatting from STATE_CHANGED:"), console.log(` Bold: ${_}`), console.log(` Italic: ${C}`), console.log(` Underline: ${D}`), console.log(` FontName: ${U}`), console.log(` FontSize: ${V}`), console.log(` Color: ${k}`), i.push({ operation: "getCharacterFormatting", success: !0, result: { stateChangeCount: p.size, note: p.size === 0 ? "Callback queue empty - C++ shims may need to be added to WASM build" : void 0, bold: _, italic: C, underline: D, fontName: U, fontSize: V, color: k, allStates: O } }); } catch (u) { console.error("[LOK Worker] getCharacterFormatting error:", u), i.push({ operation: "getCharacterFormatting", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing setTextSelection..."); try { c.resetSelection(o), c.setTextSelection(o, 0, 500, 500), c.setTextSelection(o, 1, 3e3, 500); let u = c.getTextSelection(o, "text/plain;charset=utf-8"); console.log(`[LOK Worker] Coordinate-selected text: "${u}"`), i.push({ operation: "setTextSelection", success: !0, result: { selectedText: u } }); } catch (u) { console.error("[LOK Worker] setTextSelection error:", u), i.push({ operation: "setTextSelection", success: !1, error: String(u) }); } console.log("[LOK Worker] Testing document save..."); try { let u = t || "docx", f = { docx: "docx", doc: "doc", odt: "odt", xlsx: "xlsx", xls: "xls", ods: "ods", pptx: "pptx", ppt: "ppt", odp: "odp" }[u] || u; c.documentSaveAs(o, n, f, ""); let P = E.FS.readFile(n); i.push({ operation: "documentSave", success: P.length > 0, result: { savedBytes: P.length, originalBytes: e.length } }); } catch (u) { console.error("[LOK Worker] Save error:", u), i.push({ operation: "documentSave", success: !1, error: String(u) }); } let m = `${i.filter(u => u.success).length}/${i.length} operations succeeded`; console.log(`[LOK Worker] Test results summary: ${m}`), y({ type: "testLokOperations", id: l.id, testLokOperationsResult: { operations: i, summary: m } }); } catch (a) { console.error("[LOK Worker] Error in handleTestLokOperations:", a), y({ type: "error", id: l.id, error: a instanceof Error ? a.message : String(a) }); } finally { if (o !== 0 && c) { try { c.unregisterCallback(o); } catch { } if (s >= 0) try { c.destroyView(o, s); } catch { } try { c.documentDestroy(o); } catch { } } if (E) { try { E.FS.unlink(r); } catch { } try { E.FS.unlink(n); } catch { } } } } async function ze(l) { if (!b || !E || !c) { y({ type: "error", id: l.id, error: "Worker not initialized" }); return } let e = l.inputData, t = l.inputExt || "docx"; if (!e || e.length === 0) { y({ type: "error", id: l.id, error: "No input data provided" }); return } try { let r = `session_${++Te}_${Date.now()}`, n = `/tmp/edit_${r}.${t}`; E.FS.writeFile(n, e); let o = c.documentLoad(n); if (o === 0) { let h = c.getError(); E.FS.unlink(n), y({ type: "error", id: l.id, error: `Failed to load document: ${String(h)}` }); return } c.documentInitializeForRendering(o); let s = c.createView(o); c.setView(o, s), c.registerCallback(o), c.postUnoCommand(o, ".uno:Edit"); let i = le(c, o), a = i.getDocumentType(), d = c.documentGetParts(o); N.set(r, { sessionId: r, docPtr: o, filePath: n, editor: i, documentType: a }), console.log(`[LOK Worker] Opened document session: ${r}, type: ${a}, pages: ${d}`), y({ type: "editorSession", id: l.id, editorSession: { sessionId: r, documentType: a, pageCount: d } }); } catch (r) { console.error("[LOK Worker] Error in handleOpenDocument:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }); } } async function Ge(l) { let { sessionId: e, editorMethod: t, editorArgs: r } = l; if (!e || !t) { y({ type: "error", id: l.id, error: "Missing sessionId or editorMethod" }); return } let n = N.get(e); if (!n) { y({ type: "error", id: l.id, error: `Session not found: ${e}` }); return } try { let { editor: o } = n, s = r || [], i = o[t]; if (typeof i != "function") { y({ type: "error", id: l.id, error: `Unknown editor method: ${t}` }); return } let a = i.apply(o, s), d = a.data; a.data instanceof Map && (d = Object.fromEntries(a.data)), y({ type: "editorOperationResult", id: l.id, editorOperationResult: { success: a.success, verified: a.verified, data: d, error: a.error, suggestion: a.suggestion } }); } catch (o) { console.error(`[LOK Worker] Error in handleEditorOperation (${t}):`, o), y({ type: "error", id: l.id, error: o instanceof Error ? o.message : String(o) }); } } async function He(l) { let { sessionId: e } = l; if (!e) { y({ type: "error", id: l.id, error: "Missing sessionId" }); return } let t = N.get(e); if (!t) { y({ type: "error", id: l.id, error: `Session not found: ${e}` }); return } try { let { docPtr: r, filePath: n } = t, o; if (E) try { let s = n.split(".").pop() || "docx"; c?.documentSaveAs(r, n, s, ""), o = E.FS.readFile(n); } catch (s) { console.warn("[LOK Worker] Could not save document:", s); } if (c && r !== 0) { try { c.unregisterCallback(r); } catch { } try { c.documentDestroy(r); } catch { } } if (E) try { E.FS.unlink(n); } catch { } N.delete(e), console.log(`[LOK Worker] Closed document session: ${e}`), y({ type: "documentClosed", id: l.id, data: o }); } catch (r) { console.error("[LOK Worker] Error in handleCloseDocument:", r), y({ type: "error", id: l.id, error: r instanceof Error ? r.message : String(r) }); } } function je(l) { console.log("handleDestroy"); for (let [, e] of N) try { if (c && e.docPtr !== 0) { try { c.unregisterCallback(e.docPtr); } catch { } try { c.documentDestroy(e.docPtr); } catch { } } if (E) try { E.FS.unlink(e.filePath); } catch { } } catch { } if (N.clear(), A(), W) { try { W.destroy(); } catch { } W = null, c = null; } else if (c) { try { c.destroy(); } catch { } c = null; } if (E && E.PThread?.terminateAllThreads) try { E.PThread.terminateAllThreads(); } catch { } E = null, b = false, y({ type: "ready", id: l.id }), setTimeout(() => self.close(), 100); } self.onmessage = async l => { let e = l.data; switch (e.type) { case "init": await ve(e); break; case "convert": await Ie(e); break; case "getPageCount": await Fe(e); break; case "renderPreviews": await De(e); break; case "renderSinglePage": await We(e); break; case "renderPageViaConvert": await Ne(e); break; case "renderPageFullQuality": await Ue(e); break; case "getDocumentInfo": await Ke(e); break; case "getLokInfo": await $e(e); break; case "editText": await Me(e); break; case "renderPageRectangles": await Be(e); break; case "testLokOperations": await Ve(e); break; case "openDocument": await ze(e); break; case "editorOperation": await Ge(e); break; case "closeDocument": await He(e); break; case "destroy": je(e); break } }; self.postMessage({ type: "loaded" });
})();//# sourceMappingURL=browser.worker.global.js.map
//# sourceMappingURL=browser.worker.global.js.map
\ No newline at end of file
diff --git a/messages/ar.json b/messages/ar.json
index 06c9f37cf..6dea80c2c 100644
--- a/messages/ar.json
+++ b/messages/ar.json
@@ -32,6 +32,10 @@
"convertPdf": "تحويل PDF",
"freePdfTools": "أدوات PDF مجانية",
"onlinePdfEditor": "محرر PDF عبر الإنترنت"
+ },
+ "terms": {
+ "title": "شروط الخدمة",
+ "description": "شروط الخدمة لأدوات PDF المجانية من Craftisle."
}
},
"common": {
diff --git a/messages/de.json b/messages/de.json
index 7be9a362f..6ff8502b7 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -32,6 +32,10 @@
"convertPdf": "PDF konvertieren",
"freePdfTools": "kostenlose PDF-Werkzeuge",
"onlinePdfEditor": "Online-PDF-Editor"
+ },
+ "terms": {
+ "title": "Nutzungsbedingungen",
+ "description": "Nutzungsbedingungen für Craftisle PDF kostenlose PDF-Tools."
}
},
"common": {
diff --git a/messages/en.json b/messages/en.json
index 71188ebdd..df7357417 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -2,7 +2,7 @@
"metadata": {
"home": {
"title": "PDFCraft - Professional PDF Tools",
- "description": "Free, Private & Browser-Based. Merge, edit, and edit PDF files online without uploading to servers."
+ "description": "Free online PDF tools by Craftisle. Merge, split, compress, and convert PDF files. 100% browser-based, no server uploads, maximum privacy."
},
"tools": {
"title": "All PDF Tools",
@@ -32,6 +32,10 @@
"convertPdf": "convert PDF",
"freePdfTools": "free PDF tools",
"onlinePdfEditor": "online PDF editor"
+ },
+ "terms": {
+ "title": "Terms of Service",
+ "description": "Terms of Service for Craftisle PDF free online PDF tools."
}
},
"common": {
@@ -167,7 +171,13 @@
"auto": "Auto",
"portrait": "Portrait",
"landscape": "Landscape"
- }
+ },
+ "fileUploaderEncrypted": "This document is encrypted",
+ "fileUploaderEnterPassword": "Enter password to unlock and load:",
+ "fileUploaderPasswordPlaceholder": "Enter document password",
+ "fileUploaderCancel": "Cancel",
+ "fileUploaderDecrypting": "Decrypting...",
+ "fileUploaderDecryptAndContinue": "Decrypt and continue"
},
"toolsPage": {
"title": "Professional PDF Tools",
@@ -734,7 +744,8 @@
"pages": "pages",
"previewInfoAllPages": "{fileCount} PDF(s) with {totalPages} total pages will be arranged in a {layout} grid across {outputPages} output page(s).",
"previewInfoFirstPage": "{fileCount} PDF(s) will be arranged in a {layout} grid across {outputPages} page(s).",
- "minFilesError": "Please add at least 2 PDF files to combine."
+ "minFilesError": "Please add at least 2 PDF files to combine.",
+ "showErrorDetails": "Show Error Details"
},
"nUpPdf": {
"uploadLabel": "Upload PDF File",
@@ -767,6 +778,9 @@
"pagesLabel": "pages",
"sheetsLabel": "sheets",
"perSheetLabel": "per sheet",
+ "orientationLandscape": "Landscape",
+ "orientationPortrait": "Portrait",
+ "orientationAuto": "Auto",
"successMessage": "N-Up PDF created successfully! Click the download button to save your file."
},
"splitPdf": {
@@ -1024,7 +1038,23 @@
"fontSize": "Font Size",
"inkColor": "Ink Color",
"inkThickness": "Ink Thickness"
- }
+ },
+ "toolCloud": "Cloud",
+ "toolRectangle": "Rectangle",
+ "toolCircle": "Circle",
+ "toolArrow": "Arrow",
+ "toolFreehand": "Freehand",
+ "toolFreeText": "Text",
+ "toolFreeHighlight": "Free Highlight",
+ "toolNote": "Note",
+ "toolSignature": "Signature",
+ "toolStamp": "Stamp",
+ "annotationLabel": "Annotation",
+ "anonymousUser": "Anonymous User",
+ "undo": "Undo",
+ "redo": "Redo",
+ "customStrokeColor": "Custom stroke color:",
+ "enableFillColor": "Enable fill color:"
},
"imageToPdf": {
"uploadLabel": "Upload Images",
@@ -1096,7 +1126,30 @@
"downloadAllZip": "Download All as ZIP",
"originalSize": "Original:",
"compressedSize": "Compressed:",
- "saved": "Saved:"
+ "saved": "Saved:",
+ "clearAll": "Clear All",
+ "compressionExecuted": "Compression Complete",
+ "compressionResult": "Compression Result",
+ "documentOptimizationComplete": "Document Optimization Complete",
+ "downloadZipCount": "Download All ({count} files)",
+ "dragToCompare": "Click to Compare",
+ "fileList": "File List ({count})",
+ "leftOriginalRightCompressed": "Left: Original | Right: Compressed",
+ "optimizeGraphics": "Optimize Images",
+ "optimizing": "Optimizing...",
+ "pixelClarity": "Pixel Clarity",
+ "qualityHighFullDesc": "High quality, larger file size, best for printing",
+ "qualityHighLabel": "High",
+ "qualityLowFullDesc": "Low quality, maximum compression, for sharing only",
+ "qualityLowLabel": "Low",
+ "qualityMaximumFullDesc": "Maximum quality, minimal compression, best for archiving",
+ "qualityMaximumLabel": "Maximum",
+ "qualityMediumFullDesc": "Medium quality, balanced compression, recommended",
+ "qualityMediumLabel": "Medium",
+ "qualityPreset": "Quality Preset",
+ "removeMetadataForce": "Force Remove Metadata",
+ "sizeReduction": "Size Reduction",
+ "startOptimization": "Start Optimization"
},
"signPdf": {
"uploadLabel": "Upload PDF File",
@@ -1244,7 +1297,35 @@
"applyTo": "Apply to",
"allPages": "All Pages",
"oddPages": "Odd Pages",
- "evenPages": "Even Pages"
+ "evenPages": "Even Pages",
+ "calibrationCenter": "Calibration Control Center",
+ "calibrationHint": "Select pages below, use quick adjust or fine-tune dial to precisely correct skewed or flipped documents.",
+ "selectedPages": "Selected {selected} / {total} pages",
+ "selectAll": "Select All",
+ "clearAll": "Clear",
+ "quickAdjust": "Quick Adjust",
+ "fineAdjust": "Fine-tune (Granular)",
+ "rotateLeft90Btn": "Rotate Left 90°",
+ "rotateRight90Btn": "Rotate Right 90°",
+ "rotate180Btn": "Flip 180°",
+ "resetAll": "Reset All",
+ "quickSelect": "Quick Select Pages:",
+ "oddPagesOnly": "Odd pages only",
+ "evenPagesOnly": "Even pages only",
+ "correction": "Correction",
+ "scrollToAdjust": "Scroll to fine-tune",
+ "leftAngle": "-180.0° (Left)",
+ "fineSlider": "Fine-tune Slider",
+ "rightAngle": "+180.0° (Right)",
+ "precisionInput": "Precision Input:",
+ "inputHint": "Input hint: You can enter any angle. The system will automatically normalize it to the equivalent range within [-180°, 180°] when blurred or Enter is pressed.",
+ "processing": "Rotating...",
+ "startRotate": "Start Rotating {count} calibrated page(s)",
+ "completeMessage": "PDF page rotation saved successfully! Click the button above to download.",
+ "previewTitle": "Real-time Physical Preview Window",
+ "previewHint": "Click page to toggle selection • Drag left control for fine-grained adjustment",
+ "loadingPreview": "Decompressing and loading PDF preview images...",
+ "pageNumber": "Page {pageNumber}"
},
"rotateCustom": {
"title": "Custom Rotation",
@@ -1340,25 +1421,103 @@
"saveButton": "Save Changes",
"successMessage": "Attachments removed successfully! Click the download button to save your file."
},
+ "citationLinker": {
+ "uploadLabel": "Upload Academic PDF",
+ "uploadDescription": "Drag and drop academic papers, journal articles, or conference reports. The system will automatically find citation markers (e.g., [1]) and link references.",
+ "pagesText": "pages",
+ "scanningText": "Scanning document structure...",
+ "optionsTitle": "Citation Linking Options",
+ "detectDoiLabel": "Auto-detect reference DOIs and add hyperlinks",
+ "fallbackToPageJumpLabel": "Enable 'in-page jump' (GoTo Page) when no DOI is available",
+ "editingCitation": "Editing citation: {marker}",
+ "editingCitationPage": "Page: {pageNum}",
+ "editingCitationRefText": "Reference: {refText}",
+ "editUrlPlaceholder": "Enter DOI / URL for this reference",
+ "citationList": "Scanned citations ({count})",
+ "pageJumpLabel": "Page jump",
+ "processButton": "Activate Hyperlinks",
+ "legendDoi": "Green solid line: DOI external link",
+ "legendPageJump": "Gray dashed line: Reference page jump",
+ "processing": "Injecting high-strength clickable citation annotations...",
+ "completionTitle": "Citation Hyperlinks Activated!",
+ "completionMessage": "Added linked references and page jump points for {count} citation markers. The document will work perfectly in any standard PDF reader."
+ },
"comparePdfs": {
- "file1Label": "First PDF (Original)",
- "uploadFile1": "Upload First PDF",
- "file2Label": "Second PDF (Modified)",
- "uploadFile2": "Upload Second PDF",
- "uploadDescription": "Drag and drop or click to browse",
- "compareButton": "Compare PDFs",
- "resultsTitle": "Comparison Results",
- "newComparison": "New Comparison",
- "viewMode": "View Mode:",
- "sideBySide": "Side by Side",
- "overlay": "Overlay",
- "differences": "Differences",
- "opacity": "Opacity:",
- "diffView": "Difference View (Red areas show changes)",
- "pageOverview": "Page Overview",
- "fullscreen": "Fullscreen",
+ "uploadLabel1": "Upload Original PDF",
+ "uploadDescription1": "As the basic original layout for differential comparison",
+ "uploadLabel2": "Upload Modified PDF",
+ "uploadDescription2": "Latest layout with modifications, additions, deletions or position offsets",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading...",
+ "errorLoading1": "Unable to extract source document.",
+ "errorLoading2": "Unable to extract comparison document.",
+ "errorComparing": "Algorithm exception occurred during intelligent semantic comparison.",
+ "startCompare": "Start Intelligent Semantic Diff Comparison",
+ "processing": "Running intelligent CJK dual-end semantic alignment and paragraph diff...",
+ "completeTitle": "Intelligent Semantic Comparison Complete (Acrobat Commercial-grade Alignment)",
+ "diffSummary": "Aligned {count} pages • {diffCount} pages contain semantic differences",
+ "filterLabel": "Highlight Filter (Filter)",
+ "filterText": "Text Added/Deleted",
+ "filterFormatting": "Format Changes (Fonts)",
+ "filterHeaderFooter": "Header/Footer (Low Noise)",
+ "filterMoved": "Paragraph Displacement",
+ "resetComparison": "Reset New Comparison",
+ "prevPage": "Previous Page Alignment",
+ "nextPage": "Next Page Alignment",
+ "pageAlignment": "Alignment Sequence {current} / {total} pages",
+ "insertedPage": "Inserted Page",
+ "deletedPage": "Deleted Page",
+ "diffPercentage": "Detected {percentage}% semantic difference",
+ "noDifference": "No difference (Completely identical)",
+ "fullscreen": "Fullscreen Immersive Comparison",
"exitFullscreen": "Exit Fullscreen",
- "successMessage": "Comparison complete! Use the view modes and page navigation to explore differences."
+ "originalVersion": "Original Version",
+ "modifiedVersion": "Modified Version",
+ "pageNumber": "Page {number}",
+ "insertedPageDesc": "This page was forcibly added in the modified version. The original version has no corresponding mapping here.",
+ "deletedPageDesc": "This page has been completely deleted in the modified version. Blank alignment inserted to prevent disturbing subsequent page comparison order.",
+ "diffMoved": "Paragraph displaced at this location",
+ "diffAdded": "Added content",
+ "diffDeleted": "Deleted content",
+ "diffModified": "Modified content",
+ "loadingFile1": "Loading original PDF...",
+ "loadingFile2": "Loading modified PDF..."
+ },
+ "pdfToTiff": {
+ "metadataError": "Unable to parse main PDF metadata, the file may be corrupted.",
+ "uploadPrompt": "Please upload a PDF file to convert to TIFF.",
+ "processingMessage": "Serializing page sequence to single multi-page TIFF...",
+ "compileError": "Failed to compile multi-page TIFF file.",
+ "unknownError": "Unknown error occurred during serialization.",
+ "step1Upload": "1. Upload document (PDF)",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "uploadLabel": "Click to upload PDF file to convert",
+ "uploadDescription": "Hand-written binary IFD assembler, directly merges and generates a single legal high-fidelity TIFF with multiple pages (Multi-page).",
+ "previewTitle": "3D lattice pixel density and spectrum real-time preview",
+ "colorMode24bit": "24-bit print full color (RGB): 3 bytes per pixel, perfectly restores rich spectral colors.",
+ "colorMode8bit": "8-bit professional grayscale: Uses classic light sensitivity coefficient desaturation, distinct layers, suitable for B&W document archiving.",
+ "colorMode1bit": "1-bit pure black and white binary: Binarized based on halftone 127 threshold, extremely high contrast, volume reduced to 1/24.",
+ "outputConfigTitle": "2. Print-grade multi-page TIFF output configuration",
+ "colorModeLabel": "A. Color Expression Mode",
+ "colorModeColor": "Full color (RGB 24-bit)",
+ "colorModeGrayscale": "Grayscale (8-bit)",
+ "colorModeMono": "Black & white monochrome (1-bit)",
+ "compressionLabel": "B. Image Compression Algorithm",
+ "compressionNone": "No compression (None - maximum compatibility)",
+ "compressionPackbits": "Lossless run-length compression (PackBits RLE)",
+ "dpiLabel": "C. High-precision DPI resolution slider",
+ "dpiDisplay": "{dpi} DPI ({scale}% retinal zoom)",
+ "dpi72": "72 DPI (screen low precision)",
+ "dpi150": "150 DPI (normal office)",
+ "dpi300": "300 DPI (print-grade HD)",
+ "dpi600": "600 DPI (retinal ultra-clear)",
+ "printHintTitle": "Printing and archiving hints:",
+ "printHint": "Multi-page TIFF (Multi-page TIFF) can be scrolled up and down like PDF when imported into Acrobat or Photoshop, but it is completely composed of raster bitmaps. For charts and text, we strongly recommend using {highlight} to ensure crisp character edges.",
+ "printHintHighlight": "300 DPI",
+ "processButton": "Start compiling and generating multi-page TIFF",
+ "successMessage": "Single-file multi-page TIFF compilation successful! All pages have been merged and are ready.",
+ "loading": "Loading...",
+ "processing": "Serializing raster to TIFF..."
},
"pdfToZip": {
"uploadLabel": "Upload PDF Files",
@@ -1433,7 +1592,15 @@
"uploadLabel": "Upload JSON File",
"uploadDescription": "Drag and drop a JSON file.",
"convertButton": "Convert to PDF",
- "successMessage": "JSON converted to PDF successfully!"
+ "successMessage": "JSON converted to PDF successfully!",
+ "filesTitle": "JSON Files",
+ "fontSize": "Font Size",
+ "indentSpaces": "Indent Spaces",
+ "optionsTitle": "Options",
+ "pageSize": "Page Size",
+ "prettyPrint": "Pretty Print",
+ "preview": "Preview",
+ "showLineNumbers": "Show Line Numbers"
},
"pdfToImage": {
"uploadLabel": "Upload PDF File",
@@ -1529,7 +1696,9 @@
"previewTitle": "Extracted Text Preview",
"successMessage": "OCR completed successfully! Click the download button to save your file.",
"infoTitle": "About OCR",
- "infoText": "OCR (Optical Character Recognition) extracts text from scanned documents and images. For best results, use high-quality scans and select the correct language(s)."
+ "infoText": "OCR (Optical Character Recognition) extracts text from scanned documents and images. For best results, use high-quality scans and select the correct language(s).",
+ "coreAdvantages": "Core Advantages of Searchable PDF:",
+ "completionTitle": "OCR Completed!"
},
"linearizePdf": {
"uploadLabel": "Upload PDF Files",
@@ -1600,7 +1769,8 @@
"removeAnnotations": "Remove Annotations",
"sanitizeButton": "Sanitize PDF",
"successMessage": "PDF sanitized successfully!",
- "removedItems": "Removed:"
+ "removedItems": "Removed:",
+ "flattenForms": "Remove PDF forms"
},
"flattenPdf": {
"uploadLabel": "Upload PDF File",
@@ -1609,7 +1779,13 @@
"flattenForms": "Flatten Form Fields",
"flattenAnnotations": "Flatten Annotations",
"flattenButton": "Flatten PDF",
- "successMessage": "PDF flattened successfully!"
+ "successMessage": "PDF flattened successfully!",
+ "flattenAnnotationsDesc": "Remove PDF annotations",
+ "flattenFormsDesc": "Remove PDF forms",
+ "flattenLayersDesc": "Remove PDF layers",
+ "flattenedItems": "{count} items flattened",
+ "info": "Flatten PDF Info",
+ "flattenLayers": "{count} layers flattened"
},
"removeMetadata": {
"uploadLabel": "Upload PDF File",
@@ -2008,7 +2184,27 @@
"manualRemove": "Forced Delete",
"entropy": "Entropy",
"page": "Page {number}",
- "noBlankPages": "No blank pages found."
+ "noBlankPages": "No blank pages found.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "statusSummary": "Filter Status Summary",
+ "totalPages": "Total: {count} pages",
+ "blankPages": "To remove: {count}",
+ "keptPages": "Kept: {count}",
+ "resetOverrides": "Reset manual changes",
+ "keepAll": "Keep all pages",
+ "removeAll": "Remove all pages",
+ "allPages": "All pages ({count})",
+ "recommendedDelete": "Recommended ({count})",
+ "keptPagesTab": "Kept ({count})",
+ "noPagesInView": "No pages to display in current view",
+ "cleanupMessage": "System cleaned {count} blank pages, kept and recompiled remaining pages.",
+ "noPagesRemoved": "No blank pages detected for removal, exported directly.",
+ "processNewFile": "Process new file",
+ "clickToKeep": "Click to keep this page",
+ "clickToRemove": "Click to remove this page",
+ "forceRemove": "Force Remove",
+ "forceKeep": "Force Keep",
+ "blankPage": "Blank"
},
"tableOfContents": {
"uploadLabel": "Upload PDF File",
@@ -2051,7 +2247,8 @@
"preserveFormatting": "Preserve formatting",
"extractImages": "Extract images",
"convertButton": "Convert to DOCX",
- "successMessage": "Your PDF has been successfully converted to DOCX! Click the download button to save your file."
+ "successMessage": "Your PDF has been successfully converted to DOCX! Click the download button to save your file.",
+ "successTitle": "Conversion Complete"
},
"pdfToMarkdown": {
"uploadLabel": "Upload PDF File",
@@ -2066,7 +2263,8 @@
"previewTab": "Preview",
"sourceTab": "Markdown Source",
"successMessage": "Your PDF has been successfully converted to Markdown! Click the download button to save your file.",
- "failed": "Failed to convert PDF to Markdown."
+ "failed": "Failed to convert PDF to Markdown.",
+ "successTitle": "Conversion Complete"
},
"pdfToExcel": {
"uploadLabel": "Upload PDF File",
@@ -2096,55 +2294,64 @@
"uploadLabel": "Upload Word Document",
"uploadDescription": "Drag and drop a Word document (.docx) here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your Word document has been successfully converted to PDF!"
+ "successMessage": "Your Word document has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"psdToPdf": {
"uploadLabel": "Upload PSD File",
"uploadDescription": "Drag and drop a PSD (Photoshop) file here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "PSD converted to PDF successfully! Click the download button to save your file."
+ "successMessage": "PSD converted to PDF successfully! Click the download button to save your file.",
+ "reorderHint": "Reorder pages if needed"
},
"excelToPdf": {
"uploadLabel": "Upload Excel File",
"uploadDescription": "Drag and drop an Excel file (.xlsx) here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your Excel file has been successfully converted to PDF!"
+ "successMessage": "Your Excel file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"pptxToPdf": {
"uploadLabel": "Upload PowerPoint File",
"uploadDescription": "Drag and drop a PowerPoint file (.pptx) here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your PowerPoint file has been successfully converted to PDF!"
+ "successMessage": "Your PowerPoint file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"xpsToPdf": {
"uploadLabel": "Upload XPS File",
"uploadDescription": "Drag and drop an XPS file here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your XPS file has been successfully converted to PDF!"
+ "successMessage": "Your XPS file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"rtfToPdf": {
"uploadLabel": "Upload RTF File",
"uploadDescription": "Drag and drop an RTF file here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your RTF file has been successfully converted to PDF!"
+ "successMessage": "Your RTF file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"epubToPdf": {
"uploadLabel": "Upload EPUB File",
"uploadDescription": "Drag and drop an EPUB e-book file here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your EPUB file has been successfully converted to PDF!"
+ "successMessage": "Your EPUB file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"mobiToPdf": {
"uploadLabel": "Upload MOBI File",
"uploadDescription": "Drag and drop a MOBI/AZW e-book file here, or click to browse.",
"convertButton": "Convert to PDF",
- "successMessage": "Your MOBI file has been successfully converted to PDF!"
+ "successMessage": "Your MOBI file has been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"fb2ToPdf": {
"uploadLabel": "Upload FB2 Files",
"uploadDescription": "Drag and drop FB2 e-book files here, or click to browse. Supports multiple files.",
"convertButton": "Convert to PDF",
- "successMessage": "Your FB2 file(s) have been successfully converted to PDF!"
+ "successMessage": "Your FB2 file(s) have been successfully converted to PDF!",
+ "successTitle": "Conversion Complete"
},
"djvuToPdf": {
"uploadLabel": "Upload DJVU File",
@@ -2246,7 +2453,10 @@
"pageRange": "Page Range",
"convertButton": "Convert Fonts to Outlines",
"downloadAllZip": "Download All as ZIP",
- "successMessage": "Successfully converted file(s)!"
+ "successMessage": "Successfully converted file(s)!",
+ "dpiDesc": "DPI for font outline conversion",
+ "preserveTextDesc": "Preserve text layer",
+ "preserveTextLabel": "Preserve Text"
},
"extractTables": {
"uploadLabel": "Upload PDF File",
@@ -2309,8 +2519,218 @@
"successMessage": "Successfully redacted the selected text! Click download to save.",
"previewTitle": "Preview",
"pagesWithMatches": "Pages with matches:",
+ "allMatches": "All ({count})",
"selectedMatch": "Selected",
"unselectedMatch": "Not selected"
+ },
+ "deepSanitize": {
+ "uploadLabel": "Upload PDF document for sanitization",
+ "uploadDescription": "Drag and drop commercial contracts, confidential documents, or government archives. The system will scan optional layers, PieceInfo history, and force reconstruction of xref tree.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Deep structure pre-check...",
+ "optionsTitle": "Deep erasure control options",
+ "stripMetadataTitle": "Erase XMP XML metadata and conventional",
+ "stripMetadataDesc": "Title, Author, Producer, various modification history summary streams",
+ "stripPieceInfoTitle": "Clean PieceInfo proprietary editor attributes",
+ "stripPieceInfoDesc": "Page node modification traces left by software like Adobe Acrobat",
+ "stripOcgWatermarksTitle": "Strip OCProperties optional content watermark layer",
+ "stripOcgWatermarksDesc": "The underlying承载层 for many companies' anti-leakage dynamic invisible watermarks",
+ "stripAnnotationsTitle": "Thoroughly erase all interactive annotations and external links (use with caution)",
+ "stripAnnotationsDesc": "Will delete clickable external links, handwritten text highlights, and comment annotations in the document",
+ "processButton": "Execute deep sanitization",
+ "processing": "Wiping...",
+ "findingsTitle": "Security risk scan findings:",
+ "successMessage": "Deep sanitization completed! All traces have been erased.",
+ "successTitle": "Sanitization Complete"
+ },
+ "addPageLabels": {
+ "uploadLabel": "Upload PDF to add page labels",
+ "uploadDescription": "Drag and drop PDF to add page labels (logical page numbers).",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading...",
+ "optionsTitle": "Page Label Options",
+ "prefixLabel": "Custom prefix (Prefix)",
+ "startValueLabel": "Start value (Start Value)",
+ "styleLabel": "Numbering style",
+ "styleDecimal": "1, 2, 3... (Arabic numerals)",
+ "styleUpperRoman": "I, II, III... (Uppercase Roman)",
+ "styleLowerRoman": "i, ii, iii... (Lowercase Roman)",
+ "styleUpperAlpha": "A, B, C... (Uppercase letters)",
+ "styleLowerAlpha": "a, b, c... (Lowercase letters)",
+ "styleNone": "No numbering style (prefix only)",
+ "addRule": "Add rule",
+ "removeRule": "Remove",
+ "pageRangePlaceholder": "e.g. 1-9, odd, even",
+ "processButton": "Start injecting PageLabels",
+ "processing": "Adding page labels...",
+ "successMessage": "🎉 Page labels injected successfully! Please download the signed PDF and view the sidebar navigation.",
+ "metadataError": "Unable to parse main PDF metadata, the file may be corrupted.",
+ "uploadPrompt": "Please upload a PDF to add page labels.",
+ "processingMessage": "Batch injecting page labels...",
+ "compileError": "Failed to inject page labels.",
+ "unknownError": "An unknown error occurred.",
+ "ruleLabel": "Rule #{index}",
+ "removeRuleTitle": "Remove this rule",
+ "pageRangeLabel": "Page range",
+ "pageRangeHint": "Empty to apply to all pages",
+ "prefixPlaceholder": "e.g. Appendix-, A-",
+ "previewTitle": "Page label sequence real-time preview",
+ "algorithmTitle": "Rule priority overlay and non-intersection algorithm:",
+ "algorithmDesc": "The badges below represent the final calculated label sequence for each page inside the PDF. The gradient mini-badges next to physical page numbers are the structural labels displayed to the user.",
+ "previewCollapseHint": "There are still {count} pages not displayed, automatically collapsed to improve interaction performance.",
+ "loadFullPreview": "Load full {totalPages} page preview",
+ "step1Upload": "1. Upload Document (PDF)",
+ "step2Config": "2. Configure Label Mapping Rules (Page Label Rules)",
+ "processingText": "Adding labels and compiling...",
+ "successTitle": "Page labels injected successfully!",
+ "successDesc": "Please download the signed PDF and view the sidebar navigation."
+ },
+ "vectorExtractor": {
+ "uploadLabel": "Upload PDF for Vector Extraction",
+ "uploadDescription": "Drag and drop PDFs with logos, illustrations, CAD diagrams, or complex math formulas. The system will translate layers into high-fidelity SVG canvases.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading metadata...",
+ "pageNumber": "Page {page}",
+ "hoverHint": "Hover over elements for 3D bounding box highlight, click to select.",
+ "vectorProperties": "Vector Element Properties",
+ "noElementSelected": "No element selected",
+ "clickToSelect": "Click any vector line, text, or color block on the left canvas for high-fidelity individual extraction.",
+ "colorPreview": "Color Preview (RGB)",
+ "copyCode": "Copy SVG Source Code",
+ "codeCopied": "Code Copied!",
+ "downloadSelected": "Download Selected Vector Graphic"
+ },
+ "aiPdfReflower": {
+ "uploadLabel": "Upload PDF for AI Reflow",
+ "uploadDescription": "Drag and drop academic papers, double-column documents, or text-based PDFs here. The system will automatically perform line重组 and double-column parsing.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Parsing document structure...",
+ "reflowSettings": "Adaptive Reading Settings",
+ "realtimeHint": "Real-time modification of text layout style within the right 3D phone simulator.",
+ "backgroundScheme": "Reading Background Scheme",
+ "backgroundSepia": "Sepia Paper",
+ "backgroundLight": "Light & Clean",
+ "backgroundGreen": "Soft Green",
+ "backgroundDark": "Dark Mode",
+ "fontSize": "Reading Font Size",
+ "pullToExport": "Pull the rope to export with one click",
+ "dropdownQuickSave": "Dropdown ring quick save (Markdown)"
+ },
+ "timestampPdf": {
+ "uploadLabel": "Upload PDF for Timestamping",
+ "uploadDescription": "Drag and drop PDF file here. Supports auto-decryption of standard and encrypted PDFs.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading metadata...",
+ "selectTsaServer": "1. Select Trusted TSA Server (RFC 3161)",
+ "privacyHint": "System only sends irregular SHA-256 hash to server, absolutely guaranteeing document privacy.",
+ "speedFast": "Fast",
+ "speedMedium": "Medium",
+ "speedStable": "Stable",
+ "timestampSigning": "Timestamp Signing",
+ "waitingHint": "Upload file and select TSA, click 'Sign Trusted Timestamp' to generate encrypted certificate credential stamped by authoritative time authority.",
+ "credentialTitle": "Electronic Evidence Trusted Timestamp Credential",
+ "tsaTime": "TSA Atomic Clock Time (UTC)",
+ "hashVerification": "Secure File Hash Verification (SHA-256)",
+ "tsaAuthority": "Time Authority (TSA)",
+ "serialNumber": "Certificate Serial Number (Serial)",
+ "nameMeSign": "MeSign TSA",
+ "descMeSign": "China Information Security Trusted Timestamp Authority",
+ "nameDigiCert": "DigiCert TSA",
+ "descDigiCert": "Global leading PKI security timestamp provider",
+ "nameSectigo": "Sectigo TSA",
+ "descSectigo": "Comodo secure atomic clock time service",
+ "nameSSLCom": "SSL.com TSA",
+ "descSSLCom": "North America trusted third-party authority time node",
+ "nameFreeTSA": "FreeTSA.org",
+ "descFreeTSA": "Open source high-strength cryptography free attestation authority",
+ "speedSuperfast": "Super Fast"
+ },
+ "overlayPdf": {
+ "uploadLabelBase": "Upload Base PDF",
+ "uploadDescriptionBase": "This document's content will serve as the base skeleton for merging.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading...",
+ "uploadLabelLayer": "Upload Layer PDF",
+ "uploadDescriptionLayer": "Such as official seals, trust grids with design background, letterhead, etc.",
+ "previewTitle": "3D Layer Stacking Dynamic Preview",
+ "basePage": "Base Page",
+ "layerPage": "Layer Page",
+ "modeOverlay": "📂 Foreground Layer Mode (Overlay): Layer document renders above the main document's page content.",
+ "modeUnderlay": "🎨 Background Layer Mode (Underlay): Layer document pads at the bottom layer of all main document pages.",
+ "configTitle": "Overlay Merge Configuration",
+ "placementMode": "A. Overlay Level Mode (Placement Mode)",
+ "foregroundOverlay": "Foreground Overlay (Overlay)",
+ "backgroundUnderlay": "Background Pad (Underlay)",
+ "targetPageRange": "B. Target Page Range (Target Page Range)",
+ "targetPageHint": "Empty means apply to all main pages",
+ "targetPagePlaceholder": "e.g.: 1-5, 8, odd, even",
+ "loopShorter": "C. Loop Shorter Overlay Document",
+ "loopHint": "When layer file total pages is shorter than main PDF, automatically loop and reuse the layer (e.g. letterhead background). If turned off, pages exceeding the count will not apply overlay.",
+ "processButton": "Start applying overlay to generate PDF",
+ "successMessage": "🎉 PDF overlay merge processing successful! Click the button above to download."
+ },
+ "pdfToCbz": {
+ "uploadLabel": "Upload Comic/Illustration PDF",
+ "uploadDescription": "While rendering HD pages, automatically embed OPF/XML/Comment comic-specific multi-dimensional database information.",
+ "fileInfo": "{totalPages} pages • {size} MB",
+ "loading": "Loading...",
+ "titlePlaceholder": "Comic title",
+ "seriesPlaceholder": "e.g.: One Piece, Attack on Titan",
+ "writerPlaceholder": "e.g.: Eiichiro Oda",
+ "publisherPlaceholder": "e.g.: Viz Media",
+ "genrePlaceholder": "e.g.: Shonen, Action, Adventure",
+ "mangaLTR": "Left to Right (LTR - Normal eBook)",
+ "mangaRTL": "Right to Left (RTL - Japanese Manga)",
+ "imageQuality": "Image Compression Quality (JPEG/WebP)",
+ "scaleMultiplier": "Resolution Scale Multiplier",
+ "formatLabel": "Compression Save Image Format",
+ "grayscaleLabel": "Ink Screen Graytone Processing",
+ "grayscaleHint": "Desaturate to accelerate ink screen refresh rate and image quality contrast",
+ "processButton": "Start extracting and compiling CBZ comic package",
+ "processing": "Extracting comic pages...",
+ "successMessage": "Comic CBZ package compiled successfully! Built-in metadata.opf and ComicInfo.xml metadata. Please download with one click.",
+ "errorParsing": "Unable to parse main PDF comic metadata. The file may be damaged.",
+ "errorCompiling": "Failed to compile comic package CBZ.",
+ "errorUnknown": "Unknown error occurred during packaging conversion.",
+ "titleFallback": "Comic Title",
+ "writerFallback": "Anonymous Author",
+ "spineText": "BOOK SPINE TEXT • VOL.{volume}",
+ "genreLabel": "Genre",
+ "mangaLabel": "Manga Mode",
+ "metadataTitle": "Metadata",
+ "numberLabel": "Number",
+ "previewTitle": "Preview",
+ "publisherLabel": "Publisher",
+ "qualityTitle": "Image Quality",
+ "seriesLabel": "Series",
+ "titleLabel": "Title",
+ "volumeLabel": "Volume",
+ "writerLabel": "Writer"
}
+ },
+ "compressPdf": {
+ "fileList": "Files to compress ({count})",
+ "clearAll": "Clear all",
+ "dragToCompare": "Drag the slider to compare compression quality (Page {page})",
+ "leftOriginalRightCompressed": "Left: Original ({percent}%) | Right: Simulated ({quality})",
+ "sizeReduction": "Size reduction (light)",
+ "pixelClarity": "Pixel clarity (heavy)",
+ "qualityPreset": "Compression Quality Preset",
+ "qualityLowLabel": "Low quality",
+ "qualityMediumLabel": "Medium",
+ "qualityHighLabel": "High quality",
+ "qualityMaximumLabel": "Maximum (lossless)",
+ "qualityLowFullDesc": "Maximum compression 60%-80%, suitable for invoices and text documents.",
+ "qualityMediumFullDesc": "Balanced, achieves 40% size optimization while maintaining clear text edges.",
+ "qualityHighFullDesc": "Preserves photo-level image contrast and color dynamics, slightly reduces size.",
+ "qualityMaximumFullDesc": "Near 1:1 maximum quality, only cleans hidden garbage fragments and unreferenced blocks.",
+ "optimizeGraphics": "Optimize all embedded graphics assets",
+ "removeMetadataForce": "Force remove author/software metadata",
+ "optimizing": "Optimizing...",
+ "startOptimization": "Start Compression",
+ "compressionExecuted": "Compression executed!",
+ "downloadZipCount": "Download ZIP ({count} files)",
+ "documentOptimizationComplete": "Document optimization complete!",
+ "compressionResult": "Original: {size} • Successfully cleaned unused fragments and metadata streams locally."
}
}
diff --git a/messages/es.json b/messages/es.json
index a334083d2..a5113fa51 100644
--- a/messages/es.json
+++ b/messages/es.json
@@ -32,6 +32,10 @@
"convertPdf": "convertir PDF",
"freePdfTools": "herramientas PDF gratis",
"onlinePdfEditor": "editor PDF en línea"
+ },
+ "terms": {
+ "title": "Términos de Servicio",
+ "description": "Términos de Servicio para las herramientas PDF gratuitas de Craftisle."
}
},
"common": {
diff --git a/messages/fr.json b/messages/fr.json
index 06029a850..9d9bd3852 100644
--- a/messages/fr.json
+++ b/messages/fr.json
@@ -32,6 +32,10 @@
"convertPdf": "convertir PDF",
"freePdfTools": "outils PDF gratuits",
"onlinePdfEditor": "éditeur PDF en ligne"
+ },
+ "terms": {
+ "title": "Conditions d'utilisation",
+ "description": "Conditions d'utilisation pour les outils PDF gratuits de Craftisle."
}
},
"common": {
diff --git a/messages/id.json b/messages/id.json
index 56df846a4..75b30125b 100644
--- a/messages/id.json
+++ b/messages/id.json
@@ -32,6 +32,10 @@
"convertPdf": "konversi PDF",
"freePdfTools": "alat PDF gratis",
"onlinePdfEditor": "editor PDF online"
+ },
+ "terms": {
+ "title": "Syarat Ketentuan",
+ "description": "Syarat Ketentuan untuk alat PDF gratis Craftisle."
}
},
"common": {
diff --git a/messages/it.json b/messages/it.json
index fca553546..1c18ac4b0 100644
--- a/messages/it.json
+++ b/messages/it.json
@@ -32,6 +32,10 @@
"convertPdf": "convertire PDF",
"freePdfTools": "strumenti PDF gratuiti",
"onlinePdfEditor": "editor PDF online"
+ },
+ "terms": {
+ "title": "Termini di Servizio",
+ "description": "Termini di Servizio per gli strumenti PDF gratuiti di Craftisle."
}
},
"common": {
diff --git a/messages/ja.json b/messages/ja.json
index 2697cc516..577e540d2 100644
--- a/messages/ja.json
+++ b/messages/ja.json
@@ -32,6 +32,10 @@
"convertPdf": "PDF変換",
"freePdfTools": "無料PDFツール",
"onlinePdfEditor": "オンラインPDFエディター"
+ },
+ "terms": {
+ "title": "利用規約",
+ "description": "Craftisle PDFの無料PDFツールの利用規約。"
}
},
"common": {
diff --git a/messages/ko.json b/messages/ko.json
index a29848c75..09d59997b 100644
--- a/messages/ko.json
+++ b/messages/ko.json
@@ -32,6 +32,10 @@
"convertPdf": "PDF 변환",
"freePdfTools": "무료 PDF 도구",
"onlinePdfEditor": "온라인 PDF 편집기"
+ },
+ "terms": {
+ "title": "서비스 이용약관",
+ "description": "Craftisle PDF 무료 PDF 도구의 서비스 이용약관."
}
},
"common": {
diff --git a/messages/pt.json b/messages/pt.json
index 0644c7443..d32294373 100644
--- a/messages/pt.json
+++ b/messages/pt.json
@@ -32,6 +32,10 @@
"convertPdf": "converter PDF",
"freePdfTools": "ferramentas PDF grátis",
"onlinePdfEditor": "editor PDF online"
+ },
+ "terms": {
+ "title": "Termos de Serviço",
+ "description": "Termos de Serviço para as ferramentas PDF gratuitas da Craftisle."
}
},
"common": {
diff --git a/messages/ro.json b/messages/ro.json
index fb2a0fe70..c1bb5a6b8 100644
--- a/messages/ro.json
+++ b/messages/ro.json
@@ -32,6 +32,10 @@
"convertPdf": "convertește PDF",
"freePdfTools": "instrumente PDF gratuite",
"onlinePdfEditor": "editor PDF online"
+ },
+ "terms": {
+ "title": "Termeni și Condiții",
+ "description": "Termeni și Condiții pentru instrumentele PDF gratuite Craftisle."
}
},
"common": {
@@ -169,2138 +173,2138 @@
"landscape": "Peisaj"
}
},
- "toolsPage": {
- "title": "Instrumente PDF Profesionale",
- "subtitle": "{count}+ instrumente gratuite, sigure și ușor de utilizat pentru toate nevoile tale PDF.",
- "filters": "Filtre",
- "allTools": "Toate Instrumentele",
- "clearAll": "Șterge Tot",
- "clearFilters": "Șterge Filtrele",
- "showingAll": "Se afișează toate cele {count} instrumente",
- "showingFiltered": "Se afișează {filtered} din {total} instrumente",
- "forQuery": "pentru \"{query}\"",
- "inCategory": "în {category}",
- "noToolsFound": "Niciun instrument găsit"
- },
- "faqPage": {
- "title": "Întrebări Frecvente",
- "subtitle": "Găsește răspunsuri la întrebări comune despre {brand}",
- "searchPlaceholder": "Caută în FAQ...",
- "noResults": "Nicio întrebare găsită care să corespundă căutării tale.",
- "expandAll": "Extinde Tot",
- "collapseAll": "Restrânge Tot",
- "categories": {
- "all": "Toate",
- "general": "General",
- "privacy": "Confidențialitate și Securitate",
- "features": "Funcționalități",
- "technical": "Tehnic",
- "languages": "Limbi"
- },
- "sections": {
- "general": {
- "whatIs": {
- "question": "Ce este PDFCraft?",
- "answer": "PDFCraft este un set de instrumente PDF gratuit, axat pe confidențialitate, care rulează în întregime în browser-ul tău. Oferă peste 80 de instrumente profesionale pentru editarea, convertirea, combinarea, divizarea și securizarea fișierelor PDF fără a le încărca pe niciun server."
- },
- "isFree": {
- "question": "Este PDFCraft cu adevărat gratuit?",
- "answer": "Da, PDFCraft este complet gratuit de utilizat. Nu există costuri ascunse, niveluri premium și nu este necesară înregistrarea. Toate funcționalitățile sunt disponibile pentru toată lumea."
- },
- "account": {
- "question": "Trebuie să îmi creez un cont?",
- "answer": "Nu, nu este nevoie să îți creezi un cont sau să te înregistrezi pentru a folosi PDFCraft. Pur și simplu vizitează site-ul și începe să folosești orice instrument imediat."
- }
- },
- "privacy": {
- "uploaded": {
- "question": "Sunt fișierele mele încărcate pe un server?",
- "answer": "Nu, fișierele tale nu sunt niciodată încărcate pe niciun server. Toată procesarea PDF are loc local în browser-ul tău folosind JavaScript și WebAssembly. Fișierele tale nu părăsesc niciodată dispozitivul."
- },
- "safe": {
- "question": "Este sigur să folosesc PDFCraft cu documente sensibile?",
- "answer": "Da, PDFCraft este conceput având în vedere confidențialitatea. Deoarece toată procesarea are loc local în browser-ul tău, documentele tale sensibile rămân pe dispozitivul tău și nu sunt niciodată transmise prin internet."
- },
- "storage": {
- "question": "Ce se întâmplă cu fișierele mele după procesare?",
- "answer": "Fișierele tale sunt stocate temporar în memoria browser-ului tău în timpul procesării. Odată ce închizi fila browser-ului sau navighezi în altă parte, toate datele fișierului sunt șterse automat. Nu stocăm niciunul dintre fișierele tale."
- }
- },
- "features": {
- "operations": {
- "question": "Ce operațiuni PDF pot efectua?",
- "answer": "PDFCraft oferă peste 67 de instrumente, inclusiv: combinare, divizare, comprimare, conversie (spre/dinspre imagini, text, JSON), editare, adnotare, semnare, adăugare de filigrane, criptare/decriptare, OCR și multe altele."
- },
- "merge": {
- "question": "Pot combina mai multe fișiere PDF?",
- "answer": "Da, poți combina mai multe fișiere PDF într-unul singur. Pur și simplu folosește instrumentul Combină PDF, încarcă fișierele, aranjează-le în ordinea dorită și fă clic pe combină."
- },
- "images": {
- "question": "Pot converti imagini în PDF?",
- "answer": "Da, PDFCraft acceptă conversia diferitelor formate de imagine (JPG, PNG, WebP, BMP, TIFF, SVG, HEIC) în PDF. Poți converti imagini individuale sau mai multe imagini deodată."
- },
- "edit": {
- "question": "Pot edita textul întrun PDF?",
- "answer": "PDFCraft oferă instrumente de adnotare și editare, inclusiv evidențierea, adăugarea de text, forme, imagini și semnături. Pentru editarea completă a textului, instrumentul Editor PDF oferă capabilități complete de adnotare."
- }
- },
- "technical": {
- "browsers": {
- "question": "Ce browsere sunt acceptate?",
- "answer": "PDFCraft funcționează pe toate browserele moderne, inclusiv Chrome, Firefox, Safari și Edge. Recomandăm folosirea celei mai recente versiuni a browser-ului pentru cea mai bună experiență."
- },
- "sizeLimit": {
- "question": "Există o limită de dimensiune a fișierului?",
- "answer": "Majoritatea instrumentelor acceptă fișiere de până la 100MB, cu unele instrumente precum combinarea și comprimarea acceptând până la 500MB. Aceste limite sunt stabilite pentru a asigura o performanță fluidă în browser-ul tău."
- },
- "slow": {
- "question": "De ce este procesarea lentă pentru fișiere mari?",
- "answer": "Deoarece toată procesarea are loc în browser-ul tău, performanța depinde de capacitățile dispozitivului tău. Fișierele mari necesită mai multă memorie și putere de procesare. Pentru cele mai bune rezultate, închide alte file de browser și aplicații."
- },
- "offline": {
- "question": "Funcționează PDFCraft offline?",
- "answer": "În prezent, PDFCraft necesită o conexiune la internet pentru a încărca aplicația. Cu toate acestea, odată încărcată, procesarea PDF în sine are loc local și nu necesită o conexiune."
- }
- },
- "languages": {
- "supported": {
- "question": "What languages are supported?",
- "answer": "PDFCraft is available in 9 languages: English, Japanese, Korean, Spanish, French, German, Chinese, Portuguese, and Arabic (with RTL support)."
- },
- "change": {
- "question": "How do I change the language?",
- "answer": "You can change the language using the language selector in the header. Your preference will be saved for future visits."
- }
- }
- },
- "cta": {
- "title": "Still have questions?",
- "description": "Can't find the answer you're looking for? Feel free to reach out to us.",
- "button": "Contact Us"
- }
+ "toolsPage": {
+ "title": "Instrumente PDF Profesionale",
+ "subtitle": "{count}+ instrumente gratuite, sigure și ușor de utilizat pentru toate nevoile tale PDF.",
+ "filters": "Filtre",
+ "allTools": "Toate Instrumentele",
+ "clearAll": "Șterge Tot",
+ "clearFilters": "Șterge Filtrele",
+ "showingAll": "Se afișează toate cele {count} instrumente",
+ "showingFiltered": "Se afișează {filtered} din {total} instrumente",
+ "forQuery": "pentru \"{query}\"",
+ "inCategory": "în {category}",
+ "noToolsFound": "Niciun instrument găsit"
+ },
+ "faqPage": {
+ "title": "Întrebări Frecvente",
+ "subtitle": "Găsește răspunsuri la întrebări comune despre {brand}",
+ "searchPlaceholder": "Caută în FAQ...",
+ "noResults": "Nicio întrebare găsită care să corespundă căutării tale.",
+ "expandAll": "Extinde Tot",
+ "collapseAll": "Restrânge Tot",
+ "categories": {
+ "all": "Toate",
+ "general": "General",
+ "privacy": "Confidențialitate și Securitate",
+ "features": "Funcționalități",
+ "technical": "Tehnic",
+ "languages": "Limbi"
},
- "aboutPage": {
- "title": "Despre {brand}",
- "description": "{brand} este un set de instrumente PDF gratuit, axat pe confidențialitate, care rulează în întregime în browser-ul tău. Cu peste {count} instrumente profesionale, poți edita, converti, combina, diviza și securiza fișierele PDF fără a le încărca vreodată pe un server.",
- "mission": {
- "title": "Misiunea Noastră",
- "p1": "Credem că toată lumea ar trebui să aibă acces la instrumente PDF puternice fără a-și compromite confidențialitatea sau a plăti taxe de abonament scumpe. De aceea am creat {brand} – un set cuprinzător de instrumente PDF care pune confidențialitatea pe primul loc.",
- "p2": "Spre deosebire de serviciile PDF tradiționale care necesită încărcarea fișierelor pe serverre la distanță, {brand} procesează totul local în browser-ul tău. Documentele tale sensibile nu părăsesc niciodată dispozitivul, oferindu-ți control complet asupra datelor tale.",
- "p3": "Indiferent dacă ești student, profesionist sau utilizator ocazional, {brand} oferă toate instrumentele de care ai nevoie pentru a lucra cu fișiere PDF eficient și în siguranță."
- },
- "values": {
- "title": "Valorile Noastre",
- "privacy": {
- "title": "Confidențialitatea pe Primul Loc",
- "description": "Fișierele tale nu părăsesc niciodată dispozitivul. Toată procesarea are loc local în browser-ul tău, asigurând confidențialitate și securitate deplină."
- },
- "fast": {
- "title": "Rapid și Eficient",
- "description": "Bazat pe tehnologii web moderne, PDFCraft oferă o procesare PDF extrem de rapidă, fără a fi nevoie de încărcări sau descărcări."
- },
- "accessible": {
- "title": "Accesibil de Oriunde",
- "description": "Disponibil în 9 limbi și funcționează pe orice dispozitiv cu un browser modern. Nu este necesară nicio instalare."
- },
- "free": {
- "title": "Gratuit pentru Totdeauna",
- "description": "PDFCraft este complet gratuit de utilizat, fără costuri ascunse, fără înregistrare necesară și fără limite de utilizare."
- },
- "openSource": {
- "title": "Sursă Deschisă",
- "description": "Construit având în vedere transparența. Codul nostru este open source, permițând oricui să verifice afirmațiile noastre privind confidențialitatea."
- },
- "community": {
- "title": "Condus de Comunitate",
- "description": "Dezvoltat pe baza feedback-ului de la utilizatori din întreaga lume. Îmbunătățim continuu în funcție de nevoile tale."
- }
- },
- "technology": {
- "title": "Construit cu Tehnologie Modernă",
- "description": "{brand} este construit folosind tehnologii web de ultimă oră pentru a asigura cea mai bună experiență posibilă:",
- "list": {
- "nextjs": "
");
+ const fontSize = options?.fontSize ?? 11;
+ const pageSize = options?.pageSize ?? "a4";
+ const margins = options?.margins ?? 72;
+ const fontMap = {
+ "helv": "sans-serif",
+ "tiro": "serif",
+ "cour": "monospace",
+ "times": "serif"
+ };
+ const fontName = options?.fontName ?? "helv";
+ const fontFamily = fontMap[fontName] || "sans-serif";
+ const result = pyodide.runPython(`
+import base64
+import io
+
+html_content = '''
+
+${escapedText} +
+''' + +css_content = "* { font-family: ${fontFamily}; font-size: ${fontSize}pt; }" + +mediabox = pymupdf.paper_rect("${pageSize}") +margin = ${margins} +where = mediabox + (margin, margin, -margin, -margin) + +story = pymupdf.Story(html=html_content, user_css=css_content) + +buffer = io.BytesIO() +writer = pymupdf.DocumentWriter(buffer) + +def rectfn(rect_num, filled): + return mediabox, where, None + +story.write(writer, rectfn) +writer.close() + +buffer.seek(0) +doc = pymupdf.open("pdf", buffer.read()) +doc.subset_fonts() +pdf_bytes = doc.tobytes(garbage=3, deflate=True) +doc.close() + +base64.b64encode(pdf_bytes).decode('ascii') +`); + const binaryStr = atob(result); + const bytes = new Uint8Array(binaryStr.length); + for (let i = 0; i < binaryStr.length; i++) { + bytes[i] = binaryStr.charCodeAt(i); + } + return new Blob([bytes], { type: "application/pdf" }); + } + async htmlToPdf(html, options) { + const pyodide = await this.getPyodide(); + const escapedHtml = html.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n"); + const escapedCss = options?.css?.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n") ?? ""; + const pageSize = options?.pageSize ?? "a4"; + let margins = { top: 36, right: 36, bottom: 36, left: 36 }; + if (typeof options?.margins === "number") { + margins = { top: options.margins, right: options.margins, bottom: options.margins, left: options.margins }; + } else if (options?.margins) { + margins = options.margins; + } + const result = pyodide.runPython(` +import base64 +import io +import re +import json + +html_content = '''${escapedHtml}''' +css_content = '''${escapedCss}''' + +# Extract links from HTML before processing +link_pattern = r']*href=["\\'](https?://[^"\\'>]+)["\\'"][^>]*>([^<]+)' +links = re.findall(link_pattern, html_content, re.IGNORECASE) +# links is a list of (url, text) tuples + +html_content = re.sub(r']*stylesheet[^>]*>', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r']*href=[^>]*>', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'