: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
} = await pdfDocument.getDownloadInfo();
filename: contentDispositionFilename || getPdfFilenameFromUrl(url),
metadata: metadata?.getRaw(),
authors: metadata?.get("dc:creator"),
numPages: pdfDocument.numPages,
constructor(sandboxBundleSrc) {
this._ready = new Promise((resolve, reject) => {
const sandbox = import( /*webpackIgnore: true*/sandboxBundleSrc);
sandbox.then(pdfjsSandbox => {
resolve(pdfjsSandbox.QuickJSSandbox());
async createSandbox(data) {
const sandbox = await this._ready;
async dispatchEventInSandbox(event) {
const sandbox = await this._ready;
setTimeout(() => sandbox.dispatchEvent(event), 0);
const sandbox = await this._ready;
;// CONCATENATED MODULE: ./web/genericcom.js
class Preferences extends BasePreferences {
async _writeToStorage(prefObj) {
localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj));
async _readFromStorage(prefObj) {
prefs: JSON.parse(localStorage.getItem("pdfjs.preferences"))
class ExternalServices extends BaseExternalServices {
return new genericl10n_GenericL10n(AppOptions.get("locale"));
return new GenericScripting(AppOptions.get("sandboxBundleSrc"));
;// CONCATENATED MODULE: ./web/alt_text_manager.js
#boundUpdateUIState = this.#updateUIState.bind(this);
#boundSetPosition = this.#setPosition.bind(this);
#boundOnClick = this.#onClick.bind(this);
}, container, overlayManager, eventBus) {
this.#optionDescription = optionDescription;
this.#optionDecorative = optionDecorative;
this.#textarea = textarea;
this.#cancelButton = cancelButton;
this.#saveButton = saveButton;
this.#overlayManager = overlayManager;
this.#eventBus = eventBus;
this.#container = container;
dialog.addEventListener("close", this.#close.bind(this));
dialog.addEventListener("contextmenu", event => {
if (event.target !== this.#textarea) {
cancelButton.addEventListener("click", this.#finish.bind(this));
saveButton.addEventListener("click", this.#save.bind(this));
optionDescription.addEventListener("change", this.#boundUpdateUIState);
optionDecorative.addEventListener("change", this.#boundUpdateUIState);
this.#overlayManager.register(dialog);
return shadow(this, "_elements", [this.#optionDescription, this.#optionDecorative, this.#textarea, this.#saveButton, this.#cancelButton]);
const svgFactory = new DOMSVGFactory();
const svg = this.#svgElement = svgFactory.createElement("svg");
svg.setAttribute("width", "0");
svg.setAttribute("height", "0");
const defs = svgFactory.createElement("defs");
const mask = svgFactory.createElement("mask");
mask.setAttribute("id", "alttext-manager-mask");
mask.setAttribute("maskContentUnits", "objectBoundingBox");
let rect = svgFactory.createElement("rect");
rect.setAttribute("fill", "white");
rect.setAttribute("width", "1");
rect.setAttribute("height", "1");
rect.setAttribute("x", "0");
rect.setAttribute("y", "0");
rect = this.#rectElement = svgFactory.createElement("rect");
rect.setAttribute("fill", "black");
this.#dialog.append(svg);
async editAltText(uiManager, editor) {
if (this.#currentEditor || !editor) {
this.#createSVGElement();
this.#hasUsedPointer = false;
for (const element of this._elements) {
element.addEventListener("click", this.#boundOnClick);
if (decorative === true) {
this.#optionDecorative.checked = true;
this.#optionDescription.checked = false;
this.#optionDecorative.checked = false;
this.#optionDescription.checked = true;
this.#previousAltText = this.#textarea.value = altText?.trim() || "";
this.#currentEditor = editor;
this.#uiManager = uiManager;
this.#uiManager.removeEditListeners();
this.#eventBus._on("resize", this.#boundSetPosition);
await this.#overlayManager.open(this.#dialog);
if (!this.#currentEditor) {
const dialog = this.#dialog;
} = this.#container.getBoundingClientRect();
} = dialog.getBoundingClientRect();
} = this.#currentEditor.getClientDimensions();
const isLTR = this.#uiManager.direction === "ltr";
const xs = Math.max(x, containerX);
const xe = Math.min(x + width, containerX + containerW);
const ys = Math.max(y, containerY);
const ye = Math.min(y + height, containerY + containerH);
this.#rectElement.setAttribute("width", `${(xe - xs) / windowW}`);
this.#rectElement.setAttribute("height", `${(ye - ys) / windowH}`);
this.#rectElement.setAttribute("x", `${xs / windowW}`);
this.#rectElement.setAttribute("y", `${ys / windowH}`);
let top = Math.max(y, 0);
top += Math.min(windowH - (top + dialogH), 0);
if (x + width + MARGIN + dialogW < windowW) {
left = x + width + MARGIN;
} else if (x > dialogW + MARGIN) {
left = x - dialogW - MARGIN;
} else if (x > dialogW + MARGIN) {
left = x - dialogW - MARGIN;
} else if (x + width + MARGIN + dialogW < windowW) {
left = x + width + MARGIN;
left += Math.min(windowW - (left + dialogW), 0);
if (y > dialogH + MARGIN) {
top = y - dialogH - MARGIN;
} else if (y + height + MARGIN + dialogH < windowH) {
top = y + height + MARGIN;
dialog.classList.add("positioned");
style.left = `${left}px`;
style.right = `${windowW - left - dialogW}px`;
dialog.classList.remove("positioned");
if (this.#overlayManager.active === this.#dialog) {
this.#overlayManager.close(this.#dialog);
this.#currentEditor._reportTelemetry(this.#telemetryData || {
action: "alt_text_cancel",
alt_text_keyboard: !this.#hasUsedPointer
this.#telemetryData = null;
this.#removeOnClickListeners();
this.#uiManager?.addEditListeners();
this.#eventBus._off("resize", this.#boundSetPosition);
this.#currentEditor.altTextFinish();
this.#currentEditor = null;
this.#textarea.disabled = this.#optionDecorative.checked;
const altText = this.#textarea.value.trim();
const decorative = this.#optionDecorative.checked;
this.#currentEditor.altTextData = {
alt_text_description: !!altText,
alt_text_edit: !!this.#previousAltText && this.#previousAltText !== altText,
alt_text_decorative: decorative,
alt_text_keyboard: !this.#hasUsedPointer
this.#hasUsedPointer = true;
this.#removeOnClickListeners();
#removeOnClickListeners() {
for (const element of this._elements) {
element.removeEventListener("click", this.#boundOnClick);
this.#svgElement?.remove();
this.#svgElement = this.#rectElement = null;
;// CONCATENATED MODULE: ./web/annotation_editor_params.js
class AnnotationEditorParams {
constructor(options, eventBus) {
this.eventBus = eventBus;
this.#bindListeners(options);
editorFreeHighlightThickness,
const dispatchEvent = (typeStr, value) => {
this.eventBus.dispatch("switchannotationeditorparams", {
type: AnnotationEditorParamsType[typeStr],
editorFreeTextFontSize.addEventListener("input", function () {
dispatchEvent("FREETEXT_SIZE", this.valueAsNumber);
editorFreeTextColor.addEventListener("input", function () {
dispatchEvent("FREETEXT_COLOR", this.value);
editorInkColor.addEventListener("input", function () {
dispatchEvent("INK_COLOR", this.value);
editorInkThickness.addEventListener("input", function () {
dispatchEvent("INK_THICKNESS", this.valueAsNumber);
editorInkOpacity.addEventListener("input", function () {
dispatchEvent("INK_OPACITY", this.valueAsNumber);
editorStampAddImage.addEventListener("click", () => {
editorFreeHighlightThickness.addEventListener("input", function () {
dispatchEvent("HIGHLIGHT_THICKNESS", this.valueAsNumber);
editorHighlightShowAll.addEventListener("click", function () {
const checked = this.getAttribute("aria-pressed") === "true";
this.setAttribute("aria-pressed", !checked);
dispatchEvent("HIGHLIGHT_SHOW_ALL", !checked);
this.eventBus._on("annotationeditorparamschanged", evt => {
for (const [type, value] of evt.details) {
case AnnotationEditorParamsType.FREETEXT_SIZE:
editorFreeTextFontSize.value = value;
case AnnotationEditorParamsType.FREETEXT_COLOR:
editorFreeTextColor.value = value;
case AnnotationEditorParamsType.INK_COLOR:
editorInkColor.value = value;
case AnnotationEditorParamsType.INK_THICKNESS:
editorInkThickness.value = value;
case AnnotationEditorParamsType.INK_OPACITY:
editorInkOpacity.value = value;
case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
editorFreeHighlightThickness.value = value;
case AnnotationEditorParamsType.HIGHLIGHT_FREE:
editorFreeHighlightThickness.disabled = !value;
case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
editorHighlightShowAll.setAttribute("aria-pressed", value);
;// CONCATENATED MODULE: ./web/caret_browsing.js
class CaretBrowsingMode {
constructor(mainContainer, viewerContainer, toolbarContainer) {
this.#mainContainer = mainContainer;
this.#viewerContainer = viewerContainer;
this.#toolBarHeight = toolbarContainer?.getBoundingClientRect().height ?? 0;
#isOnSameLine(rect1, rect2) {
const bot1 = rect1.bottom;
const mid1 = rect1.y + rect1.height / 2;
const bot2 = rect2.bottom;
const mid2 = rect2.y + rect2.height / 2;
return top1 <= mid2 && mid2 <= bot1 || top2 <= mid1 && mid1 <= bot2;
#isUnderOver(rect, x, y, isUp) {
const midY = rect.y + rect.height / 2;
return (isUp ? y >= midY : y <= midY) && rect.x - PRECISION <= x && x <= rect.right + PRECISION;
return rect.top >= this.#toolBarHeight && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
#getCaretPosition(selection, isUp) {
const range = document.createRange();
range.setStart(focusNode, focusOffset);
range.setEnd(focusNode, focusOffset);
const rect = range.getBoundingClientRect();
return [rect.x, isUp ? rect.top : rect.bottom];
static #caretPositionFromPoint(x, y) {
if (!document.caretPositionFromPoint) {
startContainer: offsetNode,
} = document.caretRangeFromPoint(x, y);
return document.caretPositionFromPoint(x, y);
#setCaretPositionHelper(selection, caretX, select, element, rect) {
rect ||= element.getBoundingClientRect();
if (caretX <= rect.x + PRECISION) {
selection.extend(element.firstChild, 0);
selection.setPosition(element.firstChild, 0);
if (rect.right - PRECISION <= caretX) {
selection.extend(lastChild, lastChild.length);
selection.setPosition(lastChild, lastChild.length);
const midY = rect.y + rect.height / 2;
let caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
let parentElement = caretPosition.offsetNode?.parentElement;
if (parentElement && parentElement !== element) {
const elementsAtPoint = document.elementsFromPoint(caretX, midY);
const savedVisibilities = [];
for (const el of elementsAtPoint) {
savedVisibilities.push([el, style.visibility]);
style.visibility = "hidden";
caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
parentElement = caretPosition.offsetNode?.parentElement;
for (const [el, visibility] of savedVisibilities) {
el.style.visibility = visibility;
if (parentElement !== element) {
selection.extend(element.firstChild, 0);
selection.setPosition(element.firstChild, 0);