Skip to content

PDF Generation Template Editor

Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.

View on GitHub

Core Bridge ​

The core bridge (packages/webview/src/core/) is the stateless facade between the Vue webview UI and the ComPDFKit Core engine. It hides the monolithic ComPDFKitViewer class behind ~120 thin functions and is the only layer permitted to call the engine.

Role and rules ​

  • Stateless: no business state, no DOM operations. The only mutable structure is the documentViewers Map (the multi-instance registry).
  • One function per file: filename === function name; default-exported arrow function.
  • docNum is always the last parameter when present, forwarded to getDocumentViewer(docNum).
  • Pure delegation: a typical bridge file is one line — getDocumentViewer(docNum).<engineMethod>(args...). Light argument destructuring is the only transformation.
  • One-way dependency: apis/ → core/ → engine. The bridge never touches Pinia stores or the DOM.

The multi-instance registry — documentViewers.js ​

The only stateful file (24 lines):

javascript
import ComPDFKitViewer from '../../lib/webview.min.js'
const documentViewerMap = new Map();

export const setDocumentViewer = (number, documentViewer, options) => {
  if (documentViewer) {
    documentViewerMap.set(number, documentViewer);   // pre-built viewer
  } else {
    const viewer = new ComPDFKitViewer(options);     // or construct here
    documentViewerMap.set(number, viewer);
  }
};
export const deleteDocumentViewer = (number) => { documentViewerMap.delete(number); };
export const getDocumentViewer = (number = 1) => documentViewerMap.get(number);
export const getDocumentViewers = () => Array.from(documentViewerMap.values());
  • Default instance = 1. getDocumentViewer() resolves to instance 1 (the primary document).
  • Two registration modes: store an externally-constructed viewer, or construct one internally from options.
  • Registration sites: helpers/initDocument.js registers instance 1; CompareDocumentContainer.vue registers instances 2 and 3 (the compare old/new file viewers).
  • Only ~13 of ~120 bridge files plumb docNum through; the rest are hardwired to instance 1.

Categorized capability map ​

core/index.js re-exports ~120 bridge functions. By domain:

Lifecycle & multi-instance ​

getDocumentViewer, setDocumentViewer, getDocumentViewers, deleteDocumentViewer, init, initConfig, initializeViewer.

Document loading, metadata & editing ​

loadDocument, getPagesCount, getCurrentPage, getDocumentName, setDocumentName, getOutlines, getOptionUrl, download, getDocEditorPages, saveDocumentEdit, compare.

nextPage, previousPage, pageNumberChanged, rotateClockwise, rotateCounterclockwise, zoomIn, zoomOut, scaleChanged, getScale, getScrollViewElement, getSelectedPage, pageToWindow, windowToPage, requestFullScreenMode, toggleSidebar, switchScrollMode, switchSpreadMode, webViewerNamedAction, webViewerPageMode.

Search & text ​

search, setActiveSearchResult, clearSearchResults, getSelectedText.

Annotations — CRUD, manager & history ​

getAnnotationsList, getAnnotationManager, getAnnotationHistoryManager, importAnnotations, exportAnnotations, exportXfdf, saveAnnotations, removeAllAnnotations, selectAnnotation, jumpToAnnotation, setAnnotationStyles, addAnnotationImage, handleReplyAnnotation, setUnselectableAnnotationTypes, getUnselectableAnnotationTypes, enableAutoSelectOnCreate, disableAutoSelectOnCreate, updateViewWithColorIndex, showPopup, handlePopup, setAnnotator.

Annotations — stamps & highlights ​

getDynamicStampPreview, getStampRect, handleStamp, setHighlightLink, setHighlightForm.

Tools ​

setTool, switchTool, setToolMode, getToolMode, getToolStyles, setToolStyles, registerTool, setDefaultSelect, setEraseMode, getEraseMode.

Content editing ​

switchAnnotationEditorMode, setContentEditorProperty, getContentEditManager, getContentEditHistoryManager, addEditorImage, getCropedPageImage.

Forms ​

handleField, enableSkipNoRequired, disableSkipNoRequired, isSkipNoRequired, setConsecutiveType, getConsecutiveType, disableFillConsecutively, isFillConsecutively, getFormSignFilledAndUnfilled, getRequiredFormSign, setAutoJumpNextSign.

Digital signatures ​

handleSign, getSignature, deleteSignature, verifySignature, getVerificationResult.

Certificates, security & permissions ​

loadCertificates, addToTrustedCertificateLists, checkCertificateIsTrusted, checkPermissionPassword, getPermission, setPassword, removePassword, checkPassword.

Redaction & flatten ​

applyRedactions, flattenPdf, flattenPdfDownload.

Layers & measurement ​

setLayers, exportLayers, setMeasurementDefaults.

Users & access control ​

setCurrentUser, getCurrentUser, isUserAdmin, isReadOnlyModeEnabled.

Property panel, events, printing, viewer element ​

setPropertyPanel, setInitProperty, eventBus, addEvent, removeEvent, triggerPrinting, getViewerElement, handleCreateStatus.

How apis/ consumes the bridge ​

apis/index.js does import core from '@/core' and spreads the entire bridge into objForWebViewerCore, published as window.instance.Core. It also exposes the default instance directly: window.instance.docViewer = core.getDocumentViewer().

Only 2 of ~67 apis/ files import core directly (index.js, registerTool.js); all others receive it via injection. The apis/ layer is the join point that composes bridge calls with store mutations (e.g. saveDocumentEditor.js calls core.saveDocumentEdit(), then orchestrates store actions and more bridge calls).

Notable exceptions ​

A few bridge files deviate from the clean one-liner pattern (useful to know when debugging):

  • registerTool.js (26 lines) — probes documentViewer.toolRegistry.register, falls back to documentViewer.registerTool, returns false if neither exists.
  • initializeViewer.js (15 lines) — destructures { container, viewer, thumbnailView, outlineView, toggleButton } before forwarding.
  • eventBus.js — returns getDocumentViewer().eventBus (not stateful, despite the name).
  • setDocumentName.js / getDocumentName.js — direct property access (getDocumentViewer().docName).

Previously-fixed issues: checkCertificateIsTrusted.js used to reference an undefined data (it now forwards its data argument, matching its sibling certificate functions); setActiveSearchResult.js had a reseult parameter typo (now result); and the search, setActiveSearchResult, clearSearchResults, and setAnnotationStyles bridge files used an inline getDocumentViewer(docNum = 1) reassignment idiom (now getDocumentViewer(docNum), relying on the getDocumentViewer(number = 1) default).

Architectural takeaways ​

  1. Facade over the engine — a flat, categorized, stable surface over a monolithic class.
  2. One stateful seam, by design — documentViewers.js is the file to inspect when debugging "which viewer am I talking to".
  3. Default-instance bias — instance 1 is the norm; multi-instance is opt-in per method.
  4. Clean layering — the bridge never touches stores or DOM; apis/ is the join point.