No description
Find a file
Ambursley 3b4244686b Replace jszip with a hand-rolled zip reader (fixes review flag)
Obsidian's community-plugin review flagged "code obfuscation: found 4
dynamic <script> element creations" on 1.0.13. Traced it to jszip's
"lie" and "setimmediate" dependencies — both bundle a legacy
IE-compatibility trick that creates an empty <script> element purely
to fire an onreadystatechange event as a task-scheduling hack, never
setting src or executing anything. Harmless in Obsidian's Electron
runtime, but indistinguishable from something malicious to a static
scanner.

Rather than fight a third-party dependency's internals, dropped jszip
entirely and added miniZip.ts, a ~60-line reader for the one thing we
actually need (pull xl/workbook.xml, a small named file, out of a
plain non-zip64 zip) — consistent with how this plugin already
hand-rolls its Mac/Windows/Linux install extraction instead of pulling
in general-purpose archive libraries. Verified it's a correct drop-in:
re-ran every existing getHiddenSheetNames test (6-visible/4-hidden
workbook, special-character sheet names, missing file, no-hidden-sheets
case) and the end-to-end outline-filtering check against a real
converted PDF — all identical results to the jszip-based version.
Confirmed zero dynamic script-element creations left in the built
main.js (was 4).
2026-07-20 03:17:33 -04:00
docs Initial commit 2026-07-18 23:21:41 -04:00
src Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00
.gitignore Embed pdf.js worker source into main.js instead of a separate file 2026-07-19 12:02:49 -04:00
esbuild.config.mjs Embed pdf.js worker source into main.js instead of a separate file 2026-07-19 12:02:49 -04:00
eslint.config.mjs Initial commit 2026-07-18 23:21:41 -04:00
LICENSE.txt Initial commit 2026-07-18 23:21:41 -04:00
main.js Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00
manifest.json Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00
package-lock.json Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00
package.json Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00
README.md Filter hidden Excel sheets out of the tab bar and page count 2026-07-20 03:06:08 -04:00
styles.css Add Excel (.xlsx) support with sheet-tabs navigation 2026-07-20 01:50:32 -04:00
tsconfig.json Explicitly declare types: ["node"] in tsconfig 2026-07-19 01:49:13 -04:00
versions.json Replace jszip with a hand-rolled zip reader (fixes review flag) 2026-07-20 03:17:33 -04:00

Doc Preview

Preview PowerPoint, Word, and Excel files inside Obsidian — no need to open the real app.

Renders locally via a headless LibreOffice install (no window ever opens), through a custom in-app viewer rather than the browser's generic embedded PDF plugin. The preview auto-refreshes whenever the file changes on disk — including edits made by an external tool or an AI agent (e.g. Claude Code CLI editing the file directly) — and jumps to whichever slide/page actually changed.

Claude Code CLI edits a slide's title directly in the pptx file; the Doc Preview panel auto-refreshes and jumps to the updated slide

Features

  • Opens .pptx, .docx, and .xlsx files directly in an Obsidian tab instead of launching PowerPoint/Word/Excel
  • Rendered headless via LibreOffice — no window ever flashes on screen
  • Auto-refreshes on external file changes (debounced, so a mid-write save doesn't get converted half-finished)
  • Jumps to the page/slide that actually changed on refresh, not just back to page 1
  • Excel workbooks get sheet tabs, pulled from the PDF's own outline, so you can jump straight to a sheet — the page indicator also shows which sheet you're currently viewing. Sheets hidden in Excel stay hidden here too, matching what you'd actually see if you opened the file yourself
  • Custom PDF viewer: zoom in/out (including trackpad pinch-to-zoom), fit-to-page, rotate, space+drag panning when zoomed in, selectable/copyable text, a toggleable thumbnail rail, keyboard arrow-key navigation, and a download button
  • A fading page-number indicator (bottom-center), not a fixed toolbar element
  • Settings can install LibreOffice for you, to a folder of your choosing — it doesn't have to go into Applications / Program Files

Requirements

  • Desktop Obsidian only (this plugin is not available on mobile)
  • LibreOffice — if you don't already have it, install it from the plugin's settings tab

Installation

  1. Open Settings → Community plugins in Obsidian.
  2. Select Browse and search for Doc Preview.
  3. Select Install, then Enable.

Settings

  • Detected installation — shows the LibreOffice install currently in use (path + version), or "not found."
  • Install location — where to install LibreOffice if you use the Install button. Pick any folder you have write access to; browse via the native folder picker or type a path directly.
  • Install LibreOffice — downloads the current stable release from documentfoundation.org and installs it into the folder above.

How it works

  1. Clicking a .pptx/.docx/.xlsx file opens Doc Preview's own view instead of the OS default app (via registerExtensions).
  2. The file is converted to PDF with soffice --headless --convert-to pdf.
  3. The PDF is rendered with pdf.js onto a <canvas> — not the browser's built-in PDF viewer, which can't be restyled or have parts of its UI hidden.
  4. A vault filesystem watcher (vault.on("modify")) triggers a debounced re-conversion whenever the source file changes on disk, from any process — not just edits made through Obsidian itself.

Known limitations

  • LibreOffice is a real dependency (~300500MB download) — there's no way around it for now. See the settings tab for an in-app install flow.
  • Each conversion spins up a fresh LibreOffice process (~1520s). There's no persistent/warm LibreOffice listener yet, so refreshes aren't instant.
  • The "jump to changed page" heuristic compares extracted text per page, not pixels — a purely visual edit with no text change (e.g. only a fill color) won't be detected. It also won't guess if the total page count changed (inserted/deleted slides shift every later page's position), and just leaves the view where it was in that case.
  • Sheet tabs rely on LibreOffice's PDF export including a bookmark/outline entry per sheet, which it does by default. If a given workbook's export somehow lacks one, the file still previews fine — it just falls back to a plain page list with no sheet tabs.
  • Each sheet is exported as a single whole-sheet page (via LibreOffice's SinglePageSheets option) rather than tiled across print-sized pages, so a large sheet becomes one large page — you may need to zoom in to read a very dense sheet clearly. This option needs a reasonably recent LibreOffice (24.8+); older installs will silently fall back to the normal tiled/paginated export instead.
  • LibreOffice's headless PDF export includes hidden sheets even though its own GUI export doesn't — a known discrepancy, not something this plugin can fix on LibreOffice's side. Worked around by reading sheet visibility straight out of the .xlsx's own XML and filtering those pages back out, so they never reach the tab bar or page count.
  • The auto-installer's Windows (MSI, custom INSTALLLOCATION) and Linux (dpkg-deb -x extraction, no dependency resolution) paths are implemented per documented conventions but are less battle-tested than the macOS path.

License

MIT