: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
#annotationEditorHighlightColors = null;
#annotationEditorMode = AnnotationEditorType.NONE;
#annotationEditorUIManager = null;
#annotationMode = AnnotationMode.ENABLE_FORMS;
#containerTopLeft = null;
#enableHighlightFloatingButton = false;
#enablePermissions = false;
#eventAbortController = null;
#getAllTextInProgress = false;
#hiddenCopyElement = null;
#interruptCopyCondition = false;
#previousContainerHeight = 0;
#resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this));
#scrollModePageState = null;
#textLayerMode = TextLayerMode.ENABLE;
const viewerVersion = "4.3.136";
if (version !== viewerVersion) {
throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`);
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
if (this.container?.tagName !== "DIV" || this.viewer?.tagName !== "DIV") {
throw new Error("Invalid `container` and/or `viewer` option.");
if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") {
throw new Error("The `container` must be absolutely positioned.");
this.#resizeObserver.observe(this.container);
this.eventBus = options.eventBus;
this.linkService = options.linkService || new SimpleLinkService();
this.downloadManager = options.downloadManager || null;
this.findController = options.findController || null;
this.#altTextManager = options.altTextManager || null;
if (this.findController) {
this.findController.onIsPageVisible = pageNumber => this._getVisiblePages().ids.has(pageNumber);
this._scriptingManager = options.scriptingManager || null;
this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE;
this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null;
this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true;
this.imageResourcesPath = options.imageResourcesPath || "";
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
this.removePageBorders = options.removePageBorders || false;
this.maxCanvasPixels = options.maxCanvasPixels;
this.l10n = options.l10n;
this.l10n ||= new genericl10n_GenericL10n();
this.#enablePermissions = options.enablePermissions || false;
this.pageColors = options.pageColors || null;
this.#mlManager = options.mlManager || null;
this.defaultRenderingQueue = !options.renderingQueue;
if (this.defaultRenderingQueue) {
this.renderingQueue = new PDFRenderingQueue();
this.renderingQueue.setViewer(this);
this.renderingQueue = options.renderingQueue;
this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this));
this.presentationModeState = PresentationModeState.UNKNOWN;
if (this.removePageBorders) {
this.viewer.classList.add("removePageBorders");
this.#updateContainerHeightCss();
this.eventBus._on("thumbnailrendered", ({
const pageView = this._pages[pageNumber - 1];
if (!this.#buffer.has(pageView)) {
this.l10n.translate(this.container);
return this._pages.length;
return this._pages[index];
return new Set(this.#buffer);
return this._pages.every(pageView => pageView?.pdfPage);
return this.#annotationMode === AnnotationMode.ENABLE_FORMS;
return !!this._scriptingManager;
get currentPageNumber() {
return this._currentPageNumber;
set currentPageNumber(val) {
if (!Number.isInteger(val)) {
throw new Error("Invalid page number.");
if (!this._setCurrentPageNumber(val, true)) {
console.error(`currentPageNumber: "${val}" is not a valid page.`);
_setCurrentPageNumber(val, resetCurrentPageView = false) {
if (this._currentPageNumber === val) {
if (resetCurrentPageView) {
this.#resetCurrentPageView();
if (!(0 < val && val <= this.pagesCount)) {
const previous = this._currentPageNumber;
this._currentPageNumber = val;
this.eventBus.dispatch("pagechanging", {
pageLabel: this._pageLabels?.[val - 1] ?? null,
if (resetCurrentPageView) {
this.#resetCurrentPageView();
return this._pageLabels?.[this._currentPageNumber - 1] ?? null;
set currentPageLabel(val) {
const i = this._pageLabels.indexOf(val);
if (!this._setCurrentPageNumber(page, true)) {
console.error(`currentPageLabel: "${val}" is not a valid page.`);
return this._currentScale !== UNKNOWN_SCALE ? this._currentScale : DEFAULT_SCALE;
throw new Error("Invalid numeric scale.");
get currentScaleValue() {
return this._currentScaleValue;
set currentScaleValue(val) {
return this._pagesRotation;
set pagesRotation(rotation) {
if (!isValidRotation(rotation)) {
throw new Error("Invalid pages rotation angle.");
if (this._pagesRotation === rotation) {
this._pagesRotation = rotation;
const pageNumber = this._currentPageNumber;
if (this._currentScaleValue) {
this.#setScale(this._currentScaleValue, {
this.eventBus.dispatch("rotationchanging", {
if (this.defaultRenderingQueue) {
return this.pdfDocument ? this._firstPageCapability.promise : null;
return this.pdfDocument ? this._onePageRenderedCapability.promise : null;
return this.pdfDocument ? this._pagesCapability.promise : null;
return shadow(this, "_layerProperties", {
get annotationEditorUIManager() {
return self.#annotationEditorUIManager;
get annotationStorage() {
return self.pdfDocument?.annotationStorage;
return self.downloadManager;
return !!self._scriptingManager;
get fieldObjectsPromise() {
return self.pdfDocument?.getFieldObjects();
return self.findController;
get hasJSActionsPromise() {
return self.pdfDocument?.hasJSActions();
#initializePermissions(permissions) {
annotationEditorMode: this.#annotationEditorMode,
annotationMode: this.#annotationMode,
textLayerMode: this.#textLayerMode
if (!permissions.includes(PermissionFlag.COPY) && this.#textLayerMode === TextLayerMode.ENABLE) {
params.textLayerMode = TextLayerMode.ENABLE_PERMISSIONS;
if (!permissions.includes(PermissionFlag.MODIFY_CONTENTS)) {
params.annotationEditorMode = AnnotationEditorType.DISABLE;
if (!permissions.includes(PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.includes(PermissionFlag.FILL_INTERACTIVE_FORMS) && this.#annotationMode === AnnotationMode.ENABLE_FORMS) {
params.annotationMode = AnnotationMode.ENABLE;
async #onePageRenderedOrForceFetch(signal) {
if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) {
const hiddenCapability = Promise.withResolvers();
function onVisibilityChange() {
if (document.visibilityState === "hidden") {
hiddenCapability.resolve();
document.addEventListener("visibilitychange", onVisibilityChange, {
await Promise.race([this._onePageRenderedCapability.promise, hiddenCapability.promise]);
document.removeEventListener("visibilitychange", onVisibilityChange);
for (let pageNum = 1, pagesCount = this.pdfDocument.numPages; pageNum <= pagesCount; ++pageNum) {
if (this.#interruptCopyCondition) {
const page = await this.pdfDocument.getPage(pageNum);
} = await page.getTextContent();
for (const item of items) {
texts.push(removeNullCharacters(buffer.join("")));
#copyCallback(textLayerMode, event) {
const selection = document.getSelection();
if (anchorNode && focusNode && selection.containsNode(this.#hiddenCopyElement)) {
if (this.#getAllTextInProgress || textLayerMode === TextLayerMode.ENABLE_PERMISSIONS) {
this.#getAllTextInProgress = true;
const savedCursor = this.container.style.cursor;
this.container.style.cursor = "wait";
const interruptCopy = ev => this.#interruptCopyCondition = ev.key === "Escape";
window.addEventListener("keydown", interruptCopy);
this.getAllText().then(async text => {
await navigator.clipboard.writeText(text);
console.warn(`Something goes wrong when extracting the text: ${reason.message}`);
this.#getAllTextInProgress = false;
this.#interruptCopyCondition = false;
window.removeEventListener("keydown", interruptCopy);
this.container.style.cursor = savedCursor;
setDocument(pdfDocument) {
this.eventBus.dispatch("pagesdestroy", {
this.findController?.setDocument(null);
this._scriptingManager?.setDocument(null);
if (this.#annotationEditorUIManager) {
this.#annotationEditorUIManager.destroy();
this.#annotationEditorUIManager = null;
this.pdfDocument = pdfDocument;
const pagesCount = pdfDocument.numPages;
const firstPagePromise = pdfDocument.getPage(1);
const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve();
this.#eventAbortController = new AbortController();
} = this.#eventAbortController;
if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document.");
const mode = this._scrollMode = ScrollMode.PAGE;
eventBus.dispatch("scrollmodechanged", {
this._pagesCapability.promise.then(() => {
eventBus.dispatch("pagesloaded", {
const onBeforeDraw = evt => {
const pageView = this._pages[evt.pageNumber - 1];
this.#buffer.push(pageView);
eventBus._on("pagerender", onBeforeDraw, {
const onAfterDraw = evt => {
this._onePageRenderedCapability.resolve({
eventBus._off("pagerendered", onAfterDraw);
eventBus._on("pagerendered", onAfterDraw, {
Promise.all([firstPagePromise, permissionsPromise]).then(([firstPdfPage, permissions]) => {
if (pdfDocument !== this.pdfDocument) {
this._firstPageCapability.resolve(firstPdfPage);
this._optionalContentConfigPromise = optionalContentConfigPromise;
} = this.#initializePermissions(permissions);
if (textLayerMode !== TextLayerMode.DISABLE) {
const element = this.#hiddenCopyElement = document.createElement("div");
element.id = "hiddenCopyElement";
if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
const mode = annotationEditorMode;
if (pdfDocument.isPureXfa) {
console.warn("Warning: XFA-editing is not implemented.");
} else if (isValidAnnotationEditorMode(mode)) {
this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, viewer, this.#altTextManager, eventBus, pdfDocument, pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#mlManager);
eventBus.dispatch("annotationeditoruimanager", {
uiManager: this.#annotationEditorUIManager
if (mode !== AnnotationEditorType.NONE) {
this.#annotationEditorUIManager.updateMode(mode);
console.error(`Invalid AnnotationEditor mode: ${mode}`);
const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : viewer;
const scale = this.currentScale;
const viewport = firstPdfPage.getViewport({
scale: scale * PixelsPerInch.PDF_TO_CSS_UNITS
viewer.style.setProperty("--scale-factor", viewport.scale);
if (pageColors?.foreground === "CanvasText" || pageColors?.background === "Canvas") {
viewer.style.setProperty("--hcm-highlight-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight"));
viewer.style.setProperty("--hcm-highlight-selected-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "ButtonText"));
for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
const pageView = new PDFPageView({
container: viewerElement,
defaultViewport: viewport.clone(),
optionalContentConfigPromise,
renderingQueue: this.renderingQueue,
imageResourcesPath: this.imageResourcesPath,
maxCanvasPixels: this.maxCanvasPixels,
layerProperties: this._layerProperties
this._pages.push(pageView);
this._pages[0]?.setPdfPage(firstPdfPage);
if (this._scrollMode === ScrollMode.PAGE) {
this.#ensurePageViewVisible();
} else if (this._spreadMode !== SpreadMode.NONE) {
this._updateSpreadMode();
this.#onePageRenderedOrForceFetch(signal).then(async () => {
if (pdfDocument !== this.pdfDocument) {
this.findController?.setDocument(pdfDocument);
this._scriptingManager?.setDocument(pdfDocument);
if (this.#hiddenCopyElement) {
document.addEventListener("copy", this.#copyCallback.bind(this, textLayerMode), {
if (this.#annotationEditorUIManager) {
eventBus.dispatch("annotationeditormodechanged", {
mode: this.#annotationEditorMode