This document details the features of Markdown Viewer, focusing on their architectural execution, performance strategies, and code-level configurations for version v3.7.4.
To prevent typing lag and main-thread blocks, Markdown Viewer offloads compilation to a background Web Worker (preview-worker.js).
The main thread throttles render requests based on the character length of the active document to conserve CPU cycles:
\n\n) while respecting boundary exclusions (like block math $$ and code fences `).FNV-1a Alphanumeric Hashing: For each block, the worker computes a 32-bit FNV-1a hash. This is a non-cryptographic hash function designed for speed:
$$Hi = (H{i-1} \oplus d_i) \times p$$
where $p = 16777619$ (FNV prime) and $H_0 = 2166136261$ (offset basis).
Selective Compilation: If the document doesn't use complex global footnotes or reference-style declarations, the worker compiles only changed blocks using marked.js and highlight.js. It returns an array of compiled HTML strings paired with their FNV-1a hashes.
Updating the entire preview pane using element.innerHTML causes layout repaints, resets scrollbar offsets, wipes focus states, and collapses open toggle elements (like <details>). Markdown Viewer employs a custom patching controller:
replaceWith().Layout Containment: Every block is wrapped in a <section> container configured with modern CSS rules:
content-visibility: auto;
contain-intrinsic-size: auto 220px;
This instructs the browser's layout engine to bypass formatting and rendering of off-screen markdown sections, reducing repaint and reflow overhead.
When editing in Split View, scrolling the editor textarea scrolls the HTML preview pane proportionally, and vice versa.
Proportional scrolling is mapped using the scroll ratio:
$$R_{\text{scroll}} = \frac{\text{scrollTop}}{\text{scrollHeight} - \text{clientHeight}}$$
The target container's scroll position is then calculated as:
$$\text{Target-scroll-top} = R_{\text{scroll}} \times (\text{Target-scroll-height} - \text{Target-client-height})$$
Since scrolling the target pane triggers its own scroll events, this can create an infinite update loop. To prevent this:
isEditorScrolling = true and isPreviewScrolling = true.requestAnimationFrame().LaTeX parsing uses MathJax loaded dynamically from a CDN.
/\$\$|\$[^$]|\\\(|\\\[/.Once loaded, equations are rendered by calling:
MathJax.typesetPromise([previewElement]);
By default, MathJax appends assistive MathML containers (<mjx-assistive-mml>) with tabindex="0". This interrupts keyboard tab order. A post-processing script runs after typesetting:
<mjx-assistive-mml> tags in the preview.tabindex attribute from each element.Mermaid code blocks are rendered as SVG diagrams with custom interactive features.
Every rendered Mermaid diagram is wrapped in a container that appends a floating toolbar with four actions:
Copy Image: Renders the diagram as a PNG blob and copies it to the system clipboard using the asynchronous Clipboard API:
navigator.clipboard.write([
new ClipboardItem({ "image/png": pngBlob })
]);
Inside the zoom modal, the SVG transform matrix is updated during mouse events:
Scale: Computed using mouse-wheel offsets:
$$\text{scale} = \max(0.1, \min(\text{scale} + \text{delta}, 10))$$
Panning: Tracks the difference between starting coordinates and current pointer coordinates:
$$X{\text{pan}} = X{\text{current}} - X_{\text{dragStart}}$$
$$Y{\text{pan}} = Y{\text{current}} - Y_{\text{dragStart}}$$
CSS Transform: The updates are applied using hardware-accelerated CSS properties:
svg.style.transform = `translate(${modalPanX}px, ${modalPanY}px) scale(${modalZoomScale})`;
Exporting long, complex Markdown previews to PDF often leads to sliced text lines and cut-off images. Markdown Viewer uses a custom pagination engine:
.pdf-export class) set to A4 width (210mm).html2canvas struggles to render inline SVGs, all Mermaid diagrams are converted to Base64-encoded PNG image elements inside the sandbox..pdf-page-break-spacer).<thead>) is duplicated onto the subsequent page.html2canvas, and the resulting canvases are compiled into a PDF via jsPDF.Markdown Viewer supports working with multiple documents simultaneously via a tabbed workspace.
The workspace is managed in a global tabs array:
{
id: "tab_" + Date.now() + "_" + Math.random().toString(36).substring(2, 8),
title: "Document Title",
content: "# Markdown Content...",
scrollPos: 0,
viewMode: "split", // split | editor | preview
createdAt: 1718042710000
}
beforeunload and visibilitychange events (when the page is hidden).draggable="true".draggedTabId).localStorage, and updates the tab bar.To prevent importing corrupted binary files, the file reader scans the first 8 KB of any imported file:
\x00) is found, the import is aborted, and an error is displayed.Users can import documents directly from public GitHub repositories:
api.github.com/repos/.../contents/...) to fetch file trees.Markdown Viewer lets you share documents via links that contain the entire compressed document content, eliminating the need for a database.
$$\text{Markdown Text} \xrightarrow{\text{TextEncoder}} \text{Bytes} \xrightarrow{\text{Pako.deflate (zlib)}} \text{Compressed Bytes} \xrightarrow{\text{Base64-URL Encoding}} \text{URL Hash}$$
Pako.js (DEFLATE).+ with -, / with _, and removing trailing = padding.#share=<encoded_string>.background-color, border-color) rather than using transition: all.<body> element was removed to prevent repainting the entire viewport during theme shifts.All compiled HTML is sanitized on the main thread using DOMPurify before being rendered:
const cleanHtml = DOMPurify.sanitize(rawHtml, {
USE_PROFILES: { html: true },
ADD_ATTR: ['target', 'draggable', 'contenteditable']
});
This strips inline script handlers (e.g. onload, onclick) and <script> elements to prevent Cross-Site Scripting (XSS) when importing or loading external markdown files.