: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
rotation: this.linkService.rotation
if (!this._popStateInProgress) {
this._popStateInProgress = true;
Promise.resolve().then(() => {
this._popStateInProgress = false;
if (!this._initialized) {
if (!this.#isValidPage(pageNumber)) {
console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`);
if (this._destination?.page === pageNumber) {
if (this._popStateInProgress) {
this.#pushOrReplaceState({
hash: `page=${pageNumber}`,
rotation: this.linkService.rotation
if (!this._popStateInProgress) {
this._popStateInProgress = true;
Promise.resolve().then(() => {
this._popStateInProgress = false;
if (!this._initialized || this._popStateInProgress) {
this.#tryPushCurrentPosition();
if (!this._initialized || this._popStateInProgress) {
const state = window.history.state;
if (this.#isValidState(state) && state.uid > 0) {
if (!this._initialized || this._popStateInProgress) {
const state = window.history.state;
if (this.#isValidState(state) && state.uid < this._maxUid) {
window.history.forward();
get popStateInProgress() {
return this._initialized && (this._popStateInProgress || this._blockHashChange > 0);
return this._initialized ? this._initialBookmark : null;
return this._initialized ? this._initialRotation : null;
#pushOrReplaceState(destination, forceReplace = false) {
const shouldReplace = forceReplace || !this._destination;
fingerprint: this._fingerprint,
uid: shouldReplace ? this._uid : this._uid + 1,
this.#updateInternalState(destination, newState.uid);
if (this._updateUrl && destination?.hash) {
const baseUrl = document.location.href.split("#", 1)[0];
if (!baseUrl.startsWith("file://")) {
newUrl = `${baseUrl}#${destination.hash}`;
window.history.replaceState(newState, "", newUrl);
window.history.pushState(newState, "", newUrl);
#tryPushCurrentPosition(temporary = false) {
let position = this._position;
position = Object.assign(Object.create(null), this._position);
position.temporary = true;
if (!this._destination) {
this.#pushOrReplaceState(position);
if (this._destination.temporary) {
this.#pushOrReplaceState(position, true);
if (this._destination.hash === position.hash) {
if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) {
let forceReplace = false;
if (this._destination.page >= position.first && this._destination.page <= position.page) {
if (this._destination.dest !== undefined || !this._destination.first) {
this.#pushOrReplaceState(position, forceReplace);
return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount;
#isValidState(state, checkReload = false) {
if (state.fingerprint !== this._fingerprint) {
if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) {
const [perfEntry] = performance.getEntriesByType("navigation");
if (perfEntry?.type !== "reload") {
if (!Number.isInteger(state.uid) || state.uid < 0) {
if (state.destination === null || typeof state.destination !== "object") {
#updateInternalState(destination, uid, removeTemporary = false) {
if (this._updateViewareaTimeout) {
clearTimeout(this._updateViewareaTimeout);
this._updateViewareaTimeout = null;
if (removeTemporary && destination?.temporary) {
delete destination.temporary;
this._destination = destination;
this._maxUid = Math.max(this._maxUid, uid);
this._numPositionUpdates = 0;
#parseCurrentHash(checkNameddest = false) {
const hash = unescape(getCurrentHash()).substring(1);
const params = parseQueryString(hash);
const nameddest = params.get("nameddest") || "";
let page = params.get("page") | 0;
if (!this.#isValidPage(page) || checkNameddest && nameddest.length > 0) {
rotation: this.linkService.rotation
if (this._updateViewareaTimeout) {
clearTimeout(this._updateViewareaTimeout);
this._updateViewareaTimeout = null;
hash: location.pdfOpenParams.substring(1),
page: this.linkService.page,
first: location.pageNumber,
rotation: location.rotation
if (this._popStateInProgress) {
if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) {
this._numPositionUpdates++;
if (UPDATE_VIEWAREA_TIMEOUT > 0) {
this._updateViewareaTimeout = setTimeout(() => {
if (!this._popStateInProgress) {
this.#tryPushCurrentPosition(true);
this._updateViewareaTimeout = null;
}, UPDATE_VIEWAREA_TIMEOUT);
const newHash = getCurrentHash(),
hashChanged = this._currentHash !== newHash;
this._currentHash = newHash;
} = this.#parseCurrentHash();
this.#pushOrReplaceState({
if (!this.#isValidState(state)) {
this._popStateInProgress = true;
delay: HASH_CHANGE_TIMEOUT
const destination = state.destination;
this.#updateInternalState(destination, state.uid, true);
if (isValidRotation(destination.rotation)) {
this.linkService.rotation = destination.rotation;
this.linkService.goToDestination(destination.dest);
} else if (destination.hash) {
this.linkService.setHash(destination.hash);
} else if (destination.page) {
this.linkService.page = destination.page;
Promise.resolve().then(() => {
this._popStateInProgress = false;
if (!this._destination || this._destination.temporary) {
this.#tryPushCurrentPosition();
if (this.#eventAbortController) {
this.#eventAbortController = new AbortController();
} = this.#eventAbortController;
this.eventBus._on("updateviewarea", this.#updateViewarea.bind(this), {
window.addEventListener("popstate", this.#popState.bind(this), {
window.addEventListener("pagehide", this.#pageHide.bind(this), {
this.#eventAbortController?.abort();
this.#eventAbortController = null;
function isDestHashesEqual(destHash, pushHash) {
if (typeof destHash !== "string" || typeof pushHash !== "string") {
if (destHash === pushHash) {
const nameddest = parseQueryString(destHash).get("nameddest");
if (nameddest === pushHash) {
function isDestArraysEqual(firstDest, secondDest) {
function isEntryEqual(first, second) {
if (typeof first !== typeof second) {
if (Array.isArray(first) || Array.isArray(second)) {
if (first !== null && typeof first === "object" && second !== null) {
if (Object.keys(first).length !== Object.keys(second).length) {
for (const key in first) {
if (!isEntryEqual(first[key], second[key])) {
return first === second || Number.isNaN(first) && Number.isNaN(second);
if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) {
if (firstDest.length !== secondDest.length) {
for (let i = 0, ii = firstDest.length; i < ii; i++) {
if (!isEntryEqual(firstDest[i], secondDest[i])) {
;// CONCATENATED MODULE: ./web/pdf_layer_viewer.js
class PDFLayerViewer extends BaseTreeViewer {
this.eventBus._on("optionalcontentconfigchanged", evt => {
this.#updateLayers(evt.promise);
this.eventBus._on("resetlayers", () => {
this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this));
this._optionalContentConfig = null;
this._optionalContentHash = null;
_dispatchEvent(layersCount) {
this.eventBus.dispatch("layersloaded", {
const setVisibility = () => {
this._optionalContentConfig.setVisibility(groupId, input.checked);
this._optionalContentHash = this._optionalContentConfig.getHash();
this.eventBus.dispatch("optionalcontentconfig", {
promise: Promise.resolve(this._optionalContentConfig)
element.onclick = evt => {
if (evt.target === input) {
} else if (evt.target !== element) {
input.checked = !input.checked;
async _setNestedName(element, {
if (typeof name === "string") {
element.textContent = this._normalizeTextContent(name);
element.textContent = await this._l10n.get("pdfjs-additional-layers");
element.style.fontStyle = "italic";
super._addToggleButton(div, name === null);
if (!this._optionalContentConfig) {
super._toggleAllTreeItems();
if (this._optionalContentConfig) {
this._optionalContentConfig = optionalContentConfig || null;
this._pdfDocument = pdfDocument || null;
const groups = optionalContentConfig?.getOrder();
this._optionalContentHash = optionalContentConfig.getHash();
const fragment = document.createDocumentFragment(),
while (queue.length > 0) {
const levelData = queue.shift();
for (const groupId of levelData.groups) {
const div = document.createElement("div");
div.className = "treeItem";
const element = document.createElement("a");
if (typeof groupId === "object") {
this._addToggleButton(div, groupId);
this._setNestedName(element, groupId);
const itemsDiv = document.createElement("div");
itemsDiv.className = "treeItems";
const group = optionalContentConfig.getGroup(groupId);
const input = document.createElement("input");
this._bindLink(element, {
input.checked = group.visible;
const label = document.createElement("label");
label.textContent = this._normalizeTextContent(group.name);
levelData.parent.append(div);
this._finishRendering(fragment, layersCount, hasAnyNesting);
async #updateLayers(promise = null) {
if (!this._optionalContentConfig) {
const pdfDocument = this._pdfDocument;
const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig({
if (pdfDocument !== this._pdfDocument) {
if (optionalContentConfig.getHash() === this._optionalContentHash) {
this.eventBus.dispatch("optionalcontentconfig", {
promise: Promise.resolve(optionalContentConfig)
pdfDocument: this._pdfDocument
;// CONCATENATED MODULE: ./web/pdf_outline_viewer.js
class PDFOutlineViewer extends BaseTreeViewer {
this.linkService = options.linkService;
this.downloadManager = options.downloadManager;