: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
this.eventBus._on("toggleoutlinetree", this._toggleAllTreeItems.bind(this));
this.eventBus._on("currentoutlineitem", this._currentOutlineItem.bind(this));
this.eventBus._on("pagechanging", evt => {
this._currentPageNumber = evt.pageNumber;
this.eventBus._on("pagesloaded", evt => {
this._isPagesLoaded = !!evt.pagesCount;
this._currentOutlineItemCapability?.resolve(this._isPagesLoaded);
this.eventBus._on("sidebarviewchanged", evt => {
this._sidebarView = evt.view;
this._pageNumberToDestHashCapability = null;
this._currentPageNumber = 1;
this._isPagesLoaded = null;
this._currentOutlineItemCapability?.resolve(false);
this._currentOutlineItemCapability = null;
_dispatchEvent(outlineCount) {
this._currentOutlineItemCapability = Promise.withResolvers();
if (outlineCount === 0 || this._pdfDocument?.loadingParams.disableAutoFetch) {
this._currentOutlineItemCapability.resolve(false);
} else if (this._isPagesLoaded !== null) {
this._currentOutlineItemCapability.resolve(this._isPagesLoaded);
this.eventBus.dispatch("outlineloaded", {
currentOutlineItemPromise: this._currentOutlineItemCapability.promise
linkService.addLinkAttributes(element, url, newWindow);
element.href = linkService.getAnchorUrl("");
element.onclick = () => {
linkService.executeNamedAction(action);
element.href = linkService.getAnchorUrl("");
element.onclick = () => {
this.downloadManager.openOrDownloadData(attachment.content, attachment.filename);
element.href = linkService.getAnchorUrl("");
element.onclick = () => {
linkService.executeSetOCGState(setOCGState);
element.href = linkService.getDestinationHash(dest);
element.onclick = evt => {
this._updateCurrentTreeItem(evt.target.parentNode);
linkService.goToDestination(dest);
element.style.fontWeight = "bold";
element.style.fontStyle = "italic";
let totalCount = items.length;
const queue = [...items];
while (queue.length > 0) {
if (nestedCount > 0 && nestedItems.length > 0) {
totalCount += nestedItems.length;
queue.push(...nestedItems);
if (Math.abs(count) === totalCount) {
super._addToggleButton(div, hidden);
super._toggleAllTreeItems();
this._outline = outline || null;
this._pdfDocument = pdfDocument || null;
const fragment = document.createDocumentFragment();
while (queue.length > 0) {
const levelData = queue.shift();
for (const item of levelData.items) {
const div = document.createElement("div");
div.className = "treeItem";
const element = document.createElement("a");
this._bindLink(element, item);
this._setStyles(element, item);
element.textContent = this._normalizeTextContent(item.title);
if (item.items.length > 0) {
this._addToggleButton(div, item);
const itemsDiv = document.createElement("div");
itemsDiv.className = "treeItems";
levelData.parent.append(div);
this._finishRendering(fragment, outlineCount, hasAnyNesting);
async _currentOutlineItem() {
if (!this._isPagesLoaded) {
throw new Error("_currentOutlineItem: All pages have not been loaded.");
if (!this._outline || !this._pdfDocument) {
const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument);
if (!pageNumberToDestHash) {
this._updateCurrentTreeItem(null);
if (this._sidebarView !== SidebarView.OUTLINE) {
for (let i = this._currentPageNumber; i > 0; i--) {
const destHash = pageNumberToDestHash.get(i);
const linkElement = this.container.querySelector(`a[href="${destHash}"]`);
this._scrollToCurrentTreeItem(linkElement.parentNode);
async _getPageNumberToDestHash(pdfDocument) {
if (this._pageNumberToDestHashCapability) {
return this._pageNumberToDestHashCapability.promise;
this._pageNumberToDestHashCapability = Promise.withResolvers();
const pageNumberToDestHash = new Map(),
pageNumberNesting = new Map();
while (queue.length > 0) {
const levelData = queue.shift(),
currentNesting = levelData.nesting;
let explicitDest, pageNumber;
if (typeof dest === "string") {
explicitDest = await pdfDocument.getDestination(dest);
if (pdfDocument !== this._pdfDocument) {
if (Array.isArray(explicitDest)) {
const [destRef] = explicitDest;
if (destRef && typeof destRef === "object") {
pageNumber = pdfDocument.cachedPageNumber(destRef);
} else if (Number.isInteger(destRef)) {
pageNumber = destRef + 1;
if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) {
const destHash = this.linkService.getDestinationHash(dest);
pageNumberToDestHash.set(pageNumber, destHash);
pageNumberNesting.set(pageNumber, currentNesting);
nesting: currentNesting + 1,
this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null);
return this._pageNumberToDestHashCapability.promise;
;// CONCATENATED MODULE: ./web/pdf_presentation_mode.js
const DELAY_BEFORE_HIDING_CONTROLS = 3000;
const ACTIVE_SELECTOR = "pdfPresentationMode";
const CONTROLS_SELECTOR = "pdfPresentationModeControls";
const MOUSE_SCROLL_COOLDOWN_TIME = 50;
const PAGE_SWITCH_THRESHOLD = 0.1;
const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
class PDFPresentationMode {
#state = PresentationModeState.UNKNOWN;
#fullscreenChangeAbortController = null;
#windowAbortController = null;
this.container = container;
this.pdfViewer = pdfViewer;
this.eventBus = eventBus;
this.contextMenuOpen = false;
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
this.touchSwipeState = null;
if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) {
this.#addFullscreenChangeListeners();
this.#notifyStateChange(PresentationModeState.CHANGING);
const promise = container.requestFullscreen();
pageNumber: pdfViewer.currentPageNumber,
scaleValue: pdfViewer.currentScaleValue,
scrollMode: pdfViewer.scrollMode,
annotationEditorMode: null
if (pdfViewer.spreadMode !== SpreadMode.NONE && !(pdfViewer.pageViewsReady && pdfViewer.hasEqualPageSizes)) {
console.warn("Ignoring Spread modes when entering PresentationMode, " + "since the document may contain varying page sizes.");
this.#args.spreadMode = pdfViewer.spreadMode;
if (pdfViewer.annotationEditorMode !== AnnotationEditorType.DISABLE) {
this.#args.annotationEditorMode = pdfViewer.annotationEditorMode;
this.#removeFullscreenChangeListeners();
this.#notifyStateChange(PresentationModeState.NORMAL);
return this.#state === PresentationModeState.CHANGING || this.#state === PresentationModeState.FULLSCREEN;
const delta = normalizeWheelEventDelta(evt);
const currentTime = Date.now();
const storedTime = this.mouseScrollTimeStamp;
if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
this.#resetMouseScrollState();
this.mouseScrollDelta += delta;
if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
const totalDelta = this.mouseScrollDelta;
this.#resetMouseScrollState();
const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage();
this.mouseScrollTimeStamp = currentTime;
#notifyStateChange(state) {
this.eventBus.dispatch("presentationmodechanged", {
this.#notifyStateChange(PresentationModeState.FULLSCREEN);
this.container.classList.add(ACTIVE_SELECTOR);
this.pdfViewer.scrollMode = ScrollMode.PAGE;
if (this.#args.spreadMode !== null) {
this.pdfViewer.spreadMode = SpreadMode.NONE;
this.pdfViewer.currentPageNumber = this.#args.pageNumber;
this.pdfViewer.currentScaleValue = "page-fit";
if (this.#args.annotationEditorMode !== null) {
this.pdfViewer.annotationEditorMode = {
mode: AnnotationEditorType.NONE
this.#addWindowListeners();
this.contextMenuOpen = false;
document.getSelection().empty();
const pageNumber = this.pdfViewer.currentPageNumber;
this.container.classList.remove(ACTIVE_SELECTOR);
this.#removeFullscreenChangeListeners();
this.#notifyStateChange(PresentationModeState.NORMAL);
this.pdfViewer.scrollMode = this.#args.scrollMode;
if (this.#args.spreadMode !== null) {
this.pdfViewer.spreadMode = this.#args.spreadMode;
this.pdfViewer.currentScaleValue = this.#args.scaleValue;
this.pdfViewer.currentPageNumber = pageNumber;
if (this.#args.annotationEditorMode !== null) {
this.pdfViewer.annotationEditorMode = {
mode: this.#args.annotationEditorMode
this.#removeWindowListeners();
this.#resetMouseScrollState();
this.contextMenuOpen = false;
if (this.contextMenuOpen) {
this.contextMenuOpen = false;
if (evt.target.href && evt.target.parentNode?.hasAttribute("data-internal-link")) {
this.pdfViewer.previousPage();
this.pdfViewer.nextPage();
this.contextMenuOpen = true;
if (this.controlsTimeout) {
clearTimeout(this.controlsTimeout);
this.container.classList.add(CONTROLS_SELECTOR);
this.controlsTimeout = setTimeout(() => {
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
}, DELAY_BEFORE_HIDING_CONTROLS);
if (!this.controlsTimeout) {
clearTimeout(this.controlsTimeout);
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
#resetMouseScrollState() {
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
if (evt.touches.length > 1) {
this.touchSwipeState = null;
startX: evt.touches[0].pageX,
startY: evt.touches[0].pageY,
endX: evt.touches[0].pageX,
endY: evt.touches[0].pageY
if (this.touchSwipeState === null) {
this.touchSwipeState.endX = evt.touches[0].pageX;
this.touchSwipeState.endY = evt.touches[0].pageY;
if (this.touchSwipeState === null) {
const dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
const dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
const absAngle = Math.abs(Math.atan2(dy, dx));
if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
} else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
this.pdfViewer.previousPage();
this.pdfViewer.nextPage();
if (this.#windowAbortController) {
this.#windowAbortController = new AbortController();
} = this.#windowAbortController;
const touchSwipeBind = this.#touchSwipe.bind(this);
window.addEventListener("mousemove", this.#showControls.bind(this), {
window.addEventListener("mousedown", this.#mouseDown.bind(this), {