/** * @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.SimpleLinkService = exports.PDFLinkService = exports.LinkTarget = void 0; var _ui_utils = require("./ui_utils.js"); const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; const LinkTarget = { NONE: 0, SELF: 1, BLANK: 2, PARENT: 3, TOP: 4 }; exports.LinkTarget = LinkTarget; function addLinkAttributes(link, { url, target, rel, enabled = true } = {}) { if (!url || typeof url !== "string") { throw new Error('A valid "url" parameter must provided.'); } const urlNullRemoved = (0, _ui_utils.removeNullCharacters)(url); if (enabled) { link.href = link.title = urlNullRemoved; } else { link.href = ""; link.title = `Disabled: ${urlNullRemoved}`; link.onclick = () => { return false; }; } let targetStr = ""; switch (target) { case LinkTarget.NONE: break; case LinkTarget.SELF: targetStr = "_self"; break; case LinkTarget.BLANK: targetStr = "_blank"; break; case LinkTarget.PARENT: targetStr = "_parent"; break; case LinkTarget.TOP: targetStr = "_top"; break; } link.target = targetStr; link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL; } class PDFLinkService { #pagesRefCache = new Map(); constructor({ eventBus, externalLinkTarget = null, externalLinkRel = null, ignoreDestinationZoom = false } = {}) { this.eventBus = eventBus; this.externalLinkTarget = externalLinkTarget; this.externalLinkRel = externalLinkRel; this.externalLinkEnabled = true; this._ignoreDestinationZoom = ignoreDestinationZoom; this.baseUrl = null; this.pdfDocument = null; this.pdfViewer = null; this.pdfHistory = null; } setDocument(pdfDocument, baseUrl = null) { this.baseUrl = baseUrl; this.pdfDocument = pdfDocument; this.#pagesRefCache.clear(); } setViewer(pdfViewer) { this.pdfViewer = pdfViewer; } setHistory(pdfHistory) { this.pdfHistory = pdfHistory; } get pagesCount() { return this.pdfDocument ? this.pdfDocument.numPages : 0; } get page() { return this.pdfViewer.currentPageNumber; } set page(value) { this.pdfViewer.currentPageNumber = value; } get rotation() { return this.pdfViewer.pagesRotation; } set rotation(value) { this.pdfViewer.pagesRotation = value; } #goToDestinationHelper(rawDest, namedDest = null, explicitDest) { const destRef = explicitDest[0]; let pageNumber; if (typeof destRef === "object" && destRef !== null) { pageNumber = this._cachedPageNumber(destRef); if (!pageNumber) { this.pdfDocument.getPageIndex(destRef).then(pageIndex => { this.cachePageRef(pageIndex + 1, destRef); this.#goToDestinationHelper(rawDest, namedDest, explicitDest); }).catch(() => { console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid page reference, for dest="${rawDest}".`); }); return; } } else if (Number.isInteger(destRef)) { pageNumber = destRef + 1; } else { console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid destination reference, for dest="${rawDest}".`); return; } if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { console.error(`PDFLinkService.#goToDestinationHelper: "${pageNumber}" is not ` + `a valid page number, for dest="${rawDest}".`); return; } if (this.pdfHistory) { this.pdfHistory.pushCurrentPosition(); this.pdfHistory.push({ namedDest, explicitDest, pageNumber }); } this.pdfViewer.scrollPageIntoView({ pageNumber, destArray: explicitDest, ignoreDestinationZoom: this._ignoreDestinationZoom }); } async goToDestination(dest) { if (!this.pdfDocument) { return; } let namedDest, explicitDest; if (typeof dest === "string") { namedDest = dest; explicitDest = await this.pdfDocument.getDestination(dest); } else { namedDest = null; explicitDest = await dest; } if (!Array.isArray(explicitDest)) { console.error(`PDFLinkService.goToDestination: "${explicitDest}" is not ` + `a valid destination array, for dest="${dest}".`); return; } this.#goToDestinationHelper(dest, namedDest, explicitDest); } goToPage(val) { if (!this.pdfDocument) { return; } const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0; if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`); return; } if (this.pdfHistory) { this.pdfHistory.pushCurrentPosition(); this.pdfHistory.pushPage(pageNumber); } this.pdfViewer.scrollPageIntoView({ pageNumber }); } addLinkAttributes(link, url, newWindow = false) { addLinkAttributes(link, { url, target: newWindow ? LinkTarget.BLANK : this.externalLinkTarget, rel: this.externalLinkRel, enabled: this.externalLinkEnabled }); } getDestinationHash(dest) { if (typeof dest === "string") { if (dest.length > 0) { return this.getAnchorUrl("#" + escape(dest)); } } else if (Array.isArray(dest)) { const str = JSON.stringify(dest); if (str.length > 0) { return this.getAnchorUrl("#" + escape(str)); } } return this.getAnchorUrl(""); } getAnchorUrl(anchor) { return (this.baseUrl || "") + anchor; } setHash(hash) { if (!this.pdfDocument) { return; } let pageNumber, dest; if (hash.includes("=")) { const params = (0, _ui_utils.parseQueryString)(hash); if (params.has("search")) { this.eventBus.dispatch("findfromurlhash", { source: this, query: params.get("search").replace(/"/g, ""), phraseSearch: params.get("phrase") === "true" }); } if (params.has("page")) { pageNumber = params.get("page") | 0 || 1; } if (params.has("zoom")) { const zoomArgs = params.get("zoom").split(","); const zoomArg = zoomArgs[0]; const zoomArgNumber = parseFloat(zoomArg); if (!zoomArg.includes("Fit")) { dest = [null, { name: "XYZ" }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg]; } else { if (zoomArg === "Fit" || zoomArg === "FitB") { dest = [null, { name: zoomArg }]; } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") { dest = [null, { name: zoomArg }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null]; } else if (zoomArg === "FitR") { if (zoomArgs.length !== 5) { console.error('PDFLinkService.setHash: Not enough parameters for "FitR".'); } else { dest = [null, { name: zoomArg }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0]; } } else { console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`); } } } if (dest) { this.pdfViewer.scrollPageIntoView({ pageNumber: pageNumber || this.page, destArray: dest, allowNegativeOffset: true }); } else if (pageNumber) { this.page = pageNumber; } if (params.has("pagemode")) { this.eventBus.dispatch("pagemode", { source: this, mode: params.get("pagemode") }); } if (params.has("nameddest")) { this.goToDestination(params.get("nameddest")); } } else { dest = unescape(hash); try { dest = JSON.parse(dest); if (!Array.isArray(dest)) { dest = dest.toString(); } } catch (ex) {} if (typeof dest === "string" || PDFLinkService.#isValidExplicitDestination(dest)) { this.goToDestination(dest); return; } console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`); } } executeNamedAction(action) { switch (action) { case "GoBack": this.pdfHistory?.back(); break; case "GoForward": this.pdfHistory?.forward(); break; case "NextPage": this.pdfViewer.nextPage(); break; case "PrevPage": this.pdfViewer.previousPage(); break; case "LastPage": this.page = this.pagesCount; break; case "FirstPage": this.page = 1; break; default: break; } this.eventBus.dispatch("namedaction", { source: this, action }); } cachePageRef(pageNum, pageRef) { if (!pageRef) { return; } const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; this.#pagesRefCache.set(refStr, pageNum); } _cachedPageNumber(pageRef) { if (!pageRef) { return null; } const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; return this.#pagesRefCache.get(refStr) || null; } isPageVisible(pageNumber) { return this.pdfViewer.isPageVisible(pageNumber); } isPageCached(pageNumber) { return this.pdfViewer.isPageCached(pageNumber); } static #isValidExplicitDestination(dest) { if (!Array.isArray(dest)) { return false; } const destLength = dest.length; if (destLength < 2) { return false; } const page = dest[0]; if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) { return false; } const zoom = dest[1]; if (!(typeof zoom === "object" && typeof zoom.name === "string")) { return false; } let allowNull = true; switch (zoom.name) { case "XYZ": if (destLength !== 5) { return false; } break; case "Fit": case "FitB": return destLength === 2; case "FitH": case "FitBH": case "FitV": case "FitBV": if (destLength !== 3) { return false; } break; case "FitR": if (destLength !== 6) { return false; } allowNull = false; break; default: return false; } for (let i = 2; i < destLength; i++) { const param = dest[i]; if (!(typeof param === "number" || allowNull && param === null)) { return false; } } return true; } } exports.PDFLinkService = PDFLinkService; class SimpleLinkService { constructor() { this.externalLinkEnabled = true; } get pagesCount() { return 0; } get page() { return 0; } set page(value) {} get rotation() { return 0; } set rotation(value) {} async goToDestination(dest) {} goToPage(val) {} addLinkAttributes(link, url, newWindow = false) { addLinkAttributes(link, { url, enabled: this.externalLinkEnabled }); } getDestinationHash(dest) { return "#"; } getAnchorUrl(hash) { return "#"; } setHash(hash) {} executeNamedAction(action) {} cachePageRef(pageNum, pageRef) {} isPageVisible(pageNumber) { return true; } isPageCached(pageNumber) { return true; } } exports.SimpleLinkService = SimpleLinkService;