: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
selection.extend(caretPosition.offsetNode, caretPosition.offset);
selection.setPosition(caretPosition.offsetNode, caretPosition.offset);
#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX) {
if (this.#isVisible(newLineElementRect)) {
this.#setCaretPositionHelper(selection, caretX, select, newLineElement, newLineElementRect);
this.#mainContainer.addEventListener("scrollend", this.#setCaretPositionHelper.bind(this, selection, caretX, select, newLineElement, null), {
newLineElement.scrollIntoView();
#getNodeOnNextPage(textLayer, isUp) {
const page = textLayer.closest(".page");
const pageNumber = parseInt(page.getAttribute("data-page-number"));
const nextPage = isUp ? pageNumber - 1 : pageNumber + 1;
textLayer = this.#viewerContainer.querySelector(`.page[data-page-number="${nextPage}"] .textLayer`);
const walker = document.createTreeWalker(textLayer, NodeFilter.SHOW_TEXT);
const node = isUp ? walker.lastChild() : walker.firstChild();
moveCaret(isUp, select) {
const selection = document.getSelection();
if (selection.rangeCount === 0) {
const focusElement = focusNode.nodeType !== Node.ELEMENT_NODE ? focusNode.parentElement : focusNode;
const root = focusElement.closest(".textLayer");
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
walker.currentNode = focusNode;
const focusRect = focusElement.getBoundingClientRect();
let newLineElement = null;
const nodeIterator = (isUp ? walker.previousSibling : walker.nextSibling).bind(walker);
const element = walker.currentNode.parentElement;
if (!this.#isOnSameLine(focusRect, element.getBoundingClientRect())) {
newLineElement = element;
const node = this.#getNodeOnNextPage(root, isUp);
const lastNode = (isUp ? walker.firstChild() : walker.lastChild()) || focusNode;
selection.extend(lastNode, isUp ? 0 : lastNode.length);
const range = document.createRange();
range.setStart(node, isUp ? node.length : 0);
range.setEnd(node, isUp ? node.length : 0);
selection.addRange(range);
const [caretX] = this.#getCaretPosition(selection, isUp);
this.#setCaretPosition(select, selection, parentElement, parentElement.getBoundingClientRect(), caretX);
const [caretX, caretY] = this.#getCaretPosition(selection, isUp);
const newLineElementRect = newLineElement.getBoundingClientRect();
if (this.#isUnderOver(newLineElementRect, caretX, caretY, isUp)) {
this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
const element = walker.currentNode.parentElement;
const elementRect = element.getBoundingClientRect();
if (!this.#isOnSameLine(newLineElementRect, elementRect)) {
if (this.#isUnderOver(elementRect, caretX, caretY, isUp)) {
this.#setCaretPosition(select, selection, element, elementRect, caretX);
this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
;// CONCATENATED MODULE: ./web/download_manager.js
function download(blobUrl, filename) {
const a = document.createElement("a");
throw new Error('DownloadManager: "a.click()" is not supported.');
(document.body || document.documentElement).append(a);
#openBlobUrls = new WeakMap();
downloadUrl(url, filename, _options) {
if (!createValidAbsoluteUrl(url, "http://example.com")) {
console.error(`downloadUrl - not a valid URL: ${url}`);
download(url + "#pdfjs.action=download", filename);
downloadData(data, filename, contentType) {
const blobUrl = URL.createObjectURL(new Blob([data], {
download(blobUrl, filename);
openOrDownloadData(data, filename, dest = null) {
const isPdfData = isPdfFile(filename);
const contentType = isPdfData ? "application/pdf" : "";
let blobUrl = this.#openBlobUrls.get(data);
blobUrl = URL.createObjectURL(new Blob([data], {
this.#openBlobUrls.set(data, blobUrl);
viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename);
viewerUrl += `#${escape(dest)}`;
console.error(`openOrDownloadData: ${ex}`);
URL.revokeObjectURL(blobUrl);
this.#openBlobUrls.delete(data);
this.downloadData(data, filename, contentType);
download(blob, url, filename, _options) {
const blobUrl = URL.createObjectURL(blob);
download(blobUrl, filename);
;// CONCATENATED MODULE: ./web/overlay_manager.js
#overlays = new WeakMap();
async register(dialog, canForceClose = false) {
if (typeof dialog !== "object") {
throw new Error("Not enough parameters.");
} else if (this.#overlays.has(dialog)) {
throw new Error("The overlay is already registered.");
this.#overlays.set(dialog, {
dialog.addEventListener("cancel", evt => {
if (!this.#overlays.has(dialog)) {
throw new Error("The overlay does not exist.");
} else if (this.#active) {
if (this.#active === dialog) {
throw new Error("The overlay is already active.");
} else if (this.#overlays.get(dialog).canForceClose) {
throw new Error("Another overlay is currently active.");
async close(dialog = this.#active) {
if (!this.#overlays.has(dialog)) {
throw new Error("The overlay does not exist.");
} else if (!this.#active) {
throw new Error("The overlay is currently not active.");
} else if (this.#active !== dialog) {
throw new Error("Another overlay is currently active.");
;// CONCATENATED MODULE: ./web/password_prompt.js
#activeCapability = null;
constructor(options, overlayManager, isViewerEmbedded = false) {
this.dialog = options.dialog;
this.label = options.label;
this.input = options.input;
this.submitButton = options.submitButton;
this.cancelButton = options.cancelButton;
this.overlayManager = overlayManager;
this._isViewerEmbedded = isViewerEmbedded;
this.submitButton.addEventListener("click", this.#verify.bind(this));
this.cancelButton.addEventListener("click", this.close.bind(this));
this.input.addEventListener("keydown", e => {
this.overlayManager.register(this.dialog, true);
this.dialog.addEventListener("close", this.#cancel.bind(this));
await this.#activeCapability?.promise;
this.#activeCapability = Promise.withResolvers();
await this.overlayManager.open(this.dialog);
this.#activeCapability.resolve();
const passwordIncorrect = this.#reason === PasswordResponses.INCORRECT_PASSWORD;
if (!this._isViewerEmbedded || passwordIncorrect) {
this.label.setAttribute("data-l10n-id", `pdfjs-password-${passwordIncorrect ? "invalid" : "label"}`);
if (this.overlayManager.active === this.dialog) {
this.overlayManager.close(this.dialog);
const password = this.input.value;
if (password?.length > 0) {
this.#invokeCallback(password);
this.#invokeCallback(new Error("PasswordPrompt cancelled."));
this.#activeCapability.resolve();
#invokeCallback(password) {
if (!this.#updateCallback) {
this.#updateCallback(password);
this.#updateCallback = null;
async setUpdateCallback(updateCallback, reason) {
if (this.#activeCapability) {
await this.#activeCapability.promise;
this.#updateCallback = updateCallback;
;// CONCATENATED MODULE: ./web/base_tree_viewer.js
const TREEITEM_OFFSET_TOP = -100;
const TREEITEM_SELECTED_CLASS = "selected";
if (this.constructor === BaseTreeViewer) {
throw new Error("Cannot initialize BaseTreeViewer.");
this.container = options.container;
this.eventBus = options.eventBus;
this._l10n = options.l10n;
this._pdfDocument = null;
this._lastToggleIsShow = true;
this._currentTreeItem = null;
this.container.textContent = "";
this.container.classList.remove("treeWithDeepNesting");
throw new Error("Not implemented: _dispatchEvent");
_bindLink(element, params) {
throw new Error("Not implemented: _bindLink");
_normalizeTextContent(str) {
return removeNullCharacters(str, true) || "\u2013";
_addToggleButton(div, hidden = false) {
const toggler = document.createElement("div");
toggler.className = "treeItemToggler";
toggler.classList.add("treeItemsHidden");
toggler.onclick = evt => {
toggler.classList.toggle("treeItemsHidden");
const shouldShowAll = !toggler.classList.contains("treeItemsHidden");
this._toggleTreeItem(div, shouldShowAll);
_toggleTreeItem(root, show = false) {
this._lastToggleIsShow = show;
for (const toggler of root.querySelectorAll(".treeItemToggler")) {
toggler.classList.toggle("treeItemsHidden", !show);
this._toggleTreeItem(this.container, !this._lastToggleIsShow);
_finishRendering(fragment, count, hasAnyNesting = false) {
this.container.classList.add("treeWithDeepNesting");
this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden");
this.container.append(fragment);
this._dispatchEvent(count);
throw new Error("Not implemented: render");
_updateCurrentTreeItem(treeItem = null) {
if (this._currentTreeItem) {
this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS);
this._currentTreeItem = null;
treeItem.classList.add(TREEITEM_SELECTED_CLASS);
this._currentTreeItem = treeItem;
_scrollToCurrentTreeItem(treeItem) {
let currentNode = treeItem.parentNode;
while (currentNode && currentNode !== this.container) {
if (currentNode.classList.contains("treeItem")) {
const toggler = currentNode.firstElementChild;
toggler?.classList.remove("treeItemsHidden");
currentNode = currentNode.parentNode;
this._updateCurrentTreeItem(treeItem);
this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP);
;// CONCATENATED MODULE: ./web/pdf_attachment_viewer.js
class PDFAttachmentViewer extends BaseTreeViewer {
this.downloadManager = options.downloadManager;
this.eventBus._on("fileattachmentannotation", this.#appendAttachment.bind(this));
reset(keepRenderedCapability = false) {
this._attachments = null;
if (!keepRenderedCapability) {
this._renderedCapability = Promise.withResolvers();
this._pendingDispatchEvent = false;
async _dispatchEvent(attachmentsCount) {
this._renderedCapability.resolve();
if (attachmentsCount === 0 && !this._pendingDispatchEvent) {
this._pendingDispatchEvent = true;
await waitOnEventOrTimeout({
name: "annotationlayerrendered",
if (!this._pendingDispatchEvent) {
this._pendingDispatchEvent = false;
this.eventBus.dispatch("attachmentsloaded", {
element.title = description;
element.onclick = () => {
this.downloadManager.openOrDownloadData(content, filename);
keepRenderedCapability = false
this.reset(keepRenderedCapability);
this._attachments = attachments || null;
const fragment = document.createDocumentFragment();
let attachmentsCount = 0;
for (const name in attachments) {
const item = attachments[name];
const div = document.createElement("div");
div.className = "treeItem";
const element = document.createElement("a");
this._bindLink(element, item);
element.textContent = this._normalizeTextContent(item.filename);
this._finishRendering(fragment, attachmentsCount);
#appendAttachment(item) {
const renderedPromise = this._renderedCapability.promise;
renderedPromise.then(() => {
if (renderedPromise !== this._renderedCapability.promise) {
const attachments = this._attachments || Object.create(null);
for (const name in attachments) {
if (item.filename === name) {
attachments[item.filename] = item;
keepRenderedCapability: true
;// CONCATENATED MODULE: ./web/grab_to_pan.js
const CSS_CLASS_GRAB = "grab-to-pan-grab";
this.document = element.ownerDocument;
this.activate = this.activate.bind(this);
this.deactivate = this.deactivate.bind(this);
this.toggle = this.toggle.bind(this);
this._onMouseDown = this.#onMouseDown.bind(this);