/** * @licstart The following is the entire license notice for the * JavaScript code in this page * * Copyright 2022 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * JavaScript code in this page */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PDFOutlineViewer = void 0; var _base_tree_viewer = require("./base_tree_viewer.js"); var _pdf = require("../pdf"); var _ui_utils = require("./ui_utils.js"); class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { super(options); this.linkService = options.linkService; 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; if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { this._currentOutlineItemCapability.resolve(this._isPagesLoaded); } }); this.eventBus._on("sidebarviewchanged", evt => { this._sidebarView = evt.view; }); } reset() { super.reset(); this._outline = null; this._pageNumberToDestHashCapability = null; this._currentPageNumber = 1; this._isPagesLoaded = null; if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { this._currentOutlineItemCapability.resolve(false); } this._currentOutlineItemCapability = null; } _dispatchEvent(outlineCount) { this._currentOutlineItemCapability = (0, _pdf.createPromiseCapability)(); 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", { source: this, outlineCount, currentOutlineItemPromise: this._currentOutlineItemCapability.promise }); } _bindLink(element, { url, newWindow, dest }) { const { linkService } = this; if (url) { linkService.addLinkAttributes(element, url, newWindow); return; } element.href = linkService.getDestinationHash(dest); element.onclick = evt => { this._updateCurrentTreeItem(evt.target.parentNode); if (dest) { linkService.goToDestination(dest); } return false; }; } _setStyles(element, { bold, italic }) { if (bold) { element.style.fontWeight = "bold"; } if (italic) { element.style.fontStyle = "italic"; } } _addToggleButton(div, { count, items }) { let hidden = false; if (count < 0) { let totalCount = items.length; if (totalCount > 0) { const queue = [...items]; while (queue.length > 0) { const { count: nestedCount, items: nestedItems } = queue.shift(); if (nestedCount > 0 && nestedItems.length > 0) { totalCount += nestedItems.length; queue.push(...nestedItems); } } } if (Math.abs(count) === totalCount) { hidden = true; } } super._addToggleButton(div, hidden); } _toggleAllTreeItems() { if (!this._outline) { return; } super._toggleAllTreeItems(); } render({ outline, pdfDocument }) { if (this._outline) { this.reset(); } this._outline = outline || null; this._pdfDocument = pdfDocument || null; if (!outline) { this._dispatchEvent(0); return; } const fragment = document.createDocumentFragment(); const queue = [{ parent: fragment, items: outline }]; let outlineCount = 0, hasAnyNesting = false; 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); div.append(element); if (item.items.length > 0) { hasAnyNesting = true; this._addToggleButton(div, item); const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; div.append(itemsDiv); queue.push({ parent: itemsDiv, items: item.items }); } levelData.parent.append(div); outlineCount++; } } 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) { return; } const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument); if (!pageNumberToDestHash) { return; } this._updateCurrentTreeItem(null); if (this._sidebarView !== _ui_utils.SidebarView.OUTLINE) { return; } for (let i = this._currentPageNumber; i > 0; i--) { const destHash = pageNumberToDestHash.get(i); if (!destHash) { continue; } const linkElement = this.container.querySelector(`a[href="${destHash}"]`); if (!linkElement) { continue; } this._scrollToCurrentTreeItem(linkElement.parentNode); break; } } async _getPageNumberToDestHash(pdfDocument) { if (this._pageNumberToDestHashCapability) { return this._pageNumberToDestHashCapability.promise; } this._pageNumberToDestHashCapability = (0, _pdf.createPromiseCapability)(); const pageNumberToDestHash = new Map(), pageNumberNesting = new Map(); const queue = [{ nesting: 0, items: this._outline }]; while (queue.length > 0) { const levelData = queue.shift(), currentNesting = levelData.nesting; for (const { dest, items } of levelData.items) { let explicitDest, pageNumber; if (typeof dest === "string") { explicitDest = await pdfDocument.getDestination(dest); if (pdfDocument !== this._pdfDocument) { return null; } } else { explicitDest = dest; } if (Array.isArray(explicitDest)) { const [destRef] = explicitDest; if (typeof destRef === "object" && destRef !== null) { pageNumber = this.linkService._cachedPageNumber(destRef); if (!pageNumber) { try { pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1; if (pdfDocument !== this._pdfDocument) { return null; } this.linkService.cachePageRef(pageNumber, destRef); } catch (ex) {} } } 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); } } if (items.length > 0) { queue.push({ nesting: currentNesting + 1, items }); } } } this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null); return this._pageNumberToDestHashCapability.promise; } } exports.PDFOutlineViewer = PDFOutlineViewer;