You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					15219 lines
				
				461 KiB
			
		
		
			
		
	
	
					15219 lines
				
				461 KiB
			| 
											11 months ago
										 | /** | ||
|  |  * @licstart The following is the entire license notice for the | ||
|  |  * JavaScript code in this page | ||
|  |  * | ||
|  |  * Copyright 2024 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 | ||
|  |  */ | ||
|  | 
 | ||
|  | /******/ // The require scope
 | ||
|  | /******/ var __webpack_require__ = {}; | ||
|  | /******/  | ||
|  | /************************************************************************/ | ||
|  | /******/ /* webpack/runtime/define property getters */ | ||
|  | /******/ (() => { | ||
|  | /******/ 	// define getter functions for harmony exports
 | ||
|  | /******/ 	__webpack_require__.d = (exports, definition) => { | ||
|  | /******/ 		for(var key in definition) { | ||
|  | /******/ 			if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { | ||
|  | /******/ 				Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); | ||
|  | /******/ 			} | ||
|  | /******/ 		} | ||
|  | /******/ 	}; | ||
|  | /******/ })(); | ||
|  | /******/  | ||
|  | /******/ /* webpack/runtime/hasOwnProperty shorthand */ | ||
|  | /******/ (() => { | ||
|  | /******/ 	__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) | ||
|  | /******/ })(); | ||
|  | /******/  | ||
|  | /************************************************************************/ | ||
|  | var __webpack_exports__ = {}; | ||
|  | 
 | ||
|  | // EXPORTS
 | ||
|  | __webpack_require__.d(__webpack_exports__, { | ||
|  |   PDFViewerApplication: () => (/* reexport */ PDFViewerApplication), | ||
|  |   PDFViewerApplicationConstants: () => (/* binding */ AppConstants), | ||
|  |   PDFViewerApplicationOptions: () => (/* reexport */ AppOptions) | ||
|  | }); | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/ui_utils.js
 | ||
|  | const DEFAULT_SCALE_VALUE = "auto"; | ||
|  | const DEFAULT_SCALE = 1.0; | ||
|  | const DEFAULT_SCALE_DELTA = 1.1; | ||
|  | const MIN_SCALE = 0.1; | ||
|  | const MAX_SCALE = 10.0; | ||
|  | const UNKNOWN_SCALE = 0; | ||
|  | const MAX_AUTO_SCALE = 1.25; | ||
|  | const SCROLLBAR_PADDING = 40; | ||
|  | const VERTICAL_PADDING = 5; | ||
|  | const RenderingStates = { | ||
|  |   INITIAL: 0, | ||
|  |   RUNNING: 1, | ||
|  |   PAUSED: 2, | ||
|  |   FINISHED: 3 | ||
|  | }; | ||
|  | const PresentationModeState = { | ||
|  |   UNKNOWN: 0, | ||
|  |   NORMAL: 1, | ||
|  |   CHANGING: 2, | ||
|  |   FULLSCREEN: 3 | ||
|  | }; | ||
|  | const SidebarView = { | ||
|  |   UNKNOWN: -1, | ||
|  |   NONE: 0, | ||
|  |   THUMBS: 1, | ||
|  |   OUTLINE: 2, | ||
|  |   ATTACHMENTS: 3, | ||
|  |   LAYERS: 4 | ||
|  | }; | ||
|  | const TextLayerMode = { | ||
|  |   DISABLE: 0, | ||
|  |   ENABLE: 1, | ||
|  |   ENABLE_PERMISSIONS: 2 | ||
|  | }; | ||
|  | const ScrollMode = { | ||
|  |   UNKNOWN: -1, | ||
|  |   VERTICAL: 0, | ||
|  |   HORIZONTAL: 1, | ||
|  |   WRAPPED: 2, | ||
|  |   PAGE: 3 | ||
|  | }; | ||
|  | const SpreadMode = { | ||
|  |   UNKNOWN: -1, | ||
|  |   NONE: 0, | ||
|  |   ODD: 1, | ||
|  |   EVEN: 2 | ||
|  | }; | ||
|  | const CursorTool = { | ||
|  |   SELECT: 0, | ||
|  |   HAND: 1, | ||
|  |   ZOOM: 2 | ||
|  | }; | ||
|  | const AutoPrintRegExp = /\bprint\s*\(/; | ||
|  | class OutputScale { | ||
|  |   constructor() { | ||
|  |     const pixelRatio = window.devicePixelRatio || 1; | ||
|  |     this.sx = pixelRatio; | ||
|  |     this.sy = pixelRatio; | ||
|  |   } | ||
|  |   get scaled() { | ||
|  |     return this.sx !== 1 || this.sy !== 1; | ||
|  |   } | ||
|  | } | ||
|  | function scrollIntoView(element, spot, scrollMatches = false) { | ||
|  |   let parent = element.offsetParent; | ||
|  |   if (!parent) { | ||
|  |     console.error("offsetParent is not set -- cannot scroll"); | ||
|  |     return; | ||
|  |   } | ||
|  |   let offsetY = element.offsetTop + element.clientTop; | ||
|  |   let offsetX = element.offsetLeft + element.clientLeft; | ||
|  |   while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || scrollMatches && (parent.classList.contains("markedContent") || getComputedStyle(parent).overflow === "hidden")) { | ||
|  |     offsetY += parent.offsetTop; | ||
|  |     offsetX += parent.offsetLeft; | ||
|  |     parent = parent.offsetParent; | ||
|  |     if (!parent) { | ||
|  |       return; | ||
|  |     } | ||
|  |   } | ||
|  |   if (spot) { | ||
|  |     if (spot.top !== undefined) { | ||
|  |       offsetY += spot.top; | ||
|  |     } | ||
|  |     if (spot.left !== undefined) { | ||
|  |       offsetX += spot.left; | ||
|  |       parent.scrollLeft = offsetX; | ||
|  |     } | ||
|  |   } | ||
|  |   parent.scrollTop = offsetY; | ||
|  | } | ||
|  | function watchScroll(viewAreaElement, callback, abortSignal = undefined) { | ||
|  |   const debounceScroll = function (evt) { | ||
|  |     if (rAF) { | ||
|  |       return; | ||
|  |     } | ||
|  |     rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { | ||
|  |       rAF = null; | ||
|  |       const currentX = viewAreaElement.scrollLeft; | ||
|  |       const lastX = state.lastX; | ||
|  |       if (currentX !== lastX) { | ||
|  |         state.right = currentX > lastX; | ||
|  |       } | ||
|  |       state.lastX = currentX; | ||
|  |       const currentY = viewAreaElement.scrollTop; | ||
|  |       const lastY = state.lastY; | ||
|  |       if (currentY !== lastY) { | ||
|  |         state.down = currentY > lastY; | ||
|  |       } | ||
|  |       state.lastY = currentY; | ||
|  |       callback(state); | ||
|  |     }); | ||
|  |   }; | ||
|  |   const state = { | ||
|  |     right: true, | ||
|  |     down: true, | ||
|  |     lastX: viewAreaElement.scrollLeft, | ||
|  |     lastY: viewAreaElement.scrollTop, | ||
|  |     _eventHandler: debounceScroll | ||
|  |   }; | ||
|  |   let rAF = null; | ||
|  |   viewAreaElement.addEventListener("scroll", debounceScroll, { | ||
|  |     useCapture: true, | ||
|  |     signal: abortSignal | ||
|  |   }); | ||
|  |   abortSignal?.addEventListener("abort", () => window.cancelAnimationFrame(rAF), { | ||
|  |     once: true | ||
|  |   }); | ||
|  |   return state; | ||
|  | } | ||
|  | function parseQueryString(query) { | ||
|  |   const params = new Map(); | ||
|  |   for (const [key, value] of new URLSearchParams(query)) { | ||
|  |     params.set(key.toLowerCase(), value); | ||
|  |   } | ||
|  |   return params; | ||
|  | } | ||
|  | const InvisibleCharsRegExp = /[\x00-\x1F]/g; | ||
|  | function removeNullCharacters(str, replaceInvisible = false) { | ||
|  |   if (!InvisibleCharsRegExp.test(str)) { | ||
|  |     return str; | ||
|  |   } | ||
|  |   if (replaceInvisible) { | ||
|  |     return str.replaceAll(InvisibleCharsRegExp, m => m === "\x00" ? "" : " "); | ||
|  |   } | ||
|  |   return str.replaceAll("\x00", ""); | ||
|  | } | ||
|  | function binarySearchFirstItem(items, condition, start = 0) { | ||
|  |   let minIndex = start; | ||
|  |   let maxIndex = items.length - 1; | ||
|  |   if (maxIndex < 0 || !condition(items[maxIndex])) { | ||
|  |     return items.length; | ||
|  |   } | ||
|  |   if (condition(items[minIndex])) { | ||
|  |     return minIndex; | ||
|  |   } | ||
|  |   while (minIndex < maxIndex) { | ||
|  |     const currentIndex = minIndex + maxIndex >> 1; | ||
|  |     const currentItem = items[currentIndex]; | ||
|  |     if (condition(currentItem)) { | ||
|  |       maxIndex = currentIndex; | ||
|  |     } else { | ||
|  |       minIndex = currentIndex + 1; | ||
|  |     } | ||
|  |   } | ||
|  |   return minIndex; | ||
|  | } | ||
|  | function approximateFraction(x) { | ||
|  |   if (Math.floor(x) === x) { | ||
|  |     return [x, 1]; | ||
|  |   } | ||
|  |   const xinv = 1 / x; | ||
|  |   const limit = 8; | ||
|  |   if (xinv > limit) { | ||
|  |     return [1, limit]; | ||
|  |   } else if (Math.floor(xinv) === xinv) { | ||
|  |     return [1, xinv]; | ||
|  |   } | ||
|  |   const x_ = x > 1 ? xinv : x; | ||
|  |   let a = 0, | ||
|  |     b = 1, | ||
|  |     c = 1, | ||
|  |     d = 1; | ||
|  |   while (true) { | ||
|  |     const p = a + c, | ||
|  |       q = b + d; | ||
|  |     if (q > limit) { | ||
|  |       break; | ||
|  |     } | ||
|  |     if (x_ <= p / q) { | ||
|  |       c = p; | ||
|  |       d = q; | ||
|  |     } else { | ||
|  |       a = p; | ||
|  |       b = q; | ||
|  |     } | ||
|  |   } | ||
|  |   let result; | ||
|  |   if (x_ - a / b < c / d - x_) { | ||
|  |     result = x_ === x ? [a, b] : [b, a]; | ||
|  |   } else { | ||
|  |     result = x_ === x ? [c, d] : [d, c]; | ||
|  |   } | ||
|  |   return result; | ||
|  | } | ||
|  | function floorToDivide(x, div) { | ||
|  |   return x - x % div; | ||
|  | } | ||
|  | function getPageSizeInches({ | ||
|  |   view, | ||
|  |   userUnit, | ||
|  |   rotate | ||
|  | }) { | ||
|  |   const [x1, y1, x2, y2] = view; | ||
|  |   const changeOrientation = rotate % 180 !== 0; | ||
|  |   const width = (x2 - x1) / 72 * userUnit; | ||
|  |   const height = (y2 - y1) / 72 * userUnit; | ||
|  |   return { | ||
|  |     width: changeOrientation ? height : width, | ||
|  |     height: changeOrientation ? width : height | ||
|  |   }; | ||
|  | } | ||
|  | function backtrackBeforeAllVisibleElements(index, views, top) { | ||
|  |   if (index < 2) { | ||
|  |     return index; | ||
|  |   } | ||
|  |   let elt = views[index].div; | ||
|  |   let pageTop = elt.offsetTop + elt.clientTop; | ||
|  |   if (pageTop >= top) { | ||
|  |     elt = views[index - 1].div; | ||
|  |     pageTop = elt.offsetTop + elt.clientTop; | ||
|  |   } | ||
|  |   for (let i = index - 2; i >= 0; --i) { | ||
|  |     elt = views[i].div; | ||
|  |     if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) { | ||
|  |       break; | ||
|  |     } | ||
|  |     index = i; | ||
|  |   } | ||
|  |   return index; | ||
|  | } | ||
|  | function getVisibleElements({ | ||
|  |   scrollEl, | ||
|  |   views, | ||
|  |   sortByVisibility = false, | ||
|  |   horizontal = false, | ||
|  |   rtl = false | ||
|  | }) { | ||
|  |   const top = scrollEl.scrollTop, | ||
|  |     bottom = top + scrollEl.clientHeight; | ||
|  |   const left = scrollEl.scrollLeft, | ||
|  |     right = left + scrollEl.clientWidth; | ||
|  |   function isElementBottomAfterViewTop(view) { | ||
|  |     const element = view.div; | ||
|  |     const elementBottom = element.offsetTop + element.clientTop + element.clientHeight; | ||
|  |     return elementBottom > top; | ||
|  |   } | ||
|  |   function isElementNextAfterViewHorizontally(view) { | ||
|  |     const element = view.div; | ||
|  |     const elementLeft = element.offsetLeft + element.clientLeft; | ||
|  |     const elementRight = elementLeft + element.clientWidth; | ||
|  |     return rtl ? elementLeft < right : elementRight > left; | ||
|  |   } | ||
|  |   const visible = [], | ||
|  |     ids = new Set(), | ||
|  |     numViews = views.length; | ||
|  |   let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop); | ||
|  |   if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) { | ||
|  |     firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top); | ||
|  |   } | ||
|  |   let lastEdge = horizontal ? right : -1; | ||
|  |   for (let i = firstVisibleElementInd; i < numViews; i++) { | ||
|  |     const view = views[i], | ||
|  |       element = view.div; | ||
|  |     const currentWidth = element.offsetLeft + element.clientLeft; | ||
|  |     const currentHeight = element.offsetTop + element.clientTop; | ||
|  |     const viewWidth = element.clientWidth, | ||
|  |       viewHeight = element.clientHeight; | ||
|  |     const viewRight = currentWidth + viewWidth; | ||
|  |     const viewBottom = currentHeight + viewHeight; | ||
|  |     if (lastEdge === -1) { | ||
|  |       if (viewBottom >= bottom) { | ||
|  |         lastEdge = viewBottom; | ||
|  |       } | ||
|  |     } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) { | ||
|  |       break; | ||
|  |     } | ||
|  |     if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) { | ||
|  |       continue; | ||
|  |     } | ||
|  |     const hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom); | ||
|  |     const hiddenWidth = Math.max(0, left - currentWidth) + Math.max(0, viewRight - right); | ||
|  |     const fractionHeight = (viewHeight - hiddenHeight) / viewHeight, | ||
|  |       fractionWidth = (viewWidth - hiddenWidth) / viewWidth; | ||
|  |     const percent = fractionHeight * fractionWidth * 100 | 0; | ||
|  |     visible.push({ | ||
|  |       id: view.id, | ||
|  |       x: currentWidth, | ||
|  |       y: currentHeight, | ||
|  |       view, | ||
|  |       percent, | ||
|  |       widthPercent: fractionWidth * 100 | 0 | ||
|  |     }); | ||
|  |     ids.add(view.id); | ||
|  |   } | ||
|  |   const first = visible[0], | ||
|  |     last = visible.at(-1); | ||
|  |   if (sortByVisibility) { | ||
|  |     visible.sort(function (a, b) { | ||
|  |       const pc = a.percent - b.percent; | ||
|  |       if (Math.abs(pc) > 0.001) { | ||
|  |         return -pc; | ||
|  |       } | ||
|  |       return a.id - b.id; | ||
|  |     }); | ||
|  |   } | ||
|  |   return { | ||
|  |     first, | ||
|  |     last, | ||
|  |     views: visible, | ||
|  |     ids | ||
|  |   }; | ||
|  | } | ||
|  | function normalizeWheelEventDirection(evt) { | ||
|  |   let delta = Math.hypot(evt.deltaX, evt.deltaY); | ||
|  |   const angle = Math.atan2(evt.deltaY, evt.deltaX); | ||
|  |   if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) { | ||
|  |     delta = -delta; | ||
|  |   } | ||
|  |   return delta; | ||
|  | } | ||
|  | function normalizeWheelEventDelta(evt) { | ||
|  |   const deltaMode = evt.deltaMode; | ||
|  |   let delta = normalizeWheelEventDirection(evt); | ||
|  |   const MOUSE_PIXELS_PER_LINE = 30; | ||
|  |   const MOUSE_LINES_PER_PAGE = 30; | ||
|  |   if (deltaMode === WheelEvent.DOM_DELTA_PIXEL) { | ||
|  |     delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE; | ||
|  |   } else if (deltaMode === WheelEvent.DOM_DELTA_LINE) { | ||
|  |     delta /= MOUSE_LINES_PER_PAGE; | ||
|  |   } | ||
|  |   return delta; | ||
|  | } | ||
|  | function isValidRotation(angle) { | ||
|  |   return Number.isInteger(angle) && angle % 90 === 0; | ||
|  | } | ||
|  | function isValidScrollMode(mode) { | ||
|  |   return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN; | ||
|  | } | ||
|  | function isValidSpreadMode(mode) { | ||
|  |   return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN; | ||
|  | } | ||
|  | function isPortraitOrientation(size) { | ||
|  |   return size.width <= size.height; | ||
|  | } | ||
|  | const animationStarted = new Promise(function (resolve) { | ||
|  |   window.requestAnimationFrame(resolve); | ||
|  | }); | ||
|  | const docStyle = document.documentElement.style; | ||
|  | function clamp(v, min, max) { | ||
|  |   return Math.min(Math.max(v, min), max); | ||
|  | } | ||
|  | class ProgressBar { | ||
|  |   #classList = null; | ||
|  |   #disableAutoFetchTimeout = null; | ||
|  |   #percent = 0; | ||
|  |   #style = null; | ||
|  |   #visible = true; | ||
|  |   constructor(bar) { | ||
|  |     this.#classList = bar.classList; | ||
|  |     this.#style = bar.style; | ||
|  |   } | ||
|  |   get percent() { | ||
|  |     return this.#percent; | ||
|  |   } | ||
|  |   set percent(val) { | ||
|  |     this.#percent = clamp(val, 0, 100); | ||
|  |     if (isNaN(val)) { | ||
|  |       this.#classList.add("indeterminate"); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#classList.remove("indeterminate"); | ||
|  |     this.#style.setProperty("--progressBar-percent", `${this.#percent}%`); | ||
|  |   } | ||
|  |   setWidth(viewer) { | ||
|  |     if (!viewer) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const container = viewer.parentNode; | ||
|  |     const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; | ||
|  |     if (scrollbarWidth > 0) { | ||
|  |       this.#style.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`); | ||
|  |     } | ||
|  |   } | ||
|  |   setDisableAutoFetch(delay = 5000) { | ||
|  |     if (this.#percent === 100 || isNaN(this.#percent)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.#disableAutoFetchTimeout) { | ||
|  |       clearTimeout(this.#disableAutoFetchTimeout); | ||
|  |     } | ||
|  |     this.show(); | ||
|  |     this.#disableAutoFetchTimeout = setTimeout(() => { | ||
|  |       this.#disableAutoFetchTimeout = null; | ||
|  |       this.hide(); | ||
|  |     }, delay); | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (!this.#visible) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#visible = false; | ||
|  |     this.#classList.add("hidden"); | ||
|  |   } | ||
|  |   show() { | ||
|  |     if (this.#visible) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#visible = true; | ||
|  |     this.#classList.remove("hidden"); | ||
|  |   } | ||
|  | } | ||
|  | function getActiveOrFocusedElement() { | ||
|  |   let curRoot = document; | ||
|  |   let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); | ||
|  |   while (curActiveOrFocused?.shadowRoot) { | ||
|  |     curRoot = curActiveOrFocused.shadowRoot; | ||
|  |     curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); | ||
|  |   } | ||
|  |   return curActiveOrFocused; | ||
|  | } | ||
|  | function apiPageLayoutToViewerModes(layout) { | ||
|  |   let scrollMode = ScrollMode.VERTICAL, | ||
|  |     spreadMode = SpreadMode.NONE; | ||
|  |   switch (layout) { | ||
|  |     case "SinglePage": | ||
|  |       scrollMode = ScrollMode.PAGE; | ||
|  |       break; | ||
|  |     case "OneColumn": | ||
|  |       break; | ||
|  |     case "TwoPageLeft": | ||
|  |       scrollMode = ScrollMode.PAGE; | ||
|  |     case "TwoColumnLeft": | ||
|  |       spreadMode = SpreadMode.ODD; | ||
|  |       break; | ||
|  |     case "TwoPageRight": | ||
|  |       scrollMode = ScrollMode.PAGE; | ||
|  |     case "TwoColumnRight": | ||
|  |       spreadMode = SpreadMode.EVEN; | ||
|  |       break; | ||
|  |   } | ||
|  |   return { | ||
|  |     scrollMode, | ||
|  |     spreadMode | ||
|  |   }; | ||
|  | } | ||
|  | function apiPageModeToSidebarView(mode) { | ||
|  |   switch (mode) { | ||
|  |     case "UseNone": | ||
|  |       return SidebarView.NONE; | ||
|  |     case "UseThumbs": | ||
|  |       return SidebarView.THUMBS; | ||
|  |     case "UseOutlines": | ||
|  |       return SidebarView.OUTLINE; | ||
|  |     case "UseAttachments": | ||
|  |       return SidebarView.ATTACHMENTS; | ||
|  |     case "UseOC": | ||
|  |       return SidebarView.LAYERS; | ||
|  |   } | ||
|  |   return SidebarView.NONE; | ||
|  | } | ||
|  | function toggleCheckedBtn(button, toggle, view = null) { | ||
|  |   button.classList.toggle("toggled", toggle); | ||
|  |   button.setAttribute("aria-checked", toggle); | ||
|  |   view?.classList.toggle("hidden", !toggle); | ||
|  | } | ||
|  | function toggleExpandedBtn(button, toggle, view = null) { | ||
|  |   button.classList.toggle("toggled", toggle); | ||
|  |   button.setAttribute("aria-expanded", toggle); | ||
|  |   view?.classList.toggle("hidden", !toggle); | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/app_options.js
 | ||
|  | { | ||
|  |   var compatParams = new Map(); | ||
|  |   const userAgent = navigator.userAgent || ""; | ||
|  |   const platform = navigator.platform || ""; | ||
|  |   const maxTouchPoints = navigator.maxTouchPoints || 1; | ||
|  |   const isAndroid = /Android/.test(userAgent); | ||
|  |   const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1; | ||
|  |   (function () { | ||
|  |     if (isIOS || isAndroid) { | ||
|  |       compatParams.set("maxCanvasPixels", 5242880); | ||
|  |     } | ||
|  |   })(); | ||
|  |   (function () { | ||
|  |     if (isAndroid) { | ||
|  |       compatParams.set("useSystemFonts", false); | ||
|  |     } | ||
|  |   })(); | ||
|  | } | ||
|  | const OptionKind = { | ||
|  |   BROWSER: 0x01, | ||
|  |   VIEWER: 0x02, | ||
|  |   API: 0x04, | ||
|  |   WORKER: 0x08, | ||
|  |   EVENT_DISPATCH: 0x10, | ||
|  |   PREFERENCE: 0x80 | ||
|  | }; | ||
|  | const Type = { | ||
|  |   BOOLEAN: 0x01, | ||
|  |   NUMBER: 0x02, | ||
|  |   OBJECT: 0x04, | ||
|  |   STRING: 0x08, | ||
|  |   UNDEFINED: 0x10 | ||
|  | }; | ||
|  | const defaultOptions = { | ||
|  |   allowedGlobalEvents: { | ||
|  |     value: null, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   canvasMaxAreaInBytes: { | ||
|  |     value: -1, | ||
|  |     kind: OptionKind.BROWSER + OptionKind.API | ||
|  |   }, | ||
|  |   isInAutomation: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   localeProperties: { | ||
|  |     value: { | ||
|  |       lang: navigator.language || "en-US" | ||
|  |     }, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   nimbusDataStr: { | ||
|  |     value: "", | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsCaretBrowsingMode: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsDocumentFonts: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsIntegratedFind: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsMouseWheelZoomCtrlKey: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsMouseWheelZoomMetaKey: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   supportsPinchToZoom: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.BROWSER | ||
|  |   }, | ||
|  |   toolbarDensity: { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.BROWSER + OptionKind.EVENT_DISPATCH | ||
|  |   }, | ||
|  |   altTextLearnMoreUrl: { | ||
|  |     value: "", | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   annotationEditorMode: { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   annotationMode: { | ||
|  |     value: 2, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   cursorToolOnLoad: { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   debuggerSrc: { | ||
|  |     value: "./debugger.mjs", | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   defaultZoomDelay: { | ||
|  |     value: 400, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   defaultZoomValue: { | ||
|  |     value: "", | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   disableHistory: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   disablePageLabels: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableAltText: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableAltTextModelDownload: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH | ||
|  |   }, | ||
|  |   enableGuessAltText: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH | ||
|  |   }, | ||
|  |   enableHighlightFloatingButton: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableNewAltTextWhenAddingImage: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enablePermissions: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enablePrintAutoRotate: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableScripting: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableUpdatedAddImage: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   externalLinkRel: { | ||
|  |     value: "noopener noreferrer nofollow", | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   externalLinkTarget: { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   highlightEditorColors: { | ||
|  |     value: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F", | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   historyUpdateUrl: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   ignoreDestinationZoom: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   imageResourcesPath: { | ||
|  |     value: "./images/", | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   maxCanvasPixels: { | ||
|  |     value: 2 ** 25, | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   forcePageColors: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   pageColorsBackground: { | ||
|  |     value: "Canvas", | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   pageColorsForeground: { | ||
|  |     value: "CanvasText", | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   pdfBugEnabled: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   printResolution: { | ||
|  |     value: 150, | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }, | ||
|  |   sidebarViewOnLoad: { | ||
|  |     value: -1, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   scrollModeOnLoad: { | ||
|  |     value: -1, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   spreadModeOnLoad: { | ||
|  |     value: -1, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   textLayerMode: { | ||
|  |     value: 1, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   viewOnLoad: { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   cMapPacked: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   cMapUrl: { | ||
|  |     value: "../web/cmaps/", | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   disableAutoFetch: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   disableFontFace: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   disableRange: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   disableStream: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   docBaseUrl: { | ||
|  |     value: "", | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   enableHWA: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.API + OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   enableXfa: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.API + OptionKind.PREFERENCE | ||
|  |   }, | ||
|  |   fontExtraProperties: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   isEvalSupported: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   isOffscreenCanvasSupported: { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   maxImageSize: { | ||
|  |     value: -1, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   pdfBug: { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   standardFontDataUrl: { | ||
|  |     value: "../web/standard_fonts/", | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   useSystemFonts: { | ||
|  |     value: undefined, | ||
|  |     kind: OptionKind.API, | ||
|  |     type: Type.BOOLEAN + Type.UNDEFINED | ||
|  |   }, | ||
|  |   verbosity: { | ||
|  |     value: 1, | ||
|  |     kind: OptionKind.API | ||
|  |   }, | ||
|  |   workerPort: { | ||
|  |     value: null, | ||
|  |     kind: OptionKind.WORKER | ||
|  |   }, | ||
|  |   workerSrc: { | ||
|  |     value: "../build/pdf.worker.mjs", | ||
|  |     kind: OptionKind.WORKER | ||
|  |   } | ||
|  | }; | ||
|  | { | ||
|  |   defaultOptions.defaultUrl = { | ||
|  |     value: "compressed.tracemonkey-pldi-09.pdf", | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }; | ||
|  |   defaultOptions.sandboxBundleSrc = { | ||
|  |     value: "../build/pdf.sandbox.mjs", | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }; | ||
|  |   defaultOptions.viewerCssTheme = { | ||
|  |     value: 0, | ||
|  |     kind: OptionKind.VIEWER + OptionKind.PREFERENCE | ||
|  |   }; | ||
|  |   defaultOptions.enableFakeMLManager = { | ||
|  |     value: true, | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }; | ||
|  | } | ||
|  | { | ||
|  |   defaultOptions.disablePreferences = { | ||
|  |     value: false, | ||
|  |     kind: OptionKind.VIEWER | ||
|  |   }; | ||
|  | } | ||
|  | class AppOptions { | ||
|  |   static eventBus; | ||
|  |   static #opts = new Map(); | ||
|  |   static { | ||
|  |     for (const name in defaultOptions) { | ||
|  |       this.#opts.set(name, defaultOptions[name].value); | ||
|  |     } | ||
|  |     for (const [name, value] of compatParams) { | ||
|  |       this.#opts.set(name, value); | ||
|  |     } | ||
|  |     this._hasInvokedSet = false; | ||
|  |     this._checkDisablePreferences = () => { | ||
|  |       if (this.get("disablePreferences")) { | ||
|  |         return true; | ||
|  |       } | ||
|  |       if (this._hasInvokedSet) { | ||
|  |         console.warn("The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option to prevent that.'); | ||
|  |       } | ||
|  |       return false; | ||
|  |     }; | ||
|  |   } | ||
|  |   static get(name) { | ||
|  |     return this.#opts.get(name); | ||
|  |   } | ||
|  |   static getAll(kind = null, defaultOnly = false) { | ||
|  |     const options = Object.create(null); | ||
|  |     for (const name in defaultOptions) { | ||
|  |       const defaultOpt = defaultOptions[name]; | ||
|  |       if (kind && !(kind & defaultOpt.kind)) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       options[name] = !defaultOnly ? this.#opts.get(name) : defaultOpt.value; | ||
|  |     } | ||
|  |     return options; | ||
|  |   } | ||
|  |   static set(name, value) { | ||
|  |     this.setAll({ | ||
|  |       [name]: value | ||
|  |     }); | ||
|  |   } | ||
|  |   static setAll(options, prefs = false) { | ||
|  |     this._hasInvokedSet ||= true; | ||
|  |     let events; | ||
|  |     for (const name in options) { | ||
|  |       const defaultOpt = defaultOptions[name], | ||
|  |         userOpt = options[name]; | ||
|  |       if (!defaultOpt || !(typeof userOpt === typeof defaultOpt.value || Type[(typeof userOpt).toUpperCase()] & defaultOpt.type)) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       const { | ||
|  |         kind | ||
|  |       } = defaultOpt; | ||
|  |       if (prefs && !(kind & OptionKind.BROWSER || kind & OptionKind.PREFERENCE)) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       if (this.eventBus && kind & OptionKind.EVENT_DISPATCH) { | ||
|  |         (events ||= new Map()).set(name, userOpt); | ||
|  |       } | ||
|  |       this.#opts.set(name, userOpt); | ||
|  |     } | ||
|  |     if (events) { | ||
|  |       for (const [name, value] of events) { | ||
|  |         this.eventBus.dispatch(name.toLowerCase(), { | ||
|  |           source: this, | ||
|  |           value | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_link_service.js
 | ||
|  | 
 | ||
|  | const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; | ||
|  | const LinkTarget = { | ||
|  |   NONE: 0, | ||
|  |   SELF: 1, | ||
|  |   BLANK: 2, | ||
|  |   PARENT: 3, | ||
|  |   TOP: 4 | ||
|  | }; | ||
|  | class PDFLinkService { | ||
|  |   externalLinkEnabled = true; | ||
|  |   constructor({ | ||
|  |     eventBus, | ||
|  |     externalLinkTarget = null, | ||
|  |     externalLinkRel = null, | ||
|  |     ignoreDestinationZoom = false | ||
|  |   } = {}) { | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.externalLinkTarget = externalLinkTarget; | ||
|  |     this.externalLinkRel = externalLinkRel; | ||
|  |     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; | ||
|  |   } | ||
|  |   setViewer(pdfViewer) { | ||
|  |     this.pdfViewer = pdfViewer; | ||
|  |   } | ||
|  |   setHistory(pdfHistory) { | ||
|  |     this.pdfHistory = pdfHistory; | ||
|  |   } | ||
|  |   get pagesCount() { | ||
|  |     return this.pdfDocument ? this.pdfDocument.numPages : 0; | ||
|  |   } | ||
|  |   get page() { | ||
|  |     return this.pdfDocument ? this.pdfViewer.currentPageNumber : 1; | ||
|  |   } | ||
|  |   set page(value) { | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.pdfViewer.currentPageNumber = value; | ||
|  |     } | ||
|  |   } | ||
|  |   get rotation() { | ||
|  |     return this.pdfDocument ? this.pdfViewer.pagesRotation : 0; | ||
|  |   } | ||
|  |   set rotation(value) { | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.pdfViewer.pagesRotation = value; | ||
|  |     } | ||
|  |   } | ||
|  |   get isInPresentationMode() { | ||
|  |     return this.pdfDocument ? this.pdfViewer.isInPresentationMode : false; | ||
|  |   } | ||
|  |   async goToDestination(dest) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let namedDest, explicitDest, pageNumber; | ||
|  |     if (typeof dest === "string") { | ||
|  |       namedDest = dest; | ||
|  |       explicitDest = await this.pdfDocument.getDestination(dest); | ||
|  |     } else { | ||
|  |       namedDest = null; | ||
|  |       explicitDest = await dest; | ||
|  |     } | ||
|  |     if (!Array.isArray(explicitDest)) { | ||
|  |       console.error(`goToDestination: "${explicitDest}" is not a valid destination array, for dest="${dest}".`); | ||
|  |       return; | ||
|  |     } | ||
|  |     const [destRef] = explicitDest; | ||
|  |     if (destRef && typeof destRef === "object") { | ||
|  |       pageNumber = this.pdfDocument.cachedPageNumber(destRef); | ||
|  |       if (!pageNumber) { | ||
|  |         try { | ||
|  |           pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1; | ||
|  |         } catch { | ||
|  |           console.error(`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`); | ||
|  |           return; | ||
|  |         } | ||
|  |       } | ||
|  |     } else if (Number.isInteger(destRef)) { | ||
|  |       pageNumber = destRef + 1; | ||
|  |     } | ||
|  |     if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { | ||
|  |       console.error(`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.pdfHistory) { | ||
|  |       this.pdfHistory.pushCurrentPosition(); | ||
|  |       this.pdfHistory.push({ | ||
|  |         namedDest, | ||
|  |         explicitDest, | ||
|  |         pageNumber | ||
|  |       }); | ||
|  |     } | ||
|  |     this.pdfViewer.scrollPageIntoView({ | ||
|  |       pageNumber, | ||
|  |       destArray: explicitDest, | ||
|  |       ignoreDestinationZoom: this._ignoreDestinationZoom | ||
|  |     }); | ||
|  |   } | ||
|  |   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) { | ||
|  |     if (!url || typeof url !== "string") { | ||
|  |       throw new Error('A valid "url" parameter must provided.'); | ||
|  |     } | ||
|  |     const target = newWindow ? LinkTarget.BLANK : this.externalLinkTarget, | ||
|  |       rel = this.externalLinkRel; | ||
|  |     if (this.externalLinkEnabled) { | ||
|  |       link.href = link.title = url; | ||
|  |     } else { | ||
|  |       link.href = ""; | ||
|  |       link.title = `Disabled: ${url}`; | ||
|  |       link.onclick = () => 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; | ||
|  |   } | ||
|  |   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 ? this.baseUrl + anchor : anchor; | ||
|  |   } | ||
|  |   setHash(hash) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let pageNumber, dest; | ||
|  |     if (hash.includes("=")) { | ||
|  |       const params = parseQueryString(hash); | ||
|  |       if (params.has("search")) { | ||
|  |         const query = params.get("search").replaceAll('"', ""), | ||
|  |           phrase = params.get("phrase") === "true"; | ||
|  |         this.eventBus.dispatch("findfromurlhash", { | ||
|  |           source: this, | ||
|  |           query: phrase ? query : query.match(/\S+/g) | ||
|  |         }); | ||
|  |       } | ||
|  |       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")); | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     dest = unescape(hash); | ||
|  |     try { | ||
|  |       dest = JSON.parse(dest); | ||
|  |       if (!Array.isArray(dest)) { | ||
|  |         dest = dest.toString(); | ||
|  |       } | ||
|  |     } catch {} | ||
|  |     if (typeof dest === "string" || PDFLinkService.#isValidExplicitDest(dest)) { | ||
|  |       this.goToDestination(dest); | ||
|  |       return; | ||
|  |     } | ||
|  |     console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`); | ||
|  |   } | ||
|  |   executeNamedAction(action) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     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 | ||
|  |     }); | ||
|  |   } | ||
|  |   async executeSetOCGState(action) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pdfDocument = this.pdfDocument, | ||
|  |       optionalContentConfig = await this.pdfViewer.optionalContentConfigPromise; | ||
|  |     if (pdfDocument !== this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     optionalContentConfig.setOCGState(action); | ||
|  |     this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig); | ||
|  |   } | ||
|  |   static #isValidExplicitDest(dest) { | ||
|  |     if (!Array.isArray(dest) || dest.length < 2) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     const [page, zoom, ...args] = dest; | ||
|  |     if (!(typeof page === "object" && Number.isInteger(page?.num) && Number.isInteger(page?.gen)) && !Number.isInteger(page)) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     if (!(typeof zoom === "object" && typeof zoom?.name === "string")) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     const argsLen = args.length; | ||
|  |     let allowNull = true; | ||
|  |     switch (zoom.name) { | ||
|  |       case "XYZ": | ||
|  |         if (argsLen < 2 || argsLen > 3) { | ||
|  |           return false; | ||
|  |         } | ||
|  |         break; | ||
|  |       case "Fit": | ||
|  |       case "FitB": | ||
|  |         return argsLen === 0; | ||
|  |       case "FitH": | ||
|  |       case "FitBH": | ||
|  |       case "FitV": | ||
|  |       case "FitBV": | ||
|  |         if (argsLen > 1) { | ||
|  |           return false; | ||
|  |         } | ||
|  |         break; | ||
|  |       case "FitR": | ||
|  |         if (argsLen !== 4) { | ||
|  |           return false; | ||
|  |         } | ||
|  |         allowNull = false; | ||
|  |         break; | ||
|  |       default: | ||
|  |         return false; | ||
|  |     } | ||
|  |     for (const arg of args) { | ||
|  |       if (!(typeof arg === "number" || allowNull && arg === null)) { | ||
|  |         return false; | ||
|  |       } | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  | } | ||
|  | class SimpleLinkService extends PDFLinkService { | ||
|  |   setDocument(pdfDocument, baseUrl = null) {} | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdfjs.js
 | ||
|  | const { | ||
|  |   AbortException, | ||
|  |   AnnotationEditorLayer, | ||
|  |   AnnotationEditorParamsType, | ||
|  |   AnnotationEditorType, | ||
|  |   AnnotationEditorUIManager, | ||
|  |   AnnotationLayer, | ||
|  |   AnnotationMode, | ||
|  |   build, | ||
|  |   CMapCompressionType, | ||
|  |   ColorPicker, | ||
|  |   createValidAbsoluteUrl, | ||
|  |   DOMSVGFactory, | ||
|  |   DrawLayer, | ||
|  |   FeatureTest, | ||
|  |   fetchData, | ||
|  |   getDocument, | ||
|  |   getFilenameFromUrl, | ||
|  |   getPdfFilenameFromUrl: pdfjs_getPdfFilenameFromUrl, | ||
|  |   getXfaPageViewport, | ||
|  |   GlobalWorkerOptions, | ||
|  |   ImageKind, | ||
|  |   InvalidPDFException, | ||
|  |   isDataScheme, | ||
|  |   isPdfFile, | ||
|  |   MissingPDFException, | ||
|  |   noContextMenu, | ||
|  |   normalizeUnicode, | ||
|  |   OPS, | ||
|  |   PasswordResponses, | ||
|  |   PDFDataRangeTransport, | ||
|  |   PDFDateString, | ||
|  |   PDFWorker, | ||
|  |   PermissionFlag, | ||
|  |   PixelsPerInch, | ||
|  |   RenderingCancelledException, | ||
|  |   setLayerDimensions, | ||
|  |   shadow, | ||
|  |   TextLayer, | ||
|  |   UnexpectedResponseException, | ||
|  |   Util, | ||
|  |   VerbosityLevel, | ||
|  |   version, | ||
|  |   XfaLayer | ||
|  | } = globalThis.pdfjsLib; | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/event_utils.js
 | ||
|  | const WaitOnType = { | ||
|  |   EVENT: "event", | ||
|  |   TIMEOUT: "timeout" | ||
|  | }; | ||
|  | async function waitOnEventOrTimeout({ | ||
|  |   target, | ||
|  |   name, | ||
|  |   delay = 0 | ||
|  | }) { | ||
|  |   if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) { | ||
|  |     throw new Error("waitOnEventOrTimeout - invalid parameters."); | ||
|  |   } | ||
|  |   const { | ||
|  |     promise, | ||
|  |     resolve | ||
|  |   } = Promise.withResolvers(); | ||
|  |   const ac = new AbortController(); | ||
|  |   function handler(type) { | ||
|  |     ac.abort(); | ||
|  |     clearTimeout(timeout); | ||
|  |     resolve(type); | ||
|  |   } | ||
|  |   const evtMethod = target instanceof EventBus ? "_on" : "addEventListener"; | ||
|  |   target[evtMethod](name, handler.bind(null, WaitOnType.EVENT), { | ||
|  |     signal: ac.signal | ||
|  |   }); | ||
|  |   const timeout = setTimeout(handler.bind(null, WaitOnType.TIMEOUT), delay); | ||
|  |   return promise; | ||
|  | } | ||
|  | class EventBus { | ||
|  |   #listeners = Object.create(null); | ||
|  |   on(eventName, listener, options = null) { | ||
|  |     this._on(eventName, listener, { | ||
|  |       external: true, | ||
|  |       once: options?.once, | ||
|  |       signal: options?.signal | ||
|  |     }); | ||
|  |   } | ||
|  |   off(eventName, listener, options = null) { | ||
|  |     this._off(eventName, listener); | ||
|  |   } | ||
|  |   dispatch(eventName, data) { | ||
|  |     const eventListeners = this.#listeners[eventName]; | ||
|  |     if (!eventListeners || eventListeners.length === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let externalListeners; | ||
|  |     for (const { | ||
|  |       listener, | ||
|  |       external, | ||
|  |       once | ||
|  |     } of eventListeners.slice(0)) { | ||
|  |       if (once) { | ||
|  |         this._off(eventName, listener); | ||
|  |       } | ||
|  |       if (external) { | ||
|  |         (externalListeners ||= []).push(listener); | ||
|  |         continue; | ||
|  |       } | ||
|  |       listener(data); | ||
|  |     } | ||
|  |     if (externalListeners) { | ||
|  |       for (const listener of externalListeners) { | ||
|  |         listener(data); | ||
|  |       } | ||
|  |       externalListeners = null; | ||
|  |     } | ||
|  |   } | ||
|  |   _on(eventName, listener, options = null) { | ||
|  |     let rmAbort = null; | ||
|  |     if (options?.signal instanceof AbortSignal) { | ||
|  |       const { | ||
|  |         signal | ||
|  |       } = options; | ||
|  |       if (signal.aborted) { | ||
|  |         console.error("Cannot use an `aborted` signal."); | ||
|  |         return; | ||
|  |       } | ||
|  |       const onAbort = () => this._off(eventName, listener); | ||
|  |       rmAbort = () => signal.removeEventListener("abort", onAbort); | ||
|  |       signal.addEventListener("abort", onAbort); | ||
|  |     } | ||
|  |     const eventListeners = this.#listeners[eventName] ||= []; | ||
|  |     eventListeners.push({ | ||
|  |       listener, | ||
|  |       external: options?.external === true, | ||
|  |       once: options?.once === true, | ||
|  |       rmAbort | ||
|  |     }); | ||
|  |   } | ||
|  |   _off(eventName, listener, options = null) { | ||
|  |     const eventListeners = this.#listeners[eventName]; | ||
|  |     if (!eventListeners) { | ||
|  |       return; | ||
|  |     } | ||
|  |     for (let i = 0, ii = eventListeners.length; i < ii; i++) { | ||
|  |       const evt = eventListeners[i]; | ||
|  |       if (evt.listener === listener) { | ||
|  |         evt.rmAbort?.(); | ||
|  |         eventListeners.splice(i, 1); | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | class FirefoxEventBus extends EventBus { | ||
|  |   #externalServices; | ||
|  |   #globalEventNames; | ||
|  |   #isInAutomation; | ||
|  |   constructor(globalEventNames, externalServices, isInAutomation) { | ||
|  |     super(); | ||
|  |     this.#globalEventNames = globalEventNames; | ||
|  |     this.#externalServices = externalServices; | ||
|  |     this.#isInAutomation = isInAutomation; | ||
|  |   } | ||
|  |   dispatch(eventName, data) { | ||
|  |     throw new Error("Not implemented: FirefoxEventBus.dispatch"); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/external_services.js
 | ||
|  | class BaseExternalServices { | ||
|  |   updateFindControlState(data) {} | ||
|  |   updateFindMatchesCount(data) {} | ||
|  |   initPassiveLoading() {} | ||
|  |   reportTelemetry(data) {} | ||
|  |   async createL10n() { | ||
|  |     throw new Error("Not implemented: createL10n"); | ||
|  |   } | ||
|  |   createScripting() { | ||
|  |     throw new Error("Not implemented: createScripting"); | ||
|  |   } | ||
|  |   updateEditorStates(data) { | ||
|  |     throw new Error("Not implemented: updateEditorStates"); | ||
|  |   } | ||
|  |   dispatchGlobalEvent(_event) {} | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/preferences.js
 | ||
|  | 
 | ||
|  | class BasePreferences { | ||
|  |   #defaults = Object.freeze({ | ||
|  |     altTextLearnMoreUrl: "", | ||
|  |     annotationEditorMode: 0, | ||
|  |     annotationMode: 2, | ||
|  |     cursorToolOnLoad: 0, | ||
|  |     defaultZoomDelay: 400, | ||
|  |     defaultZoomValue: "", | ||
|  |     disablePageLabels: false, | ||
|  |     enableAltText: false, | ||
|  |     enableAltTextModelDownload: true, | ||
|  |     enableGuessAltText: true, | ||
|  |     enableHighlightFloatingButton: false, | ||
|  |     enableNewAltTextWhenAddingImage: true, | ||
|  |     enablePermissions: false, | ||
|  |     enablePrintAutoRotate: true, | ||
|  |     enableScripting: true, | ||
|  |     enableUpdatedAddImage: false, | ||
|  |     externalLinkTarget: 0, | ||
|  |     highlightEditorColors: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F", | ||
|  |     historyUpdateUrl: false, | ||
|  |     ignoreDestinationZoom: false, | ||
|  |     forcePageColors: false, | ||
|  |     pageColorsBackground: "Canvas", | ||
|  |     pageColorsForeground: "CanvasText", | ||
|  |     pdfBugEnabled: false, | ||
|  |     sidebarViewOnLoad: -1, | ||
|  |     scrollModeOnLoad: -1, | ||
|  |     spreadModeOnLoad: -1, | ||
|  |     textLayerMode: 1, | ||
|  |     viewOnLoad: 0, | ||
|  |     disableAutoFetch: false, | ||
|  |     disableFontFace: false, | ||
|  |     disableRange: false, | ||
|  |     disableStream: false, | ||
|  |     enableHWA: true, | ||
|  |     enableXfa: true, | ||
|  |     viewerCssTheme: 0 | ||
|  |   }); | ||
|  |   #initializedPromise = null; | ||
|  |   constructor() { | ||
|  |     this.#initializedPromise = this._readFromStorage(this.#defaults).then(({ | ||
|  |       browserPrefs, | ||
|  |       prefs | ||
|  |     }) => { | ||
|  |       if (AppOptions._checkDisablePreferences()) { | ||
|  |         return; | ||
|  |       } | ||
|  |       AppOptions.setAll({ | ||
|  |         ...browserPrefs, | ||
|  |         ...prefs | ||
|  |       }, true); | ||
|  |     }); | ||
|  |   } | ||
|  |   async _writeToStorage(prefObj) { | ||
|  |     throw new Error("Not implemented: _writeToStorage"); | ||
|  |   } | ||
|  |   async _readFromStorage(prefObj) { | ||
|  |     throw new Error("Not implemented: _readFromStorage"); | ||
|  |   } | ||
|  |   async reset() { | ||
|  |     await this.#initializedPromise; | ||
|  |     AppOptions.setAll(this.#defaults, true); | ||
|  |     await this._writeToStorage(this.#defaults); | ||
|  |   } | ||
|  |   async set(name, value) { | ||
|  |     await this.#initializedPromise; | ||
|  |     AppOptions.setAll({ | ||
|  |       [name]: value | ||
|  |     }, true); | ||
|  |     await this._writeToStorage(AppOptions.getAll(OptionKind.PREFERENCE)); | ||
|  |   } | ||
|  |   async get(name) { | ||
|  |     await this.#initializedPromise; | ||
|  |     return AppOptions.get(name); | ||
|  |   } | ||
|  |   get initializedPromise() { | ||
|  |     return this.#initializedPromise; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/types.js
 | ||
|  | class FluentType { | ||
|  |   constructor(value) { | ||
|  |     this.value = value; | ||
|  |   } | ||
|  |   valueOf() { | ||
|  |     return this.value; | ||
|  |   } | ||
|  | } | ||
|  | class FluentNone extends FluentType { | ||
|  |   constructor(value = "???") { | ||
|  |     super(value); | ||
|  |   } | ||
|  |   toString(scope) { | ||
|  |     return `{${this.value}}`; | ||
|  |   } | ||
|  | } | ||
|  | class FluentNumber extends FluentType { | ||
|  |   constructor(value, opts = {}) { | ||
|  |     super(value); | ||
|  |     this.opts = opts; | ||
|  |   } | ||
|  |   toString(scope) { | ||
|  |     try { | ||
|  |       const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts); | ||
|  |       return nf.format(this.value); | ||
|  |     } catch (err) { | ||
|  |       scope.reportError(err); | ||
|  |       return this.value.toString(10); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | class FluentDateTime extends FluentType { | ||
|  |   constructor(value, opts = {}) { | ||
|  |     super(value); | ||
|  |     this.opts = opts; | ||
|  |   } | ||
|  |   toString(scope) { | ||
|  |     try { | ||
|  |       const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts); | ||
|  |       return dtf.format(this.value); | ||
|  |     } catch (err) { | ||
|  |       scope.reportError(err); | ||
|  |       return new Date(this.value).toISOString(); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/resolver.js
 | ||
|  | 
 | ||
|  | const MAX_PLACEABLES = 100; | ||
|  | const FSI = "\u2068"; | ||
|  | const PDI = "\u2069"; | ||
|  | function match(scope, selector, key) { | ||
|  |   if (key === selector) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   if (key instanceof FluentNumber && selector instanceof FluentNumber && key.value === selector.value) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   if (selector instanceof FluentNumber && typeof key === "string") { | ||
|  |     let category = scope.memoizeIntlObject(Intl.PluralRules, selector.opts).select(selector.value); | ||
|  |     if (key === category) { | ||
|  |       return true; | ||
|  |     } | ||
|  |   } | ||
|  |   return false; | ||
|  | } | ||
|  | function getDefault(scope, variants, star) { | ||
|  |   if (variants[star]) { | ||
|  |     return resolvePattern(scope, variants[star].value); | ||
|  |   } | ||
|  |   scope.reportError(new RangeError("No default")); | ||
|  |   return new FluentNone(); | ||
|  | } | ||
|  | function getArguments(scope, args) { | ||
|  |   const positional = []; | ||
|  |   const named = Object.create(null); | ||
|  |   for (const arg of args) { | ||
|  |     if (arg.type === "narg") { | ||
|  |       named[arg.name] = resolveExpression(scope, arg.value); | ||
|  |     } else { | ||
|  |       positional.push(resolveExpression(scope, arg)); | ||
|  |     } | ||
|  |   } | ||
|  |   return { | ||
|  |     positional, | ||
|  |     named | ||
|  |   }; | ||
|  | } | ||
|  | function resolveExpression(scope, expr) { | ||
|  |   switch (expr.type) { | ||
|  |     case "str": | ||
|  |       return expr.value; | ||
|  |     case "num": | ||
|  |       return new FluentNumber(expr.value, { | ||
|  |         minimumFractionDigits: expr.precision | ||
|  |       }); | ||
|  |     case "var": | ||
|  |       return resolveVariableReference(scope, expr); | ||
|  |     case "mesg": | ||
|  |       return resolveMessageReference(scope, expr); | ||
|  |     case "term": | ||
|  |       return resolveTermReference(scope, expr); | ||
|  |     case "func": | ||
|  |       return resolveFunctionReference(scope, expr); | ||
|  |     case "select": | ||
|  |       return resolveSelectExpression(scope, expr); | ||
|  |     default: | ||
|  |       return new FluentNone(); | ||
|  |   } | ||
|  | } | ||
|  | function resolveVariableReference(scope, { | ||
|  |   name | ||
|  | }) { | ||
|  |   let arg; | ||
|  |   if (scope.params) { | ||
|  |     if (Object.prototype.hasOwnProperty.call(scope.params, name)) { | ||
|  |       arg = scope.params[name]; | ||
|  |     } else { | ||
|  |       return new FluentNone(`$${name}`); | ||
|  |     } | ||
|  |   } else if (scope.args && Object.prototype.hasOwnProperty.call(scope.args, name)) { | ||
|  |     arg = scope.args[name]; | ||
|  |   } else { | ||
|  |     scope.reportError(new ReferenceError(`Unknown variable: $${name}`)); | ||
|  |     return new FluentNone(`$${name}`); | ||
|  |   } | ||
|  |   if (arg instanceof FluentType) { | ||
|  |     return arg; | ||
|  |   } | ||
|  |   switch (typeof arg) { | ||
|  |     case "string": | ||
|  |       return arg; | ||
|  |     case "number": | ||
|  |       return new FluentNumber(arg); | ||
|  |     case "object": | ||
|  |       if (arg instanceof Date) { | ||
|  |         return new FluentDateTime(arg.getTime()); | ||
|  |       } | ||
|  |     default: | ||
|  |       scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`)); | ||
|  |       return new FluentNone(`$${name}`); | ||
|  |   } | ||
|  | } | ||
|  | function resolveMessageReference(scope, { | ||
|  |   name, | ||
|  |   attr | ||
|  | }) { | ||
|  |   const message = scope.bundle._messages.get(name); | ||
|  |   if (!message) { | ||
|  |     scope.reportError(new ReferenceError(`Unknown message: ${name}`)); | ||
|  |     return new FluentNone(name); | ||
|  |   } | ||
|  |   if (attr) { | ||
|  |     const attribute = message.attributes[attr]; | ||
|  |     if (attribute) { | ||
|  |       return resolvePattern(scope, attribute); | ||
|  |     } | ||
|  |     scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`)); | ||
|  |     return new FluentNone(`${name}.${attr}`); | ||
|  |   } | ||
|  |   if (message.value) { | ||
|  |     return resolvePattern(scope, message.value); | ||
|  |   } | ||
|  |   scope.reportError(new ReferenceError(`No value: ${name}`)); | ||
|  |   return new FluentNone(name); | ||
|  | } | ||
|  | function resolveTermReference(scope, { | ||
|  |   name, | ||
|  |   attr, | ||
|  |   args | ||
|  | }) { | ||
|  |   const id = `-${name}`; | ||
|  |   const term = scope.bundle._terms.get(id); | ||
|  |   if (!term) { | ||
|  |     scope.reportError(new ReferenceError(`Unknown term: ${id}`)); | ||
|  |     return new FluentNone(id); | ||
|  |   } | ||
|  |   if (attr) { | ||
|  |     const attribute = term.attributes[attr]; | ||
|  |     if (attribute) { | ||
|  |       scope.params = getArguments(scope, args).named; | ||
|  |       const resolved = resolvePattern(scope, attribute); | ||
|  |       scope.params = null; | ||
|  |       return resolved; | ||
|  |     } | ||
|  |     scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`)); | ||
|  |     return new FluentNone(`${id}.${attr}`); | ||
|  |   } | ||
|  |   scope.params = getArguments(scope, args).named; | ||
|  |   const resolved = resolvePattern(scope, term.value); | ||
|  |   scope.params = null; | ||
|  |   return resolved; | ||
|  | } | ||
|  | function resolveFunctionReference(scope, { | ||
|  |   name, | ||
|  |   args | ||
|  | }) { | ||
|  |   let func = scope.bundle._functions[name]; | ||
|  |   if (!func) { | ||
|  |     scope.reportError(new ReferenceError(`Unknown function: ${name}()`)); | ||
|  |     return new FluentNone(`${name}()`); | ||
|  |   } | ||
|  |   if (typeof func !== "function") { | ||
|  |     scope.reportError(new TypeError(`Function ${name}() is not callable`)); | ||
|  |     return new FluentNone(`${name}()`); | ||
|  |   } | ||
|  |   try { | ||
|  |     let resolved = getArguments(scope, args); | ||
|  |     return func(resolved.positional, resolved.named); | ||
|  |   } catch (err) { | ||
|  |     scope.reportError(err); | ||
|  |     return new FluentNone(`${name}()`); | ||
|  |   } | ||
|  | } | ||
|  | function resolveSelectExpression(scope, { | ||
|  |   selector, | ||
|  |   variants, | ||
|  |   star | ||
|  | }) { | ||
|  |   let sel = resolveExpression(scope, selector); | ||
|  |   if (sel instanceof FluentNone) { | ||
|  |     return getDefault(scope, variants, star); | ||
|  |   } | ||
|  |   for (const variant of variants) { | ||
|  |     const key = resolveExpression(scope, variant.key); | ||
|  |     if (match(scope, sel, key)) { | ||
|  |       return resolvePattern(scope, variant.value); | ||
|  |     } | ||
|  |   } | ||
|  |   return getDefault(scope, variants, star); | ||
|  | } | ||
|  | function resolveComplexPattern(scope, ptn) { | ||
|  |   if (scope.dirty.has(ptn)) { | ||
|  |     scope.reportError(new RangeError("Cyclic reference")); | ||
|  |     return new FluentNone(); | ||
|  |   } | ||
|  |   scope.dirty.add(ptn); | ||
|  |   const result = []; | ||
|  |   const useIsolating = scope.bundle._useIsolating && ptn.length > 1; | ||
|  |   for (const elem of ptn) { | ||
|  |     if (typeof elem === "string") { | ||
|  |       result.push(scope.bundle._transform(elem)); | ||
|  |       continue; | ||
|  |     } | ||
|  |     scope.placeables++; | ||
|  |     if (scope.placeables > MAX_PLACEABLES) { | ||
|  |       scope.dirty.delete(ptn); | ||
|  |       throw new RangeError(`Too many placeables expanded: ${scope.placeables}, ` + `max allowed is ${MAX_PLACEABLES}`); | ||
|  |     } | ||
|  |     if (useIsolating) { | ||
|  |       result.push(FSI); | ||
|  |     } | ||
|  |     result.push(resolveExpression(scope, elem).toString(scope)); | ||
|  |     if (useIsolating) { | ||
|  |       result.push(PDI); | ||
|  |     } | ||
|  |   } | ||
|  |   scope.dirty.delete(ptn); | ||
|  |   return result.join(""); | ||
|  | } | ||
|  | function resolvePattern(scope, value) { | ||
|  |   if (typeof value === "string") { | ||
|  |     return scope.bundle._transform(value); | ||
|  |   } | ||
|  |   return resolveComplexPattern(scope, value); | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/scope.js
 | ||
|  | class Scope { | ||
|  |   constructor(bundle, errors, args) { | ||
|  |     this.dirty = new WeakSet(); | ||
|  |     this.params = null; | ||
|  |     this.placeables = 0; | ||
|  |     this.bundle = bundle; | ||
|  |     this.errors = errors; | ||
|  |     this.args = args; | ||
|  |   } | ||
|  |   reportError(error) { | ||
|  |     if (!this.errors || !(error instanceof Error)) { | ||
|  |       throw error; | ||
|  |     } | ||
|  |     this.errors.push(error); | ||
|  |   } | ||
|  |   memoizeIntlObject(ctor, opts) { | ||
|  |     let cache = this.bundle._intls.get(ctor); | ||
|  |     if (!cache) { | ||
|  |       cache = {}; | ||
|  |       this.bundle._intls.set(ctor, cache); | ||
|  |     } | ||
|  |     let id = JSON.stringify(opts); | ||
|  |     if (!cache[id]) { | ||
|  |       cache[id] = new ctor(this.bundle.locales, opts); | ||
|  |     } | ||
|  |     return cache[id]; | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/builtins.js
 | ||
|  | 
 | ||
|  | function values(opts, allowed) { | ||
|  |   const unwrapped = Object.create(null); | ||
|  |   for (const [name, opt] of Object.entries(opts)) { | ||
|  |     if (allowed.includes(name)) { | ||
|  |       unwrapped[name] = opt.valueOf(); | ||
|  |     } | ||
|  |   } | ||
|  |   return unwrapped; | ||
|  | } | ||
|  | const NUMBER_ALLOWED = ["unitDisplay", "currencyDisplay", "useGrouping", "minimumIntegerDigits", "minimumFractionDigits", "maximumFractionDigits", "minimumSignificantDigits", "maximumSignificantDigits"]; | ||
|  | function NUMBER(args, opts) { | ||
|  |   let arg = args[0]; | ||
|  |   if (arg instanceof FluentNone) { | ||
|  |     return new FluentNone(`NUMBER(${arg.valueOf()})`); | ||
|  |   } | ||
|  |   if (arg instanceof FluentNumber) { | ||
|  |     return new FluentNumber(arg.valueOf(), { | ||
|  |       ...arg.opts, | ||
|  |       ...values(opts, NUMBER_ALLOWED) | ||
|  |     }); | ||
|  |   } | ||
|  |   if (arg instanceof FluentDateTime) { | ||
|  |     return new FluentNumber(arg.valueOf(), { | ||
|  |       ...values(opts, NUMBER_ALLOWED) | ||
|  |     }); | ||
|  |   } | ||
|  |   throw new TypeError("Invalid argument to NUMBER"); | ||
|  | } | ||
|  | const DATETIME_ALLOWED = ["dateStyle", "timeStyle", "fractionalSecondDigits", "dayPeriod", "hour12", "weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"]; | ||
|  | function DATETIME(args, opts) { | ||
|  |   let arg = args[0]; | ||
|  |   if (arg instanceof FluentNone) { | ||
|  |     return new FluentNone(`DATETIME(${arg.valueOf()})`); | ||
|  |   } | ||
|  |   if (arg instanceof FluentDateTime) { | ||
|  |     return new FluentDateTime(arg.valueOf(), { | ||
|  |       ...arg.opts, | ||
|  |       ...values(opts, DATETIME_ALLOWED) | ||
|  |     }); | ||
|  |   } | ||
|  |   if (arg instanceof FluentNumber) { | ||
|  |     return new FluentDateTime(arg.valueOf(), { | ||
|  |       ...values(opts, DATETIME_ALLOWED) | ||
|  |     }); | ||
|  |   } | ||
|  |   throw new TypeError("Invalid argument to DATETIME"); | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/memoizer.js
 | ||
|  | const cache = new Map(); | ||
|  | function getMemoizerForLocale(locales) { | ||
|  |   const stringLocale = Array.isArray(locales) ? locales.join(" ") : locales; | ||
|  |   let memoizer = cache.get(stringLocale); | ||
|  |   if (memoizer === undefined) { | ||
|  |     memoizer = new Map(); | ||
|  |     cache.set(stringLocale, memoizer); | ||
|  |   } | ||
|  |   return memoizer; | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/bundle.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class FluentBundle { | ||
|  |   constructor(locales, { | ||
|  |     functions, | ||
|  |     useIsolating = true, | ||
|  |     transform = v => v | ||
|  |   } = {}) { | ||
|  |     this._terms = new Map(); | ||
|  |     this._messages = new Map(); | ||
|  |     this.locales = Array.isArray(locales) ? locales : [locales]; | ||
|  |     this._functions = { | ||
|  |       NUMBER: NUMBER, | ||
|  |       DATETIME: DATETIME, | ||
|  |       ...functions | ||
|  |     }; | ||
|  |     this._useIsolating = useIsolating; | ||
|  |     this._transform = transform; | ||
|  |     this._intls = getMemoizerForLocale(locales); | ||
|  |   } | ||
|  |   hasMessage(id) { | ||
|  |     return this._messages.has(id); | ||
|  |   } | ||
|  |   getMessage(id) { | ||
|  |     return this._messages.get(id); | ||
|  |   } | ||
|  |   addResource(res, { | ||
|  |     allowOverrides = false | ||
|  |   } = {}) { | ||
|  |     const errors = []; | ||
|  |     for (let i = 0; i < res.body.length; i++) { | ||
|  |       let entry = res.body[i]; | ||
|  |       if (entry.id.startsWith("-")) { | ||
|  |         if (allowOverrides === false && this._terms.has(entry.id)) { | ||
|  |           errors.push(new Error(`Attempt to override an existing term: "${entry.id}"`)); | ||
|  |           continue; | ||
|  |         } | ||
|  |         this._terms.set(entry.id, entry); | ||
|  |       } else { | ||
|  |         if (allowOverrides === false && this._messages.has(entry.id)) { | ||
|  |           errors.push(new Error(`Attempt to override an existing message: "${entry.id}"`)); | ||
|  |           continue; | ||
|  |         } | ||
|  |         this._messages.set(entry.id, entry); | ||
|  |       } | ||
|  |     } | ||
|  |     return errors; | ||
|  |   } | ||
|  |   formatPattern(pattern, args = null, errors = null) { | ||
|  |     if (typeof pattern === "string") { | ||
|  |       return this._transform(pattern); | ||
|  |     } | ||
|  |     let scope = new Scope(this, errors, args); | ||
|  |     try { | ||
|  |       let value = resolveComplexPattern(scope, pattern); | ||
|  |       return value.toString(scope); | ||
|  |     } catch (err) { | ||
|  |       if (scope.errors && err instanceof Error) { | ||
|  |         scope.errors.push(err); | ||
|  |         return new FluentNone().toString(scope); | ||
|  |       } | ||
|  |       throw err; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/resource.js
 | ||
|  | const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */gm; | ||
|  | const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y; | ||
|  | const RE_VARIANT_START = /\*?\[/y; | ||
|  | const RE_NUMBER_LITERAL = /(-?[0-9]+(?:\.([0-9]+))?)/y; | ||
|  | const RE_IDENTIFIER = /([a-zA-Z][\w-]*)/y; | ||
|  | const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y; | ||
|  | const RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/; | ||
|  | const RE_TEXT_RUN = /([^{}\n\r]+)/y; | ||
|  | const RE_STRING_RUN = /([^\\"\n\r]*)/y; | ||
|  | const RE_STRING_ESCAPE = /\\([\\"])/y; | ||
|  | const RE_UNICODE_ESCAPE = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{6})/y; | ||
|  | const RE_LEADING_NEWLINES = /^\n+/; | ||
|  | const RE_TRAILING_SPACES = / +$/; | ||
|  | const RE_BLANK_LINES = / *\r?\n/g; | ||
|  | const RE_INDENT = /( *)$/; | ||
|  | const TOKEN_BRACE_OPEN = /{\s*/y; | ||
|  | const TOKEN_BRACE_CLOSE = /\s*}/y; | ||
|  | const TOKEN_BRACKET_OPEN = /\[\s*/y; | ||
|  | const TOKEN_BRACKET_CLOSE = /\s*] */y; | ||
|  | const TOKEN_PAREN_OPEN = /\s*\(\s*/y; | ||
|  | const TOKEN_ARROW = /\s*->\s*/y; | ||
|  | const TOKEN_COLON = /\s*:\s*/y; | ||
|  | const TOKEN_COMMA = /\s*,?\s*/y; | ||
|  | const TOKEN_BLANK = /\s+/y; | ||
|  | class FluentResource { | ||
|  |   constructor(source) { | ||
|  |     this.body = []; | ||
|  |     RE_MESSAGE_START.lastIndex = 0; | ||
|  |     let cursor = 0; | ||
|  |     while (true) { | ||
|  |       let next = RE_MESSAGE_START.exec(source); | ||
|  |       if (next === null) { | ||
|  |         break; | ||
|  |       } | ||
|  |       cursor = RE_MESSAGE_START.lastIndex; | ||
|  |       try { | ||
|  |         this.body.push(parseMessage(next[1])); | ||
|  |       } catch (err) { | ||
|  |         if (err instanceof SyntaxError) { | ||
|  |           continue; | ||
|  |         } | ||
|  |         throw err; | ||
|  |       } | ||
|  |     } | ||
|  |     function test(re) { | ||
|  |       re.lastIndex = cursor; | ||
|  |       return re.test(source); | ||
|  |     } | ||
|  |     function consumeChar(char, errorClass) { | ||
|  |       if (source[cursor] === char) { | ||
|  |         cursor++; | ||
|  |         return true; | ||
|  |       } | ||
|  |       if (errorClass) { | ||
|  |         throw new errorClass(`Expected ${char}`); | ||
|  |       } | ||
|  |       return false; | ||
|  |     } | ||
|  |     function consumeToken(re, errorClass) { | ||
|  |       if (test(re)) { | ||
|  |         cursor = re.lastIndex; | ||
|  |         return true; | ||
|  |       } | ||
|  |       if (errorClass) { | ||
|  |         throw new errorClass(`Expected ${re.toString()}`); | ||
|  |       } | ||
|  |       return false; | ||
|  |     } | ||
|  |     function match(re) { | ||
|  |       re.lastIndex = cursor; | ||
|  |       let result = re.exec(source); | ||
|  |       if (result === null) { | ||
|  |         throw new SyntaxError(`Expected ${re.toString()}`); | ||
|  |       } | ||
|  |       cursor = re.lastIndex; | ||
|  |       return result; | ||
|  |     } | ||
|  |     function match1(re) { | ||
|  |       return match(re)[1]; | ||
|  |     } | ||
|  |     function parseMessage(id) { | ||
|  |       let value = parsePattern(); | ||
|  |       let attributes = parseAttributes(); | ||
|  |       if (value === null && Object.keys(attributes).length === 0) { | ||
|  |         throw new SyntaxError("Expected message value or attributes"); | ||
|  |       } | ||
|  |       return { | ||
|  |         id, | ||
|  |         value, | ||
|  |         attributes | ||
|  |       }; | ||
|  |     } | ||
|  |     function parseAttributes() { | ||
|  |       let attrs = Object.create(null); | ||
|  |       while (test(RE_ATTRIBUTE_START)) { | ||
|  |         let name = match1(RE_ATTRIBUTE_START); | ||
|  |         let value = parsePattern(); | ||
|  |         if (value === null) { | ||
|  |           throw new SyntaxError("Expected attribute value"); | ||
|  |         } | ||
|  |         attrs[name] = value; | ||
|  |       } | ||
|  |       return attrs; | ||
|  |     } | ||
|  |     function parsePattern() { | ||
|  |       let first; | ||
|  |       if (test(RE_TEXT_RUN)) { | ||
|  |         first = match1(RE_TEXT_RUN); | ||
|  |       } | ||
|  |       if (source[cursor] === "{" || source[cursor] === "}") { | ||
|  |         return parsePatternElements(first ? [first] : [], Infinity); | ||
|  |       } | ||
|  |       let indent = parseIndent(); | ||
|  |       if (indent) { | ||
|  |         if (first) { | ||
|  |           return parsePatternElements([first, indent], indent.length); | ||
|  |         } | ||
|  |         indent.value = trim(indent.value, RE_LEADING_NEWLINES); | ||
|  |         return parsePatternElements([indent], indent.length); | ||
|  |       } | ||
|  |       if (first) { | ||
|  |         return trim(first, RE_TRAILING_SPACES); | ||
|  |       } | ||
|  |       return null; | ||
|  |     } | ||
|  |     function parsePatternElements(elements = [], commonIndent) { | ||
|  |       while (true) { | ||
|  |         if (test(RE_TEXT_RUN)) { | ||
|  |           elements.push(match1(RE_TEXT_RUN)); | ||
|  |           continue; | ||
|  |         } | ||
|  |         if (source[cursor] === "{") { | ||
|  |           elements.push(parsePlaceable()); | ||
|  |           continue; | ||
|  |         } | ||
|  |         if (source[cursor] === "}") { | ||
|  |           throw new SyntaxError("Unbalanced closing brace"); | ||
|  |         } | ||
|  |         let indent = parseIndent(); | ||
|  |         if (indent) { | ||
|  |           elements.push(indent); | ||
|  |           commonIndent = Math.min(commonIndent, indent.length); | ||
|  |           continue; | ||
|  |         } | ||
|  |         break; | ||
|  |       } | ||
|  |       let lastIndex = elements.length - 1; | ||
|  |       let lastElement = elements[lastIndex]; | ||
|  |       if (typeof lastElement === "string") { | ||
|  |         elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES); | ||
|  |       } | ||
|  |       let baked = []; | ||
|  |       for (let element of elements) { | ||
|  |         if (element instanceof Indent) { | ||
|  |           element = element.value.slice(0, element.value.length - commonIndent); | ||
|  |         } | ||
|  |         if (element) { | ||
|  |           baked.push(element); | ||
|  |         } | ||
|  |       } | ||
|  |       return baked; | ||
|  |     } | ||
|  |     function parsePlaceable() { | ||
|  |       consumeToken(TOKEN_BRACE_OPEN, SyntaxError); | ||
|  |       let selector = parseInlineExpression(); | ||
|  |       if (consumeToken(TOKEN_BRACE_CLOSE)) { | ||
|  |         return selector; | ||
|  |       } | ||
|  |       if (consumeToken(TOKEN_ARROW)) { | ||
|  |         let variants = parseVariants(); | ||
|  |         consumeToken(TOKEN_BRACE_CLOSE, SyntaxError); | ||
|  |         return { | ||
|  |           type: "select", | ||
|  |           selector, | ||
|  |           ...variants | ||
|  |         }; | ||
|  |       } | ||
|  |       throw new SyntaxError("Unclosed placeable"); | ||
|  |     } | ||
|  |     function parseInlineExpression() { | ||
|  |       if (source[cursor] === "{") { | ||
|  |         return parsePlaceable(); | ||
|  |       } | ||
|  |       if (test(RE_REFERENCE)) { | ||
|  |         let [, sigil, name, attr = null] = match(RE_REFERENCE); | ||
|  |         if (sigil === "$") { | ||
|  |           return { | ||
|  |             type: "var", | ||
|  |             name | ||
|  |           }; | ||
|  |         } | ||
|  |         if (consumeToken(TOKEN_PAREN_OPEN)) { | ||
|  |           let args = parseArguments(); | ||
|  |           if (sigil === "-") { | ||
|  |             return { | ||
|  |               type: "term", | ||
|  |               name, | ||
|  |               attr, | ||
|  |               args | ||
|  |             }; | ||
|  |           } | ||
|  |           if (RE_FUNCTION_NAME.test(name)) { | ||
|  |             return { | ||
|  |               type: "func", | ||
|  |               name, | ||
|  |               args | ||
|  |             }; | ||
|  |           } | ||
|  |           throw new SyntaxError("Function names must be all upper-case"); | ||
|  |         } | ||
|  |         if (sigil === "-") { | ||
|  |           return { | ||
|  |             type: "term", | ||
|  |             name, | ||
|  |             attr, | ||
|  |             args: [] | ||
|  |           }; | ||
|  |         } | ||
|  |         return { | ||
|  |           type: "mesg", | ||
|  |           name, | ||
|  |           attr | ||
|  |         }; | ||
|  |       } | ||
|  |       return parseLiteral(); | ||
|  |     } | ||
|  |     function parseArguments() { | ||
|  |       let args = []; | ||
|  |       while (true) { | ||
|  |         switch (source[cursor]) { | ||
|  |           case ")": | ||
|  |             cursor++; | ||
|  |             return args; | ||
|  |           case undefined: | ||
|  |             throw new SyntaxError("Unclosed argument list"); | ||
|  |         } | ||
|  |         args.push(parseArgument()); | ||
|  |         consumeToken(TOKEN_COMMA); | ||
|  |       } | ||
|  |     } | ||
|  |     function parseArgument() { | ||
|  |       let expr = parseInlineExpression(); | ||
|  |       if (expr.type !== "mesg") { | ||
|  |         return expr; | ||
|  |       } | ||
|  |       if (consumeToken(TOKEN_COLON)) { | ||
|  |         return { | ||
|  |           type: "narg", | ||
|  |           name: expr.name, | ||
|  |           value: parseLiteral() | ||
|  |         }; | ||
|  |       } | ||
|  |       return expr; | ||
|  |     } | ||
|  |     function parseVariants() { | ||
|  |       let variants = []; | ||
|  |       let count = 0; | ||
|  |       let star; | ||
|  |       while (test(RE_VARIANT_START)) { | ||
|  |         if (consumeChar("*")) { | ||
|  |           star = count; | ||
|  |         } | ||
|  |         let key = parseVariantKey(); | ||
|  |         let value = parsePattern(); | ||
|  |         if (value === null) { | ||
|  |           throw new SyntaxError("Expected variant value"); | ||
|  |         } | ||
|  |         variants[count++] = { | ||
|  |           key, | ||
|  |           value | ||
|  |         }; | ||
|  |       } | ||
|  |       if (count === 0) { | ||
|  |         return null; | ||
|  |       } | ||
|  |       if (star === undefined) { | ||
|  |         throw new SyntaxError("Expected default variant"); | ||
|  |       } | ||
|  |       return { | ||
|  |         variants, | ||
|  |         star | ||
|  |       }; | ||
|  |     } | ||
|  |     function parseVariantKey() { | ||
|  |       consumeToken(TOKEN_BRACKET_OPEN, SyntaxError); | ||
|  |       let key; | ||
|  |       if (test(RE_NUMBER_LITERAL)) { | ||
|  |         key = parseNumberLiteral(); | ||
|  |       } else { | ||
|  |         key = { | ||
|  |           type: "str", | ||
|  |           value: match1(RE_IDENTIFIER) | ||
|  |         }; | ||
|  |       } | ||
|  |       consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError); | ||
|  |       return key; | ||
|  |     } | ||
|  |     function parseLiteral() { | ||
|  |       if (test(RE_NUMBER_LITERAL)) { | ||
|  |         return parseNumberLiteral(); | ||
|  |       } | ||
|  |       if (source[cursor] === '"') { | ||
|  |         return parseStringLiteral(); | ||
|  |       } | ||
|  |       throw new SyntaxError("Invalid expression"); | ||
|  |     } | ||
|  |     function parseNumberLiteral() { | ||
|  |       let [, value, fraction = ""] = match(RE_NUMBER_LITERAL); | ||
|  |       let precision = fraction.length; | ||
|  |       return { | ||
|  |         type: "num", | ||
|  |         value: parseFloat(value), | ||
|  |         precision | ||
|  |       }; | ||
|  |     } | ||
|  |     function parseStringLiteral() { | ||
|  |       consumeChar('"', SyntaxError); | ||
|  |       let value = ""; | ||
|  |       while (true) { | ||
|  |         value += match1(RE_STRING_RUN); | ||
|  |         if (source[cursor] === "\\") { | ||
|  |           value += parseEscapeSequence(); | ||
|  |           continue; | ||
|  |         } | ||
|  |         if (consumeChar('"')) { | ||
|  |           return { | ||
|  |             type: "str", | ||
|  |             value | ||
|  |           }; | ||
|  |         } | ||
|  |         throw new SyntaxError("Unclosed string literal"); | ||
|  |       } | ||
|  |     } | ||
|  |     function parseEscapeSequence() { | ||
|  |       if (test(RE_STRING_ESCAPE)) { | ||
|  |         return match1(RE_STRING_ESCAPE); | ||
|  |       } | ||
|  |       if (test(RE_UNICODE_ESCAPE)) { | ||
|  |         let [, codepoint4, codepoint6] = match(RE_UNICODE_ESCAPE); | ||
|  |         let codepoint = parseInt(codepoint4 || codepoint6, 16); | ||
|  |         return codepoint <= 0xd7ff || 0xe000 <= codepoint ? String.fromCodePoint(codepoint) : "�"; | ||
|  |       } | ||
|  |       throw new SyntaxError("Unknown escape sequence"); | ||
|  |     } | ||
|  |     function parseIndent() { | ||
|  |       let start = cursor; | ||
|  |       consumeToken(TOKEN_BLANK); | ||
|  |       switch (source[cursor]) { | ||
|  |         case ".": | ||
|  |         case "[": | ||
|  |         case "*": | ||
|  |         case "}": | ||
|  |         case undefined: | ||
|  |           return false; | ||
|  |         case "{": | ||
|  |           return makeIndent(source.slice(start, cursor)); | ||
|  |       } | ||
|  |       if (source[cursor - 1] === " ") { | ||
|  |         return makeIndent(source.slice(start, cursor)); | ||
|  |       } | ||
|  |       return false; | ||
|  |     } | ||
|  |     function trim(text, re) { | ||
|  |       return text.replace(re, ""); | ||
|  |     } | ||
|  |     function makeIndent(blank) { | ||
|  |       let value = blank.replace(RE_BLANK_LINES, "\n"); | ||
|  |       let length = RE_INDENT.exec(blank)[1].length; | ||
|  |       return new Indent(value, length); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | class Indent { | ||
|  |   constructor(value, length) { | ||
|  |     this.value = value; | ||
|  |     this.length = length; | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/index.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/dom/esm/overlay.js
 | ||
|  | const reOverlay = /<|&#?\w+;/; | ||
|  | const TEXT_LEVEL_ELEMENTS = { | ||
|  |   "http://www.w3.org/1999/xhtml": ["em", "strong", "small", "s", "cite", "q", "dfn", "abbr", "data", "time", "code", "var", "samp", "kbd", "sub", "sup", "i", "b", "u", "mark", "bdi", "bdo", "span", "br", "wbr"] | ||
|  | }; | ||
|  | const LOCALIZABLE_ATTRIBUTES = { | ||
|  |   "http://www.w3.org/1999/xhtml": { | ||
|  |     global: ["title", "aria-label", "aria-valuetext"], | ||
|  |     a: ["download"], | ||
|  |     area: ["download", "alt"], | ||
|  |     input: ["alt", "placeholder"], | ||
|  |     menuitem: ["label"], | ||
|  |     menu: ["label"], | ||
|  |     optgroup: ["label"], | ||
|  |     option: ["label"], | ||
|  |     track: ["label"], | ||
|  |     img: ["alt"], | ||
|  |     textarea: ["placeholder"], | ||
|  |     th: ["abbr"] | ||
|  |   }, | ||
|  |   "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": { | ||
|  |     global: ["accesskey", "aria-label", "aria-valuetext", "label", "title", "tooltiptext"], | ||
|  |     description: ["value"], | ||
|  |     key: ["key", "keycode"], | ||
|  |     label: ["value"], | ||
|  |     textbox: ["placeholder", "value"] | ||
|  |   } | ||
|  | }; | ||
|  | function translateElement(element, translation) { | ||
|  |   const { | ||
|  |     value | ||
|  |   } = translation; | ||
|  |   if (typeof value === "string") { | ||
|  |     if (element.localName === "title" && element.namespaceURI === "http://www.w3.org/1999/xhtml") { | ||
|  |       element.textContent = value; | ||
|  |     } else if (!reOverlay.test(value)) { | ||
|  |       element.textContent = value; | ||
|  |     } else { | ||
|  |       const templateElement = element.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml", "template"); | ||
|  |       templateElement.innerHTML = value; | ||
|  |       overlayChildNodes(templateElement.content, element); | ||
|  |     } | ||
|  |   } | ||
|  |   overlayAttributes(translation, element); | ||
|  | } | ||
|  | function overlayChildNodes(fromFragment, toElement) { | ||
|  |   for (const childNode of fromFragment.childNodes) { | ||
|  |     if (childNode.nodeType === childNode.TEXT_NODE) { | ||
|  |       continue; | ||
|  |     } | ||
|  |     if (childNode.hasAttribute("data-l10n-name")) { | ||
|  |       const sanitized = getNodeForNamedElement(toElement, childNode); | ||
|  |       fromFragment.replaceChild(sanitized, childNode); | ||
|  |       continue; | ||
|  |     } | ||
|  |     if (isElementAllowed(childNode)) { | ||
|  |       const sanitized = createSanitizedElement(childNode); | ||
|  |       fromFragment.replaceChild(sanitized, childNode); | ||
|  |       continue; | ||
|  |     } | ||
|  |     console.warn(`An element of forbidden type "${childNode.localName}" was found in ` + "the translation. Only safe text-level elements and elements with " + "data-l10n-name are allowed."); | ||
|  |     fromFragment.replaceChild(createTextNodeFromTextContent(childNode), childNode); | ||
|  |   } | ||
|  |   toElement.textContent = ""; | ||
|  |   toElement.appendChild(fromFragment); | ||
|  | } | ||
|  | function hasAttribute(attributes, name) { | ||
|  |   if (!attributes) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   for (let attr of attributes) { | ||
|  |     if (attr.name === name) { | ||
|  |       return true; | ||
|  |     } | ||
|  |   } | ||
|  |   return false; | ||
|  | } | ||
|  | function overlayAttributes(fromElement, toElement) { | ||
|  |   const explicitlyAllowed = toElement.hasAttribute("data-l10n-attrs") ? toElement.getAttribute("data-l10n-attrs").split(",").map(i => i.trim()) : null; | ||
|  |   for (const attr of Array.from(toElement.attributes)) { | ||
|  |     if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && !hasAttribute(fromElement.attributes, attr.name)) { | ||
|  |       toElement.removeAttribute(attr.name); | ||
|  |     } | ||
|  |   } | ||
|  |   if (!fromElement.attributes) { | ||
|  |     return; | ||
|  |   } | ||
|  |   for (const attr of Array.from(fromElement.attributes)) { | ||
|  |     if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && toElement.getAttribute(attr.name) !== attr.value) { | ||
|  |       toElement.setAttribute(attr.name, attr.value); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | function getNodeForNamedElement(sourceElement, translatedChild) { | ||
|  |   const childName = translatedChild.getAttribute("data-l10n-name"); | ||
|  |   const sourceChild = sourceElement.querySelector(`[data-l10n-name="${childName}"]`); | ||
|  |   if (!sourceChild) { | ||
|  |     console.warn(`An element named "${childName}" wasn't found in the source.`); | ||
|  |     return createTextNodeFromTextContent(translatedChild); | ||
|  |   } | ||
|  |   if (sourceChild.localName !== translatedChild.localName) { | ||
|  |     console.warn(`An element named "${childName}" was found in the translation ` + `but its type ${translatedChild.localName} didn't match the ` + `element found in the source (${sourceChild.localName}).`); | ||
|  |     return createTextNodeFromTextContent(translatedChild); | ||
|  |   } | ||
|  |   sourceElement.removeChild(sourceChild); | ||
|  |   const clone = sourceChild.cloneNode(false); | ||
|  |   return shallowPopulateUsing(translatedChild, clone); | ||
|  | } | ||
|  | function createSanitizedElement(element) { | ||
|  |   const clone = element.ownerDocument.createElement(element.localName); | ||
|  |   return shallowPopulateUsing(element, clone); | ||
|  | } | ||
|  | function createTextNodeFromTextContent(element) { | ||
|  |   return element.ownerDocument.createTextNode(element.textContent); | ||
|  | } | ||
|  | function isElementAllowed(element) { | ||
|  |   const allowed = TEXT_LEVEL_ELEMENTS[element.namespaceURI]; | ||
|  |   return allowed && allowed.includes(element.localName); | ||
|  | } | ||
|  | function isAttrNameLocalizable(name, element, explicitlyAllowed = null) { | ||
|  |   if (explicitlyAllowed && explicitlyAllowed.includes(name)) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   const allowed = LOCALIZABLE_ATTRIBUTES[element.namespaceURI]; | ||
|  |   if (!allowed) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   const attrName = name.toLowerCase(); | ||
|  |   const elemName = element.localName; | ||
|  |   if (allowed.global.includes(attrName)) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   if (!allowed[elemName]) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   if (allowed[elemName].includes(attrName)) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   if (element.namespaceURI === "http://www.w3.org/1999/xhtml" && elemName === "input" && attrName === "value") { | ||
|  |     const type = element.type.toLowerCase(); | ||
|  |     if (type === "submit" || type === "button" || type === "reset") { | ||
|  |       return true; | ||
|  |     } | ||
|  |   } | ||
|  |   return false; | ||
|  | } | ||
|  | function shallowPopulateUsing(fromElement, toElement) { | ||
|  |   toElement.textContent = fromElement.textContent; | ||
|  |   overlayAttributes(fromElement, toElement); | ||
|  |   return toElement; | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/cached-iterable/src/cached_iterable.mjs
 | ||
|  | class CachedIterable extends Array { | ||
|  |   static from(iterable) { | ||
|  |     if (iterable instanceof this) { | ||
|  |       return iterable; | ||
|  |     } | ||
|  |     return new this(iterable); | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/cached-iterable/src/cached_sync_iterable.mjs
 | ||
|  | 
 | ||
|  | class CachedSyncIterable extends CachedIterable { | ||
|  |   constructor(iterable) { | ||
|  |     super(); | ||
|  |     if (Symbol.iterator in Object(iterable)) { | ||
|  |       this.iterator = iterable[Symbol.iterator](); | ||
|  |     } else { | ||
|  |       throw new TypeError("Argument must implement the iteration protocol."); | ||
|  |     } | ||
|  |   } | ||
|  |   [Symbol.iterator]() { | ||
|  |     const cached = this; | ||
|  |     let cur = 0; | ||
|  |     return { | ||
|  |       next() { | ||
|  |         if (cached.length <= cur) { | ||
|  |           cached.push(cached.iterator.next()); | ||
|  |         } | ||
|  |         return cached[cur++]; | ||
|  |       } | ||
|  |     }; | ||
|  |   } | ||
|  |   touchNext(count = 1) { | ||
|  |     let idx = 0; | ||
|  |     while (idx++ < count) { | ||
|  |       const last = this[this.length - 1]; | ||
|  |       if (last && last.done) { | ||
|  |         break; | ||
|  |       } | ||
|  |       this.push(this.iterator.next()); | ||
|  |     } | ||
|  |     return this[this.length - 1]; | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/cached-iterable/src/cached_async_iterable.mjs
 | ||
|  | 
 | ||
|  | class CachedAsyncIterable extends CachedIterable { | ||
|  |   constructor(iterable) { | ||
|  |     super(); | ||
|  |     if (Symbol.asyncIterator in Object(iterable)) { | ||
|  |       this.iterator = iterable[Symbol.asyncIterator](); | ||
|  |     } else if (Symbol.iterator in Object(iterable)) { | ||
|  |       this.iterator = iterable[Symbol.iterator](); | ||
|  |     } else { | ||
|  |       throw new TypeError("Argument must implement the iteration protocol."); | ||
|  |     } | ||
|  |   } | ||
|  |   [Symbol.asyncIterator]() { | ||
|  |     const cached = this; | ||
|  |     let cur = 0; | ||
|  |     return { | ||
|  |       async next() { | ||
|  |         if (cached.length <= cur) { | ||
|  |           cached.push(cached.iterator.next()); | ||
|  |         } | ||
|  |         return cached[cur++]; | ||
|  |       } | ||
|  |     }; | ||
|  |   } | ||
|  |   async touchNext(count = 1) { | ||
|  |     let idx = 0; | ||
|  |     while (idx++ < count) { | ||
|  |       const last = this[this.length - 1]; | ||
|  |       if (last && (await last).done) { | ||
|  |         break; | ||
|  |       } | ||
|  |       this.push(this.iterator.next()); | ||
|  |     } | ||
|  |     return this[this.length - 1]; | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/cached-iterable/src/index.mjs
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/dom/esm/localization.js
 | ||
|  | 
 | ||
|  | class Localization { | ||
|  |   constructor(resourceIds = [], generateBundles) { | ||
|  |     this.resourceIds = resourceIds; | ||
|  |     this.generateBundles = generateBundles; | ||
|  |     this.onChange(true); | ||
|  |   } | ||
|  |   addResourceIds(resourceIds, eager = false) { | ||
|  |     this.resourceIds.push(...resourceIds); | ||
|  |     this.onChange(eager); | ||
|  |     return this.resourceIds.length; | ||
|  |   } | ||
|  |   removeResourceIds(resourceIds) { | ||
|  |     this.resourceIds = this.resourceIds.filter(r => !resourceIds.includes(r)); | ||
|  |     this.onChange(); | ||
|  |     return this.resourceIds.length; | ||
|  |   } | ||
|  |   async formatWithFallback(keys, method) { | ||
|  |     const translations = []; | ||
|  |     let hasAtLeastOneBundle = false; | ||
|  |     for await (const bundle of this.bundles) { | ||
|  |       hasAtLeastOneBundle = true; | ||
|  |       const missingIds = keysFromBundle(method, bundle, keys, translations); | ||
|  |       if (missingIds.size === 0) { | ||
|  |         break; | ||
|  |       } | ||
|  |       if (typeof console !== "undefined") { | ||
|  |         const locale = bundle.locales[0]; | ||
|  |         const ids = Array.from(missingIds).join(", "); | ||
|  |         console.warn(`[fluent] Missing translations in ${locale}: ${ids}`); | ||
|  |       } | ||
|  |     } | ||
|  |     if (!hasAtLeastOneBundle && typeof console !== "undefined") { | ||
|  |       console.warn(`[fluent] Request for keys failed because no resource bundles got generated.
 | ||
|  |   keys: ${JSON.stringify(keys)}. | ||
|  |   resourceIds: ${JSON.stringify(this.resourceIds)}.`);
 | ||
|  |     } | ||
|  |     return translations; | ||
|  |   } | ||
|  |   formatMessages(keys) { | ||
|  |     return this.formatWithFallback(keys, messageFromBundle); | ||
|  |   } | ||
|  |   formatValues(keys) { | ||
|  |     return this.formatWithFallback(keys, valueFromBundle); | ||
|  |   } | ||
|  |   async formatValue(id, args) { | ||
|  |     const [val] = await this.formatValues([{ | ||
|  |       id, | ||
|  |       args | ||
|  |     }]); | ||
|  |     return val; | ||
|  |   } | ||
|  |   handleEvent() { | ||
|  |     this.onChange(); | ||
|  |   } | ||
|  |   onChange(eager = false) { | ||
|  |     this.bundles = CachedAsyncIterable.from(this.generateBundles(this.resourceIds)); | ||
|  |     if (eager) { | ||
|  |       this.bundles.touchNext(2); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | function valueFromBundle(bundle, errors, message, args) { | ||
|  |   if (message.value) { | ||
|  |     return bundle.formatPattern(message.value, args, errors); | ||
|  |   } | ||
|  |   return null; | ||
|  | } | ||
|  | function messageFromBundle(bundle, errors, message, args) { | ||
|  |   const formatted = { | ||
|  |     value: null, | ||
|  |     attributes: null | ||
|  |   }; | ||
|  |   if (message.value) { | ||
|  |     formatted.value = bundle.formatPattern(message.value, args, errors); | ||
|  |   } | ||
|  |   let attrNames = Object.keys(message.attributes); | ||
|  |   if (attrNames.length > 0) { | ||
|  |     formatted.attributes = new Array(attrNames.length); | ||
|  |     for (let [i, name] of attrNames.entries()) { | ||
|  |       let value = bundle.formatPattern(message.attributes[name], args, errors); | ||
|  |       formatted.attributes[i] = { | ||
|  |         name, | ||
|  |         value | ||
|  |       }; | ||
|  |     } | ||
|  |   } | ||
|  |   return formatted; | ||
|  | } | ||
|  | function keysFromBundle(method, bundle, keys, translations) { | ||
|  |   const messageErrors = []; | ||
|  |   const missingIds = new Set(); | ||
|  |   keys.forEach(({ | ||
|  |     id, | ||
|  |     args | ||
|  |   }, i) => { | ||
|  |     if (translations[i] !== undefined) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let message = bundle.getMessage(id); | ||
|  |     if (message) { | ||
|  |       messageErrors.length = 0; | ||
|  |       translations[i] = method(bundle, messageErrors, message, args); | ||
|  |       if (messageErrors.length > 0 && typeof console !== "undefined") { | ||
|  |         const locale = bundle.locales[0]; | ||
|  |         const errors = messageErrors.join(", "); | ||
|  |         console.warn(`[fluent][resolver] errors in ${locale}/${id}: ${errors}.`); | ||
|  |       } | ||
|  |     } else { | ||
|  |       missingIds.add(id); | ||
|  |     } | ||
|  |   }); | ||
|  |   return missingIds; | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/dom/esm/dom_localization.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const L10NID_ATTR_NAME = "data-l10n-id"; | ||
|  | const L10NARGS_ATTR_NAME = "data-l10n-args"; | ||
|  | const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`; | ||
|  | class DOMLocalization extends Localization { | ||
|  |   constructor(resourceIds, generateBundles) { | ||
|  |     super(resourceIds, generateBundles); | ||
|  |     this.roots = new Set(); | ||
|  |     this.pendingrAF = null; | ||
|  |     this.pendingElements = new Set(); | ||
|  |     this.windowElement = null; | ||
|  |     this.mutationObserver = null; | ||
|  |     this.observerConfig = { | ||
|  |       attributes: true, | ||
|  |       characterData: false, | ||
|  |       childList: true, | ||
|  |       subtree: true, | ||
|  |       attributeFilter: [L10NID_ATTR_NAME, L10NARGS_ATTR_NAME] | ||
|  |     }; | ||
|  |   } | ||
|  |   onChange(eager = false) { | ||
|  |     super.onChange(eager); | ||
|  |     if (this.roots) { | ||
|  |       this.translateRoots(); | ||
|  |     } | ||
|  |   } | ||
|  |   setAttributes(element, id, args) { | ||
|  |     element.setAttribute(L10NID_ATTR_NAME, id); | ||
|  |     if (args) { | ||
|  |       element.setAttribute(L10NARGS_ATTR_NAME, JSON.stringify(args)); | ||
|  |     } else { | ||
|  |       element.removeAttribute(L10NARGS_ATTR_NAME); | ||
|  |     } | ||
|  |     return element; | ||
|  |   } | ||
|  |   getAttributes(element) { | ||
|  |     return { | ||
|  |       id: element.getAttribute(L10NID_ATTR_NAME), | ||
|  |       args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null) | ||
|  |     }; | ||
|  |   } | ||
|  |   connectRoot(newRoot) { | ||
|  |     for (const root of this.roots) { | ||
|  |       if (root === newRoot || root.contains(newRoot) || newRoot.contains(root)) { | ||
|  |         throw new Error("Cannot add a root that overlaps with existing root."); | ||
|  |       } | ||
|  |     } | ||
|  |     if (this.windowElement) { | ||
|  |       if (this.windowElement !== newRoot.ownerDocument.defaultView) { | ||
|  |         throw new Error(`Cannot connect a root:
 | ||
|  |           DOMLocalization already has a root from a different window.`);
 | ||
|  |       } | ||
|  |     } else { | ||
|  |       this.windowElement = newRoot.ownerDocument.defaultView; | ||
|  |       this.mutationObserver = new this.windowElement.MutationObserver(mutations => this.translateMutations(mutations)); | ||
|  |     } | ||
|  |     this.roots.add(newRoot); | ||
|  |     this.mutationObserver.observe(newRoot, this.observerConfig); | ||
|  |   } | ||
|  |   disconnectRoot(root) { | ||
|  |     this.roots.delete(root); | ||
|  |     this.pauseObserving(); | ||
|  |     if (this.roots.size === 0) { | ||
|  |       this.mutationObserver = null; | ||
|  |       if (this.windowElement && this.pendingrAF) { | ||
|  |         this.windowElement.cancelAnimationFrame(this.pendingrAF); | ||
|  |       } | ||
|  |       this.windowElement = null; | ||
|  |       this.pendingrAF = null; | ||
|  |       this.pendingElements.clear(); | ||
|  |       return true; | ||
|  |     } | ||
|  |     this.resumeObserving(); | ||
|  |     return false; | ||
|  |   } | ||
|  |   translateRoots() { | ||
|  |     const roots = Array.from(this.roots); | ||
|  |     return Promise.all(roots.map(root => this.translateFragment(root))); | ||
|  |   } | ||
|  |   pauseObserving() { | ||
|  |     if (!this.mutationObserver) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.translateMutations(this.mutationObserver.takeRecords()); | ||
|  |     this.mutationObserver.disconnect(); | ||
|  |   } | ||
|  |   resumeObserving() { | ||
|  |     if (!this.mutationObserver) { | ||
|  |       return; | ||
|  |     } | ||
|  |     for (const root of this.roots) { | ||
|  |       this.mutationObserver.observe(root, this.observerConfig); | ||
|  |     } | ||
|  |   } | ||
|  |   translateMutations(mutations) { | ||
|  |     for (const mutation of mutations) { | ||
|  |       switch (mutation.type) { | ||
|  |         case "attributes": | ||
|  |           if (mutation.target.hasAttribute("data-l10n-id")) { | ||
|  |             this.pendingElements.add(mutation.target); | ||
|  |           } | ||
|  |           break; | ||
|  |         case "childList": | ||
|  |           for (const addedNode of mutation.addedNodes) { | ||
|  |             if (addedNode.nodeType === addedNode.ELEMENT_NODE) { | ||
|  |               if (addedNode.childElementCount) { | ||
|  |                 for (const element of this.getTranslatables(addedNode)) { | ||
|  |                   this.pendingElements.add(element); | ||
|  |                 } | ||
|  |               } else if (addedNode.hasAttribute(L10NID_ATTR_NAME)) { | ||
|  |                 this.pendingElements.add(addedNode); | ||
|  |               } | ||
|  |             } | ||
|  |           } | ||
|  |           break; | ||
|  |       } | ||
|  |     } | ||
|  |     if (this.pendingElements.size > 0) { | ||
|  |       if (this.pendingrAF === null) { | ||
|  |         this.pendingrAF = this.windowElement.requestAnimationFrame(() => { | ||
|  |           this.translateElements(Array.from(this.pendingElements)); | ||
|  |           this.pendingElements.clear(); | ||
|  |           this.pendingrAF = null; | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   translateFragment(frag) { | ||
|  |     return this.translateElements(this.getTranslatables(frag)); | ||
|  |   } | ||
|  |   async translateElements(elements) { | ||
|  |     if (!elements.length) { | ||
|  |       return undefined; | ||
|  |     } | ||
|  |     const keys = elements.map(this.getKeysForElement); | ||
|  |     const translations = await this.formatMessages(keys); | ||
|  |     return this.applyTranslations(elements, translations); | ||
|  |   } | ||
|  |   applyTranslations(elements, translations) { | ||
|  |     this.pauseObserving(); | ||
|  |     for (let i = 0; i < elements.length; i++) { | ||
|  |       if (translations[i] !== undefined) { | ||
|  |         translateElement(elements[i], translations[i]); | ||
|  |       } | ||
|  |     } | ||
|  |     this.resumeObserving(); | ||
|  |   } | ||
|  |   getTranslatables(element) { | ||
|  |     const nodes = Array.from(element.querySelectorAll(L10N_ELEMENT_QUERY)); | ||
|  |     if (typeof element.hasAttribute === "function" && element.hasAttribute(L10NID_ATTR_NAME)) { | ||
|  |       nodes.push(element); | ||
|  |     } | ||
|  |     return nodes; | ||
|  |   } | ||
|  |   getKeysForElement(element) { | ||
|  |     return { | ||
|  |       id: element.getAttribute(L10NID_ATTR_NAME), | ||
|  |       args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null) | ||
|  |     }; | ||
|  |   } | ||
|  | } | ||
|  | ;// CONCATENATED MODULE: ./node_modules/@fluent/dom/esm/index.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/l10n.js
 | ||
|  | class L10n { | ||
|  |   #dir; | ||
|  |   #elements = new Set(); | ||
|  |   #lang; | ||
|  |   #l10n; | ||
|  |   constructor({ | ||
|  |     lang, | ||
|  |     isRTL | ||
|  |   }, l10n = null) { | ||
|  |     this.#lang = L10n.#fixupLangCode(lang); | ||
|  |     this.#l10n = l10n; | ||
|  |     this.#dir = isRTL ?? L10n.#isRTL(this.#lang) ? "rtl" : "ltr"; | ||
|  |   } | ||
|  |   _setL10n(l10n) { | ||
|  |     this.#l10n = l10n; | ||
|  |   } | ||
|  |   getLanguage() { | ||
|  |     return this.#lang; | ||
|  |   } | ||
|  |   getDirection() { | ||
|  |     return this.#dir; | ||
|  |   } | ||
|  |   async get(ids, args = null, fallback) { | ||
|  |     if (Array.isArray(ids)) { | ||
|  |       ids = ids.map(id => ({ | ||
|  |         id | ||
|  |       })); | ||
|  |       const messages = await this.#l10n.formatMessages(ids); | ||
|  |       return messages.map(message => message.value); | ||
|  |     } | ||
|  |     const messages = await this.#l10n.formatMessages([{ | ||
|  |       id: ids, | ||
|  |       args | ||
|  |     }]); | ||
|  |     return messages[0]?.value || fallback; | ||
|  |   } | ||
|  |   async translate(element) { | ||
|  |     this.#elements.add(element); | ||
|  |     try { | ||
|  |       this.#l10n.connectRoot(element); | ||
|  |       await this.#l10n.translateRoots(); | ||
|  |     } catch {} | ||
|  |   } | ||
|  |   async translateOnce(element) { | ||
|  |     try { | ||
|  |       await this.#l10n.translateElements([element]); | ||
|  |     } catch (ex) { | ||
|  |       console.error(`translateOnce: "${ex}".`); | ||
|  |     } | ||
|  |   } | ||
|  |   async destroy() { | ||
|  |     for (const element of this.#elements) { | ||
|  |       this.#l10n.disconnectRoot(element); | ||
|  |     } | ||
|  |     this.#elements.clear(); | ||
|  |     this.#l10n.pauseObserving(); | ||
|  |   } | ||
|  |   pause() { | ||
|  |     this.#l10n.pauseObserving(); | ||
|  |   } | ||
|  |   resume() { | ||
|  |     this.#l10n.resumeObserving(); | ||
|  |   } | ||
|  |   static #fixupLangCode(langCode) { | ||
|  |     langCode = langCode?.toLowerCase() || "en-us"; | ||
|  |     const PARTIAL_LANG_CODES = { | ||
|  |       en: "en-us", | ||
|  |       es: "es-es", | ||
|  |       fy: "fy-nl", | ||
|  |       ga: "ga-ie", | ||
|  |       gu: "gu-in", | ||
|  |       hi: "hi-in", | ||
|  |       hy: "hy-am", | ||
|  |       nb: "nb-no", | ||
|  |       ne: "ne-np", | ||
|  |       nn: "nn-no", | ||
|  |       pa: "pa-in", | ||
|  |       pt: "pt-pt", | ||
|  |       sv: "sv-se", | ||
|  |       zh: "zh-cn" | ||
|  |     }; | ||
|  |     return PARTIAL_LANG_CODES[langCode] || langCode; | ||
|  |   } | ||
|  |   static #isRTL(lang) { | ||
|  |     const shortCode = lang.split("-", 1)[0]; | ||
|  |     return ["ar", "he", "fa", "ps", "ur"].includes(shortCode); | ||
|  |   } | ||
|  | } | ||
|  | const GenericL10n = null; | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/genericl10n.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function createBundle(lang, text) { | ||
|  |   const resource = new FluentResource(text); | ||
|  |   const bundle = new FluentBundle(lang); | ||
|  |   const errors = bundle.addResource(resource); | ||
|  |   if (errors.length) { | ||
|  |     console.error("L10n errors", errors); | ||
|  |   } | ||
|  |   return bundle; | ||
|  | } | ||
|  | class genericl10n_GenericL10n extends L10n { | ||
|  |   constructor(lang) { | ||
|  |     super({ | ||
|  |       lang | ||
|  |     }); | ||
|  |     const generateBundles = !lang ? genericl10n_GenericL10n.#generateBundlesFallback.bind(genericl10n_GenericL10n, this.getLanguage()) : genericl10n_GenericL10n.#generateBundles.bind(genericl10n_GenericL10n, "en-us", this.getLanguage()); | ||
|  |     this._setL10n(new DOMLocalization([], generateBundles)); | ||
|  |   } | ||
|  |   static async *#generateBundles(defaultLang, baseLang) { | ||
|  |     const { | ||
|  |       baseURL, | ||
|  |       paths | ||
|  |     } = await this.#getPaths(); | ||
|  |     const langs = [baseLang]; | ||
|  |     if (defaultLang !== baseLang) { | ||
|  |       const shortLang = baseLang.split("-", 1)[0]; | ||
|  |       if (shortLang !== baseLang) { | ||
|  |         langs.push(shortLang); | ||
|  |       } | ||
|  |       langs.push(defaultLang); | ||
|  |     } | ||
|  |     for (const lang of langs) { | ||
|  |       const bundle = await this.#createBundle(lang, baseURL, paths); | ||
|  |       if (bundle) { | ||
|  |         yield bundle; | ||
|  |       } else if (lang === "en-us") { | ||
|  |         yield this.#createBundleFallback(lang); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   static async #createBundle(lang, baseURL, paths) { | ||
|  |     const path = paths[lang]; | ||
|  |     if (!path) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     const url = new URL(path, baseURL); | ||
|  |     const text = await fetchData(url, "text"); | ||
|  |     return createBundle(lang, text); | ||
|  |   } | ||
|  |   static async #getPaths() { | ||
|  |     try { | ||
|  |       const { | ||
|  |         href | ||
|  |       } = document.querySelector(`link[type="application/l10n"]`); | ||
|  |       const paths = await fetchData(href, "json"); | ||
|  |       return { | ||
|  |         baseURL: href.replace(/[^/]*$/, "") || "./", | ||
|  |         paths | ||
|  |       }; | ||
|  |     } catch {} | ||
|  |     return { | ||
|  |       baseURL: "./", | ||
|  |       paths: Object.create(null) | ||
|  |     }; | ||
|  |   } | ||
|  |   static async *#generateBundlesFallback(lang) { | ||
|  |     yield this.#createBundleFallback(lang); | ||
|  |   } | ||
|  |   static async #createBundleFallback(lang) { | ||
|  |     const text = "pdfjs-previous-button =\n    .title = Previous Page\npdfjs-previous-button-label = Previous\npdfjs-next-button =\n    .title = Next Page\npdfjs-next-button-label = Next\npdfjs-page-input =\n    .title = Page\npdfjs-of-pages = of { $pagesCount }\npdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })\npdfjs-zoom-out-button =\n    .title = Zoom Out\npdfjs-zoom-out-button-label = Zoom Out\npdfjs-zoom-in-button =\n    .title = Zoom In\npdfjs-zoom-in-button-label = Zoom In\npdfjs-zoom-select =\n    .title = Zoom\npdfjs-presentation-mode-button =\n    .title = Switch to Presentation Mode\npdfjs-presentation-mode-button-label = Presentation Mode\npdfjs-open-file-button =\n    .title = Open File\npdfjs-open-file-button-label = Open\npdfjs-print-button =\n    .title = Print\npdfjs-print-button-label = Print\npdfjs-save-button =\n    .title = Save\npdfjs-save-button-label = Save\npdfjs-download-button =\n    .title = Download\npdfjs-download-button-label = Download\npdfjs-bookmark-button =\n    .title = Current Page (View URL from Current Page)\npdfjs-bookmark-button-label = Current Page\npdfjs-tools-button =\n    .title = Tools\npdfjs-tools-button-label = Tools\npdfjs-first-page-button =\n    .title = Go to First Page\npdfjs-first-page-button-label = Go to First Page\npdfjs-last-page-button =\n    .title = Go to Last Page\npdfjs-last-page-button-label = Go to Last Page\npdfjs-page-rotate-cw-button =\n    .title = Rotate Clockwise\npdfjs-page-rotate-cw-button-label = Rotate Clockwise\npdfjs-page-rotate-ccw-button =\n    .title = Rotate Counterclockwise\npdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise\npdfjs-cursor-text-select-tool-button =\n    .title = Enable Text Selection Tool\npdfjs-cursor-text-select-tool-button-label = Text Selection Tool\npdfjs-cursor-hand-tool-button =\n    .title = Enable Hand Tool\npdfjs-cursor-hand-tool-button-label = Hand Tool\npdfjs-scroll-page-button =\n    .title = Use Page Scrolling\npdfjs-scroll-page-button-label = Page Scrolling\npdfjs-scroll-vertical-button =\n    .title = Use Vertical Scrolling\npdfjs-scroll-vertical-button-label = Vertical Scrolling\npdfjs-scroll-horizontal-button =\n    .title = Use Horizontal Scrolling\npdfjs-scroll-horizontal-button-label = Horizontal Scrolling\npdfjs-scroll-wrapped-button =\n    .title = Use Wrapped Scrolling\npdfjs-scroll-wrapped-button-label = Wrapped Scrolling\npdfjs-spread-none-button =\n    .title = Do not join page spreads\npdfjs-spread-none-button-label = No Spreads\npdfjs-spread-odd-button =\n    .title = Join page spreads starting with odd-numbered pages\npdfjs-spread-odd-button-label = Odd Spreads\npdfjs-spread-even-button =\n    .title = Join page spreads starting with even-numbered pages\npdfjs-spread-even-button-label = Even Spreads\npdfjs-document-properties-button =\n    .title = Document Properties\u2026\npdfjs-document-properties-button-label = Document Properties\u2026\npdfjs-document-properties-file-name = File name:\npdfjs-document-properties-file-size = File size:\npdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)\npdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)\npdfjs-document-properties-title = Title:\npdfjs-document-properties-author = Author:\npdfjs-document-properties-subject = Subject:\npdfjs-document-properties-keywords = Keywords:\npdfjs-document-properties-creation-date = Creation Date:\npdfjs-document-properties-modification-date = Modification Date:\npdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-document-properties-creator = Creator:\npdfjs-document-properties-producer = PDF Producer:\npdfjs-document-properties-version = PDF Version:\npdfjs-document-properties-page-count = Page Count:\npdfjs-document-properties-page-size = Page Size:\npdfjs-document-properties-page-size-unit-inches = in\npdfjs-document-properties-page-size-unit-millimeters = mm\npdfjs-document-properties-page-size-orientation-portrait = portrait\npdfjs | ||
|  |     return createBundle(lang, text); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/generic_scripting.js
 | ||
|  | 
 | ||
|  | async function docProperties(pdfDocument) { | ||
|  |   const url = "", | ||
|  |     baseUrl = url.split("#", 1)[0]; | ||
|  |   let { | ||
|  |     info, | ||
|  |     metadata, | ||
|  |     contentDispositionFilename, | ||
|  |     contentLength | ||
|  |   } = await pdfDocument.getMetadata(); | ||
|  |   if (!contentLength) { | ||
|  |     const { | ||
|  |       length | ||
|  |     } = await pdfDocument.getDownloadInfo(); | ||
|  |     contentLength = length; | ||
|  |   } | ||
|  |   return { | ||
|  |     ...info, | ||
|  |     baseURL: baseUrl, | ||
|  |     filesize: contentLength, | ||
|  |     filename: contentDispositionFilename || getPdfFilenameFromUrl(url), | ||
|  |     metadata: metadata?.getRaw(), | ||
|  |     authors: metadata?.get("dc:creator"), | ||
|  |     numPages: pdfDocument.numPages, | ||
|  |     URL: url | ||
|  |   }; | ||
|  | } | ||
|  | class GenericScripting { | ||
|  |   constructor(sandboxBundleSrc) { | ||
|  |     this._ready = new Promise((resolve, reject) => { | ||
|  |       const sandbox = import( /*webpackIgnore: true*/sandboxBundleSrc); | ||
|  |       sandbox.then(pdfjsSandbox => { | ||
|  |         resolve(pdfjsSandbox.QuickJSSandbox()); | ||
|  |       }).catch(reject); | ||
|  |     }); | ||
|  |   } | ||
|  |   async createSandbox(data) { | ||
|  |     const sandbox = await this._ready; | ||
|  |     sandbox.create(data); | ||
|  |   } | ||
|  |   async dispatchEventInSandbox(event) { | ||
|  |     const sandbox = await this._ready; | ||
|  |     setTimeout(() => sandbox.dispatchEvent(event), 0); | ||
|  |   } | ||
|  |   async destroySandbox() { | ||
|  |     const sandbox = await this._ready; | ||
|  |     sandbox.nukeSandbox(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/genericcom.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function initCom(app) {} | ||
|  | class Preferences extends BasePreferences { | ||
|  |   async _writeToStorage(prefObj) { | ||
|  |     localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj)); | ||
|  |   } | ||
|  |   async _readFromStorage(prefObj) { | ||
|  |     return { | ||
|  |       prefs: JSON.parse(localStorage.getItem("pdfjs.preferences")) | ||
|  |     }; | ||
|  |   } | ||
|  | } | ||
|  | class ExternalServices extends BaseExternalServices { | ||
|  |   async createL10n() { | ||
|  |     return new genericl10n_GenericL10n(AppOptions.get("localeProperties")?.lang); | ||
|  |   } | ||
|  |   createScripting() { | ||
|  |     return new GenericScripting(AppOptions.get("sandboxBundleSrc")); | ||
|  |   } | ||
|  | } | ||
|  | class MLManager { | ||
|  |   async isEnabledFor(_name) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   async deleteModel(_service) { | ||
|  |     return null; | ||
|  |   } | ||
|  |   isReady(_name) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   guess(_data) {} | ||
|  |   toggleService(_name, _enabled) {} | ||
|  |   static getFakeMLManager(options) { | ||
|  |     return new FakeMLManager(options); | ||
|  |   } | ||
|  | } | ||
|  | class FakeMLManager { | ||
|  |   eventBus = null; | ||
|  |   hasProgress = false; | ||
|  |   constructor({ | ||
|  |     enableGuessAltText, | ||
|  |     enableAltTextModelDownload | ||
|  |   }) { | ||
|  |     this.enableGuessAltText = enableGuessAltText; | ||
|  |     this.enableAltTextModelDownload = enableAltTextModelDownload; | ||
|  |   } | ||
|  |   setEventBus(eventBus, abortSignal) { | ||
|  |     this.eventBus = eventBus; | ||
|  |   } | ||
|  |   async isEnabledFor(_name) { | ||
|  |     return this.enableGuessAltText; | ||
|  |   } | ||
|  |   async deleteModel(_name) { | ||
|  |     this.enableAltTextModelDownload = false; | ||
|  |     return null; | ||
|  |   } | ||
|  |   async loadModel(_name) {} | ||
|  |   async downloadModel(_name) { | ||
|  |     this.hasProgress = true; | ||
|  |     const { | ||
|  |       promise, | ||
|  |       resolve | ||
|  |     } = Promise.withResolvers(); | ||
|  |     const total = 1e8; | ||
|  |     const end = 1.5 * total; | ||
|  |     const increment = 5e6; | ||
|  |     let loaded = 0; | ||
|  |     const id = setInterval(() => { | ||
|  |       loaded += increment; | ||
|  |       if (loaded <= end) { | ||
|  |         this.eventBus.dispatch("loadaiengineprogress", { | ||
|  |           source: this, | ||
|  |           detail: { | ||
|  |             total, | ||
|  |             totalLoaded: loaded, | ||
|  |             finished: loaded + increment >= end | ||
|  |           } | ||
|  |         }); | ||
|  |         return; | ||
|  |       } | ||
|  |       clearInterval(id); | ||
|  |       this.hasProgress = false; | ||
|  |       this.enableAltTextModelDownload = true; | ||
|  |       resolve(true); | ||
|  |     }, 900); | ||
|  |     return promise; | ||
|  |   } | ||
|  |   isReady(_name) { | ||
|  |     return this.enableAltTextModelDownload; | ||
|  |   } | ||
|  |   guess({ | ||
|  |     request: { | ||
|  |       data | ||
|  |     } | ||
|  |   }) { | ||
|  |     return new Promise(resolve => { | ||
|  |       setTimeout(() => { | ||
|  |         resolve(data ? { | ||
|  |           output: "Fake alt text" | ||
|  |         } : { | ||
|  |           error: true | ||
|  |         }); | ||
|  |       }, 3000); | ||
|  |     }); | ||
|  |   } | ||
|  |   toggleService(_name, enabled) { | ||
|  |     this.enableGuessAltText = enabled; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/new_alt_text_manager.js
 | ||
|  | 
 | ||
|  | class NewAltTextManager { | ||
|  |   #boundCancel = this.#cancel.bind(this); | ||
|  |   #createAutomaticallyButton; | ||
|  |   #currentEditor = null; | ||
|  |   #cancelButton; | ||
|  |   #descriptionContainer; | ||
|  |   #dialog; | ||
|  |   #disclaimer; | ||
|  |   #downloadModel; | ||
|  |   #downloadModelDescription; | ||
|  |   #eventBus; | ||
|  |   #firstTime = false; | ||
|  |   #guessedAltText; | ||
|  |   #isEditing = null; | ||
|  |   #imagePreview; | ||
|  |   #imageData; | ||
|  |   #isAILoading = false; | ||
|  |   #wasAILoading = false; | ||
|  |   #learnMore; | ||
|  |   #notNowButton; | ||
|  |   #overlayManager; | ||
|  |   #textarea; | ||
|  |   #title; | ||
|  |   #uiManager; | ||
|  |   #previousAltText = null; | ||
|  |   constructor({ | ||
|  |     descriptionContainer, | ||
|  |     dialog, | ||
|  |     imagePreview, | ||
|  |     cancelButton, | ||
|  |     disclaimer, | ||
|  |     notNowButton, | ||
|  |     saveButton, | ||
|  |     textarea, | ||
|  |     learnMore, | ||
|  |     errorCloseButton, | ||
|  |     createAutomaticallyButton, | ||
|  |     downloadModel, | ||
|  |     downloadModelDescription, | ||
|  |     title | ||
|  |   }, overlayManager, eventBus) { | ||
|  |     this.#cancelButton = cancelButton; | ||
|  |     this.#createAutomaticallyButton = createAutomaticallyButton; | ||
|  |     this.#descriptionContainer = descriptionContainer; | ||
|  |     this.#dialog = dialog; | ||
|  |     this.#disclaimer = disclaimer; | ||
|  |     this.#notNowButton = notNowButton; | ||
|  |     this.#imagePreview = imagePreview; | ||
|  |     this.#textarea = textarea; | ||
|  |     this.#learnMore = learnMore; | ||
|  |     this.#title = title; | ||
|  |     this.#downloadModel = downloadModel; | ||
|  |     this.#downloadModelDescription = downloadModelDescription; | ||
|  |     this.#overlayManager = overlayManager; | ||
|  |     this.#eventBus = eventBus; | ||
|  |     dialog.addEventListener("close", this.#close.bind(this)); | ||
|  |     dialog.addEventListener("contextmenu", event => { | ||
|  |       if (event.target !== this.#textarea) { | ||
|  |         event.preventDefault(); | ||
|  |       } | ||
|  |     }); | ||
|  |     cancelButton.addEventListener("click", this.#boundCancel); | ||
|  |     notNowButton.addEventListener("click", this.#boundCancel); | ||
|  |     saveButton.addEventListener("click", this.#save.bind(this)); | ||
|  |     errorCloseButton.addEventListener("click", () => { | ||
|  |       this.#toggleError(false); | ||
|  |     }); | ||
|  |     createAutomaticallyButton.addEventListener("click", async () => { | ||
|  |       const checked = createAutomaticallyButton.getAttribute("aria-pressed") !== "true"; | ||
|  |       this.#currentEditor._reportTelemetry({ | ||
|  |         action: "pdfjs.image.alt_text.ai_generation_check", | ||
|  |         data: { | ||
|  |           status: checked | ||
|  |         } | ||
|  |       }); | ||
|  |       if (this.#uiManager) { | ||
|  |         this.#uiManager.setPreference("enableGuessAltText", checked); | ||
|  |         await this.#uiManager.mlManager.toggleService("altText", checked); | ||
|  |       } | ||
|  |       this.#toggleGuessAltText(checked, false); | ||
|  |     }); | ||
|  |     textarea.addEventListener("focus", () => { | ||
|  |       this.#wasAILoading = this.#isAILoading; | ||
|  |       this.#toggleLoading(false); | ||
|  |     }); | ||
|  |     textarea.addEventListener("blur", () => { | ||
|  |       if (textarea.value) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#toggleLoading(this.#wasAILoading); | ||
|  |     }); | ||
|  |     textarea.addEventListener("input", () => { | ||
|  |       this.#toggleTitle(); | ||
|  |       this.#toggleDisclaimer(); | ||
|  |     }); | ||
|  |     eventBus._on("enableguessalttext", ({ | ||
|  |       value | ||
|  |     }) => { | ||
|  |       this.#toggleGuessAltText(value, false); | ||
|  |     }); | ||
|  |     this.#overlayManager.register(dialog); | ||
|  |     this.#learnMore.addEventListener("click", () => { | ||
|  |       this.#currentEditor._reportTelemetry({ | ||
|  |         action: "pdfjs.image.alt_text.info", | ||
|  |         data: { | ||
|  |           topic: "alt_text" | ||
|  |         } | ||
|  |       }); | ||
|  |     }); | ||
|  |   } | ||
|  |   #toggleLoading(value) { | ||
|  |     if (!this.#uiManager || this.#isAILoading === value) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#isAILoading = value; | ||
|  |     this.#descriptionContainer.classList.toggle("loading", value); | ||
|  |   } | ||
|  |   #toggleError(value) { | ||
|  |     if (!this.#uiManager) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#dialog.classList.toggle("error", value); | ||
|  |   } | ||
|  |   #toggleTitle() { | ||
|  |     const isEditing = this.#isAILoading || !!this.#textarea.value; | ||
|  |     if (this.#isEditing === isEditing) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#isEditing = isEditing; | ||
|  |     this.#title.setAttribute("data-l10n-id", isEditing ? "pdfjs-editor-new-alt-text-dialog-edit-label" : "pdfjs-editor-new-alt-text-dialog-add-label"); | ||
|  |   } | ||
|  |   async #toggleGuessAltText(value, isInitial = false) { | ||
|  |     if (!this.#uiManager) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#dialog.classList.toggle("aiDisabled", !value); | ||
|  |     this.#createAutomaticallyButton.setAttribute("aria-pressed", value); | ||
|  |     if (value) { | ||
|  |       const { | ||
|  |         altTextLearnMoreUrl | ||
|  |       } = this.#uiManager.mlManager; | ||
|  |       if (altTextLearnMoreUrl) { | ||
|  |         this.#learnMore.href = altTextLearnMoreUrl; | ||
|  |       } | ||
|  |       this.#mlGuessAltText(isInitial); | ||
|  |     } else { | ||
|  |       this.#toggleLoading(false); | ||
|  |       this.#isAILoading = false; | ||
|  |       this.#toggleTitle(); | ||
|  |       this.#toggleDisclaimer(); | ||
|  |     } | ||
|  |   } | ||
|  |   #toggleNotNow() { | ||
|  |     this.#notNowButton.classList.toggle("hidden", !this.#firstTime); | ||
|  |     this.#cancelButton.classList.toggle("hidden", this.#firstTime); | ||
|  |   } | ||
|  |   #toggleAI(value) { | ||
|  |     this.#dialog.classList.toggle("noAi", !value); | ||
|  |     this.#toggleTitle(); | ||
|  |   } | ||
|  |   #toggleDisclaimer(value = null) { | ||
|  |     if (!this.#uiManager) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const hidden = value === null ? !this.#guessedAltText || this.#guessedAltText !== this.#textarea.value : !value; | ||
|  |     this.#disclaimer.classList.toggle("hidden", hidden); | ||
|  |   } | ||
|  |   async #mlGuessAltText(isInitial) { | ||
|  |     if (this.#isAILoading) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.#textarea.value) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (isInitial && this.#previousAltText !== null) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#guessedAltText = this.#currentEditor.guessedAltText; | ||
|  |     if (this.#previousAltText === null && this.#guessedAltText) { | ||
|  |       this.#addAltText(this.#guessedAltText); | ||
|  |       this.#toggleDisclaimer(); | ||
|  |       this.#toggleTitle(); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#toggleLoading(true); | ||
|  |     this.#toggleTitle(); | ||
|  |     this.#toggleDisclaimer(true); | ||
|  |     let hasError = false; | ||
|  |     try { | ||
|  |       const altText = await this.#currentEditor.mlGuessAltText(this.#imageData, false); | ||
|  |       if (altText) { | ||
|  |         this.#guessedAltText = altText; | ||
|  |         this.#wasAILoading = this.#isAILoading; | ||
|  |         if (this.#isAILoading) { | ||
|  |           this.#addAltText(altText); | ||
|  |         } | ||
|  |       } | ||
|  |     } catch (e) { | ||
|  |       console.error(e); | ||
|  |       hasError = true; | ||
|  |     } | ||
|  |     this.#toggleLoading(false); | ||
|  |     if (hasError && this.#uiManager) { | ||
|  |       this.#toggleError(true); | ||
|  |       this.#toggleTitle(); | ||
|  |       this.#toggleDisclaimer(); | ||
|  |     } | ||
|  |   } | ||
|  |   #addAltText(altText) { | ||
|  |     if (!this.#uiManager || this.#textarea.value) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#textarea.value = altText; | ||
|  |   } | ||
|  |   #setProgress() { | ||
|  |     this.#downloadModel.classList.toggle("hidden", false); | ||
|  |     const callback = async ({ | ||
|  |       detail: { | ||
|  |         finished, | ||
|  |         total, | ||
|  |         totalLoaded | ||
|  |       } | ||
|  |     }) => { | ||
|  |       const ONE_MEGA_BYTES = 1e6; | ||
|  |       totalLoaded = Math.min(0.99 * total, totalLoaded); | ||
|  |       const totalSize = this.#downloadModelDescription.ariaValueMax = Math.round(total / ONE_MEGA_BYTES); | ||
|  |       const downloadedSize = this.#downloadModelDescription.ariaValueNow = Math.round(totalLoaded / ONE_MEGA_BYTES); | ||
|  |       this.#downloadModelDescription.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |         totalSize, | ||
|  |         downloadedSize | ||
|  |       })); | ||
|  |       if (!finished) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#eventBus._off("loadaiengineprogress", callback); | ||
|  |       this.#downloadModel.classList.toggle("hidden", true); | ||
|  |       this.#toggleAI(true); | ||
|  |       if (!this.#uiManager) { | ||
|  |         return; | ||
|  |       } | ||
|  |       const { | ||
|  |         mlManager | ||
|  |       } = this.#uiManager; | ||
|  |       mlManager.toggleService("altText", true); | ||
|  |       this.#toggleGuessAltText(await mlManager.isEnabledFor("altText"), true); | ||
|  |     }; | ||
|  |     this.#eventBus._on("loadaiengineprogress", callback); | ||
|  |   } | ||
|  |   async editAltText(uiManager, editor, firstTime) { | ||
|  |     if (this.#currentEditor || !editor) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (firstTime && editor.hasAltTextData()) { | ||
|  |       editor.altTextFinish(); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#firstTime = firstTime; | ||
|  |     let { | ||
|  |       mlManager | ||
|  |     } = uiManager; | ||
|  |     let hasAI = !!mlManager; | ||
|  |     if (mlManager && !mlManager.isReady("altText")) { | ||
|  |       hasAI = false; | ||
|  |       if (mlManager.hasProgress) { | ||
|  |         this.#setProgress(); | ||
|  |       } else { | ||
|  |         mlManager = null; | ||
|  |       } | ||
|  |     } else { | ||
|  |       this.#downloadModel.classList.toggle("hidden", true); | ||
|  |     } | ||
|  |     const isAltTextEnabledPromise = mlManager?.isEnabledFor("altText"); | ||
|  |     this.#currentEditor = editor; | ||
|  |     this.#uiManager = uiManager; | ||
|  |     this.#uiManager.removeEditListeners(); | ||
|  |     ({ | ||
|  |       altText: this.#previousAltText | ||
|  |     } = editor.altTextData); | ||
|  |     this.#textarea.value = this.#previousAltText ?? ""; | ||
|  |     const AI_MAX_IMAGE_DIMENSION = 224; | ||
|  |     let canvas; | ||
|  |     if (mlManager) { | ||
|  |       ({ | ||
|  |         canvas, | ||
|  |         imageData: this.#imageData | ||
|  |       } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, true)); | ||
|  |       if (hasAI) { | ||
|  |         this.#toggleGuessAltText(await isAltTextEnabledPromise, true); | ||
|  |       } | ||
|  |     } else { | ||
|  |       ({ | ||
|  |         canvas | ||
|  |       } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, false)); | ||
|  |     } | ||
|  |     canvas.setAttribute("role", "presentation"); | ||
|  |     this.#imagePreview.append(canvas); | ||
|  |     this.#toggleNotNow(); | ||
|  |     this.#toggleAI(hasAI); | ||
|  |     this.#toggleError(false); | ||
|  |     try { | ||
|  |       await this.#overlayManager.open(this.#dialog); | ||
|  |     } catch (ex) { | ||
|  |       this.#close(); | ||
|  |       throw ex; | ||
|  |     } | ||
|  |   } | ||
|  |   #cancel() { | ||
|  |     this.#currentEditor.altTextData = { | ||
|  |       cancel: true | ||
|  |     }; | ||
|  |     const altText = this.#textarea.value.trim(); | ||
|  |     this.#currentEditor._reportTelemetry({ | ||
|  |       action: "pdfjs.image.alt_text.dismiss", | ||
|  |       data: { | ||
|  |         alt_text_type: altText ? "present" : "empty", | ||
|  |         flow: this.#firstTime ? "image_add" : "alt_text_edit" | ||
|  |       } | ||
|  |     }); | ||
|  |     this.#currentEditor._reportTelemetry({ | ||
|  |       action: "pdfjs.image.image_added", | ||
|  |       data: { | ||
|  |         alt_text_modal: true, | ||
|  |         alt_text_type: "skipped" | ||
|  |       } | ||
|  |     }); | ||
|  |     this.#finish(); | ||
|  |   } | ||
|  |   #finish() { | ||
|  |     if (this.#overlayManager.active === this.#dialog) { | ||
|  |       this.#overlayManager.close(this.#dialog); | ||
|  |     } | ||
|  |   } | ||
|  |   #close() { | ||
|  |     const canvas = this.#imagePreview.firstChild; | ||
|  |     canvas.remove(); | ||
|  |     canvas.width = canvas.height = 0; | ||
|  |     this.#imageData = null; | ||
|  |     this.#toggleLoading(false); | ||
|  |     this.#uiManager?.addEditListeners(); | ||
|  |     this.#currentEditor.altTextFinish(); | ||
|  |     this.#uiManager?.setSelected(this.#currentEditor); | ||
|  |     this.#currentEditor = null; | ||
|  |     this.#uiManager = null; | ||
|  |   } | ||
|  |   #save() { | ||
|  |     const altText = this.#textarea.value.trim(); | ||
|  |     this.#currentEditor.altTextData = { | ||
|  |       altText, | ||
|  |       decorative: false | ||
|  |     }; | ||
|  |     this.#currentEditor.altTextData.guessedAltText = this.#guessedAltText; | ||
|  |     if (this.#guessedAltText && this.#guessedAltText !== altText) { | ||
|  |       const guessedWords = new Set(this.#guessedAltText.split(/\s+/)); | ||
|  |       const words = new Set(altText.split(/\s+/)); | ||
|  |       this.#currentEditor._reportTelemetry({ | ||
|  |         action: "pdfjs.image.alt_text.user_edit", | ||
|  |         data: { | ||
|  |           total_words: guessedWords.size, | ||
|  |           words_removed: guessedWords.difference(words).size, | ||
|  |           words_added: words.difference(guessedWords).size | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |     this.#currentEditor._reportTelemetry({ | ||
|  |       action: "pdfjs.image.image_added", | ||
|  |       data: { | ||
|  |         alt_text_modal: true, | ||
|  |         alt_text_type: altText ? "present" : "empty" | ||
|  |       } | ||
|  |     }); | ||
|  |     this.#currentEditor._reportTelemetry({ | ||
|  |       action: "pdfjs.image.alt_text.save", | ||
|  |       data: { | ||
|  |         alt_text_type: altText ? "present" : "empty", | ||
|  |         flow: this.#firstTime ? "image_add" : "alt_text_edit" | ||
|  |       } | ||
|  |     }); | ||
|  |     this.#finish(); | ||
|  |   } | ||
|  |   destroy() { | ||
|  |     this.#uiManager = null; | ||
|  |     this.#finish(); | ||
|  |   } | ||
|  | } | ||
|  | class ImageAltTextSettings { | ||
|  |   #aiModelSettings; | ||
|  |   #createModelButton; | ||
|  |   #downloadModelButton; | ||
|  |   #dialog; | ||
|  |   #eventBus; | ||
|  |   #mlManager; | ||
|  |   #overlayManager; | ||
|  |   #showAltTextDialogButton; | ||
|  |   constructor({ | ||
|  |     dialog, | ||
|  |     createModelButton, | ||
|  |     aiModelSettings, | ||
|  |     learnMore, | ||
|  |     closeButton, | ||
|  |     deleteModelButton, | ||
|  |     downloadModelButton, | ||
|  |     showAltTextDialogButton | ||
|  |   }, overlayManager, eventBus, mlManager) { | ||
|  |     this.#dialog = dialog; | ||
|  |     this.#aiModelSettings = aiModelSettings; | ||
|  |     this.#createModelButton = createModelButton; | ||
|  |     this.#downloadModelButton = downloadModelButton; | ||
|  |     this.#showAltTextDialogButton = showAltTextDialogButton; | ||
|  |     this.#overlayManager = overlayManager; | ||
|  |     this.#eventBus = eventBus; | ||
|  |     this.#mlManager = mlManager; | ||
|  |     const { | ||
|  |       altTextLearnMoreUrl | ||
|  |     } = mlManager; | ||
|  |     if (altTextLearnMoreUrl) { | ||
|  |       learnMore.href = altTextLearnMoreUrl; | ||
|  |     } | ||
|  |     dialog.addEventListener("contextmenu", noContextMenu); | ||
|  |     createModelButton.addEventListener("click", async e => { | ||
|  |       const checked = this.#togglePref("enableGuessAltText", e); | ||
|  |       await mlManager.toggleService("altText", checked); | ||
|  |       this.#reportTelemetry({ | ||
|  |         type: "stamp", | ||
|  |         action: "pdfjs.image.alt_text.settings_ai_generation_check", | ||
|  |         data: { | ||
|  |           status: checked | ||
|  |         } | ||
|  |       }); | ||
|  |     }); | ||
|  |     showAltTextDialogButton.addEventListener("click", e => { | ||
|  |       const checked = this.#togglePref("enableNewAltTextWhenAddingImage", e); | ||
|  |       this.#reportTelemetry({ | ||
|  |         type: "stamp", | ||
|  |         action: "pdfjs.image.alt_text.settings_edit_alt_text_check", | ||
|  |         data: { | ||
|  |           status: checked | ||
|  |         } | ||
|  |       }); | ||
|  |     }); | ||
|  |     deleteModelButton.addEventListener("click", this.#delete.bind(this, true)); | ||
|  |     downloadModelButton.addEventListener("click", this.#download.bind(this, true)); | ||
|  |     closeButton.addEventListener("click", this.#finish.bind(this)); | ||
|  |     learnMore.addEventListener("click", () => { | ||
|  |       this.#reportTelemetry({ | ||
|  |         type: "stamp", | ||
|  |         action: "pdfjs.image.alt_text.info", | ||
|  |         data: { | ||
|  |           topic: "ai_generation" | ||
|  |         } | ||
|  |       }); | ||
|  |     }); | ||
|  |     eventBus._on("enablealttextmodeldownload", ({ | ||
|  |       value | ||
|  |     }) => { | ||
|  |       if (value) { | ||
|  |         this.#download(false); | ||
|  |       } else { | ||
|  |         this.#delete(false); | ||
|  |       } | ||
|  |     }); | ||
|  |     this.#overlayManager.register(dialog); | ||
|  |   } | ||
|  |   #reportTelemetry(data) { | ||
|  |     this.#eventBus.dispatch("reporttelemetry", { | ||
|  |       source: this, | ||
|  |       details: { | ||
|  |         type: "editing", | ||
|  |         data | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   async #download(isFromUI = false) { | ||
|  |     if (isFromUI) { | ||
|  |       this.#downloadModelButton.disabled = true; | ||
|  |       const span = this.#downloadModelButton.firstChild; | ||
|  |       span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-downloading-model-button"); | ||
|  |       await this.#mlManager.downloadModel("altText"); | ||
|  |       span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-download-model-button"); | ||
|  |       this.#createModelButton.disabled = false; | ||
|  |       this.#setPref("enableGuessAltText", true); | ||
|  |       this.#mlManager.toggleService("altText", true); | ||
|  |       this.#setPref("enableAltTextModelDownload", true); | ||
|  |       this.#downloadModelButton.disabled = false; | ||
|  |     } | ||
|  |     this.#aiModelSettings.classList.toggle("download", false); | ||
|  |     this.#createModelButton.setAttribute("aria-pressed", true); | ||
|  |   } | ||
|  |   async #delete(isFromUI = false) { | ||
|  |     if (isFromUI) { | ||
|  |       await this.#mlManager.deleteModel("altText"); | ||
|  |       this.#setPref("enableGuessAltText", false); | ||
|  |       this.#setPref("enableAltTextModelDownload", false); | ||
|  |     } | ||
|  |     this.#aiModelSettings.classList.toggle("download", true); | ||
|  |     this.#createModelButton.disabled = true; | ||
|  |     this.#createModelButton.setAttribute("aria-pressed", false); | ||
|  |   } | ||
|  |   async open({ | ||
|  |     enableGuessAltText, | ||
|  |     enableNewAltTextWhenAddingImage | ||
|  |   }) { | ||
|  |     const { | ||
|  |       enableAltTextModelDownload | ||
|  |     } = this.#mlManager; | ||
|  |     this.#createModelButton.disabled = !enableAltTextModelDownload; | ||
|  |     this.#createModelButton.setAttribute("aria-pressed", enableAltTextModelDownload && enableGuessAltText); | ||
|  |     this.#showAltTextDialogButton.setAttribute("aria-pressed", enableNewAltTextWhenAddingImage); | ||
|  |     this.#aiModelSettings.classList.toggle("download", !enableAltTextModelDownload); | ||
|  |     await this.#overlayManager.open(this.#dialog); | ||
|  |     this.#reportTelemetry({ | ||
|  |       type: "stamp", | ||
|  |       action: "pdfjs.image.alt_text.settings_displayed" | ||
|  |     }); | ||
|  |   } | ||
|  |   #togglePref(name, { | ||
|  |     target | ||
|  |   }) { | ||
|  |     const checked = target.getAttribute("aria-pressed") !== "true"; | ||
|  |     this.#setPref(name, checked); | ||
|  |     target.setAttribute("aria-pressed", checked); | ||
|  |     return checked; | ||
|  |   } | ||
|  |   #setPref(name, value) { | ||
|  |     this.#eventBus.dispatch("setpreference", { | ||
|  |       source: this, | ||
|  |       name, | ||
|  |       value | ||
|  |     }); | ||
|  |   } | ||
|  |   #finish() { | ||
|  |     if (this.#overlayManager.active === this.#dialog) { | ||
|  |       this.#overlayManager.close(this.#dialog); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/alt_text_manager.js
 | ||
|  | 
 | ||
|  | class AltTextManager { | ||
|  |   #boundUpdateUIState = this.#updateUIState.bind(this); | ||
|  |   #boundSetPosition = this.#setPosition.bind(this); | ||
|  |   #boundOnClick = this.#onClick.bind(this); | ||
|  |   #currentEditor = null; | ||
|  |   #cancelButton; | ||
|  |   #dialog; | ||
|  |   #eventBus; | ||
|  |   #hasUsedPointer = false; | ||
|  |   #optionDescription; | ||
|  |   #optionDecorative; | ||
|  |   #overlayManager; | ||
|  |   #saveButton; | ||
|  |   #textarea; | ||
|  |   #uiManager; | ||
|  |   #previousAltText = null; | ||
|  |   #svgElement = null; | ||
|  |   #rectElement = null; | ||
|  |   #container; | ||
|  |   #telemetryData = null; | ||
|  |   constructor({ | ||
|  |     dialog, | ||
|  |     optionDescription, | ||
|  |     optionDecorative, | ||
|  |     textarea, | ||
|  |     cancelButton, | ||
|  |     saveButton | ||
|  |   }, container, overlayManager, eventBus) { | ||
|  |     this.#dialog = dialog; | ||
|  |     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) { | ||
|  |         event.preventDefault(); | ||
|  |       } | ||
|  |     }); | ||
|  |     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); | ||
|  |   } | ||
|  |   get _elements() { | ||
|  |     return shadow(this, "_elements", [this.#optionDescription, this.#optionDecorative, this.#textarea, this.#saveButton, this.#cancelButton]); | ||
|  |   } | ||
|  |   #createSVGElement() { | ||
|  |     if (this.#svgElement) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const svgFactory = new DOMSVGFactory(); | ||
|  |     const svg = this.#svgElement = svgFactory.createElement("svg"); | ||
|  |     svg.setAttribute("width", "0"); | ||
|  |     svg.setAttribute("height", "0"); | ||
|  |     const defs = svgFactory.createElement("defs"); | ||
|  |     svg.append(defs); | ||
|  |     const mask = svgFactory.createElement("mask"); | ||
|  |     defs.append(mask); | ||
|  |     mask.setAttribute("id", "alttext-manager-mask"); | ||
|  |     mask.setAttribute("maskContentUnits", "objectBoundingBox"); | ||
|  |     let rect = svgFactory.createElement("rect"); | ||
|  |     mask.append(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"); | ||
|  |     mask.append(rect); | ||
|  |     rect.setAttribute("fill", "black"); | ||
|  |     this.#dialog.append(svg); | ||
|  |   } | ||
|  |   async editAltText(uiManager, editor) { | ||
|  |     if (this.#currentEditor || !editor) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#createSVGElement(); | ||
|  |     this.#hasUsedPointer = false; | ||
|  |     for (const element of this._elements) { | ||
|  |       element.addEventListener("click", this.#boundOnClick); | ||
|  |     } | ||
|  |     const { | ||
|  |       altText, | ||
|  |       decorative | ||
|  |     } = editor.altTextData; | ||
|  |     if (decorative === true) { | ||
|  |       this.#optionDecorative.checked = true; | ||
|  |       this.#optionDescription.checked = false; | ||
|  |     } else { | ||
|  |       this.#optionDecorative.checked = false; | ||
|  |       this.#optionDescription.checked = true; | ||
|  |     } | ||
|  |     this.#previousAltText = this.#textarea.value = altText?.trim() || ""; | ||
|  |     this.#updateUIState(); | ||
|  |     this.#currentEditor = editor; | ||
|  |     this.#uiManager = uiManager; | ||
|  |     this.#uiManager.removeEditListeners(); | ||
|  |     this.#eventBus._on("resize", this.#boundSetPosition); | ||
|  |     try { | ||
|  |       await this.#overlayManager.open(this.#dialog); | ||
|  |       this.#setPosition(); | ||
|  |     } catch (ex) { | ||
|  |       this.#close(); | ||
|  |       throw ex; | ||
|  |     } | ||
|  |   } | ||
|  |   #setPosition() { | ||
|  |     if (!this.#currentEditor) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const dialog = this.#dialog; | ||
|  |     const { | ||
|  |       style | ||
|  |     } = dialog; | ||
|  |     const { | ||
|  |       x: containerX, | ||
|  |       y: containerY, | ||
|  |       width: containerW, | ||
|  |       height: containerH | ||
|  |     } = this.#container.getBoundingClientRect(); | ||
|  |     const { | ||
|  |       innerWidth: windowW, | ||
|  |       innerHeight: windowH | ||
|  |     } = window; | ||
|  |     const { | ||
|  |       width: dialogW, | ||
|  |       height: dialogH | ||
|  |     } = dialog.getBoundingClientRect(); | ||
|  |     const { | ||
|  |       x, | ||
|  |       y, | ||
|  |       width, | ||
|  |       height | ||
|  |     } = this.#currentEditor.getClientDimensions(); | ||
|  |     const MARGIN = 10; | ||
|  |     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 left = null; | ||
|  |     let top = Math.max(y, 0); | ||
|  |     top += Math.min(windowH - (top + dialogH), 0); | ||
|  |     if (isLTR) { | ||
|  |       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; | ||
|  |     } | ||
|  |     if (left === null) { | ||
|  |       top = null; | ||
|  |       left = Math.max(x, 0); | ||
|  |       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; | ||
|  |       } | ||
|  |     } | ||
|  |     if (top !== null) { | ||
|  |       dialog.classList.add("positioned"); | ||
|  |       if (isLTR) { | ||
|  |         style.left = `${left}px`; | ||
|  |       } else { | ||
|  |         style.right = `${windowW - left - dialogW}px`; | ||
|  |       } | ||
|  |       style.top = `${top}px`; | ||
|  |     } else { | ||
|  |       dialog.classList.remove("positioned"); | ||
|  |       style.left = ""; | ||
|  |       style.top = ""; | ||
|  |     } | ||
|  |   } | ||
|  |   #finish() { | ||
|  |     if (this.#overlayManager.active === this.#dialog) { | ||
|  |       this.#overlayManager.close(this.#dialog); | ||
|  |     } | ||
|  |   } | ||
|  |   #close() { | ||
|  |     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.#uiManager = null; | ||
|  |   } | ||
|  |   #updateUIState() { | ||
|  |     this.#textarea.disabled = this.#optionDecorative.checked; | ||
|  |   } | ||
|  |   #save() { | ||
|  |     const altText = this.#textarea.value.trim(); | ||
|  |     const decorative = this.#optionDecorative.checked; | ||
|  |     this.#currentEditor.altTextData = { | ||
|  |       altText, | ||
|  |       decorative | ||
|  |     }; | ||
|  |     this.#telemetryData = { | ||
|  |       action: "alt_text_save", | ||
|  |       alt_text_description: !!altText, | ||
|  |       alt_text_edit: !!this.#previousAltText && this.#previousAltText !== altText, | ||
|  |       alt_text_decorative: decorative, | ||
|  |       alt_text_keyboard: !this.#hasUsedPointer | ||
|  |     }; | ||
|  |     this.#finish(); | ||
|  |   } | ||
|  |   #onClick(evt) { | ||
|  |     if (evt.detail === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#hasUsedPointer = true; | ||
|  |     this.#removeOnClickListeners(); | ||
|  |   } | ||
|  |   #removeOnClickListeners() { | ||
|  |     for (const element of this._elements) { | ||
|  |       element.removeEventListener("click", this.#boundOnClick); | ||
|  |     } | ||
|  |   } | ||
|  |   destroy() { | ||
|  |     this.#uiManager = null; | ||
|  |     this.#finish(); | ||
|  |     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); | ||
|  |   } | ||
|  |   #bindListeners({ | ||
|  |     editorFreeTextFontSize, | ||
|  |     editorFreeTextColor, | ||
|  |     editorInkColor, | ||
|  |     editorInkThickness, | ||
|  |     editorInkOpacity, | ||
|  |     editorStampAddImage, | ||
|  |     editorFreeHighlightThickness, | ||
|  |     editorHighlightShowAll | ||
|  |   }) { | ||
|  |     const dispatchEvent = (typeStr, value) => { | ||
|  |       this.eventBus.dispatch("switchannotationeditorparams", { | ||
|  |         source: this, | ||
|  |         type: AnnotationEditorParamsType[typeStr], | ||
|  |         value | ||
|  |       }); | ||
|  |     }; | ||
|  |     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", () => { | ||
|  |       this.eventBus.dispatch("reporttelemetry", { | ||
|  |         source: this, | ||
|  |         details: { | ||
|  |           type: "editing", | ||
|  |           data: { | ||
|  |             action: "pdfjs.image.add_image_click" | ||
|  |           } | ||
|  |         } | ||
|  |       }); | ||
|  |       dispatchEvent("CREATE"); | ||
|  |     }); | ||
|  |     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) { | ||
|  |         switch (type) { | ||
|  |           case AnnotationEditorParamsType.FREETEXT_SIZE: | ||
|  |             editorFreeTextFontSize.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.FREETEXT_COLOR: | ||
|  |             editorFreeTextColor.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.INK_COLOR: | ||
|  |             editorInkColor.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.INK_THICKNESS: | ||
|  |             editorInkThickness.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.INK_OPACITY: | ||
|  |             editorInkOpacity.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS: | ||
|  |             editorFreeHighlightThickness.value = value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.HIGHLIGHT_FREE: | ||
|  |             editorFreeHighlightThickness.disabled = !value; | ||
|  |             break; | ||
|  |           case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL: | ||
|  |             editorHighlightShowAll.setAttribute("aria-pressed", value); | ||
|  |             break; | ||
|  |         } | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/caret_browsing.js
 | ||
|  | const PRECISION = 1e-1; | ||
|  | class CaretBrowsingMode { | ||
|  |   #mainContainer; | ||
|  |   #toolBarHeight; | ||
|  |   #viewerContainer; | ||
|  |   constructor(mainContainer, viewerContainer, toolbarContainer) { | ||
|  |     this.#mainContainer = mainContainer; | ||
|  |     this.#viewerContainer = viewerContainer; | ||
|  |     this.#toolBarHeight = toolbarContainer?.getBoundingClientRect().height ?? 0; | ||
|  |   } | ||
|  |   #isOnSameLine(rect1, rect2) { | ||
|  |     const top1 = rect1.y; | ||
|  |     const bot1 = rect1.bottom; | ||
|  |     const mid1 = rect1.y + rect1.height / 2; | ||
|  |     const top2 = rect2.y; | ||
|  |     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; | ||
|  |   } | ||
|  |   #isVisible(rect) { | ||
|  |     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 { | ||
|  |       focusNode, | ||
|  |       focusOffset | ||
|  |     } = selection; | ||
|  |     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) { | ||
|  |       const { | ||
|  |         startContainer: offsetNode, | ||
|  |         startOffset: offset | ||
|  |       } = document.caretRangeFromPoint(x, y); | ||
|  |       return { | ||
|  |         offsetNode, | ||
|  |         offset | ||
|  |       }; | ||
|  |     } | ||
|  |     return document.caretPositionFromPoint(x, y); | ||
|  |   } | ||
|  |   #setCaretPositionHelper(selection, caretX, select, element, rect) { | ||
|  |     rect ||= element.getBoundingClientRect(); | ||
|  |     if (caretX <= rect.x + PRECISION) { | ||
|  |       if (select) { | ||
|  |         selection.extend(element.firstChild, 0); | ||
|  |       } else { | ||
|  |         selection.setPosition(element.firstChild, 0); | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     if (rect.right - PRECISION <= caretX) { | ||
|  |       const { | ||
|  |         lastChild | ||
|  |       } = element; | ||
|  |       if (select) { | ||
|  |         selection.extend(lastChild, lastChild.length); | ||
|  |       } else { | ||
|  |         selection.setPosition(lastChild, lastChild.length); | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     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) { | ||
|  |         if (el === element) { | ||
|  |           break; | ||
|  |         } | ||
|  |         const { | ||
|  |           style | ||
|  |         } = el; | ||
|  |         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) { | ||
|  |       if (select) { | ||
|  |         selection.extend(element.firstChild, 0); | ||
|  |       } else { | ||
|  |         selection.setPosition(element.firstChild, 0); | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     if (select) { | ||
|  |       selection.extend(caretPosition.offsetNode, caretPosition.offset); | ||
|  |     } else { | ||
|  |       selection.setPosition(caretPosition.offsetNode, caretPosition.offset); | ||
|  |     } | ||
|  |   } | ||
|  |   #setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX) { | ||
|  |     if (this.#isVisible(newLineElementRect)) { | ||
|  |       this.#setCaretPositionHelper(selection, caretX, select, newLineElement, newLineElementRect); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#mainContainer.addEventListener("scrollend", this.#setCaretPositionHelper.bind(this, selection, caretX, select, newLineElement, null), { | ||
|  |       once: true | ||
|  |     }); | ||
|  |     newLineElement.scrollIntoView(); | ||
|  |   } | ||
|  |   #getNodeOnNextPage(textLayer, isUp) { | ||
|  |     while (true) { | ||
|  |       const page = textLayer.closest(".page"); | ||
|  |       const pageNumber = parseInt(page.getAttribute("data-page-number")); | ||
|  |       const nextPage = isUp ? pageNumber - 1 : pageNumber + 1; | ||
|  |       textLayer = this.#viewerContainer.querySelector(`.page[data-page-number="${nextPage}"] .textLayer`); | ||
|  |       if (!textLayer) { | ||
|  |         return null; | ||
|  |       } | ||
|  |       const walker = document.createTreeWalker(textLayer, NodeFilter.SHOW_TEXT); | ||
|  |       const node = isUp ? walker.lastChild() : walker.firstChild(); | ||
|  |       if (node) { | ||
|  |         return node; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   moveCaret(isUp, select) { | ||
|  |     const selection = document.getSelection(); | ||
|  |     if (selection.rangeCount === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       focusNode | ||
|  |     } = selection; | ||
|  |     const focusElement = focusNode.nodeType !== Node.ELEMENT_NODE ? focusNode.parentElement : focusNode; | ||
|  |     const root = focusElement.closest(".textLayer"); | ||
|  |     if (!root) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); | ||
|  |     walker.currentNode = focusNode; | ||
|  |     const focusRect = focusElement.getBoundingClientRect(); | ||
|  |     let newLineElement = null; | ||
|  |     const nodeIterator = (isUp ? walker.previousSibling : walker.nextSibling).bind(walker); | ||
|  |     while (nodeIterator()) { | ||
|  |       const element = walker.currentNode.parentElement; | ||
|  |       if (!this.#isOnSameLine(focusRect, element.getBoundingClientRect())) { | ||
|  |         newLineElement = element; | ||
|  |         break; | ||
|  |       } | ||
|  |     } | ||
|  |     if (!newLineElement) { | ||
|  |       const node = this.#getNodeOnNextPage(root, isUp); | ||
|  |       if (!node) { | ||
|  |         return; | ||
|  |       } | ||
|  |       if (select) { | ||
|  |         const lastNode = (isUp ? walker.firstChild() : walker.lastChild()) || focusNode; | ||
|  |         selection.extend(lastNode, isUp ? 0 : lastNode.length); | ||
|  |         const range = document.createRange(); | ||
|  |         range.setStart(node, isUp ? node.length : 0); | ||
|  |         range.setEnd(node, isUp ? node.length : 0); | ||
|  |         selection.addRange(range); | ||
|  |         return; | ||
|  |       } | ||
|  |       const [caretX] = this.#getCaretPosition(selection, isUp); | ||
|  |       const { | ||
|  |         parentElement | ||
|  |       } = node; | ||
|  |       this.#setCaretPosition(select, selection, parentElement, parentElement.getBoundingClientRect(), caretX); | ||
|  |       return; | ||
|  |     } | ||
|  |     const [caretX, caretY] = this.#getCaretPosition(selection, isUp); | ||
|  |     const newLineElementRect = newLineElement.getBoundingClientRect(); | ||
|  |     if (this.#isUnderOver(newLineElementRect, caretX, caretY, isUp)) { | ||
|  |       this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX); | ||
|  |       return; | ||
|  |     } | ||
|  |     while (nodeIterator()) { | ||
|  |       const element = walker.currentNode.parentElement; | ||
|  |       const elementRect = element.getBoundingClientRect(); | ||
|  |       if (!this.#isOnSameLine(newLineElementRect, elementRect)) { | ||
|  |         break; | ||
|  |       } | ||
|  |       if (this.#isUnderOver(elementRect, caretX, caretY, isUp)) { | ||
|  |         this.#setCaretPosition(select, selection, element, elementRect, caretX); | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/download_manager.js
 | ||
|  | 
 | ||
|  | function download(blobUrl, filename) { | ||
|  |   const a = document.createElement("a"); | ||
|  |   if (!a.click) { | ||
|  |     throw new Error('DownloadManager: "a.click()" is not supported.'); | ||
|  |   } | ||
|  |   a.href = blobUrl; | ||
|  |   a.target = "_parent"; | ||
|  |   if ("download" in a) { | ||
|  |     a.download = filename; | ||
|  |   } | ||
|  |   (document.body || document.documentElement).append(a); | ||
|  |   a.click(); | ||
|  |   a.remove(); | ||
|  | } | ||
|  | class DownloadManager { | ||
|  |   #openBlobUrls = new WeakMap(); | ||
|  |   downloadData(data, filename, contentType) { | ||
|  |     const blobUrl = URL.createObjectURL(new Blob([data], { | ||
|  |       type: contentType | ||
|  |     })); | ||
|  |     download(blobUrl, filename); | ||
|  |   } | ||
|  |   openOrDownloadData(data, filename, dest = null) { | ||
|  |     const isPdfData = isPdfFile(filename); | ||
|  |     const contentType = isPdfData ? "application/pdf" : ""; | ||
|  |     if (isPdfData) { | ||
|  |       let blobUrl = this.#openBlobUrls.get(data); | ||
|  |       if (!blobUrl) { | ||
|  |         blobUrl = URL.createObjectURL(new Blob([data], { | ||
|  |           type: contentType | ||
|  |         })); | ||
|  |         this.#openBlobUrls.set(data, blobUrl); | ||
|  |       } | ||
|  |       let viewerUrl; | ||
|  |       viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename); | ||
|  |       if (dest) { | ||
|  |         viewerUrl += `#${escape(dest)}`; | ||
|  |       } | ||
|  |       try { | ||
|  |         window.open(viewerUrl); | ||
|  |         return true; | ||
|  |       } catch (ex) { | ||
|  |         console.error(`openOrDownloadData: ${ex}`); | ||
|  |         URL.revokeObjectURL(blobUrl); | ||
|  |         this.#openBlobUrls.delete(data); | ||
|  |       } | ||
|  |     } | ||
|  |     this.downloadData(data, filename, contentType); | ||
|  |     return false; | ||
|  |   } | ||
|  |   download(data, url, filename) { | ||
|  |     let blobUrl; | ||
|  |     if (data) { | ||
|  |       blobUrl = URL.createObjectURL(new Blob([data], { | ||
|  |         type: "application/pdf" | ||
|  |       })); | ||
|  |     } else { | ||
|  |       if (!createValidAbsoluteUrl(url, "http://example.com")) { | ||
|  |         console.error(`download - not a valid URL: ${url}`); | ||
|  |         return; | ||
|  |       } | ||
|  |       blobUrl = url + "#pdfjs.action=download"; | ||
|  |     } | ||
|  |     download(blobUrl, filename); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/overlay_manager.js
 | ||
|  | class OverlayManager { | ||
|  |   #overlays = new WeakMap(); | ||
|  |   #active = null; | ||
|  |   get active() { | ||
|  |     return this.#active; | ||
|  |   } | ||
|  |   async register(dialog, canForceClose = false) { | ||
|  |     if (typeof dialog !== "object") { | ||
|  |       throw new Error("Not enough parameters."); | ||
|  |     } else if (this.#overlays.has(dialog)) { | ||
|  |       throw new Error("The overlay is already registered."); | ||
|  |     } | ||
|  |     this.#overlays.set(dialog, { | ||
|  |       canForceClose | ||
|  |     }); | ||
|  |     dialog.addEventListener("cancel", evt => { | ||
|  |       this.#active = null; | ||
|  |     }); | ||
|  |   } | ||
|  |   async open(dialog) { | ||
|  |     if (!this.#overlays.has(dialog)) { | ||
|  |       throw new Error("The overlay does not exist."); | ||
|  |     } else if (this.#active) { | ||
|  |       if (this.#active === dialog) { | ||
|  |         throw new Error("The overlay is already active."); | ||
|  |       } else if (this.#overlays.get(dialog).canForceClose) { | ||
|  |         await this.close(); | ||
|  |       } else { | ||
|  |         throw new Error("Another overlay is currently active."); | ||
|  |       } | ||
|  |     } | ||
|  |     this.#active = dialog; | ||
|  |     dialog.showModal(); | ||
|  |   } | ||
|  |   async close(dialog = this.#active) { | ||
|  |     if (!this.#overlays.has(dialog)) { | ||
|  |       throw new Error("The overlay does not exist."); | ||
|  |     } else if (!this.#active) { | ||
|  |       throw new Error("The overlay is currently not active."); | ||
|  |     } else if (this.#active !== dialog) { | ||
|  |       throw new Error("Another overlay is currently active."); | ||
|  |     } | ||
|  |     dialog.close(); | ||
|  |     this.#active = null; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/password_prompt.js
 | ||
|  | 
 | ||
|  | class PasswordPrompt { | ||
|  |   #activeCapability = null; | ||
|  |   #updateCallback = null; | ||
|  |   #reason = null; | ||
|  |   constructor(options, overlayManager, isViewerEmbedded = false) { | ||
|  |     this.dialog = options.dialog; | ||
|  |     this.label = options.label; | ||
|  |     this.input = options.input; | ||
|  |     this.submitButton = options.submitButton; | ||
|  |     this.cancelButton = options.cancelButton; | ||
|  |     this.overlayManager = overlayManager; | ||
|  |     this._isViewerEmbedded = isViewerEmbedded; | ||
|  |     this.submitButton.addEventListener("click", this.#verify.bind(this)); | ||
|  |     this.cancelButton.addEventListener("click", this.close.bind(this)); | ||
|  |     this.input.addEventListener("keydown", e => { | ||
|  |       if (e.keyCode === 13) { | ||
|  |         this.#verify(); | ||
|  |       } | ||
|  |     }); | ||
|  |     this.overlayManager.register(this.dialog, true); | ||
|  |     this.dialog.addEventListener("close", this.#cancel.bind(this)); | ||
|  |   } | ||
|  |   async open() { | ||
|  |     await this.#activeCapability?.promise; | ||
|  |     this.#activeCapability = Promise.withResolvers(); | ||
|  |     try { | ||
|  |       await this.overlayManager.open(this.dialog); | ||
|  |     } catch (ex) { | ||
|  |       this.#activeCapability.resolve(); | ||
|  |       throw ex; | ||
|  |     } | ||
|  |     const passwordIncorrect = this.#reason === PasswordResponses.INCORRECT_PASSWORD; | ||
|  |     if (!this._isViewerEmbedded || passwordIncorrect) { | ||
|  |       this.input.focus(); | ||
|  |     } | ||
|  |     this.label.setAttribute("data-l10n-id", passwordIncorrect ? "pdfjs-password-invalid" : "pdfjs-password-label"); | ||
|  |   } | ||
|  |   async close() { | ||
|  |     if (this.overlayManager.active === this.dialog) { | ||
|  |       this.overlayManager.close(this.dialog); | ||
|  |     } | ||
|  |   } | ||
|  |   #verify() { | ||
|  |     const password = this.input.value; | ||
|  |     if (password?.length > 0) { | ||
|  |       this.#invokeCallback(password); | ||
|  |     } | ||
|  |   } | ||
|  |   #cancel() { | ||
|  |     this.#invokeCallback(new Error("PasswordPrompt cancelled.")); | ||
|  |     this.#activeCapability.resolve(); | ||
|  |   } | ||
|  |   #invokeCallback(password) { | ||
|  |     if (!this.#updateCallback) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.close(); | ||
|  |     this.input.value = ""; | ||
|  |     this.#updateCallback(password); | ||
|  |     this.#updateCallback = null; | ||
|  |   } | ||
|  |   async setUpdateCallback(updateCallback, reason) { | ||
|  |     if (this.#activeCapability) { | ||
|  |       await this.#activeCapability.promise; | ||
|  |     } | ||
|  |     this.#updateCallback = updateCallback; | ||
|  |     this.#reason = reason; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/base_tree_viewer.js
 | ||
|  | 
 | ||
|  | const TREEITEM_OFFSET_TOP = -100; | ||
|  | const TREEITEM_SELECTED_CLASS = "selected"; | ||
|  | class BaseTreeViewer { | ||
|  |   constructor(options) { | ||
|  |     this.container = options.container; | ||
|  |     this.eventBus = options.eventBus; | ||
|  |     this._l10n = options.l10n; | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this._pdfDocument = null; | ||
|  |     this._lastToggleIsShow = true; | ||
|  |     this._currentTreeItem = null; | ||
|  |     this.container.textContent = ""; | ||
|  |     this.container.classList.remove("treeWithDeepNesting"); | ||
|  |   } | ||
|  |   _dispatchEvent(count) { | ||
|  |     throw new Error("Not implemented: _dispatchEvent"); | ||
|  |   } | ||
|  |   _bindLink(element, params) { | ||
|  |     throw new Error("Not implemented: _bindLink"); | ||
|  |   } | ||
|  |   _normalizeTextContent(str) { | ||
|  |     return removeNullCharacters(str, true) || "\u2013"; | ||
|  |   } | ||
|  |   _addToggleButton(div, hidden = false) { | ||
|  |     const toggler = document.createElement("div"); | ||
|  |     toggler.className = "treeItemToggler"; | ||
|  |     if (hidden) { | ||
|  |       toggler.classList.add("treeItemsHidden"); | ||
|  |     } | ||
|  |     toggler.onclick = evt => { | ||
|  |       evt.stopPropagation(); | ||
|  |       toggler.classList.toggle("treeItemsHidden"); | ||
|  |       if (evt.shiftKey) { | ||
|  |         const shouldShowAll = !toggler.classList.contains("treeItemsHidden"); | ||
|  |         this._toggleTreeItem(div, shouldShowAll); | ||
|  |       } | ||
|  |     }; | ||
|  |     div.prepend(toggler); | ||
|  |   } | ||
|  |   _toggleTreeItem(root, show = false) { | ||
|  |     this._l10n.pause(); | ||
|  |     this._lastToggleIsShow = show; | ||
|  |     for (const toggler of root.querySelectorAll(".treeItemToggler")) { | ||
|  |       toggler.classList.toggle("treeItemsHidden", !show); | ||
|  |     } | ||
|  |     this._l10n.resume(); | ||
|  |   } | ||
|  |   _toggleAllTreeItems() { | ||
|  |     this._toggleTreeItem(this.container, !this._lastToggleIsShow); | ||
|  |   } | ||
|  |   _finishRendering(fragment, count, hasAnyNesting = false) { | ||
|  |     if (hasAnyNesting) { | ||
|  |       this.container.classList.add("treeWithDeepNesting"); | ||
|  |       this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden"); | ||
|  |     } | ||
|  |     this._l10n.pause(); | ||
|  |     this.container.append(fragment); | ||
|  |     this._l10n.resume(); | ||
|  |     this._dispatchEvent(count); | ||
|  |   } | ||
|  |   render(params) { | ||
|  |     throw new Error("Not implemented: render"); | ||
|  |   } | ||
|  |   _updateCurrentTreeItem(treeItem = null) { | ||
|  |     if (this._currentTreeItem) { | ||
|  |       this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS); | ||
|  |       this._currentTreeItem = null; | ||
|  |     } | ||
|  |     if (treeItem) { | ||
|  |       treeItem.classList.add(TREEITEM_SELECTED_CLASS); | ||
|  |       this._currentTreeItem = treeItem; | ||
|  |     } | ||
|  |   } | ||
|  |   _scrollToCurrentTreeItem(treeItem) { | ||
|  |     if (!treeItem) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._l10n.pause(); | ||
|  |     let currentNode = treeItem.parentNode; | ||
|  |     while (currentNode && currentNode !== this.container) { | ||
|  |       if (currentNode.classList.contains("treeItem")) { | ||
|  |         const toggler = currentNode.firstElementChild; | ||
|  |         toggler?.classList.remove("treeItemsHidden"); | ||
|  |       } | ||
|  |       currentNode = currentNode.parentNode; | ||
|  |     } | ||
|  |     this._l10n.resume(); | ||
|  |     this._updateCurrentTreeItem(treeItem); | ||
|  |     this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_attachment_viewer.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class PDFAttachmentViewer extends BaseTreeViewer { | ||
|  |   constructor(options) { | ||
|  |     super(options); | ||
|  |     this.downloadManager = options.downloadManager; | ||
|  |     this.eventBus._on("fileattachmentannotation", this.#appendAttachment.bind(this)); | ||
|  |   } | ||
|  |   reset(keepRenderedCapability = false) { | ||
|  |     super.reset(); | ||
|  |     this._attachments = null; | ||
|  |     if (!keepRenderedCapability) { | ||
|  |       this._renderedCapability = Promise.withResolvers(); | ||
|  |     } | ||
|  |     this._pendingDispatchEvent = false; | ||
|  |   } | ||
|  |   async _dispatchEvent(attachmentsCount) { | ||
|  |     this._renderedCapability.resolve(); | ||
|  |     if (attachmentsCount === 0 && !this._pendingDispatchEvent) { | ||
|  |       this._pendingDispatchEvent = true; | ||
|  |       await waitOnEventOrTimeout({ | ||
|  |         target: this.eventBus, | ||
|  |         name: "annotationlayerrendered", | ||
|  |         delay: 1000 | ||
|  |       }); | ||
|  |       if (!this._pendingDispatchEvent) { | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     this._pendingDispatchEvent = false; | ||
|  |     this.eventBus.dispatch("attachmentsloaded", { | ||
|  |       source: this, | ||
|  |       attachmentsCount | ||
|  |     }); | ||
|  |   } | ||
|  |   _bindLink(element, { | ||
|  |     content, | ||
|  |     description, | ||
|  |     filename | ||
|  |   }) { | ||
|  |     if (description) { | ||
|  |       element.title = description; | ||
|  |     } | ||
|  |     element.onclick = () => { | ||
|  |       this.downloadManager.openOrDownloadData(content, filename); | ||
|  |       return false; | ||
|  |     }; | ||
|  |   } | ||
|  |   render({ | ||
|  |     attachments, | ||
|  |     keepRenderedCapability = false | ||
|  |   }) { | ||
|  |     if (this._attachments) { | ||
|  |       this.reset(keepRenderedCapability); | ||
|  |     } | ||
|  |     this._attachments = attachments || null; | ||
|  |     if (!attachments) { | ||
|  |       this._dispatchEvent(0); | ||
|  |       return; | ||
|  |     } | ||
|  |     const fragment = document.createDocumentFragment(); | ||
|  |     let attachmentsCount = 0; | ||
|  |     for (const name in attachments) { | ||
|  |       const item = attachments[name]; | ||
|  |       const div = document.createElement("div"); | ||
|  |       div.className = "treeItem"; | ||
|  |       const element = document.createElement("a"); | ||
|  |       this._bindLink(element, item); | ||
|  |       element.textContent = this._normalizeTextContent(item.filename); | ||
|  |       div.append(element); | ||
|  |       fragment.append(div); | ||
|  |       attachmentsCount++; | ||
|  |     } | ||
|  |     this._finishRendering(fragment, attachmentsCount); | ||
|  |   } | ||
|  |   #appendAttachment(item) { | ||
|  |     const renderedPromise = this._renderedCapability.promise; | ||
|  |     renderedPromise.then(() => { | ||
|  |       if (renderedPromise !== this._renderedCapability.promise) { | ||
|  |         return; | ||
|  |       } | ||
|  |       const attachments = this._attachments || Object.create(null); | ||
|  |       for (const name in attachments) { | ||
|  |         if (item.filename === name) { | ||
|  |           return; | ||
|  |         } | ||
|  |       } | ||
|  |       attachments[item.filename] = item; | ||
|  |       this.render({ | ||
|  |         attachments, | ||
|  |         keepRenderedCapability: true | ||
|  |       }); | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/grab_to_pan.js
 | ||
|  | const CSS_CLASS_GRAB = "grab-to-pan-grab"; | ||
|  | class GrabToPan { | ||
|  |   constructor({ | ||
|  |     element | ||
|  |   }) { | ||
|  |     this.element = element; | ||
|  |     this.document = element.ownerDocument; | ||
|  |     this.activate = this.activate.bind(this); | ||
|  |     this.deactivate = this.deactivate.bind(this); | ||
|  |     this.toggle = this.toggle.bind(this); | ||
|  |     this._onMouseDown = this.#onMouseDown.bind(this); | ||
|  |     this._onMouseMove = this.#onMouseMove.bind(this); | ||
|  |     this._endPan = this.#endPan.bind(this); | ||
|  |     const overlay = this.overlay = document.createElement("div"); | ||
|  |     overlay.className = "grab-to-pan-grabbing"; | ||
|  |   } | ||
|  |   activate() { | ||
|  |     if (!this.active) { | ||
|  |       this.active = true; | ||
|  |       this.element.addEventListener("mousedown", this._onMouseDown, true); | ||
|  |       this.element.classList.add(CSS_CLASS_GRAB); | ||
|  |     } | ||
|  |   } | ||
|  |   deactivate() { | ||
|  |     if (this.active) { | ||
|  |       this.active = false; | ||
|  |       this.element.removeEventListener("mousedown", this._onMouseDown, true); | ||
|  |       this._endPan(); | ||
|  |       this.element.classList.remove(CSS_CLASS_GRAB); | ||
|  |     } | ||
|  |   } | ||
|  |   toggle() { | ||
|  |     if (this.active) { | ||
|  |       this.deactivate(); | ||
|  |     } else { | ||
|  |       this.activate(); | ||
|  |     } | ||
|  |   } | ||
|  |   ignoreTarget(node) { | ||
|  |     return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option"); | ||
|  |   } | ||
|  |   #onMouseDown(event) { | ||
|  |     if (event.button !== 0 || this.ignoreTarget(event.target)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (event.originalTarget) { | ||
|  |       try { | ||
|  |         event.originalTarget.tagName; | ||
|  |       } catch { | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     this.scrollLeftStart = this.element.scrollLeft; | ||
|  |     this.scrollTopStart = this.element.scrollTop; | ||
|  |     this.clientXStart = event.clientX; | ||
|  |     this.clientYStart = event.clientY; | ||
|  |     this.document.addEventListener("mousemove", this._onMouseMove, true); | ||
|  |     this.document.addEventListener("mouseup", this._endPan, true); | ||
|  |     this.element.addEventListener("scroll", this._endPan, true); | ||
|  |     event.preventDefault(); | ||
|  |     event.stopPropagation(); | ||
|  |     const focusedElement = document.activeElement; | ||
|  |     if (focusedElement && !focusedElement.contains(event.target)) { | ||
|  |       focusedElement.blur(); | ||
|  |     } | ||
|  |   } | ||
|  |   #onMouseMove(event) { | ||
|  |     this.element.removeEventListener("scroll", this._endPan, true); | ||
|  |     if (!(event.buttons & 1)) { | ||
|  |       this._endPan(); | ||
|  |       return; | ||
|  |     } | ||
|  |     const xDiff = event.clientX - this.clientXStart; | ||
|  |     const yDiff = event.clientY - this.clientYStart; | ||
|  |     this.element.scrollTo({ | ||
|  |       top: this.scrollTopStart - yDiff, | ||
|  |       left: this.scrollLeftStart - xDiff, | ||
|  |       behavior: "instant" | ||
|  |     }); | ||
|  |     if (!this.overlay.parentNode) { | ||
|  |       document.body.append(this.overlay); | ||
|  |     } | ||
|  |   } | ||
|  |   #endPan() { | ||
|  |     this.element.removeEventListener("scroll", this._endPan, true); | ||
|  |     this.document.removeEventListener("mousemove", this._onMouseMove, true); | ||
|  |     this.document.removeEventListener("mouseup", this._endPan, true); | ||
|  |     this.overlay.remove(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_cursor_tools.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class PDFCursorTools { | ||
|  |   #active = CursorTool.SELECT; | ||
|  |   #prevActive = null; | ||
|  |   constructor({ | ||
|  |     container, | ||
|  |     eventBus, | ||
|  |     cursorToolOnLoad = CursorTool.SELECT | ||
|  |   }) { | ||
|  |     this.container = container; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.#addEventListeners(); | ||
|  |     Promise.resolve().then(() => { | ||
|  |       this.switchTool(cursorToolOnLoad); | ||
|  |     }); | ||
|  |   } | ||
|  |   get activeTool() { | ||
|  |     return this.#active; | ||
|  |   } | ||
|  |   switchTool(tool) { | ||
|  |     if (this.#prevActive !== null) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (tool === this.#active) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const disableActiveTool = () => { | ||
|  |       switch (this.#active) { | ||
|  |         case CursorTool.SELECT: | ||
|  |           break; | ||
|  |         case CursorTool.HAND: | ||
|  |           this._handTool.deactivate(); | ||
|  |           break; | ||
|  |         case CursorTool.ZOOM: | ||
|  |       } | ||
|  |     }; | ||
|  |     switch (tool) { | ||
|  |       case CursorTool.SELECT: | ||
|  |         disableActiveTool(); | ||
|  |         break; | ||
|  |       case CursorTool.HAND: | ||
|  |         disableActiveTool(); | ||
|  |         this._handTool.activate(); | ||
|  |         break; | ||
|  |       case CursorTool.ZOOM: | ||
|  |       default: | ||
|  |         console.error(`switchTool: "${tool}" is an unsupported value.`); | ||
|  |         return; | ||
|  |     } | ||
|  |     this.#active = tool; | ||
|  |     this.eventBus.dispatch("cursortoolchanged", { | ||
|  |       source: this, | ||
|  |       tool | ||
|  |     }); | ||
|  |   } | ||
|  |   #addEventListeners() { | ||
|  |     this.eventBus._on("switchcursortool", evt => { | ||
|  |       if (!evt.reset) { | ||
|  |         this.switchTool(evt.tool); | ||
|  |       } else if (this.#prevActive !== null) { | ||
|  |         annotationEditorMode = AnnotationEditorType.NONE; | ||
|  |         presentationModeState = PresentationModeState.NORMAL; | ||
|  |         enableActive(); | ||
|  |       } | ||
|  |     }); | ||
|  |     let annotationEditorMode = AnnotationEditorType.NONE, | ||
|  |       presentationModeState = PresentationModeState.NORMAL; | ||
|  |     const disableActive = () => { | ||
|  |       const prevActive = this.#active; | ||
|  |       this.switchTool(CursorTool.SELECT); | ||
|  |       this.#prevActive ??= prevActive; | ||
|  |     }; | ||
|  |     const enableActive = () => { | ||
|  |       const prevActive = this.#prevActive; | ||
|  |       if (prevActive !== null && annotationEditorMode === AnnotationEditorType.NONE && presentationModeState === PresentationModeState.NORMAL) { | ||
|  |         this.#prevActive = null; | ||
|  |         this.switchTool(prevActive); | ||
|  |       } | ||
|  |     }; | ||
|  |     this.eventBus._on("annotationeditormodechanged", ({ | ||
|  |       mode | ||
|  |     }) => { | ||
|  |       annotationEditorMode = mode; | ||
|  |       if (mode === AnnotationEditorType.NONE) { | ||
|  |         enableActive(); | ||
|  |       } else { | ||
|  |         disableActive(); | ||
|  |       } | ||
|  |     }); | ||
|  |     this.eventBus._on("presentationmodechanged", ({ | ||
|  |       state | ||
|  |     }) => { | ||
|  |       presentationModeState = state; | ||
|  |       if (state === PresentationModeState.NORMAL) { | ||
|  |         enableActive(); | ||
|  |       } else if (state === PresentationModeState.FULLSCREEN) { | ||
|  |         disableActive(); | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   get _handTool() { | ||
|  |     return shadow(this, "_handTool", new GrabToPan({ | ||
|  |       element: this.container | ||
|  |     })); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_document_properties.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"]; | ||
|  | const US_PAGE_NAMES = { | ||
|  |   "8.5x11": "pdfjs-document-properties-page-size-name-letter", | ||
|  |   "8.5x14": "pdfjs-document-properties-page-size-name-legal" | ||
|  | }; | ||
|  | const METRIC_PAGE_NAMES = { | ||
|  |   "297x420": "pdfjs-document-properties-page-size-name-a-three", | ||
|  |   "210x297": "pdfjs-document-properties-page-size-name-a-four" | ||
|  | }; | ||
|  | function getPageName(size, isPortrait, pageNames) { | ||
|  |   const width = isPortrait ? size.width : size.height; | ||
|  |   const height = isPortrait ? size.height : size.width; | ||
|  |   return pageNames[`${width}x${height}`]; | ||
|  | } | ||
|  | class PDFDocumentProperties { | ||
|  |   #fieldData = null; | ||
|  |   constructor({ | ||
|  |     dialog, | ||
|  |     fields, | ||
|  |     closeButton | ||
|  |   }, overlayManager, eventBus, l10n, fileNameLookup) { | ||
|  |     this.dialog = dialog; | ||
|  |     this.fields = fields; | ||
|  |     this.overlayManager = overlayManager; | ||
|  |     this.l10n = l10n; | ||
|  |     this._fileNameLookup = fileNameLookup; | ||
|  |     this.#reset(); | ||
|  |     closeButton.addEventListener("click", this.close.bind(this)); | ||
|  |     this.overlayManager.register(this.dialog); | ||
|  |     eventBus._on("pagechanging", evt => { | ||
|  |       this._currentPageNumber = evt.pageNumber; | ||
|  |     }); | ||
|  |     eventBus._on("rotationchanging", evt => { | ||
|  |       this._pagesRotation = evt.pagesRotation; | ||
|  |     }); | ||
|  |   } | ||
|  |   async open() { | ||
|  |     await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]); | ||
|  |     const currentPageNumber = this._currentPageNumber; | ||
|  |     const pagesRotation = this._pagesRotation; | ||
|  |     if (this.#fieldData && currentPageNumber === this.#fieldData._currentPageNumber && pagesRotation === this.#fieldData._pagesRotation) { | ||
|  |       this.#updateUI(); | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       info, | ||
|  |       contentLength | ||
|  |     } = await this.pdfDocument.getMetadata(); | ||
|  |     const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), this.#parseFileSize(contentLength), this.#parseDate(info.CreationDate), this.#parseDate(info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => { | ||
|  |       return this.#parsePageSize(getPageSizeInches(pdfPage), pagesRotation); | ||
|  |     }), this.#parseLinearization(info.IsLinearized)]); | ||
|  |     this.#fieldData = Object.freeze({ | ||
|  |       fileName, | ||
|  |       fileSize, | ||
|  |       title: info.Title, | ||
|  |       author: info.Author, | ||
|  |       subject: info.Subject, | ||
|  |       keywords: info.Keywords, | ||
|  |       creationDate, | ||
|  |       modificationDate, | ||
|  |       creator: info.Creator, | ||
|  |       producer: info.Producer, | ||
|  |       version: info.PDFFormatVersion, | ||
|  |       pageCount: this.pdfDocument.numPages, | ||
|  |       pageSize, | ||
|  |       linearized: isLinearized, | ||
|  |       _currentPageNumber: currentPageNumber, | ||
|  |       _pagesRotation: pagesRotation | ||
|  |     }); | ||
|  |     this.#updateUI(); | ||
|  |     const { | ||
|  |       length | ||
|  |     } = await this.pdfDocument.getDownloadInfo(); | ||
|  |     if (contentLength === length) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const data = Object.assign(Object.create(null), this.#fieldData); | ||
|  |     data.fileSize = await this.#parseFileSize(length); | ||
|  |     this.#fieldData = Object.freeze(data); | ||
|  |     this.#updateUI(); | ||
|  |   } | ||
|  |   async close() { | ||
|  |     this.overlayManager.close(this.dialog); | ||
|  |   } | ||
|  |   setDocument(pdfDocument) { | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.#reset(); | ||
|  |       this.#updateUI(); | ||
|  |     } | ||
|  |     if (!pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.pdfDocument = pdfDocument; | ||
|  |     this._dataAvailableCapability.resolve(); | ||
|  |   } | ||
|  |   #reset() { | ||
|  |     this.pdfDocument = null; | ||
|  |     this.#fieldData = null; | ||
|  |     this._dataAvailableCapability = Promise.withResolvers(); | ||
|  |     this._currentPageNumber = 1; | ||
|  |     this._pagesRotation = 0; | ||
|  |   } | ||
|  |   #updateUI() { | ||
|  |     if (this.#fieldData && this.overlayManager.active !== this.dialog) { | ||
|  |       return; | ||
|  |     } | ||
|  |     for (const id in this.fields) { | ||
|  |       const content = this.#fieldData?.[id]; | ||
|  |       this.fields[id].textContent = content || content === 0 ? content : "-"; | ||
|  |     } | ||
|  |   } | ||
|  |   async #parseFileSize(b = 0) { | ||
|  |     const kb = b / 1024, | ||
|  |       mb = kb / 1024; | ||
|  |     return kb ? this.l10n.get(mb >= 1 ? "pdfjs-document-properties-size-mb" : "pdfjs-document-properties-size-kb", { | ||
|  |       mb, | ||
|  |       kb, | ||
|  |       b | ||
|  |     }) : undefined; | ||
|  |   } | ||
|  |   async #parsePageSize(pageSizeInches, pagesRotation) { | ||
|  |     if (!pageSizeInches) { | ||
|  |       return undefined; | ||
|  |     } | ||
|  |     if (pagesRotation % 180 !== 0) { | ||
|  |       pageSizeInches = { | ||
|  |         width: pageSizeInches.height, | ||
|  |         height: pageSizeInches.width | ||
|  |       }; | ||
|  |     } | ||
|  |     const isPortrait = isPortraitOrientation(pageSizeInches), | ||
|  |       nonMetric = NON_METRIC_LOCALES.includes(this.l10n.getLanguage()); | ||
|  |     let sizeInches = { | ||
|  |       width: Math.round(pageSizeInches.width * 100) / 100, | ||
|  |       height: Math.round(pageSizeInches.height * 100) / 100 | ||
|  |     }; | ||
|  |     let sizeMillimeters = { | ||
|  |       width: Math.round(pageSizeInches.width * 25.4 * 10) / 10, | ||
|  |       height: Math.round(pageSizeInches.height * 25.4 * 10) / 10 | ||
|  |     }; | ||
|  |     let nameId = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES); | ||
|  |     if (!nameId && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) { | ||
|  |       const exactMillimeters = { | ||
|  |         width: pageSizeInches.width * 25.4, | ||
|  |         height: pageSizeInches.height * 25.4 | ||
|  |       }; | ||
|  |       const intMillimeters = { | ||
|  |         width: Math.round(sizeMillimeters.width), | ||
|  |         height: Math.round(sizeMillimeters.height) | ||
|  |       }; | ||
|  |       if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) { | ||
|  |         nameId = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES); | ||
|  |         if (nameId) { | ||
|  |           sizeInches = { | ||
|  |             width: Math.round(intMillimeters.width / 25.4 * 100) / 100, | ||
|  |             height: Math.round(intMillimeters.height / 25.4 * 100) / 100 | ||
|  |           }; | ||
|  |           sizeMillimeters = intMillimeters; | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     const [{ | ||
|  |       width, | ||
|  |       height | ||
|  |     }, unit, name, orientation] = await Promise.all([nonMetric ? sizeInches : sizeMillimeters, this.l10n.get(nonMetric ? "pdfjs-document-properties-page-size-unit-inches" : "pdfjs-document-properties-page-size-unit-millimeters"), nameId && this.l10n.get(nameId), this.l10n.get(isPortrait ? "pdfjs-document-properties-page-size-orientation-portrait" : "pdfjs-document-properties-page-size-orientation-landscape")]); | ||
|  |     return this.l10n.get(name ? "pdfjs-document-properties-page-size-dimension-name-string" : "pdfjs-document-properties-page-size-dimension-string", { | ||
|  |       width, | ||
|  |       height, | ||
|  |       unit, | ||
|  |       name, | ||
|  |       orientation | ||
|  |     }); | ||
|  |   } | ||
|  |   async #parseDate(inputDate) { | ||
|  |     const dateObj = PDFDateString.toDateObject(inputDate); | ||
|  |     return dateObj ? this.l10n.get("pdfjs-document-properties-date-time-string", { | ||
|  |       dateObj | ||
|  |     }) : undefined; | ||
|  |   } | ||
|  |   #parseLinearization(isLinearized) { | ||
|  |     return this.l10n.get(isLinearized ? "pdfjs-document-properties-linearized-yes" : "pdfjs-document-properties-linearized-no"); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_find_utils.js
 | ||
|  | const CharacterType = { | ||
|  |   SPACE: 0, | ||
|  |   ALPHA_LETTER: 1, | ||
|  |   PUNCT: 2, | ||
|  |   HAN_LETTER: 3, | ||
|  |   KATAKANA_LETTER: 4, | ||
|  |   HIRAGANA_LETTER: 5, | ||
|  |   HALFWIDTH_KATAKANA_LETTER: 6, | ||
|  |   THAI_LETTER: 7 | ||
|  | }; | ||
|  | function isAlphabeticalScript(charCode) { | ||
|  |   return charCode < 0x2e80; | ||
|  | } | ||
|  | function isAscii(charCode) { | ||
|  |   return (charCode & 0xff80) === 0; | ||
|  | } | ||
|  | function isAsciiAlpha(charCode) { | ||
|  |   return charCode >= 0x61 && charCode <= 0x7a || charCode >= 0x41 && charCode <= 0x5a; | ||
|  | } | ||
|  | function isAsciiDigit(charCode) { | ||
|  |   return charCode >= 0x30 && charCode <= 0x39; | ||
|  | } | ||
|  | function isAsciiSpace(charCode) { | ||
|  |   return charCode === 0x20 || charCode === 0x09 || charCode === 0x0d || charCode === 0x0a; | ||
|  | } | ||
|  | function isHan(charCode) { | ||
|  |   return charCode >= 0x3400 && charCode <= 0x9fff || charCode >= 0xf900 && charCode <= 0xfaff; | ||
|  | } | ||
|  | function isKatakana(charCode) { | ||
|  |   return charCode >= 0x30a0 && charCode <= 0x30ff; | ||
|  | } | ||
|  | function isHiragana(charCode) { | ||
|  |   return charCode >= 0x3040 && charCode <= 0x309f; | ||
|  | } | ||
|  | function isHalfwidthKatakana(charCode) { | ||
|  |   return charCode >= 0xff60 && charCode <= 0xff9f; | ||
|  | } | ||
|  | function isThai(charCode) { | ||
|  |   return (charCode & 0xff80) === 0x0e00; | ||
|  | } | ||
|  | function getCharacterType(charCode) { | ||
|  |   if (isAlphabeticalScript(charCode)) { | ||
|  |     if (isAscii(charCode)) { | ||
|  |       if (isAsciiSpace(charCode)) { | ||
|  |         return CharacterType.SPACE; | ||
|  |       } else if (isAsciiAlpha(charCode) || isAsciiDigit(charCode) || charCode === 0x5f) { | ||
|  |         return CharacterType.ALPHA_LETTER; | ||
|  |       } | ||
|  |       return CharacterType.PUNCT; | ||
|  |     } else if (isThai(charCode)) { | ||
|  |       return CharacterType.THAI_LETTER; | ||
|  |     } else if (charCode === 0xa0) { | ||
|  |       return CharacterType.SPACE; | ||
|  |     } | ||
|  |     return CharacterType.ALPHA_LETTER; | ||
|  |   } | ||
|  |   if (isHan(charCode)) { | ||
|  |     return CharacterType.HAN_LETTER; | ||
|  |   } else if (isKatakana(charCode)) { | ||
|  |     return CharacterType.KATAKANA_LETTER; | ||
|  |   } else if (isHiragana(charCode)) { | ||
|  |     return CharacterType.HIRAGANA_LETTER; | ||
|  |   } else if (isHalfwidthKatakana(charCode)) { | ||
|  |     return CharacterType.HALFWIDTH_KATAKANA_LETTER; | ||
|  |   } | ||
|  |   return CharacterType.ALPHA_LETTER; | ||
|  | } | ||
|  | let NormalizeWithNFKC; | ||
|  | function getNormalizeWithNFKC() { | ||
|  |   NormalizeWithNFKC ||= ` ¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰꟲ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`; | ||
|  |   return NormalizeWithNFKC; | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_find_controller.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const FindState = { | ||
|  |   FOUND: 0, | ||
|  |   NOT_FOUND: 1, | ||
|  |   WRAPPED: 2, | ||
|  |   PENDING: 3 | ||
|  | }; | ||
|  | const FIND_TIMEOUT = 250; | ||
|  | const MATCH_SCROLL_OFFSET_TOP = -50; | ||
|  | const MATCH_SCROLL_OFFSET_LEFT = -400; | ||
|  | const CHARACTERS_TO_NORMALIZE = { | ||
|  |   "\u2010": "-", | ||
|  |   "\u2018": "'", | ||
|  |   "\u2019": "'", | ||
|  |   "\u201A": "'", | ||
|  |   "\u201B": "'", | ||
|  |   "\u201C": '"', | ||
|  |   "\u201D": '"', | ||
|  |   "\u201E": '"', | ||
|  |   "\u201F": '"', | ||
|  |   "\u00BC": "1/4", | ||
|  |   "\u00BD": "1/2", | ||
|  |   "\u00BE": "3/4" | ||
|  | }; | ||
|  | const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]); | ||
|  | let DIACRITICS_EXCEPTION_STR; | ||
|  | const DIACRITICS_REG_EXP = /\p{M}+/gu; | ||
|  | const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu; | ||
|  | const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u; | ||
|  | const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u; | ||
|  | const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g; | ||
|  | const SYLLABLES_LENGTHS = new Map(); | ||
|  | const FIRST_CHAR_SYLLABLES_REG_EXP = "[\\u1100-\\u1112\\ud7a4-\\ud7af\\ud84a\\ud84c\\ud850\\ud854\\ud857\\ud85f]"; | ||
|  | const NFKC_CHARS_TO_NORMALIZE = new Map(); | ||
|  | let noSyllablesRegExp = null; | ||
|  | let withSyllablesRegExp = null; | ||
|  | function normalize(text) { | ||
|  |   const syllablePositions = []; | ||
|  |   let m; | ||
|  |   while ((m = SYLLABLES_REG_EXP.exec(text)) !== null) { | ||
|  |     let { | ||
|  |       index | ||
|  |     } = m; | ||
|  |     for (const char of m[0]) { | ||
|  |       let len = SYLLABLES_LENGTHS.get(char); | ||
|  |       if (!len) { | ||
|  |         len = char.normalize("NFD").length; | ||
|  |         SYLLABLES_LENGTHS.set(char, len); | ||
|  |       } | ||
|  |       syllablePositions.push([len, index++]); | ||
|  |     } | ||
|  |   } | ||
|  |   let normalizationRegex; | ||
|  |   if (syllablePositions.length === 0 && noSyllablesRegExp) { | ||
|  |     normalizationRegex = noSyllablesRegExp; | ||
|  |   } else if (syllablePositions.length > 0 && withSyllablesRegExp) { | ||
|  |     normalizationRegex = withSyllablesRegExp; | ||
|  |   } else { | ||
|  |     const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(""); | ||
|  |     const toNormalizeWithNFKC = getNormalizeWithNFKC(); | ||
|  |     const CJK = "(?:\\p{Ideographic}|[\u3040-\u30FF])"; | ||
|  |     const HKDiacritics = "(?:\u3099|\u309A)"; | ||
|  |     const regexp = `([${replace}])|([${toNormalizeWithNFKC}])|(${HKDiacritics}\\n)|(\\p{M}+(?:-\\n)?)|(\\S-\\n)|(${CJK}\\n)|(\\n)`; | ||
|  |     if (syllablePositions.length === 0) { | ||
|  |       normalizationRegex = noSyllablesRegExp = new RegExp(regexp + "|(\\u0000)", "gum"); | ||
|  |     } else { | ||
|  |       normalizationRegex = withSyllablesRegExp = new RegExp(regexp + `|(${FIRST_CHAR_SYLLABLES_REG_EXP})`, "gum"); | ||
|  |     } | ||
|  |   } | ||
|  |   const rawDiacriticsPositions = []; | ||
|  |   while ((m = DIACRITICS_REG_EXP.exec(text)) !== null) { | ||
|  |     rawDiacriticsPositions.push([m[0].length, m.index]); | ||
|  |   } | ||
|  |   let normalized = text.normalize("NFD"); | ||
|  |   const positions = [[0, 0]]; | ||
|  |   let rawDiacriticsIndex = 0; | ||
|  |   let syllableIndex = 0; | ||
|  |   let shift = 0; | ||
|  |   let shiftOrigin = 0; | ||
|  |   let eol = 0; | ||
|  |   let hasDiacritics = false; | ||
|  |   normalized = normalized.replace(normalizationRegex, (match, p1, p2, p3, p4, p5, p6, p7, p8, i) => { | ||
|  |     i -= shiftOrigin; | ||
|  |     if (p1) { | ||
|  |       const replacement = CHARACTERS_TO_NORMALIZE[p1]; | ||
|  |       const jj = replacement.length; | ||
|  |       for (let j = 1; j < jj; j++) { | ||
|  |         positions.push([i - shift + j, shift - j]); | ||
|  |       } | ||
|  |       shift -= jj - 1; | ||
|  |       return replacement; | ||
|  |     } | ||
|  |     if (p2) { | ||
|  |       let replacement = NFKC_CHARS_TO_NORMALIZE.get(p2); | ||
|  |       if (!replacement) { | ||
|  |         replacement = p2.normalize("NFKC"); | ||
|  |         NFKC_CHARS_TO_NORMALIZE.set(p2, replacement); | ||
|  |       } | ||
|  |       const jj = replacement.length; | ||
|  |       for (let j = 1; j < jj; j++) { | ||
|  |         positions.push([i - shift + j, shift - j]); | ||
|  |       } | ||
|  |       shift -= jj - 1; | ||
|  |       return replacement; | ||
|  |     } | ||
|  |     if (p3) { | ||
|  |       hasDiacritics = true; | ||
|  |       if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) { | ||
|  |         ++rawDiacriticsIndex; | ||
|  |       } else { | ||
|  |         positions.push([i - 1 - shift + 1, shift - 1]); | ||
|  |         shift -= 1; | ||
|  |         shiftOrigin += 1; | ||
|  |       } | ||
|  |       positions.push([i - shift + 1, shift]); | ||
|  |       shiftOrigin += 1; | ||
|  |       eol += 1; | ||
|  |       return p3.charAt(0); | ||
|  |     } | ||
|  |     if (p4) { | ||
|  |       const hasTrailingDashEOL = p4.endsWith("\n"); | ||
|  |       const len = hasTrailingDashEOL ? p4.length - 2 : p4.length; | ||
|  |       hasDiacritics = true; | ||
|  |       let jj = len; | ||
|  |       if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) { | ||
|  |         jj -= rawDiacriticsPositions[rawDiacriticsIndex][0]; | ||
|  |         ++rawDiacriticsIndex; | ||
|  |       } | ||
|  |       for (let j = 1; j <= jj; j++) { | ||
|  |         positions.push([i - 1 - shift + j, shift - j]); | ||
|  |       } | ||
|  |       shift -= jj; | ||
|  |       shiftOrigin += jj; | ||
|  |       if (hasTrailingDashEOL) { | ||
|  |         i += len - 1; | ||
|  |         positions.push([i - shift + 1, 1 + shift]); | ||
|  |         shift += 1; | ||
|  |         shiftOrigin += 1; | ||
|  |         eol += 1; | ||
|  |         return p4.slice(0, len); | ||
|  |       } | ||
|  |       return p4; | ||
|  |     } | ||
|  |     if (p5) { | ||
|  |       const len = p5.length - 2; | ||
|  |       positions.push([i - shift + len, 1 + shift]); | ||
|  |       shift += 1; | ||
|  |       shiftOrigin += 1; | ||
|  |       eol += 1; | ||
|  |       return p5.slice(0, -2); | ||
|  |     } | ||
|  |     if (p6) { | ||
|  |       const len = p6.length - 1; | ||
|  |       positions.push([i - shift + len, shift]); | ||
|  |       shiftOrigin += 1; | ||
|  |       eol += 1; | ||
|  |       return p6.slice(0, -1); | ||
|  |     } | ||
|  |     if (p7) { | ||
|  |       positions.push([i - shift + 1, shift - 1]); | ||
|  |       shift -= 1; | ||
|  |       shiftOrigin += 1; | ||
|  |       eol += 1; | ||
|  |       return " "; | ||
|  |     } | ||
|  |     if (i + eol === syllablePositions[syllableIndex]?.[1]) { | ||
|  |       const newCharLen = syllablePositions[syllableIndex][0] - 1; | ||
|  |       ++syllableIndex; | ||
|  |       for (let j = 1; j <= newCharLen; j++) { | ||
|  |         positions.push([i - (shift - j), shift - j]); | ||
|  |       } | ||
|  |       shift -= newCharLen; | ||
|  |       shiftOrigin += newCharLen; | ||
|  |     } | ||
|  |     return p8; | ||
|  |   }); | ||
|  |   positions.push([normalized.length, shift]); | ||
|  |   return [normalized, positions, hasDiacritics]; | ||
|  | } | ||
|  | function getOriginalIndex(diffs, pos, len) { | ||
|  |   if (!diffs) { | ||
|  |     return [pos, len]; | ||
|  |   } | ||
|  |   const start = pos; | ||
|  |   const end = pos + len - 1; | ||
|  |   let i = binarySearchFirstItem(diffs, x => x[0] >= start); | ||
|  |   if (diffs[i][0] > start) { | ||
|  |     --i; | ||
|  |   } | ||
|  |   let j = binarySearchFirstItem(diffs, x => x[0] >= end, i); | ||
|  |   if (diffs[j][0] > end) { | ||
|  |     --j; | ||
|  |   } | ||
|  |   const oldStart = start + diffs[i][1]; | ||
|  |   const oldEnd = end + diffs[j][1]; | ||
|  |   const oldLen = oldEnd + 1 - oldStart; | ||
|  |   return [oldStart, oldLen]; | ||
|  | } | ||
|  | class PDFFindController { | ||
|  |   #state = null; | ||
|  |   #updateMatchesCountOnProgress = true; | ||
|  |   #visitedPagesCount = 0; | ||
|  |   constructor({ | ||
|  |     linkService, | ||
|  |     eventBus, | ||
|  |     updateMatchesCountOnProgress = true | ||
|  |   }) { | ||
|  |     this._linkService = linkService; | ||
|  |     this._eventBus = eventBus; | ||
|  |     this.#updateMatchesCountOnProgress = updateMatchesCountOnProgress; | ||
|  |     this.onIsPageVisible = null; | ||
|  |     this.#reset(); | ||
|  |     eventBus._on("find", this.#onFind.bind(this)); | ||
|  |     eventBus._on("findbarclose", this.#onFindBarClose.bind(this)); | ||
|  |   } | ||
|  |   get highlightMatches() { | ||
|  |     return this._highlightMatches; | ||
|  |   } | ||
|  |   get pageMatches() { | ||
|  |     return this._pageMatches; | ||
|  |   } | ||
|  |   get pageMatchesLength() { | ||
|  |     return this._pageMatchesLength; | ||
|  |   } | ||
|  |   get selected() { | ||
|  |     return this._selected; | ||
|  |   } | ||
|  |   get state() { | ||
|  |     return this.#state; | ||
|  |   } | ||
|  |   setDocument(pdfDocument) { | ||
|  |     if (this._pdfDocument) { | ||
|  |       this.#reset(); | ||
|  |     } | ||
|  |     if (!pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._pdfDocument = pdfDocument; | ||
|  |     this._firstPageCapability.resolve(); | ||
|  |   } | ||
|  |   #onFind(state) { | ||
|  |     if (!state) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pdfDocument = this._pdfDocument; | ||
|  |     const { | ||
|  |       type | ||
|  |     } = state; | ||
|  |     if (this.#state === null || this.#shouldDirtyMatch(state)) { | ||
|  |       this._dirtyMatch = true; | ||
|  |     } | ||
|  |     this.#state = state; | ||
|  |     if (type !== "highlightallchange") { | ||
|  |       this.#updateUIState(FindState.PENDING); | ||
|  |     } | ||
|  |     this._firstPageCapability.promise.then(() => { | ||
|  |       if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#extractText(); | ||
|  |       const findbarClosed = !this._highlightMatches; | ||
|  |       const pendingTimeout = !!this._findTimeout; | ||
|  |       if (this._findTimeout) { | ||
|  |         clearTimeout(this._findTimeout); | ||
|  |         this._findTimeout = null; | ||
|  |       } | ||
|  |       if (!type) { | ||
|  |         this._findTimeout = setTimeout(() => { | ||
|  |           this.#nextMatch(); | ||
|  |           this._findTimeout = null; | ||
|  |         }, FIND_TIMEOUT); | ||
|  |       } else if (this._dirtyMatch) { | ||
|  |         this.#nextMatch(); | ||
|  |       } else if (type === "again") { | ||
|  |         this.#nextMatch(); | ||
|  |         if (findbarClosed && this.#state.highlightAll) { | ||
|  |           this.#updateAllPages(); | ||
|  |         } | ||
|  |       } else if (type === "highlightallchange") { | ||
|  |         if (pendingTimeout) { | ||
|  |           this.#nextMatch(); | ||
|  |         } else { | ||
|  |           this._highlightMatches = true; | ||
|  |         } | ||
|  |         this.#updateAllPages(); | ||
|  |       } else { | ||
|  |         this.#nextMatch(); | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   scrollMatchIntoView({ | ||
|  |     element = null, | ||
|  |     selectedLeft = 0, | ||
|  |     pageIndex = -1, | ||
|  |     matchIndex = -1 | ||
|  |   }) { | ||
|  |     if (!this._scrollMatches || !element) { | ||
|  |       return; | ||
|  |     } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) { | ||
|  |       return; | ||
|  |     } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._scrollMatches = false; | ||
|  |     const spot = { | ||
|  |       top: MATCH_SCROLL_OFFSET_TOP, | ||
|  |       left: selectedLeft + MATCH_SCROLL_OFFSET_LEFT | ||
|  |     }; | ||
|  |     scrollIntoView(element, spot, true); | ||
|  |   } | ||
|  |   #reset() { | ||
|  |     this._highlightMatches = false; | ||
|  |     this._scrollMatches = false; | ||
|  |     this._pdfDocument = null; | ||
|  |     this._pageMatches = []; | ||
|  |     this._pageMatchesLength = []; | ||
|  |     this.#visitedPagesCount = 0; | ||
|  |     this.#state = null; | ||
|  |     this._selected = { | ||
|  |       pageIdx: -1, | ||
|  |       matchIdx: -1 | ||
|  |     }; | ||
|  |     this._offset = { | ||
|  |       pageIdx: null, | ||
|  |       matchIdx: null, | ||
|  |       wrapped: false | ||
|  |     }; | ||
|  |     this._extractTextPromises = []; | ||
|  |     this._pageContents = []; | ||
|  |     this._pageDiffs = []; | ||
|  |     this._hasDiacritics = []; | ||
|  |     this._matchesCountTotal = 0; | ||
|  |     this._pagesToSearch = null; | ||
|  |     this._pendingFindMatches = new Set(); | ||
|  |     this._resumePageIdx = null; | ||
|  |     this._dirtyMatch = false; | ||
|  |     clearTimeout(this._findTimeout); | ||
|  |     this._findTimeout = null; | ||
|  |     this._firstPageCapability = Promise.withResolvers(); | ||
|  |   } | ||
|  |   get #query() { | ||
|  |     const { | ||
|  |       query | ||
|  |     } = this.#state; | ||
|  |     if (typeof query === "string") { | ||
|  |       if (query !== this._rawQuery) { | ||
|  |         this._rawQuery = query; | ||
|  |         [this._normalizedQuery] = normalize(query); | ||
|  |       } | ||
|  |       return this._normalizedQuery; | ||
|  |     } | ||
|  |     return (query || []).filter(q => !!q).map(q => normalize(q)[0]); | ||
|  |   } | ||
|  |   #shouldDirtyMatch(state) { | ||
|  |     const newQuery = state.query, | ||
|  |       prevQuery = this.#state.query; | ||
|  |     const newType = typeof newQuery, | ||
|  |       prevType = typeof prevQuery; | ||
|  |     if (newType !== prevType) { | ||
|  |       return true; | ||
|  |     } | ||
|  |     if (newType === "string") { | ||
|  |       if (newQuery !== prevQuery) { | ||
|  |         return true; | ||
|  |       } | ||
|  |     } else if (JSON.stringify(newQuery) !== JSON.stringify(prevQuery)) { | ||
|  |       return true; | ||
|  |     } | ||
|  |     switch (state.type) { | ||
|  |       case "again": | ||
|  |         const pageNumber = this._selected.pageIdx + 1; | ||
|  |         const linkService = this._linkService; | ||
|  |         return pageNumber >= 1 && pageNumber <= linkService.pagesCount && pageNumber !== linkService.page && !(this.onIsPageVisible?.(pageNumber) ?? true); | ||
|  |       case "highlightallchange": | ||
|  |         return false; | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  |   #isEntireWord(content, startIdx, length) { | ||
|  |     let match = content.slice(0, startIdx).match(NOT_DIACRITIC_FROM_END_REG_EXP); | ||
|  |     if (match) { | ||
|  |       const first = content.charCodeAt(startIdx); | ||
|  |       const limit = match[1].charCodeAt(0); | ||
|  |       if (getCharacterType(first) === getCharacterType(limit)) { | ||
|  |         return false; | ||
|  |       } | ||
|  |     } | ||
|  |     match = content.slice(startIdx + length).match(NOT_DIACRITIC_FROM_START_REG_EXP); | ||
|  |     if (match) { | ||
|  |       const last = content.charCodeAt(startIdx + length - 1); | ||
|  |       const limit = match[1].charCodeAt(0); | ||
|  |       if (getCharacterType(last) === getCharacterType(limit)) { | ||
|  |         return false; | ||
|  |       } | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  |   #convertToRegExpString(query, hasDiacritics) { | ||
|  |     const { | ||
|  |       matchDiacritics | ||
|  |     } = this.#state; | ||
|  |     let isUnicode = false; | ||
|  |     query = query.replaceAll(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => { | ||
|  |       if (p1) { | ||
|  |         return `[ ]*\\${p1}[ ]*`; | ||
|  |       } | ||
|  |       if (p2) { | ||
|  |         return `[ ]*${p2}[ ]*`; | ||
|  |       } | ||
|  |       if (p3) { | ||
|  |         return "[ ]+"; | ||
|  |       } | ||
|  |       if (matchDiacritics) { | ||
|  |         return p4 || p5; | ||
|  |       } | ||
|  |       if (p4) { | ||
|  |         return DIACRITICS_EXCEPTION.has(p4.charCodeAt(0)) ? p4 : ""; | ||
|  |       } | ||
|  |       if (hasDiacritics) { | ||
|  |         isUnicode = true; | ||
|  |         return `${p5}\\p{M}*`; | ||
|  |       } | ||
|  |       return p5; | ||
|  |     }); | ||
|  |     const trailingSpaces = "[ ]*"; | ||
|  |     if (query.endsWith(trailingSpaces)) { | ||
|  |       query = query.slice(0, query.length - trailingSpaces.length); | ||
|  |     } | ||
|  |     if (matchDiacritics) { | ||
|  |       if (hasDiacritics) { | ||
|  |         DIACRITICS_EXCEPTION_STR ||= String.fromCharCode(...DIACRITICS_EXCEPTION); | ||
|  |         isUnicode = true; | ||
|  |         query = `${query}(?=[${DIACRITICS_EXCEPTION_STR}]|[^\\p{M}]|$)`; | ||
|  |       } | ||
|  |     } | ||
|  |     return [isUnicode, query]; | ||
|  |   } | ||
|  |   #calculateMatch(pageIndex) { | ||
|  |     const query = this.#query; | ||
|  |     if (query.length === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pageContent = this._pageContents[pageIndex]; | ||
|  |     const matcherResult = this.match(query, pageContent, pageIndex); | ||
|  |     const matches = this._pageMatches[pageIndex] = []; | ||
|  |     const matchesLength = this._pageMatchesLength[pageIndex] = []; | ||
|  |     const diffs = this._pageDiffs[pageIndex]; | ||
|  |     matcherResult?.forEach(({ | ||
|  |       index, | ||
|  |       length | ||
|  |     }) => { | ||
|  |       const [matchPos, matchLen] = getOriginalIndex(diffs, index, length); | ||
|  |       if (matchLen) { | ||
|  |         matches.push(matchPos); | ||
|  |         matchesLength.push(matchLen); | ||
|  |       } | ||
|  |     }); | ||
|  |     if (this.#state.highlightAll) { | ||
|  |       this.#updatePage(pageIndex); | ||
|  |     } | ||
|  |     if (this._resumePageIdx === pageIndex) { | ||
|  |       this._resumePageIdx = null; | ||
|  |       this.#nextPageMatch(); | ||
|  |     } | ||
|  |     const pageMatchesCount = matches.length; | ||
|  |     this._matchesCountTotal += pageMatchesCount; | ||
|  |     if (this.#updateMatchesCountOnProgress) { | ||
|  |       if (pageMatchesCount > 0) { | ||
|  |         this.#updateUIResultsCount(); | ||
|  |       } | ||
|  |     } else if (++this.#visitedPagesCount === this._linkService.pagesCount) { | ||
|  |       this.#updateUIResultsCount(); | ||
|  |     } | ||
|  |   } | ||
|  |   match(query, pageContent, pageIndex) { | ||
|  |     const hasDiacritics = this._hasDiacritics[pageIndex]; | ||
|  |     let isUnicode = false; | ||
|  |     if (typeof query === "string") { | ||
|  |       [isUnicode, query] = this.#convertToRegExpString(query, hasDiacritics); | ||
|  |     } else { | ||
|  |       query = query.sort().reverse().map(q => { | ||
|  |         const [isUnicodePart, queryPart] = this.#convertToRegExpString(q, hasDiacritics); | ||
|  |         isUnicode ||= isUnicodePart; | ||
|  |         return `(${queryPart})`; | ||
|  |       }).join("|"); | ||
|  |     } | ||
|  |     if (!query) { | ||
|  |       return undefined; | ||
|  |     } | ||
|  |     const { | ||
|  |       caseSensitive, | ||
|  |       entireWord | ||
|  |     } = this.#state; | ||
|  |     const flags = `g${isUnicode ? "u" : ""}${caseSensitive ? "" : "i"}`; | ||
|  |     query = new RegExp(query, flags); | ||
|  |     const matches = []; | ||
|  |     let match; | ||
|  |     while ((match = query.exec(pageContent)) !== null) { | ||
|  |       if (entireWord && !this.#isEntireWord(pageContent, match.index, match[0].length)) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       matches.push({ | ||
|  |         index: match.index, | ||
|  |         length: match[0].length | ||
|  |       }); | ||
|  |     } | ||
|  |     return matches; | ||
|  |   } | ||
|  |   #extractText() { | ||
|  |     if (this._extractTextPromises.length > 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let deferred = Promise.resolve(); | ||
|  |     const textOptions = { | ||
|  |       disableNormalization: true | ||
|  |     }; | ||
|  |     for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) { | ||
|  |       const { | ||
|  |         promise, | ||
|  |         resolve | ||
|  |       } = Promise.withResolvers(); | ||
|  |       this._extractTextPromises[i] = promise; | ||
|  |       deferred = deferred.then(() => { | ||
|  |         return this._pdfDocument.getPage(i + 1).then(pdfPage => pdfPage.getTextContent(textOptions)).then(textContent => { | ||
|  |           const strBuf = []; | ||
|  |           for (const textItem of textContent.items) { | ||
|  |             strBuf.push(textItem.str); | ||
|  |             if (textItem.hasEOL) { | ||
|  |               strBuf.push("\n"); | ||
|  |             } | ||
|  |           } | ||
|  |           [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = normalize(strBuf.join("")); | ||
|  |           resolve(); | ||
|  |         }, reason => { | ||
|  |           console.error(`Unable to get text content for page ${i + 1}`, reason); | ||
|  |           this._pageContents[i] = ""; | ||
|  |           this._pageDiffs[i] = null; | ||
|  |           this._hasDiacritics[i] = false; | ||
|  |           resolve(); | ||
|  |         }); | ||
|  |       }); | ||
|  |     } | ||
|  |   } | ||
|  |   #updatePage(index) { | ||
|  |     if (this._scrollMatches && this._selected.pageIdx === index) { | ||
|  |       this._linkService.page = index + 1; | ||
|  |     } | ||
|  |     this._eventBus.dispatch("updatetextlayermatches", { | ||
|  |       source: this, | ||
|  |       pageIndex: index | ||
|  |     }); | ||
|  |   } | ||
|  |   #updateAllPages() { | ||
|  |     this._eventBus.dispatch("updatetextlayermatches", { | ||
|  |       source: this, | ||
|  |       pageIndex: -1 | ||
|  |     }); | ||
|  |   } | ||
|  |   #nextMatch() { | ||
|  |     const previous = this.#state.findPrevious; | ||
|  |     const currentPageIndex = this._linkService.page - 1; | ||
|  |     const numPages = this._linkService.pagesCount; | ||
|  |     this._highlightMatches = true; | ||
|  |     if (this._dirtyMatch) { | ||
|  |       this._dirtyMatch = false; | ||
|  |       this._selected.pageIdx = this._selected.matchIdx = -1; | ||
|  |       this._offset.pageIdx = currentPageIndex; | ||
|  |       this._offset.matchIdx = null; | ||
|  |       this._offset.wrapped = false; | ||
|  |       this._resumePageIdx = null; | ||
|  |       this._pageMatches.length = 0; | ||
|  |       this._pageMatchesLength.length = 0; | ||
|  |       this.#visitedPagesCount = 0; | ||
|  |       this._matchesCountTotal = 0; | ||
|  |       this.#updateAllPages(); | ||
|  |       for (let i = 0; i < numPages; i++) { | ||
|  |         if (this._pendingFindMatches.has(i)) { | ||
|  |           continue; | ||
|  |         } | ||
|  |         this._pendingFindMatches.add(i); | ||
|  |         this._extractTextPromises[i].then(() => { | ||
|  |           this._pendingFindMatches.delete(i); | ||
|  |           this.#calculateMatch(i); | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |     const query = this.#query; | ||
|  |     if (query.length === 0) { | ||
|  |       this.#updateUIState(FindState.FOUND); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._resumePageIdx) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const offset = this._offset; | ||
|  |     this._pagesToSearch = numPages; | ||
|  |     if (offset.matchIdx !== null) { | ||
|  |       const numPageMatches = this._pageMatches[offset.pageIdx].length; | ||
|  |       if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) { | ||
|  |         offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; | ||
|  |         this.#updateMatch(true); | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#advanceOffsetPage(previous); | ||
|  |     } | ||
|  |     this.#nextPageMatch(); | ||
|  |   } | ||
|  |   #matchesReady(matches) { | ||
|  |     const offset = this._offset; | ||
|  |     const numMatches = matches.length; | ||
|  |     const previous = this.#state.findPrevious; | ||
|  |     if (numMatches) { | ||
|  |       offset.matchIdx = previous ? numMatches - 1 : 0; | ||
|  |       this.#updateMatch(true); | ||
|  |       return true; | ||
|  |     } | ||
|  |     this.#advanceOffsetPage(previous); | ||
|  |     if (offset.wrapped) { | ||
|  |       offset.matchIdx = null; | ||
|  |       if (this._pagesToSearch < 0) { | ||
|  |         this.#updateMatch(false); | ||
|  |         return true; | ||
|  |       } | ||
|  |     } | ||
|  |     return false; | ||
|  |   } | ||
|  |   #nextPageMatch() { | ||
|  |     if (this._resumePageIdx !== null) { | ||
|  |       console.error("There can only be one pending page."); | ||
|  |     } | ||
|  |     let matches = null; | ||
|  |     do { | ||
|  |       const pageIdx = this._offset.pageIdx; | ||
|  |       matches = this._pageMatches[pageIdx]; | ||
|  |       if (!matches) { | ||
|  |         this._resumePageIdx = pageIdx; | ||
|  |         break; | ||
|  |       } | ||
|  |     } while (!this.#matchesReady(matches)); | ||
|  |   } | ||
|  |   #advanceOffsetPage(previous) { | ||
|  |     const offset = this._offset; | ||
|  |     const numPages = this._linkService.pagesCount; | ||
|  |     offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; | ||
|  |     offset.matchIdx = null; | ||
|  |     this._pagesToSearch--; | ||
|  |     if (offset.pageIdx >= numPages || offset.pageIdx < 0) { | ||
|  |       offset.pageIdx = previous ? numPages - 1 : 0; | ||
|  |       offset.wrapped = true; | ||
|  |     } | ||
|  |   } | ||
|  |   #updateMatch(found = false) { | ||
|  |     let state = FindState.NOT_FOUND; | ||
|  |     const wrapped = this._offset.wrapped; | ||
|  |     this._offset.wrapped = false; | ||
|  |     if (found) { | ||
|  |       const previousPage = this._selected.pageIdx; | ||
|  |       this._selected.pageIdx = this._offset.pageIdx; | ||
|  |       this._selected.matchIdx = this._offset.matchIdx; | ||
|  |       state = wrapped ? FindState.WRAPPED : FindState.FOUND; | ||
|  |       if (previousPage !== -1 && previousPage !== this._selected.pageIdx) { | ||
|  |         this.#updatePage(previousPage); | ||
|  |       } | ||
|  |     } | ||
|  |     this.#updateUIState(state, this.#state.findPrevious); | ||
|  |     if (this._selected.pageIdx !== -1) { | ||
|  |       this._scrollMatches = true; | ||
|  |       this.#updatePage(this._selected.pageIdx); | ||
|  |     } | ||
|  |   } | ||
|  |   #onFindBarClose(evt) { | ||
|  |     const pdfDocument = this._pdfDocument; | ||
|  |     this._firstPageCapability.promise.then(() => { | ||
|  |       if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { | ||
|  |         return; | ||
|  |       } | ||
|  |       if (this._findTimeout) { | ||
|  |         clearTimeout(this._findTimeout); | ||
|  |         this._findTimeout = null; | ||
|  |       } | ||
|  |       if (this._resumePageIdx) { | ||
|  |         this._resumePageIdx = null; | ||
|  |         this._dirtyMatch = true; | ||
|  |       } | ||
|  |       this.#updateUIState(FindState.FOUND); | ||
|  |       this._highlightMatches = false; | ||
|  |       this.#updateAllPages(); | ||
|  |     }); | ||
|  |   } | ||
|  |   #requestMatchesCount() { | ||
|  |     const { | ||
|  |       pageIdx, | ||
|  |       matchIdx | ||
|  |     } = this._selected; | ||
|  |     let current = 0, | ||
|  |       total = this._matchesCountTotal; | ||
|  |     if (matchIdx !== -1) { | ||
|  |       for (let i = 0; i < pageIdx; i++) { | ||
|  |         current += this._pageMatches[i]?.length || 0; | ||
|  |       } | ||
|  |       current += matchIdx + 1; | ||
|  |     } | ||
|  |     if (current < 1 || current > total) { | ||
|  |       current = total = 0; | ||
|  |     } | ||
|  |     return { | ||
|  |       current, | ||
|  |       total | ||
|  |     }; | ||
|  |   } | ||
|  |   #updateUIResultsCount() { | ||
|  |     this._eventBus.dispatch("updatefindmatchescount", { | ||
|  |       source: this, | ||
|  |       matchesCount: this.#requestMatchesCount() | ||
|  |     }); | ||
|  |   } | ||
|  |   #updateUIState(state, previous = false) { | ||
|  |     if (!this.#updateMatchesCountOnProgress && (this.#visitedPagesCount !== this._linkService.pagesCount || state === FindState.PENDING)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._eventBus.dispatch("updatefindcontrolstate", { | ||
|  |       source: this, | ||
|  |       state, | ||
|  |       previous, | ||
|  |       entireWord: this.#state?.entireWord ?? null, | ||
|  |       matchesCount: this.#requestMatchesCount(), | ||
|  |       rawQuery: this.#state?.query ?? null | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_find_bar.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const MATCHES_COUNT_LIMIT = 1000; | ||
|  | class PDFFindBar { | ||
|  |   #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this)); | ||
|  |   constructor(options, eventBus) { | ||
|  |     this.opened = false; | ||
|  |     this.bar = options.bar; | ||
|  |     this.toggleButton = options.toggleButton; | ||
|  |     this.findField = options.findField; | ||
|  |     this.highlightAll = options.highlightAllCheckbox; | ||
|  |     this.caseSensitive = options.caseSensitiveCheckbox; | ||
|  |     this.matchDiacritics = options.matchDiacriticsCheckbox; | ||
|  |     this.entireWord = options.entireWordCheckbox; | ||
|  |     this.findMsg = options.findMsg; | ||
|  |     this.findResultsCount = options.findResultsCount; | ||
|  |     this.findPreviousButton = options.findPreviousButton; | ||
|  |     this.findNextButton = options.findNextButton; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.toggleButton.addEventListener("click", () => { | ||
|  |       this.toggle(); | ||
|  |     }); | ||
|  |     this.findField.addEventListener("input", () => { | ||
|  |       this.dispatchEvent(""); | ||
|  |     }); | ||
|  |     this.bar.addEventListener("keydown", e => { | ||
|  |       switch (e.keyCode) { | ||
|  |         case 13: | ||
|  |           if (e.target === this.findField) { | ||
|  |             this.dispatchEvent("again", e.shiftKey); | ||
|  |           } | ||
|  |           break; | ||
|  |         case 27: | ||
|  |           this.close(); | ||
|  |           break; | ||
|  |       } | ||
|  |     }); | ||
|  |     this.findPreviousButton.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("again", true); | ||
|  |     }); | ||
|  |     this.findNextButton.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("again", false); | ||
|  |     }); | ||
|  |     this.highlightAll.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("highlightallchange"); | ||
|  |     }); | ||
|  |     this.caseSensitive.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("casesensitivitychange"); | ||
|  |     }); | ||
|  |     this.entireWord.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("entirewordchange"); | ||
|  |     }); | ||
|  |     this.matchDiacritics.addEventListener("click", () => { | ||
|  |       this.dispatchEvent("diacriticmatchingchange"); | ||
|  |     }); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this.updateUIState(); | ||
|  |   } | ||
|  |   dispatchEvent(type, findPrev = false) { | ||
|  |     this.eventBus.dispatch("find", { | ||
|  |       source: this, | ||
|  |       type, | ||
|  |       query: this.findField.value, | ||
|  |       caseSensitive: this.caseSensitive.checked, | ||
|  |       entireWord: this.entireWord.checked, | ||
|  |       highlightAll: this.highlightAll.checked, | ||
|  |       findPrevious: findPrev, | ||
|  |       matchDiacritics: this.matchDiacritics.checked | ||
|  |     }); | ||
|  |   } | ||
|  |   updateUIState(state, previous, matchesCount) { | ||
|  |     const { | ||
|  |       findField, | ||
|  |       findMsg | ||
|  |     } = this; | ||
|  |     let findMsgId = "", | ||
|  |       status = ""; | ||
|  |     switch (state) { | ||
|  |       case FindState.FOUND: | ||
|  |         break; | ||
|  |       case FindState.PENDING: | ||
|  |         status = "pending"; | ||
|  |         break; | ||
|  |       case FindState.NOT_FOUND: | ||
|  |         findMsgId = "pdfjs-find-not-found"; | ||
|  |         status = "notFound"; | ||
|  |         break; | ||
|  |       case FindState.WRAPPED: | ||
|  |         findMsgId = previous ? "pdfjs-find-reached-top" : "pdfjs-find-reached-bottom"; | ||
|  |         break; | ||
|  |     } | ||
|  |     findField.setAttribute("data-status", status); | ||
|  |     findField.setAttribute("aria-invalid", state === FindState.NOT_FOUND); | ||
|  |     findMsg.setAttribute("data-status", status); | ||
|  |     if (findMsgId) { | ||
|  |       findMsg.setAttribute("data-l10n-id", findMsgId); | ||
|  |     } else { | ||
|  |       findMsg.removeAttribute("data-l10n-id"); | ||
|  |       findMsg.textContent = ""; | ||
|  |     } | ||
|  |     this.updateResultsCount(matchesCount); | ||
|  |   } | ||
|  |   updateResultsCount({ | ||
|  |     current = 0, | ||
|  |     total = 0 | ||
|  |   } = {}) { | ||
|  |     const { | ||
|  |       findResultsCount | ||
|  |     } = this; | ||
|  |     if (total > 0) { | ||
|  |       const limit = MATCHES_COUNT_LIMIT; | ||
|  |       findResultsCount.setAttribute("data-l10n-id", total > limit ? "pdfjs-find-match-count-limit" : "pdfjs-find-match-count"); | ||
|  |       findResultsCount.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |         limit, | ||
|  |         current, | ||
|  |         total | ||
|  |       })); | ||
|  |     } else { | ||
|  |       findResultsCount.removeAttribute("data-l10n-id"); | ||
|  |       findResultsCount.textContent = ""; | ||
|  |     } | ||
|  |   } | ||
|  |   open() { | ||
|  |     if (!this.opened) { | ||
|  |       this.#resizeObserver.observe(this.bar.parentNode); | ||
|  |       this.#resizeObserver.observe(this.bar); | ||
|  |       this.opened = true; | ||
|  |       toggleExpandedBtn(this.toggleButton, true, this.bar); | ||
|  |     } | ||
|  |     this.findField.select(); | ||
|  |     this.findField.focus(); | ||
|  |   } | ||
|  |   close() { | ||
|  |     if (!this.opened) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#resizeObserver.disconnect(); | ||
|  |     this.opened = false; | ||
|  |     toggleExpandedBtn(this.toggleButton, false, this.bar); | ||
|  |     this.eventBus.dispatch("findbarclose", { | ||
|  |       source: this | ||
|  |     }); | ||
|  |   } | ||
|  |   toggle() { | ||
|  |     if (this.opened) { | ||
|  |       this.close(); | ||
|  |     } else { | ||
|  |       this.open(); | ||
|  |     } | ||
|  |   } | ||
|  |   #resizeObserverCallback(entries) { | ||
|  |     const { | ||
|  |       bar | ||
|  |     } = this; | ||
|  |     bar.classList.remove("wrapContainers"); | ||
|  |     const findbarHeight = bar.clientHeight; | ||
|  |     const inputContainerHeight = bar.firstElementChild.clientHeight; | ||
|  |     if (findbarHeight > inputContainerHeight) { | ||
|  |       bar.classList.add("wrapContainers"); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_history.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const HASH_CHANGE_TIMEOUT = 1000; | ||
|  | const POSITION_UPDATED_THRESHOLD = 50; | ||
|  | const UPDATE_VIEWAREA_TIMEOUT = 1000; | ||
|  | function getCurrentHash() { | ||
|  |   return document.location.hash; | ||
|  | } | ||
|  | class PDFHistory { | ||
|  |   #eventAbortController = null; | ||
|  |   constructor({ | ||
|  |     linkService, | ||
|  |     eventBus | ||
|  |   }) { | ||
|  |     this.linkService = linkService; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this._initialized = false; | ||
|  |     this._fingerprint = ""; | ||
|  |     this.reset(); | ||
|  |     this.eventBus._on("pagesinit", () => { | ||
|  |       this._isPagesLoaded = false; | ||
|  |       this.eventBus._on("pagesloaded", evt => { | ||
|  |         this._isPagesLoaded = !!evt.pagesCount; | ||
|  |       }, { | ||
|  |         once: true | ||
|  |       }); | ||
|  |     }); | ||
|  |   } | ||
|  |   initialize({ | ||
|  |     fingerprint, | ||
|  |     resetHistory = false, | ||
|  |     updateUrl = false | ||
|  |   }) { | ||
|  |     if (!fingerprint || typeof fingerprint !== "string") { | ||
|  |       console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.'); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._initialized) { | ||
|  |       this.reset(); | ||
|  |     } | ||
|  |     const reInitialized = this._fingerprint !== "" && this._fingerprint !== fingerprint; | ||
|  |     this._fingerprint = fingerprint; | ||
|  |     this._updateUrl = updateUrl === true; | ||
|  |     this._initialized = true; | ||
|  |     this.#bindEvents(); | ||
|  |     const state = window.history.state; | ||
|  |     this._popStateInProgress = false; | ||
|  |     this._blockHashChange = 0; | ||
|  |     this._currentHash = getCurrentHash(); | ||
|  |     this._numPositionUpdates = 0; | ||
|  |     this._uid = this._maxUid = 0; | ||
|  |     this._destination = null; | ||
|  |     this._position = null; | ||
|  |     if (!this.#isValidState(state, true) || resetHistory) { | ||
|  |       const { | ||
|  |         hash, | ||
|  |         page, | ||
|  |         rotation | ||
|  |       } = this.#parseCurrentHash(true); | ||
|  |       if (!hash || reInitialized || resetHistory) { | ||
|  |         this.#pushOrReplaceState(null, true); | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#pushOrReplaceState({ | ||
|  |         hash, | ||
|  |         page, | ||
|  |         rotation | ||
|  |       }, true); | ||
|  |       return; | ||
|  |     } | ||
|  |     const destination = state.destination; | ||
|  |     this.#updateInternalState(destination, state.uid, true); | ||
|  |     if (destination.rotation !== undefined) { | ||
|  |       this._initialRotation = destination.rotation; | ||
|  |     } | ||
|  |     if (destination.dest) { | ||
|  |       this._initialBookmark = JSON.stringify(destination.dest); | ||
|  |       this._destination.page = null; | ||
|  |     } else if (destination.hash) { | ||
|  |       this._initialBookmark = destination.hash; | ||
|  |     } else if (destination.page) { | ||
|  |       this._initialBookmark = `page=${destination.page}`; | ||
|  |     } | ||
|  |   } | ||
|  |   reset() { | ||
|  |     if (this._initialized) { | ||
|  |       this.#pageHide(); | ||
|  |       this._initialized = false; | ||
|  |       this.#unbindEvents(); | ||
|  |     } | ||
|  |     if (this._updateViewareaTimeout) { | ||
|  |       clearTimeout(this._updateViewareaTimeout); | ||
|  |       this._updateViewareaTimeout = null; | ||
|  |     } | ||
|  |     this._initialBookmark = null; | ||
|  |     this._initialRotation = null; | ||
|  |   } | ||
|  |   push({ | ||
|  |     namedDest = null, | ||
|  |     explicitDest, | ||
|  |     pageNumber | ||
|  |   }) { | ||
|  |     if (!this._initialized) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (namedDest && typeof namedDest !== "string") { | ||
|  |       console.error("PDFHistory.push: " + `"${namedDest}" is not a valid namedDest parameter.`); | ||
|  |       return; | ||
|  |     } else if (!Array.isArray(explicitDest)) { | ||
|  |       console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`); | ||
|  |       return; | ||
|  |     } else if (!this.#isValidPage(pageNumber)) { | ||
|  |       if (pageNumber !== null || this._destination) { | ||
|  |         console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`); | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     const hash = namedDest || JSON.stringify(explicitDest); | ||
|  |     if (!hash) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let forceReplace = false; | ||
|  |     if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) { | ||
|  |       if (this._destination.page) { | ||
|  |         return; | ||
|  |       } | ||
|  |       forceReplace = true; | ||
|  |     } | ||
|  |     if (this._popStateInProgress && !forceReplace) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#pushOrReplaceState({ | ||
|  |       dest: explicitDest, | ||
|  |       hash, | ||
|  |       page: pageNumber, | ||
|  |       rotation: this.linkService.rotation | ||
|  |     }, forceReplace); | ||
|  |     if (!this._popStateInProgress) { | ||
|  |       this._popStateInProgress = true; | ||
|  |       Promise.resolve().then(() => { | ||
|  |         this._popStateInProgress = false; | ||
|  |       }); | ||
|  |     } | ||
|  |   } | ||
|  |   pushPage(pageNumber) { | ||
|  |     if (!this._initialized) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this.#isValidPage(pageNumber)) { | ||
|  |       console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._destination?.page === pageNumber) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._popStateInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#pushOrReplaceState({ | ||
|  |       dest: null, | ||
|  |       hash: `page=${pageNumber}`, | ||
|  |       page: pageNumber, | ||
|  |       rotation: this.linkService.rotation | ||
|  |     }); | ||
|  |     if (!this._popStateInProgress) { | ||
|  |       this._popStateInProgress = true; | ||
|  |       Promise.resolve().then(() => { | ||
|  |         this._popStateInProgress = false; | ||
|  |       }); | ||
|  |     } | ||
|  |   } | ||
|  |   pushCurrentPosition() { | ||
|  |     if (!this._initialized || this._popStateInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#tryPushCurrentPosition(); | ||
|  |   } | ||
|  |   back() { | ||
|  |     if (!this._initialized || this._popStateInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const state = window.history.state; | ||
|  |     if (this.#isValidState(state) && state.uid > 0) { | ||
|  |       window.history.back(); | ||
|  |     } | ||
|  |   } | ||
|  |   forward() { | ||
|  |     if (!this._initialized || this._popStateInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     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); | ||
|  |   } | ||
|  |   get initialBookmark() { | ||
|  |     return this._initialized ? this._initialBookmark : null; | ||
|  |   } | ||
|  |   get initialRotation() { | ||
|  |     return this._initialized ? this._initialRotation : null; | ||
|  |   } | ||
|  |   #pushOrReplaceState(destination, forceReplace = false) { | ||
|  |     const shouldReplace = forceReplace || !this._destination; | ||
|  |     const newState = { | ||
|  |       fingerprint: this._fingerprint, | ||
|  |       uid: shouldReplace ? this._uid : this._uid + 1, | ||
|  |       destination | ||
|  |     }; | ||
|  |     this.#updateInternalState(destination, newState.uid); | ||
|  |     let newUrl; | ||
|  |     if (this._updateUrl && destination?.hash) { | ||
|  |       const baseUrl = document.location.href.split("#", 1)[0]; | ||
|  |       if (!baseUrl.startsWith("file://")) { | ||
|  |         newUrl = `${baseUrl}#${destination.hash}`; | ||
|  |       } | ||
|  |     } | ||
|  |     if (shouldReplace) { | ||
|  |       window.history.replaceState(newState, "", newUrl); | ||
|  |     } else { | ||
|  |       window.history.pushState(newState, "", newUrl); | ||
|  |     } | ||
|  |   } | ||
|  |   #tryPushCurrentPosition(temporary = false) { | ||
|  |     if (!this._position) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let position = this._position; | ||
|  |     if (temporary) { | ||
|  |       position = Object.assign(Object.create(null), this._position); | ||
|  |       position.temporary = true; | ||
|  |     } | ||
|  |     if (!this._destination) { | ||
|  |       this.#pushOrReplaceState(position); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._destination.temporary) { | ||
|  |       this.#pushOrReplaceState(position, true); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._destination.hash === position.hash) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let forceReplace = false; | ||
|  |     if (this._destination.page >= position.first && this._destination.page <= position.page) { | ||
|  |       if (this._destination.dest !== undefined || !this._destination.first) { | ||
|  |         return; | ||
|  |       } | ||
|  |       forceReplace = true; | ||
|  |     } | ||
|  |     this.#pushOrReplaceState(position, forceReplace); | ||
|  |   } | ||
|  |   #isValidPage(val) { | ||
|  |     return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount; | ||
|  |   } | ||
|  |   #isValidState(state, checkReload = false) { | ||
|  |     if (!state) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     if (state.fingerprint !== this._fingerprint) { | ||
|  |       if (checkReload) { | ||
|  |         if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) { | ||
|  |           return false; | ||
|  |         } | ||
|  |         const [perfEntry] = performance.getEntriesByType("navigation"); | ||
|  |         if (perfEntry?.type !== "reload") { | ||
|  |           return false; | ||
|  |         } | ||
|  |       } else { | ||
|  |         return false; | ||
|  |       } | ||
|  |     } | ||
|  |     if (!Number.isInteger(state.uid) || state.uid < 0) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     if (state.destination === null || typeof state.destination !== "object") { | ||
|  |       return false; | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  |   #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._uid = uid; | ||
|  |     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) { | ||
|  |       page = null; | ||
|  |     } | ||
|  |     return { | ||
|  |       hash, | ||
|  |       page, | ||
|  |       rotation: this.linkService.rotation | ||
|  |     }; | ||
|  |   } | ||
|  |   #updateViewarea({ | ||
|  |     location | ||
|  |   }) { | ||
|  |     if (this._updateViewareaTimeout) { | ||
|  |       clearTimeout(this._updateViewareaTimeout); | ||
|  |       this._updateViewareaTimeout = null; | ||
|  |     } | ||
|  |     this._position = { | ||
|  |       hash: location.pdfOpenParams.substring(1), | ||
|  |       page: this.linkService.page, | ||
|  |       first: location.pageNumber, | ||
|  |       rotation: location.rotation | ||
|  |     }; | ||
|  |     if (this._popStateInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     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); | ||
|  |     } | ||
|  |   } | ||
|  |   #popState({ | ||
|  |     state | ||
|  |   }) { | ||
|  |     const newHash = getCurrentHash(), | ||
|  |       hashChanged = this._currentHash !== newHash; | ||
|  |     this._currentHash = newHash; | ||
|  |     if (!state) { | ||
|  |       this._uid++; | ||
|  |       const { | ||
|  |         hash, | ||
|  |         page, | ||
|  |         rotation | ||
|  |       } = this.#parseCurrentHash(); | ||
|  |       this.#pushOrReplaceState({ | ||
|  |         hash, | ||
|  |         page, | ||
|  |         rotation | ||
|  |       }, true); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this.#isValidState(state)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._popStateInProgress = true; | ||
|  |     if (hashChanged) { | ||
|  |       this._blockHashChange++; | ||
|  |       waitOnEventOrTimeout({ | ||
|  |         target: window, | ||
|  |         name: "hashchange", | ||
|  |         delay: HASH_CHANGE_TIMEOUT | ||
|  |       }).then(() => { | ||
|  |         this._blockHashChange--; | ||
|  |       }); | ||
|  |     } | ||
|  |     const destination = state.destination; | ||
|  |     this.#updateInternalState(destination, state.uid, true); | ||
|  |     if (isValidRotation(destination.rotation)) { | ||
|  |       this.linkService.rotation = destination.rotation; | ||
|  |     } | ||
|  |     if (destination.dest) { | ||
|  |       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; | ||
|  |     }); | ||
|  |   } | ||
|  |   #pageHide() { | ||
|  |     if (!this._destination || this._destination.temporary) { | ||
|  |       this.#tryPushCurrentPosition(); | ||
|  |     } | ||
|  |   } | ||
|  |   #bindEvents() { | ||
|  |     if (this.#eventAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#eventAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       signal | ||
|  |     } = this.#eventAbortController; | ||
|  |     this.eventBus._on("updateviewarea", this.#updateViewarea.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("popstate", this.#popState.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("pagehide", this.#pageHide.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |   } | ||
|  |   #unbindEvents() { | ||
|  |     this.#eventAbortController?.abort(); | ||
|  |     this.#eventAbortController = null; | ||
|  |   } | ||
|  | } | ||
|  | function isDestHashesEqual(destHash, pushHash) { | ||
|  |   if (typeof destHash !== "string" || typeof pushHash !== "string") { | ||
|  |     return false; | ||
|  |   } | ||
|  |   if (destHash === pushHash) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   const nameddest = parseQueryString(destHash).get("nameddest"); | ||
|  |   if (nameddest === pushHash) { | ||
|  |     return true; | ||
|  |   } | ||
|  |   return false; | ||
|  | } | ||
|  | function isDestArraysEqual(firstDest, secondDest) { | ||
|  |   function isEntryEqual(first, second) { | ||
|  |     if (typeof first !== typeof second) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     if (Array.isArray(first) || Array.isArray(second)) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     if (first !== null && typeof first === "object" && second !== null) { | ||
|  |       if (Object.keys(first).length !== Object.keys(second).length) { | ||
|  |         return false; | ||
|  |       } | ||
|  |       for (const key in first) { | ||
|  |         if (!isEntryEqual(first[key], second[key])) { | ||
|  |           return false; | ||
|  |         } | ||
|  |       } | ||
|  |       return true; | ||
|  |     } | ||
|  |     return first === second || Number.isNaN(first) && Number.isNaN(second); | ||
|  |   } | ||
|  |   if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   if (firstDest.length !== secondDest.length) { | ||
|  |     return false; | ||
|  |   } | ||
|  |   for (let i = 0, ii = firstDest.length; i < ii; i++) { | ||
|  |     if (!isEntryEqual(firstDest[i], secondDest[i])) { | ||
|  |       return false; | ||
|  |     } | ||
|  |   } | ||
|  |   return true; | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_layer_viewer.js
 | ||
|  | 
 | ||
|  | class PDFLayerViewer extends BaseTreeViewer { | ||
|  |   constructor(options) { | ||
|  |     super(options); | ||
|  |     this.eventBus._on("optionalcontentconfigchanged", evt => { | ||
|  |       this.#updateLayers(evt.promise); | ||
|  |     }); | ||
|  |     this.eventBus._on("resetlayers", () => { | ||
|  |       this.#updateLayers(); | ||
|  |     }); | ||
|  |     this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this)); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     super.reset(); | ||
|  |     this._optionalContentConfig = null; | ||
|  |     this._optionalContentHash = null; | ||
|  |   } | ||
|  |   _dispatchEvent(layersCount) { | ||
|  |     this.eventBus.dispatch("layersloaded", { | ||
|  |       source: this, | ||
|  |       layersCount | ||
|  |     }); | ||
|  |   } | ||
|  |   _bindLink(element, { | ||
|  |     groupId, | ||
|  |     input | ||
|  |   }) { | ||
|  |     const setVisibility = () => { | ||
|  |       this._optionalContentConfig.setVisibility(groupId, input.checked); | ||
|  |       this._optionalContentHash = this._optionalContentConfig.getHash(); | ||
|  |       this.eventBus.dispatch("optionalcontentconfig", { | ||
|  |         source: this, | ||
|  |         promise: Promise.resolve(this._optionalContentConfig) | ||
|  |       }); | ||
|  |     }; | ||
|  |     element.onclick = evt => { | ||
|  |       if (evt.target === input) { | ||
|  |         setVisibility(); | ||
|  |         return true; | ||
|  |       } else if (evt.target !== element) { | ||
|  |         return true; | ||
|  |       } | ||
|  |       input.checked = !input.checked; | ||
|  |       setVisibility(); | ||
|  |       return false; | ||
|  |     }; | ||
|  |   } | ||
|  |   _setNestedName(element, { | ||
|  |     name = null | ||
|  |   }) { | ||
|  |     if (typeof name === "string") { | ||
|  |       element.textContent = this._normalizeTextContent(name); | ||
|  |       return; | ||
|  |     } | ||
|  |     element.setAttribute("data-l10n-id", "pdfjs-additional-layers"); | ||
|  |     element.style.fontStyle = "italic"; | ||
|  |     this._l10n.translateOnce(element); | ||
|  |   } | ||
|  |   _addToggleButton(div, { | ||
|  |     name = null | ||
|  |   }) { | ||
|  |     super._addToggleButton(div, name === null); | ||
|  |   } | ||
|  |   _toggleAllTreeItems() { | ||
|  |     if (!this._optionalContentConfig) { | ||
|  |       return; | ||
|  |     } | ||
|  |     super._toggleAllTreeItems(); | ||
|  |   } | ||
|  |   render({ | ||
|  |     optionalContentConfig, | ||
|  |     pdfDocument | ||
|  |   }) { | ||
|  |     if (this._optionalContentConfig) { | ||
|  |       this.reset(); | ||
|  |     } | ||
|  |     this._optionalContentConfig = optionalContentConfig || null; | ||
|  |     this._pdfDocument = pdfDocument || null; | ||
|  |     const groups = optionalContentConfig?.getOrder(); | ||
|  |     if (!groups) { | ||
|  |       this._dispatchEvent(0); | ||
|  |       return; | ||
|  |     } | ||
|  |     this._optionalContentHash = optionalContentConfig.getHash(); | ||
|  |     const fragment = document.createDocumentFragment(), | ||
|  |       queue = [{ | ||
|  |         parent: fragment, | ||
|  |         groups | ||
|  |       }]; | ||
|  |     let layersCount = 0, | ||
|  |       hasAnyNesting = false; | ||
|  |     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"); | ||
|  |         div.append(element); | ||
|  |         if (typeof groupId === "object") { | ||
|  |           hasAnyNesting = true; | ||
|  |           this._addToggleButton(div, groupId); | ||
|  |           this._setNestedName(element, groupId); | ||
|  |           const itemsDiv = document.createElement("div"); | ||
|  |           itemsDiv.className = "treeItems"; | ||
|  |           div.append(itemsDiv); | ||
|  |           queue.push({ | ||
|  |             parent: itemsDiv, | ||
|  |             groups: groupId.order | ||
|  |           }); | ||
|  |         } else { | ||
|  |           const group = optionalContentConfig.getGroup(groupId); | ||
|  |           const input = document.createElement("input"); | ||
|  |           this._bindLink(element, { | ||
|  |             groupId, | ||
|  |             input | ||
|  |           }); | ||
|  |           input.type = "checkbox"; | ||
|  |           input.checked = group.visible; | ||
|  |           const label = document.createElement("label"); | ||
|  |           label.textContent = this._normalizeTextContent(group.name); | ||
|  |           label.append(input); | ||
|  |           element.append(label); | ||
|  |           layersCount++; | ||
|  |         } | ||
|  |         levelData.parent.append(div); | ||
|  |       } | ||
|  |     } | ||
|  |     this._finishRendering(fragment, layersCount, hasAnyNesting); | ||
|  |   } | ||
|  |   async #updateLayers(promise = null) { | ||
|  |     if (!this._optionalContentConfig) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pdfDocument = this._pdfDocument; | ||
|  |     const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig({ | ||
|  |       intent: "display" | ||
|  |     })); | ||
|  |     if (pdfDocument !== this._pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (promise) { | ||
|  |       if (optionalContentConfig.getHash() === this._optionalContentHash) { | ||
|  |         return; | ||
|  |       } | ||
|  |     } else { | ||
|  |       this.eventBus.dispatch("optionalcontentconfig", { | ||
|  |         source: this, | ||
|  |         promise: Promise.resolve(optionalContentConfig) | ||
|  |       }); | ||
|  |     } | ||
|  |     this.render({ | ||
|  |       optionalContentConfig, | ||
|  |       pdfDocument: this._pdfDocument | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_outline_viewer.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class PDFOutlineViewer extends BaseTreeViewer { | ||
|  |   constructor(options) { | ||
|  |     super(options); | ||
|  |     this.linkService = options.linkService; | ||
|  |     this.downloadManager = options.downloadManager; | ||
|  |     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; | ||
|  |     }); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     super.reset(); | ||
|  |     this._outline = null; | ||
|  |     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", { | ||
|  |       source: this, | ||
|  |       outlineCount, | ||
|  |       currentOutlineItemPromise: this._currentOutlineItemCapability.promise | ||
|  |     }); | ||
|  |   } | ||
|  |   _bindLink(element, { | ||
|  |     url, | ||
|  |     newWindow, | ||
|  |     action, | ||
|  |     attachment, | ||
|  |     dest, | ||
|  |     setOCGState | ||
|  |   }) { | ||
|  |     const { | ||
|  |       linkService | ||
|  |     } = this; | ||
|  |     if (url) { | ||
|  |       linkService.addLinkAttributes(element, url, newWindow); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (action) { | ||
|  |       element.href = linkService.getAnchorUrl(""); | ||
|  |       element.onclick = () => { | ||
|  |         linkService.executeNamedAction(action); | ||
|  |         return false; | ||
|  |       }; | ||
|  |       return; | ||
|  |     } | ||
|  |     if (attachment) { | ||
|  |       element.href = linkService.getAnchorUrl(""); | ||
|  |       element.onclick = () => { | ||
|  |         this.downloadManager.openOrDownloadData(attachment.content, attachment.filename); | ||
|  |         return false; | ||
|  |       }; | ||
|  |       return; | ||
|  |     } | ||
|  |     if (setOCGState) { | ||
|  |       element.href = linkService.getAnchorUrl(""); | ||
|  |       element.onclick = () => { | ||
|  |         linkService.executeSetOCGState(setOCGState); | ||
|  |         return false; | ||
|  |       }; | ||
|  |       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 !== 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 = Promise.withResolvers(); | ||
|  |     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 (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); | ||
|  |           } | ||
|  |         } | ||
|  |         if (items.length > 0) { | ||
|  |           queue.push({ | ||
|  |             nesting: currentNesting + 1, | ||
|  |             items | ||
|  |           }); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     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; | ||
|  |   #args = null; | ||
|  |   #fullscreenChangeAbortController = null; | ||
|  |   #windowAbortController = null; | ||
|  |   constructor({ | ||
|  |     container, | ||
|  |     pdfViewer, | ||
|  |     eventBus | ||
|  |   }) { | ||
|  |     this.container = container; | ||
|  |     this.pdfViewer = pdfViewer; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.contextMenuOpen = false; | ||
|  |     this.mouseScrollTimeStamp = 0; | ||
|  |     this.mouseScrollDelta = 0; | ||
|  |     this.touchSwipeState = null; | ||
|  |   } | ||
|  |   async request() { | ||
|  |     const { | ||
|  |       container, | ||
|  |       pdfViewer | ||
|  |     } = this; | ||
|  |     if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     this.#addFullscreenChangeListeners(); | ||
|  |     this.#notifyStateChange(PresentationModeState.CHANGING); | ||
|  |     const promise = container.requestFullscreen(); | ||
|  |     this.#args = { | ||
|  |       pageNumber: pdfViewer.currentPageNumber, | ||
|  |       scaleValue: pdfViewer.currentScaleValue, | ||
|  |       scrollMode: pdfViewer.scrollMode, | ||
|  |       spreadMode: null, | ||
|  |       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; | ||
|  |     } | ||
|  |     try { | ||
|  |       await promise; | ||
|  |       pdfViewer.focus(); | ||
|  |       return true; | ||
|  |     } catch { | ||
|  |       this.#removeFullscreenChangeListeners(); | ||
|  |       this.#notifyStateChange(PresentationModeState.NORMAL); | ||
|  |     } | ||
|  |     return false; | ||
|  |   } | ||
|  |   get active() { | ||
|  |     return this.#state === PresentationModeState.CHANGING || this.#state === PresentationModeState.FULLSCREEN; | ||
|  |   } | ||
|  |   #mouseWheel(evt) { | ||
|  |     if (!this.active) { | ||
|  |       return; | ||
|  |     } | ||
|  |     evt.preventDefault(); | ||
|  |     const delta = normalizeWheelEventDelta(evt); | ||
|  |     const currentTime = Date.now(); | ||
|  |     const storedTime = this.mouseScrollTimeStamp; | ||
|  |     if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { | ||
|  |       return; | ||
|  |     } | ||
|  |     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(); | ||
|  |       if (success) { | ||
|  |         this.mouseScrollTimeStamp = currentTime; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   #notifyStateChange(state) { | ||
|  |     this.#state = state; | ||
|  |     this.eventBus.dispatch("presentationmodechanged", { | ||
|  |       source: this, | ||
|  |       state | ||
|  |     }); | ||
|  |   } | ||
|  |   #enter() { | ||
|  |     this.#notifyStateChange(PresentationModeState.FULLSCREEN); | ||
|  |     this.container.classList.add(ACTIVE_SELECTOR); | ||
|  |     setTimeout(() => { | ||
|  |       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 | ||
|  |         }; | ||
|  |       } | ||
|  |     }, 0); | ||
|  |     this.#addWindowListeners(); | ||
|  |     this.#showControls(); | ||
|  |     this.contextMenuOpen = false; | ||
|  |     document.getSelection().empty(); | ||
|  |   } | ||
|  |   #exit() { | ||
|  |     const pageNumber = this.pdfViewer.currentPageNumber; | ||
|  |     this.container.classList.remove(ACTIVE_SELECTOR); | ||
|  |     setTimeout(() => { | ||
|  |       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.#args = null; | ||
|  |     }, 0); | ||
|  |     this.#removeWindowListeners(); | ||
|  |     this.#hideControls(); | ||
|  |     this.#resetMouseScrollState(); | ||
|  |     this.contextMenuOpen = false; | ||
|  |   } | ||
|  |   #mouseDown(evt) { | ||
|  |     if (this.contextMenuOpen) { | ||
|  |       this.contextMenuOpen = false; | ||
|  |       evt.preventDefault(); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (evt.button !== 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (evt.target.href && evt.target.parentNode?.hasAttribute("data-internal-link")) { | ||
|  |       return; | ||
|  |     } | ||
|  |     evt.preventDefault(); | ||
|  |     if (evt.shiftKey) { | ||
|  |       this.pdfViewer.previousPage(); | ||
|  |     } else { | ||
|  |       this.pdfViewer.nextPage(); | ||
|  |     } | ||
|  |   } | ||
|  |   #contextMenu() { | ||
|  |     this.contextMenuOpen = true; | ||
|  |   } | ||
|  |   #showControls() { | ||
|  |     if (this.controlsTimeout) { | ||
|  |       clearTimeout(this.controlsTimeout); | ||
|  |     } else { | ||
|  |       this.container.classList.add(CONTROLS_SELECTOR); | ||
|  |     } | ||
|  |     this.controlsTimeout = setTimeout(() => { | ||
|  |       this.container.classList.remove(CONTROLS_SELECTOR); | ||
|  |       delete this.controlsTimeout; | ||
|  |     }, DELAY_BEFORE_HIDING_CONTROLS); | ||
|  |   } | ||
|  |   #hideControls() { | ||
|  |     if (!this.controlsTimeout) { | ||
|  |       return; | ||
|  |     } | ||
|  |     clearTimeout(this.controlsTimeout); | ||
|  |     this.container.classList.remove(CONTROLS_SELECTOR); | ||
|  |     delete this.controlsTimeout; | ||
|  |   } | ||
|  |   #resetMouseScrollState() { | ||
|  |     this.mouseScrollTimeStamp = 0; | ||
|  |     this.mouseScrollDelta = 0; | ||
|  |   } | ||
|  |   #touchSwipe(evt) { | ||
|  |     if (!this.active) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (evt.touches.length > 1) { | ||
|  |       this.touchSwipeState = null; | ||
|  |       return; | ||
|  |     } | ||
|  |     switch (evt.type) { | ||
|  |       case "touchstart": | ||
|  |         this.touchSwipeState = { | ||
|  |           startX: evt.touches[0].pageX, | ||
|  |           startY: evt.touches[0].pageY, | ||
|  |           endX: evt.touches[0].pageX, | ||
|  |           endY: evt.touches[0].pageY | ||
|  |         }; | ||
|  |         break; | ||
|  |       case "touchmove": | ||
|  |         if (this.touchSwipeState === null) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this.touchSwipeState.endX = evt.touches[0].pageX; | ||
|  |         this.touchSwipeState.endY = evt.touches[0].pageY; | ||
|  |         evt.preventDefault(); | ||
|  |         break; | ||
|  |       case "touchend": | ||
|  |         if (this.touchSwipeState === null) { | ||
|  |           return; | ||
|  |         } | ||
|  |         let delta = 0; | ||
|  |         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)) { | ||
|  |           delta = dx; | ||
|  |         } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) { | ||
|  |           delta = dy; | ||
|  |         } | ||
|  |         if (delta > 0) { | ||
|  |           this.pdfViewer.previousPage(); | ||
|  |         } else if (delta < 0) { | ||
|  |           this.pdfViewer.nextPage(); | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   #addWindowListeners() { | ||
|  |     if (this.#windowAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#windowAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       signal | ||
|  |     } = this.#windowAbortController; | ||
|  |     const touchSwipeBind = this.#touchSwipe.bind(this); | ||
|  |     window.addEventListener("mousemove", this.#showControls.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("mousedown", this.#mouseDown.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("wheel", this.#mouseWheel.bind(this), { | ||
|  |       passive: false, | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("keydown", this.#resetMouseScrollState.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("contextmenu", this.#contextMenu.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchstart", touchSwipeBind, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchmove", touchSwipeBind, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchend", touchSwipeBind, { | ||
|  |       signal | ||
|  |     }); | ||
|  |   } | ||
|  |   #removeWindowListeners() { | ||
|  |     this.#windowAbortController?.abort(); | ||
|  |     this.#windowAbortController = null; | ||
|  |   } | ||
|  |   #addFullscreenChangeListeners() { | ||
|  |     if (this.#fullscreenChangeAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#fullscreenChangeAbortController = new AbortController(); | ||
|  |     window.addEventListener("fullscreenchange", () => { | ||
|  |       if (document.fullscreenElement) { | ||
|  |         this.#enter(); | ||
|  |       } else { | ||
|  |         this.#exit(); | ||
|  |       } | ||
|  |     }, { | ||
|  |       signal: this.#fullscreenChangeAbortController.signal | ||
|  |     }); | ||
|  |   } | ||
|  |   #removeFullscreenChangeListeners() { | ||
|  |     this.#fullscreenChangeAbortController?.abort(); | ||
|  |     this.#fullscreenChangeAbortController = null; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/xfa_layer_builder.js
 | ||
|  | 
 | ||
|  | class XfaLayerBuilder { | ||
|  |   constructor({ | ||
|  |     pdfPage, | ||
|  |     annotationStorage = null, | ||
|  |     linkService, | ||
|  |     xfaHtml = null | ||
|  |   }) { | ||
|  |     this.pdfPage = pdfPage; | ||
|  |     this.annotationStorage = annotationStorage; | ||
|  |     this.linkService = linkService; | ||
|  |     this.xfaHtml = xfaHtml; | ||
|  |     this.div = null; | ||
|  |     this._cancelled = false; | ||
|  |   } | ||
|  |   async render(viewport, intent = "display") { | ||
|  |     if (intent === "print") { | ||
|  |       const parameters = { | ||
|  |         viewport: viewport.clone({ | ||
|  |           dontFlip: true | ||
|  |         }), | ||
|  |         div: this.div, | ||
|  |         xfaHtml: this.xfaHtml, | ||
|  |         annotationStorage: this.annotationStorage, | ||
|  |         linkService: this.linkService, | ||
|  |         intent | ||
|  |       }; | ||
|  |       this.div = document.createElement("div"); | ||
|  |       parameters.div = this.div; | ||
|  |       return XfaLayer.render(parameters); | ||
|  |     } | ||
|  |     const xfaHtml = await this.pdfPage.getXfa(); | ||
|  |     if (this._cancelled || !xfaHtml) { | ||
|  |       return { | ||
|  |         textDivs: [] | ||
|  |       }; | ||
|  |     } | ||
|  |     const parameters = { | ||
|  |       viewport: viewport.clone({ | ||
|  |         dontFlip: true | ||
|  |       }), | ||
|  |       div: this.div, | ||
|  |       xfaHtml, | ||
|  |       annotationStorage: this.annotationStorage, | ||
|  |       linkService: this.linkService, | ||
|  |       intent | ||
|  |     }; | ||
|  |     if (this.div) { | ||
|  |       return XfaLayer.update(parameters); | ||
|  |     } | ||
|  |     this.div = document.createElement("div"); | ||
|  |     parameters.div = this.div; | ||
|  |     return XfaLayer.render(parameters); | ||
|  |   } | ||
|  |   cancel() { | ||
|  |     this._cancelled = true; | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (!this.div) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.div.hidden = true; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/print_utils.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function getXfaHtmlForPrinting(printContainer, pdfDocument) { | ||
|  |   const xfaHtml = pdfDocument.allXfaHtml; | ||
|  |   const linkService = new SimpleLinkService(); | ||
|  |   const scale = Math.round(PixelsPerInch.PDF_TO_CSS_UNITS * 100) / 100; | ||
|  |   for (const xfaPage of xfaHtml.children) { | ||
|  |     const page = document.createElement("div"); | ||
|  |     page.className = "xfaPrintedPage"; | ||
|  |     printContainer.append(page); | ||
|  |     const builder = new XfaLayerBuilder({ | ||
|  |       pdfPage: null, | ||
|  |       annotationStorage: pdfDocument.annotationStorage, | ||
|  |       linkService, | ||
|  |       xfaHtml: xfaPage | ||
|  |     }); | ||
|  |     const viewport = getXfaPageViewport(xfaPage, { | ||
|  |       scale | ||
|  |     }); | ||
|  |     builder.render(viewport, "print"); | ||
|  |     page.append(builder.div); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_print_service.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | let activeService = null; | ||
|  | let dialog = null; | ||
|  | let overlayManager = null; | ||
|  | let viewerApp = { | ||
|  |   initialized: false | ||
|  | }; | ||
|  | function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) { | ||
|  |   const scratchCanvas = activeService.scratchCanvas; | ||
|  |   const PRINT_UNITS = printResolution / PixelsPerInch.PDF; | ||
|  |   scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); | ||
|  |   scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); | ||
|  |   const ctx = scratchCanvas.getContext("2d"); | ||
|  |   ctx.save(); | ||
|  |   ctx.fillStyle = "rgb(255, 255, 255)"; | ||
|  |   ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height); | ||
|  |   ctx.restore(); | ||
|  |   return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function ([pdfPage, printAnnotationStorage]) { | ||
|  |     const renderContext = { | ||
|  |       canvasContext: ctx, | ||
|  |       transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], | ||
|  |       viewport: pdfPage.getViewport({ | ||
|  |         scale: 1, | ||
|  |         rotation: size.rotation | ||
|  |       }), | ||
|  |       intent: "print", | ||
|  |       annotationMode: AnnotationMode.ENABLE_STORAGE, | ||
|  |       optionalContentConfigPromise, | ||
|  |       printAnnotationStorage | ||
|  |     }; | ||
|  |     const renderTask = pdfPage.render(renderContext); | ||
|  |     return renderTask.promise.catch(reason => { | ||
|  |       if (!(reason instanceof RenderingCancelledException)) { | ||
|  |         console.error(reason); | ||
|  |       } | ||
|  |       throw reason; | ||
|  |     }); | ||
|  |   }); | ||
|  | } | ||
|  | class PDFPrintService { | ||
|  |   constructor({ | ||
|  |     pdfDocument, | ||
|  |     pagesOverview, | ||
|  |     printContainer, | ||
|  |     printResolution, | ||
|  |     printAnnotationStoragePromise = null | ||
|  |   }) { | ||
|  |     this.pdfDocument = pdfDocument; | ||
|  |     this.pagesOverview = pagesOverview; | ||
|  |     this.printContainer = printContainer; | ||
|  |     this._printResolution = printResolution || 150; | ||
|  |     this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ | ||
|  |       intent: "print" | ||
|  |     }); | ||
|  |     this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve(); | ||
|  |     this.currentPage = -1; | ||
|  |     this.scratchCanvas = document.createElement("canvas"); | ||
|  |   } | ||
|  |   layout() { | ||
|  |     this.throwIfInactive(); | ||
|  |     const body = document.querySelector("body"); | ||
|  |     body.setAttribute("data-pdfjsprinting", true); | ||
|  |     const { | ||
|  |       width, | ||
|  |       height | ||
|  |     } = this.pagesOverview[0]; | ||
|  |     const hasEqualPageSizes = this.pagesOverview.every(size => size.width === width && size.height === height); | ||
|  |     if (!hasEqualPageSizes) { | ||
|  |       console.warn("Not all pages have the same size. The printed result may be incorrect!"); | ||
|  |     } | ||
|  |     this.pageStyleSheet = document.createElement("style"); | ||
|  |     this.pageStyleSheet.textContent = `@page { size: ${width}pt ${height}pt;}`; | ||
|  |     body.append(this.pageStyleSheet); | ||
|  |   } | ||
|  |   destroy() { | ||
|  |     if (activeService !== this) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.printContainer.textContent = ""; | ||
|  |     const body = document.querySelector("body"); | ||
|  |     body.removeAttribute("data-pdfjsprinting"); | ||
|  |     if (this.pageStyleSheet) { | ||
|  |       this.pageStyleSheet.remove(); | ||
|  |       this.pageStyleSheet = null; | ||
|  |     } | ||
|  |     this.scratchCanvas.width = this.scratchCanvas.height = 0; | ||
|  |     this.scratchCanvas = null; | ||
|  |     activeService = null; | ||
|  |     ensureOverlay().then(function () { | ||
|  |       if (overlayManager.active === dialog) { | ||
|  |         overlayManager.close(dialog); | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   renderPages() { | ||
|  |     if (this.pdfDocument.isPureXfa) { | ||
|  |       getXfaHtmlForPrinting(this.printContainer, this.pdfDocument); | ||
|  |       return Promise.resolve(); | ||
|  |     } | ||
|  |     const pageCount = this.pagesOverview.length; | ||
|  |     const renderNextPage = (resolve, reject) => { | ||
|  |       this.throwIfInactive(); | ||
|  |       if (++this.currentPage >= pageCount) { | ||
|  |         renderProgress(pageCount, pageCount); | ||
|  |         resolve(); | ||
|  |         return; | ||
|  |       } | ||
|  |       const index = this.currentPage; | ||
|  |       renderProgress(index, pageCount); | ||
|  |       renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () { | ||
|  |         renderNextPage(resolve, reject); | ||
|  |       }, reject); | ||
|  |     }; | ||
|  |     return new Promise(renderNextPage); | ||
|  |   } | ||
|  |   useRenderedPage() { | ||
|  |     this.throwIfInactive(); | ||
|  |     const img = document.createElement("img"); | ||
|  |     this.scratchCanvas.toBlob(blob => { | ||
|  |       img.src = URL.createObjectURL(blob); | ||
|  |     }); | ||
|  |     const wrapper = document.createElement("div"); | ||
|  |     wrapper.className = "printedPage"; | ||
|  |     wrapper.append(img); | ||
|  |     this.printContainer.append(wrapper); | ||
|  |     const { | ||
|  |       promise, | ||
|  |       resolve, | ||
|  |       reject | ||
|  |     } = Promise.withResolvers(); | ||
|  |     img.onload = resolve; | ||
|  |     img.onerror = reject; | ||
|  |     promise.catch(() => {}).then(() => { | ||
|  |       URL.revokeObjectURL(img.src); | ||
|  |     }); | ||
|  |     return promise; | ||
|  |   } | ||
|  |   performPrint() { | ||
|  |     this.throwIfInactive(); | ||
|  |     return new Promise(resolve => { | ||
|  |       setTimeout(() => { | ||
|  |         if (!this.active) { | ||
|  |           resolve(); | ||
|  |           return; | ||
|  |         } | ||
|  |         print.call(window); | ||
|  |         setTimeout(resolve, 20); | ||
|  |       }, 0); | ||
|  |     }); | ||
|  |   } | ||
|  |   get active() { | ||
|  |     return this === activeService; | ||
|  |   } | ||
|  |   throwIfInactive() { | ||
|  |     if (!this.active) { | ||
|  |       throw new Error("This print request was cancelled or completed."); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | const print = window.print; | ||
|  | window.print = function () { | ||
|  |   if (activeService) { | ||
|  |     console.warn("Ignored window.print() because of a pending print job."); | ||
|  |     return; | ||
|  |   } | ||
|  |   ensureOverlay().then(function () { | ||
|  |     if (activeService) { | ||
|  |       overlayManager.open(dialog); | ||
|  |     } | ||
|  |   }); | ||
|  |   try { | ||
|  |     dispatchEvent("beforeprint"); | ||
|  |   } finally { | ||
|  |     if (!activeService) { | ||
|  |       console.error("Expected print service to be initialized."); | ||
|  |       ensureOverlay().then(function () { | ||
|  |         if (overlayManager.active === dialog) { | ||
|  |           overlayManager.close(dialog); | ||
|  |         } | ||
|  |       }); | ||
|  |       return; | ||
|  |     } | ||
|  |     const activeServiceOnEntry = activeService; | ||
|  |     activeService.renderPages().then(function () { | ||
|  |       return activeServiceOnEntry.performPrint(); | ||
|  |     }).catch(function () {}).then(function () { | ||
|  |       if (activeServiceOnEntry.active) { | ||
|  |         abort(); | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  | }; | ||
|  | function dispatchEvent(eventType) { | ||
|  |   const event = new CustomEvent(eventType, { | ||
|  |     bubbles: false, | ||
|  |     cancelable: false, | ||
|  |     detail: "custom" | ||
|  |   }); | ||
|  |   window.dispatchEvent(event); | ||
|  | } | ||
|  | function abort() { | ||
|  |   if (activeService) { | ||
|  |     activeService.destroy(); | ||
|  |     dispatchEvent("afterprint"); | ||
|  |   } | ||
|  | } | ||
|  | function renderProgress(index, total) { | ||
|  |   dialog ||= document.getElementById("printServiceDialog"); | ||
|  |   const progress = Math.round(100 * index / total); | ||
|  |   const progressBar = dialog.querySelector("progress"); | ||
|  |   const progressPerc = dialog.querySelector(".relative-progress"); | ||
|  |   progressBar.value = progress; | ||
|  |   progressPerc.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |     progress | ||
|  |   })); | ||
|  | } | ||
|  | window.addEventListener("keydown", function (event) { | ||
|  |   if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) { | ||
|  |     window.print(); | ||
|  |     event.preventDefault(); | ||
|  |     event.stopImmediatePropagation(); | ||
|  |   } | ||
|  | }, true); | ||
|  | if ("onbeforeprint" in window) { | ||
|  |   const stopPropagationIfNeeded = function (event) { | ||
|  |     if (event.detail !== "custom") { | ||
|  |       event.stopImmediatePropagation(); | ||
|  |     } | ||
|  |   }; | ||
|  |   window.addEventListener("beforeprint", stopPropagationIfNeeded); | ||
|  |   window.addEventListener("afterprint", stopPropagationIfNeeded); | ||
|  | } | ||
|  | let overlayPromise; | ||
|  | function ensureOverlay() { | ||
|  |   if (!overlayPromise) { | ||
|  |     overlayManager = viewerApp.overlayManager; | ||
|  |     if (!overlayManager) { | ||
|  |       throw new Error("The overlay manager has not yet been initialized."); | ||
|  |     } | ||
|  |     dialog ||= document.getElementById("printServiceDialog"); | ||
|  |     overlayPromise = overlayManager.register(dialog, true); | ||
|  |     document.getElementById("printCancel").onclick = abort; | ||
|  |     dialog.addEventListener("close", abort); | ||
|  |   } | ||
|  |   return overlayPromise; | ||
|  | } | ||
|  | class PDFPrintServiceFactory { | ||
|  |   static initGlobals(app) { | ||
|  |     viewerApp = app; | ||
|  |   } | ||
|  |   static get supportsPrinting() { | ||
|  |     return shadow(this, "supportsPrinting", true); | ||
|  |   } | ||
|  |   static createPrintService(params) { | ||
|  |     if (activeService) { | ||
|  |       throw new Error("The print service is created and active."); | ||
|  |     } | ||
|  |     return activeService = new PDFPrintService(params); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_rendering_queue.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const CLEANUP_TIMEOUT = 30000; | ||
|  | class PDFRenderingQueue { | ||
|  |   constructor() { | ||
|  |     this.pdfViewer = null; | ||
|  |     this.pdfThumbnailViewer = null; | ||
|  |     this.onIdle = null; | ||
|  |     this.highestPriorityPage = null; | ||
|  |     this.idleTimeout = null; | ||
|  |     this.printing = false; | ||
|  |     this.isThumbnailViewEnabled = false; | ||
|  |     Object.defineProperty(this, "hasViewer", { | ||
|  |       value: () => !!this.pdfViewer | ||
|  |     }); | ||
|  |   } | ||
|  |   setViewer(pdfViewer) { | ||
|  |     this.pdfViewer = pdfViewer; | ||
|  |   } | ||
|  |   setThumbnailViewer(pdfThumbnailViewer) { | ||
|  |     this.pdfThumbnailViewer = pdfThumbnailViewer; | ||
|  |   } | ||
|  |   isHighestPriority(view) { | ||
|  |     return this.highestPriorityPage === view.renderingId; | ||
|  |   } | ||
|  |   renderHighestPriority(currentlyVisiblePages) { | ||
|  |     if (this.idleTimeout) { | ||
|  |       clearTimeout(this.idleTimeout); | ||
|  |       this.idleTimeout = null; | ||
|  |     } | ||
|  |     if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.isThumbnailViewEnabled && this.pdfThumbnailViewer?.forceRendering()) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.printing) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.onIdle) { | ||
|  |       this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); | ||
|  |     } | ||
|  |   } | ||
|  |   getHighestPriority(visible, views, scrolledDown, preRenderExtra = false) { | ||
|  |     const visibleViews = visible.views, | ||
|  |       numVisible = visibleViews.length; | ||
|  |     if (numVisible === 0) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     for (let i = 0; i < numVisible; i++) { | ||
|  |       const view = visibleViews[i].view; | ||
|  |       if (!this.isViewFinished(view)) { | ||
|  |         return view; | ||
|  |       } | ||
|  |     } | ||
|  |     const firstId = visible.first.id, | ||
|  |       lastId = visible.last.id; | ||
|  |     if (lastId - firstId + 1 > numVisible) { | ||
|  |       const visibleIds = visible.ids; | ||
|  |       for (let i = 1, ii = lastId - firstId; i < ii; i++) { | ||
|  |         const holeId = scrolledDown ? firstId + i : lastId - i; | ||
|  |         if (visibleIds.has(holeId)) { | ||
|  |           continue; | ||
|  |         } | ||
|  |         const holeView = views[holeId - 1]; | ||
|  |         if (!this.isViewFinished(holeView)) { | ||
|  |           return holeView; | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     let preRenderIndex = scrolledDown ? lastId : firstId - 2; | ||
|  |     let preRenderView = views[preRenderIndex]; | ||
|  |     if (preRenderView && !this.isViewFinished(preRenderView)) { | ||
|  |       return preRenderView; | ||
|  |     } | ||
|  |     if (preRenderExtra) { | ||
|  |       preRenderIndex += scrolledDown ? 1 : -1; | ||
|  |       preRenderView = views[preRenderIndex]; | ||
|  |       if (preRenderView && !this.isViewFinished(preRenderView)) { | ||
|  |         return preRenderView; | ||
|  |       } | ||
|  |     } | ||
|  |     return null; | ||
|  |   } | ||
|  |   isViewFinished(view) { | ||
|  |     return view.renderingState === RenderingStates.FINISHED; | ||
|  |   } | ||
|  |   renderView(view) { | ||
|  |     switch (view.renderingState) { | ||
|  |       case RenderingStates.FINISHED: | ||
|  |         return false; | ||
|  |       case RenderingStates.PAUSED: | ||
|  |         this.highestPriorityPage = view.renderingId; | ||
|  |         view.resume(); | ||
|  |         break; | ||
|  |       case RenderingStates.RUNNING: | ||
|  |         this.highestPriorityPage = view.renderingId; | ||
|  |         break; | ||
|  |       case RenderingStates.INITIAL: | ||
|  |         this.highestPriorityPage = view.renderingId; | ||
|  |         view.draw().finally(() => { | ||
|  |           this.renderHighestPriority(); | ||
|  |         }).catch(reason => { | ||
|  |           if (reason instanceof RenderingCancelledException) { | ||
|  |             return; | ||
|  |           } | ||
|  |           console.error(`renderView: "${reason}"`); | ||
|  |         }); | ||
|  |         break; | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_scripting_manager.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class PDFScriptingManager { | ||
|  |   #closeCapability = null; | ||
|  |   #destroyCapability = null; | ||
|  |   #docProperties = null; | ||
|  |   #eventAbortController = null; | ||
|  |   #eventBus = null; | ||
|  |   #externalServices = null; | ||
|  |   #pdfDocument = null; | ||
|  |   #pdfViewer = null; | ||
|  |   #ready = false; | ||
|  |   #scripting = null; | ||
|  |   #willPrintCapability = null; | ||
|  |   constructor({ | ||
|  |     eventBus, | ||
|  |     externalServices = null, | ||
|  |     docProperties = null | ||
|  |   }) { | ||
|  |     this.#eventBus = eventBus; | ||
|  |     this.#externalServices = externalServices; | ||
|  |     this.#docProperties = docProperties; | ||
|  |   } | ||
|  |   setViewer(pdfViewer) { | ||
|  |     this.#pdfViewer = pdfViewer; | ||
|  |   } | ||
|  |   async setDocument(pdfDocument) { | ||
|  |     if (this.#pdfDocument) { | ||
|  |       await this.#destroyScripting(); | ||
|  |     } | ||
|  |     this.#pdfDocument = pdfDocument; | ||
|  |     if (!pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]); | ||
|  |     if (!objects && !docActions) { | ||
|  |       await this.#destroyScripting(); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (pdfDocument !== this.#pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     try { | ||
|  |       this.#scripting = this.#initScripting(); | ||
|  |     } catch (error) { | ||
|  |       console.error(`setDocument: "${error.message}".`); | ||
|  |       await this.#destroyScripting(); | ||
|  |       return; | ||
|  |     } | ||
|  |     const eventBus = this.#eventBus; | ||
|  |     this.#eventAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       signal | ||
|  |     } = this.#eventAbortController; | ||
|  |     eventBus._on("updatefromsandbox", event => { | ||
|  |       if (event?.source === window) { | ||
|  |         this.#updateFromSandbox(event.detail); | ||
|  |       } | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("dispatcheventinsandbox", event => { | ||
|  |       this.#scripting?.dispatchEventInSandbox(event.detail); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagechanging", ({ | ||
|  |       pageNumber, | ||
|  |       previous | ||
|  |     }) => { | ||
|  |       if (pageNumber === previous) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#dispatchPageClose(previous); | ||
|  |       this.#dispatchPageOpen(pageNumber); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagerendered", ({ | ||
|  |       pageNumber | ||
|  |     }) => { | ||
|  |       if (!this._pageOpenPending.has(pageNumber)) { | ||
|  |         return; | ||
|  |       } | ||
|  |       if (pageNumber !== this.#pdfViewer.currentPageNumber) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#dispatchPageOpen(pageNumber); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagesdestroy", async () => { | ||
|  |       await this.#dispatchPageClose(this.#pdfViewer.currentPageNumber); | ||
|  |       await this.#scripting?.dispatchEventInSandbox({ | ||
|  |         id: "doc", | ||
|  |         name: "WillClose" | ||
|  |       }); | ||
|  |       this.#closeCapability?.resolve(); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     try { | ||
|  |       const docProperties = await this.#docProperties(pdfDocument); | ||
|  |       if (pdfDocument !== this.#pdfDocument) { | ||
|  |         return; | ||
|  |       } | ||
|  |       await this.#scripting.createSandbox({ | ||
|  |         objects, | ||
|  |         calculationOrder, | ||
|  |         appInfo: { | ||
|  |           platform: navigator.platform, | ||
|  |           language: navigator.language | ||
|  |         }, | ||
|  |         docInfo: { | ||
|  |           ...docProperties, | ||
|  |           actions: docActions | ||
|  |         } | ||
|  |       }); | ||
|  |       eventBus.dispatch("sandboxcreated", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |     } catch (error) { | ||
|  |       console.error(`setDocument: "${error.message}".`); | ||
|  |       await this.#destroyScripting(); | ||
|  |       return; | ||
|  |     } | ||
|  |     await this.#scripting?.dispatchEventInSandbox({ | ||
|  |       id: "doc", | ||
|  |       name: "Open" | ||
|  |     }); | ||
|  |     await this.#dispatchPageOpen(this.#pdfViewer.currentPageNumber, true); | ||
|  |     Promise.resolve().then(() => { | ||
|  |       if (pdfDocument === this.#pdfDocument) { | ||
|  |         this.#ready = true; | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   async dispatchWillSave() { | ||
|  |     return this.#scripting?.dispatchEventInSandbox({ | ||
|  |       id: "doc", | ||
|  |       name: "WillSave" | ||
|  |     }); | ||
|  |   } | ||
|  |   async dispatchDidSave() { | ||
|  |     return this.#scripting?.dispatchEventInSandbox({ | ||
|  |       id: "doc", | ||
|  |       name: "DidSave" | ||
|  |     }); | ||
|  |   } | ||
|  |   async dispatchWillPrint() { | ||
|  |     if (!this.#scripting) { | ||
|  |       return; | ||
|  |     } | ||
|  |     await this.#willPrintCapability?.promise; | ||
|  |     this.#willPrintCapability = Promise.withResolvers(); | ||
|  |     try { | ||
|  |       await this.#scripting.dispatchEventInSandbox({ | ||
|  |         id: "doc", | ||
|  |         name: "WillPrint" | ||
|  |       }); | ||
|  |     } catch (ex) { | ||
|  |       this.#willPrintCapability.resolve(); | ||
|  |       this.#willPrintCapability = null; | ||
|  |       throw ex; | ||
|  |     } | ||
|  |     await this.#willPrintCapability.promise; | ||
|  |   } | ||
|  |   async dispatchDidPrint() { | ||
|  |     return this.#scripting?.dispatchEventInSandbox({ | ||
|  |       id: "doc", | ||
|  |       name: "DidPrint" | ||
|  |     }); | ||
|  |   } | ||
|  |   get destroyPromise() { | ||
|  |     return this.#destroyCapability?.promise || null; | ||
|  |   } | ||
|  |   get ready() { | ||
|  |     return this.#ready; | ||
|  |   } | ||
|  |   get _pageOpenPending() { | ||
|  |     return shadow(this, "_pageOpenPending", new Set()); | ||
|  |   } | ||
|  |   get _visitedPages() { | ||
|  |     return shadow(this, "_visitedPages", new Map()); | ||
|  |   } | ||
|  |   async #updateFromSandbox(detail) { | ||
|  |     const pdfViewer = this.#pdfViewer; | ||
|  |     const isInPresentationMode = pdfViewer.isInPresentationMode || pdfViewer.isChangingPresentationMode; | ||
|  |     const { | ||
|  |       id, | ||
|  |       siblings, | ||
|  |       command, | ||
|  |       value | ||
|  |     } = detail; | ||
|  |     if (!id) { | ||
|  |       switch (command) { | ||
|  |         case "clear": | ||
|  |           console.clear(); | ||
|  |           break; | ||
|  |         case "error": | ||
|  |           console.error(value); | ||
|  |           break; | ||
|  |         case "layout": | ||
|  |           if (!isInPresentationMode) { | ||
|  |             const modes = apiPageLayoutToViewerModes(value); | ||
|  |             pdfViewer.spreadMode = modes.spreadMode; | ||
|  |           } | ||
|  |           break; | ||
|  |         case "page-num": | ||
|  |           pdfViewer.currentPageNumber = value + 1; | ||
|  |           break; | ||
|  |         case "print": | ||
|  |           await pdfViewer.pagesPromise; | ||
|  |           this.#eventBus.dispatch("print", { | ||
|  |             source: this | ||
|  |           }); | ||
|  |           break; | ||
|  |         case "println": | ||
|  |           console.log(value); | ||
|  |           break; | ||
|  |         case "zoom": | ||
|  |           if (!isInPresentationMode) { | ||
|  |             pdfViewer.currentScaleValue = value; | ||
|  |           } | ||
|  |           break; | ||
|  |         case "SaveAs": | ||
|  |           this.#eventBus.dispatch("download", { | ||
|  |             source: this | ||
|  |           }); | ||
|  |           break; | ||
|  |         case "FirstPage": | ||
|  |           pdfViewer.currentPageNumber = 1; | ||
|  |           break; | ||
|  |         case "LastPage": | ||
|  |           pdfViewer.currentPageNumber = pdfViewer.pagesCount; | ||
|  |           break; | ||
|  |         case "NextPage": | ||
|  |           pdfViewer.nextPage(); | ||
|  |           break; | ||
|  |         case "PrevPage": | ||
|  |           pdfViewer.previousPage(); | ||
|  |           break; | ||
|  |         case "ZoomViewIn": | ||
|  |           if (!isInPresentationMode) { | ||
|  |             pdfViewer.increaseScale(); | ||
|  |           } | ||
|  |           break; | ||
|  |         case "ZoomViewOut": | ||
|  |           if (!isInPresentationMode) { | ||
|  |             pdfViewer.decreaseScale(); | ||
|  |           } | ||
|  |           break; | ||
|  |         case "WillPrintFinished": | ||
|  |           this.#willPrintCapability?.resolve(); | ||
|  |           this.#willPrintCapability = null; | ||
|  |           break; | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     if (isInPresentationMode && detail.focus) { | ||
|  |       return; | ||
|  |     } | ||
|  |     delete detail.id; | ||
|  |     delete detail.siblings; | ||
|  |     const ids = siblings ? [id, ...siblings] : [id]; | ||
|  |     for (const elementId of ids) { | ||
|  |       const element = document.querySelector(`[data-element-id="${elementId}"]`); | ||
|  |       if (element) { | ||
|  |         element.dispatchEvent(new CustomEvent("updatefromsandbox", { | ||
|  |           detail | ||
|  |         })); | ||
|  |       } else { | ||
|  |         this.#pdfDocument?.annotationStorage.setValue(elementId, detail); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   async #dispatchPageOpen(pageNumber, initialize = false) { | ||
|  |     const pdfDocument = this.#pdfDocument, | ||
|  |       visitedPages = this._visitedPages; | ||
|  |     if (initialize) { | ||
|  |       this.#closeCapability = Promise.withResolvers(); | ||
|  |     } | ||
|  |     if (!this.#closeCapability) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pageView = this.#pdfViewer.getPageView(pageNumber - 1); | ||
|  |     if (pageView?.renderingState !== RenderingStates.FINISHED) { | ||
|  |       this._pageOpenPending.add(pageNumber); | ||
|  |       return; | ||
|  |     } | ||
|  |     this._pageOpenPending.delete(pageNumber); | ||
|  |     const actionsPromise = (async () => { | ||
|  |       const actions = await (!visitedPages.has(pageNumber) ? pageView.pdfPage?.getJSActions() : null); | ||
|  |       if (pdfDocument !== this.#pdfDocument) { | ||
|  |         return; | ||
|  |       } | ||
|  |       await this.#scripting?.dispatchEventInSandbox({ | ||
|  |         id: "page", | ||
|  |         name: "PageOpen", | ||
|  |         pageNumber, | ||
|  |         actions | ||
|  |       }); | ||
|  |     })(); | ||
|  |     visitedPages.set(pageNumber, actionsPromise); | ||
|  |   } | ||
|  |   async #dispatchPageClose(pageNumber) { | ||
|  |     const pdfDocument = this.#pdfDocument, | ||
|  |       visitedPages = this._visitedPages; | ||
|  |     if (!this.#closeCapability) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._pageOpenPending.has(pageNumber)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const actionsPromise = visitedPages.get(pageNumber); | ||
|  |     if (!actionsPromise) { | ||
|  |       return; | ||
|  |     } | ||
|  |     visitedPages.set(pageNumber, null); | ||
|  |     await actionsPromise; | ||
|  |     if (pdfDocument !== this.#pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     await this.#scripting?.dispatchEventInSandbox({ | ||
|  |       id: "page", | ||
|  |       name: "PageClose", | ||
|  |       pageNumber | ||
|  |     }); | ||
|  |   } | ||
|  |   #initScripting() { | ||
|  |     this.#destroyCapability = Promise.withResolvers(); | ||
|  |     if (this.#scripting) { | ||
|  |       throw new Error("#initScripting: Scripting already exists."); | ||
|  |     } | ||
|  |     return this.#externalServices.createScripting(); | ||
|  |   } | ||
|  |   async #destroyScripting() { | ||
|  |     if (!this.#scripting) { | ||
|  |       this.#pdfDocument = null; | ||
|  |       this.#destroyCapability?.resolve(); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.#closeCapability) { | ||
|  |       await Promise.race([this.#closeCapability.promise, new Promise(resolve => { | ||
|  |         setTimeout(resolve, 1000); | ||
|  |       })]).catch(() => {}); | ||
|  |       this.#closeCapability = null; | ||
|  |     } | ||
|  |     this.#pdfDocument = null; | ||
|  |     try { | ||
|  |       await this.#scripting.destroySandbox(); | ||
|  |     } catch {} | ||
|  |     this.#willPrintCapability?.reject(new Error("Scripting destroyed.")); | ||
|  |     this.#willPrintCapability = null; | ||
|  |     this.#eventAbortController?.abort(); | ||
|  |     this.#eventAbortController = null; | ||
|  |     this._pageOpenPending.clear(); | ||
|  |     this._visitedPages.clear(); | ||
|  |     this.#scripting = null; | ||
|  |     this.#ready = false; | ||
|  |     this.#destroyCapability?.resolve(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_sidebar.js
 | ||
|  | 
 | ||
|  | const SIDEBAR_WIDTH_VAR = "--sidebar-width"; | ||
|  | const SIDEBAR_MIN_WIDTH = 200; | ||
|  | const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; | ||
|  | const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; | ||
|  | class PDFSidebar { | ||
|  |   #isRTL = false; | ||
|  |   #mouseAC = null; | ||
|  |   #outerContainerWidth = null; | ||
|  |   #width = null; | ||
|  |   constructor({ | ||
|  |     elements, | ||
|  |     eventBus, | ||
|  |     l10n | ||
|  |   }) { | ||
|  |     this.isOpen = false; | ||
|  |     this.active = SidebarView.THUMBS; | ||
|  |     this.isInitialViewSet = false; | ||
|  |     this.isInitialEventDispatched = false; | ||
|  |     this.onToggled = null; | ||
|  |     this.onUpdateThumbnails = null; | ||
|  |     this.outerContainer = elements.outerContainer; | ||
|  |     this.sidebarContainer = elements.sidebarContainer; | ||
|  |     this.toggleButton = elements.toggleButton; | ||
|  |     this.resizer = elements.resizer; | ||
|  |     this.thumbnailButton = elements.thumbnailButton; | ||
|  |     this.outlineButton = elements.outlineButton; | ||
|  |     this.attachmentsButton = elements.attachmentsButton; | ||
|  |     this.layersButton = elements.layersButton; | ||
|  |     this.thumbnailView = elements.thumbnailView; | ||
|  |     this.outlineView = elements.outlineView; | ||
|  |     this.attachmentsView = elements.attachmentsView; | ||
|  |     this.layersView = elements.layersView; | ||
|  |     this._currentOutlineItemButton = elements.currentOutlineItemButton; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.#isRTL = l10n.getDirection() === "rtl"; | ||
|  |     this.#addEventListeners(); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this.isInitialViewSet = false; | ||
|  |     this.isInitialEventDispatched = false; | ||
|  |     this.#hideUINotification(true); | ||
|  |     this.switchView(SidebarView.THUMBS); | ||
|  |     this.outlineButton.disabled = false; | ||
|  |     this.attachmentsButton.disabled = false; | ||
|  |     this.layersButton.disabled = false; | ||
|  |     this._currentOutlineItemButton.disabled = true; | ||
|  |   } | ||
|  |   get visibleView() { | ||
|  |     return this.isOpen ? this.active : SidebarView.NONE; | ||
|  |   } | ||
|  |   setInitialView(view = SidebarView.NONE) { | ||
|  |     if (this.isInitialViewSet) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.isInitialViewSet = true; | ||
|  |     if (view === SidebarView.NONE || view === SidebarView.UNKNOWN) { | ||
|  |       this.#dispatchEvent(); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.switchView(view, true); | ||
|  |     if (!this.isInitialEventDispatched) { | ||
|  |       this.#dispatchEvent(); | ||
|  |     } | ||
|  |   } | ||
|  |   switchView(view, forceOpen = false) { | ||
|  |     const isViewChanged = view !== this.active; | ||
|  |     let forceRendering = false; | ||
|  |     switch (view) { | ||
|  |       case SidebarView.NONE: | ||
|  |         if (this.isOpen) { | ||
|  |           this.close(); | ||
|  |         } | ||
|  |         return; | ||
|  |       case SidebarView.THUMBS: | ||
|  |         if (this.isOpen && isViewChanged) { | ||
|  |           forceRendering = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case SidebarView.OUTLINE: | ||
|  |         if (this.outlineButton.disabled) { | ||
|  |           return; | ||
|  |         } | ||
|  |         break; | ||
|  |       case SidebarView.ATTACHMENTS: | ||
|  |         if (this.attachmentsButton.disabled) { | ||
|  |           return; | ||
|  |         } | ||
|  |         break; | ||
|  |       case SidebarView.LAYERS: | ||
|  |         if (this.layersButton.disabled) { | ||
|  |           return; | ||
|  |         } | ||
|  |         break; | ||
|  |       default: | ||
|  |         console.error(`PDFSidebar.switchView: "${view}" is not a valid view.`); | ||
|  |         return; | ||
|  |     } | ||
|  |     this.active = view; | ||
|  |     toggleCheckedBtn(this.thumbnailButton, view === SidebarView.THUMBS, this.thumbnailView); | ||
|  |     toggleCheckedBtn(this.outlineButton, view === SidebarView.OUTLINE, this.outlineView); | ||
|  |     toggleCheckedBtn(this.attachmentsButton, view === SidebarView.ATTACHMENTS, this.attachmentsView); | ||
|  |     toggleCheckedBtn(this.layersButton, view === SidebarView.LAYERS, this.layersView); | ||
|  |     if (forceOpen && !this.isOpen) { | ||
|  |       this.open(); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (forceRendering) { | ||
|  |       this.onUpdateThumbnails(); | ||
|  |       this.onToggled(); | ||
|  |     } | ||
|  |     if (isViewChanged) { | ||
|  |       this.#dispatchEvent(); | ||
|  |     } | ||
|  |   } | ||
|  |   open() { | ||
|  |     if (this.isOpen) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.isOpen = true; | ||
|  |     toggleExpandedBtn(this.toggleButton, true); | ||
|  |     this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); | ||
|  |     if (this.active === SidebarView.THUMBS) { | ||
|  |       this.onUpdateThumbnails(); | ||
|  |     } | ||
|  |     this.onToggled(); | ||
|  |     this.#dispatchEvent(); | ||
|  |     this.#hideUINotification(); | ||
|  |   } | ||
|  |   close(evt = null) { | ||
|  |     if (!this.isOpen) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.isOpen = false; | ||
|  |     toggleExpandedBtn(this.toggleButton, false); | ||
|  |     this.outerContainer.classList.add("sidebarMoving"); | ||
|  |     this.outerContainer.classList.remove("sidebarOpen"); | ||
|  |     this.onToggled(); | ||
|  |     this.#dispatchEvent(); | ||
|  |     if (evt?.detail > 0) { | ||
|  |       this.toggleButton.blur(); | ||
|  |     } | ||
|  |   } | ||
|  |   toggle(evt = null) { | ||
|  |     if (this.isOpen) { | ||
|  |       this.close(evt); | ||
|  |     } else { | ||
|  |       this.open(); | ||
|  |     } | ||
|  |   } | ||
|  |   #dispatchEvent() { | ||
|  |     if (this.isInitialViewSet) { | ||
|  |       this.isInitialEventDispatched ||= true; | ||
|  |     } | ||
|  |     this.eventBus.dispatch("sidebarviewchanged", { | ||
|  |       source: this, | ||
|  |       view: this.visibleView | ||
|  |     }); | ||
|  |   } | ||
|  |   #showUINotification() { | ||
|  |     this.toggleButton.setAttribute("data-l10n-id", "pdfjs-toggle-sidebar-notification-button"); | ||
|  |     if (!this.isOpen) { | ||
|  |       this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); | ||
|  |     } | ||
|  |   } | ||
|  |   #hideUINotification(reset = false) { | ||
|  |     if (this.isOpen || reset) { | ||
|  |       this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); | ||
|  |     } | ||
|  |     if (reset) { | ||
|  |       this.toggleButton.setAttribute("data-l10n-id", "pdfjs-toggle-sidebar-button"); | ||
|  |     } | ||
|  |   } | ||
|  |   #addEventListeners() { | ||
|  |     const { | ||
|  |       eventBus, | ||
|  |       outerContainer | ||
|  |     } = this; | ||
|  |     this.sidebarContainer.addEventListener("transitionend", evt => { | ||
|  |       if (evt.target === this.sidebarContainer) { | ||
|  |         outerContainer.classList.remove("sidebarMoving"); | ||
|  |         eventBus.dispatch("resize", { | ||
|  |           source: this | ||
|  |         }); | ||
|  |       } | ||
|  |     }); | ||
|  |     this.toggleButton.addEventListener("click", evt => { | ||
|  |       this.toggle(evt); | ||
|  |     }); | ||
|  |     this.thumbnailButton.addEventListener("click", () => { | ||
|  |       this.switchView(SidebarView.THUMBS); | ||
|  |     }); | ||
|  |     this.outlineButton.addEventListener("click", () => { | ||
|  |       this.switchView(SidebarView.OUTLINE); | ||
|  |     }); | ||
|  |     this.outlineButton.addEventListener("dblclick", () => { | ||
|  |       eventBus.dispatch("toggleoutlinetree", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |     }); | ||
|  |     this.attachmentsButton.addEventListener("click", () => { | ||
|  |       this.switchView(SidebarView.ATTACHMENTS); | ||
|  |     }); | ||
|  |     this.layersButton.addEventListener("click", () => { | ||
|  |       this.switchView(SidebarView.LAYERS); | ||
|  |     }); | ||
|  |     this.layersButton.addEventListener("dblclick", () => { | ||
|  |       eventBus.dispatch("resetlayers", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |     }); | ||
|  |     this._currentOutlineItemButton.addEventListener("click", () => { | ||
|  |       eventBus.dispatch("currentoutlineitem", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |     }); | ||
|  |     const onTreeLoaded = (count, button, view) => { | ||
|  |       button.disabled = !count; | ||
|  |       if (count) { | ||
|  |         this.#showUINotification(); | ||
|  |       } else if (this.active === view) { | ||
|  |         this.switchView(SidebarView.THUMBS); | ||
|  |       } | ||
|  |     }; | ||
|  |     eventBus._on("outlineloaded", evt => { | ||
|  |       onTreeLoaded(evt.outlineCount, this.outlineButton, SidebarView.OUTLINE); | ||
|  |       evt.currentOutlineItemPromise.then(enabled => { | ||
|  |         if (!this.isInitialViewSet) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this._currentOutlineItemButton.disabled = !enabled; | ||
|  |       }); | ||
|  |     }); | ||
|  |     eventBus._on("attachmentsloaded", evt => { | ||
|  |       onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, SidebarView.ATTACHMENTS); | ||
|  |     }); | ||
|  |     eventBus._on("layersloaded", evt => { | ||
|  |       onTreeLoaded(evt.layersCount, this.layersButton, SidebarView.LAYERS); | ||
|  |     }); | ||
|  |     eventBus._on("presentationmodechanged", evt => { | ||
|  |       if (evt.state === PresentationModeState.NORMAL && this.visibleView === SidebarView.THUMBS) { | ||
|  |         this.onUpdateThumbnails(); | ||
|  |       } | ||
|  |     }); | ||
|  |     this.resizer.addEventListener("mousedown", evt => { | ||
|  |       if (evt.button !== 0) { | ||
|  |         return; | ||
|  |       } | ||
|  |       outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); | ||
|  |       this.#mouseAC = new AbortController(); | ||
|  |       const opts = { | ||
|  |         signal: this.#mouseAC.signal | ||
|  |       }; | ||
|  |       window.addEventListener("mousemove", this.#mouseMove.bind(this), opts); | ||
|  |       window.addEventListener("mouseup", this.#mouseUp.bind(this), opts); | ||
|  |       window.addEventListener("blur", this.#mouseUp.bind(this), opts); | ||
|  |     }); | ||
|  |     eventBus._on("resize", evt => { | ||
|  |       if (evt.source !== window) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#outerContainerWidth = null; | ||
|  |       if (!this.#width) { | ||
|  |         return; | ||
|  |       } | ||
|  |       if (!this.isOpen) { | ||
|  |         this.#updateWidth(this.#width); | ||
|  |         return; | ||
|  |       } | ||
|  |       outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); | ||
|  |       const updated = this.#updateWidth(this.#width); | ||
|  |       Promise.resolve().then(() => { | ||
|  |         outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); | ||
|  |         if (updated) { | ||
|  |           eventBus.dispatch("resize", { | ||
|  |             source: this | ||
|  |           }); | ||
|  |         } | ||
|  |       }); | ||
|  |     }); | ||
|  |   } | ||
|  |   get outerContainerWidth() { | ||
|  |     return this.#outerContainerWidth ||= this.outerContainer.clientWidth; | ||
|  |   } | ||
|  |   #updateWidth(width = 0) { | ||
|  |     const maxWidth = Math.floor(this.outerContainerWidth / 2); | ||
|  |     if (width > maxWidth) { | ||
|  |       width = maxWidth; | ||
|  |     } | ||
|  |     if (width < SIDEBAR_MIN_WIDTH) { | ||
|  |       width = SIDEBAR_MIN_WIDTH; | ||
|  |     } | ||
|  |     if (width === this.#width) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     this.#width = width; | ||
|  |     docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); | ||
|  |     return true; | ||
|  |   } | ||
|  |   #mouseMove(evt) { | ||
|  |     let width = evt.clientX; | ||
|  |     if (this.#isRTL) { | ||
|  |       width = this.outerContainerWidth - width; | ||
|  |     } | ||
|  |     this.#updateWidth(width); | ||
|  |   } | ||
|  |   #mouseUp(evt) { | ||
|  |     this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); | ||
|  |     this.eventBus.dispatch("resize", { | ||
|  |       source: this | ||
|  |     }); | ||
|  |     this.#mouseAC?.abort(); | ||
|  |     this.#mouseAC = null; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_thumbnail_view.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const DRAW_UPSCALE_FACTOR = 2; | ||
|  | const MAX_NUM_SCALING_STEPS = 3; | ||
|  | const THUMBNAIL_WIDTH = 98; | ||
|  | class TempImageFactory { | ||
|  |   static #tempCanvas = null; | ||
|  |   static getCanvas(width, height) { | ||
|  |     const tempCanvas = this.#tempCanvas ||= document.createElement("canvas"); | ||
|  |     tempCanvas.width = width; | ||
|  |     tempCanvas.height = height; | ||
|  |     const ctx = tempCanvas.getContext("2d", { | ||
|  |       alpha: false | ||
|  |     }); | ||
|  |     ctx.save(); | ||
|  |     ctx.fillStyle = "rgb(255, 255, 255)"; | ||
|  |     ctx.fillRect(0, 0, width, height); | ||
|  |     ctx.restore(); | ||
|  |     return [tempCanvas, tempCanvas.getContext("2d")]; | ||
|  |   } | ||
|  |   static destroyCanvas() { | ||
|  |     const tempCanvas = this.#tempCanvas; | ||
|  |     if (tempCanvas) { | ||
|  |       tempCanvas.width = 0; | ||
|  |       tempCanvas.height = 0; | ||
|  |     } | ||
|  |     this.#tempCanvas = null; | ||
|  |   } | ||
|  | } | ||
|  | class PDFThumbnailView { | ||
|  |   constructor({ | ||
|  |     container, | ||
|  |     eventBus, | ||
|  |     id, | ||
|  |     defaultViewport, | ||
|  |     optionalContentConfigPromise, | ||
|  |     linkService, | ||
|  |     renderingQueue, | ||
|  |     pageColors, | ||
|  |     enableHWA | ||
|  |   }) { | ||
|  |     this.id = id; | ||
|  |     this.renderingId = "thumbnail" + id; | ||
|  |     this.pageLabel = null; | ||
|  |     this.pdfPage = null; | ||
|  |     this.rotation = 0; | ||
|  |     this.viewport = defaultViewport; | ||
|  |     this.pdfPageRotate = defaultViewport.rotation; | ||
|  |     this._optionalContentConfigPromise = optionalContentConfigPromise || null; | ||
|  |     this.pageColors = pageColors || null; | ||
|  |     this.enableHWA = enableHWA || false; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.linkService = linkService; | ||
|  |     this.renderingQueue = renderingQueue; | ||
|  |     this.renderTask = null; | ||
|  |     this.renderingState = RenderingStates.INITIAL; | ||
|  |     this.resume = null; | ||
|  |     const anchor = document.createElement("a"); | ||
|  |     anchor.href = linkService.getAnchorUrl("#page=" + id); | ||
|  |     anchor.setAttribute("data-l10n-id", "pdfjs-thumb-page-title"); | ||
|  |     anchor.setAttribute("data-l10n-args", this.#pageL10nArgs); | ||
|  |     anchor.onclick = function () { | ||
|  |       linkService.goToPage(id); | ||
|  |       return false; | ||
|  |     }; | ||
|  |     this.anchor = anchor; | ||
|  |     const div = document.createElement("div"); | ||
|  |     div.className = "thumbnail"; | ||
|  |     div.setAttribute("data-page-number", this.id); | ||
|  |     this.div = div; | ||
|  |     this.#updateDims(); | ||
|  |     const img = document.createElement("div"); | ||
|  |     img.className = "thumbnailImage"; | ||
|  |     this._placeholderImg = img; | ||
|  |     div.append(img); | ||
|  |     anchor.append(div); | ||
|  |     container.append(anchor); | ||
|  |   } | ||
|  |   #updateDims() { | ||
|  |     const { | ||
|  |       width, | ||
|  |       height | ||
|  |     } = this.viewport; | ||
|  |     const ratio = width / height; | ||
|  |     this.canvasWidth = THUMBNAIL_WIDTH; | ||
|  |     this.canvasHeight = this.canvasWidth / ratio | 0; | ||
|  |     this.scale = this.canvasWidth / width; | ||
|  |     const { | ||
|  |       style | ||
|  |     } = this.div; | ||
|  |     style.setProperty("--thumbnail-width", `${this.canvasWidth}px`); | ||
|  |     style.setProperty("--thumbnail-height", `${this.canvasHeight}px`); | ||
|  |   } | ||
|  |   setPdfPage(pdfPage) { | ||
|  |     this.pdfPage = pdfPage; | ||
|  |     this.pdfPageRotate = pdfPage.rotate; | ||
|  |     const totalRotation = (this.rotation + this.pdfPageRotate) % 360; | ||
|  |     this.viewport = pdfPage.getViewport({ | ||
|  |       scale: 1, | ||
|  |       rotation: totalRotation | ||
|  |     }); | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this.cancelRendering(); | ||
|  |     this.renderingState = RenderingStates.INITIAL; | ||
|  |     this.div.removeAttribute("data-loaded"); | ||
|  |     this.image?.replaceWith(this._placeholderImg); | ||
|  |     this.#updateDims(); | ||
|  |     if (this.image) { | ||
|  |       this.image.removeAttribute("src"); | ||
|  |       delete this.image; | ||
|  |     } | ||
|  |   } | ||
|  |   update({ | ||
|  |     rotation = null | ||
|  |   }) { | ||
|  |     if (typeof rotation === "number") { | ||
|  |       this.rotation = rotation; | ||
|  |     } | ||
|  |     const totalRotation = (this.rotation + this.pdfPageRotate) % 360; | ||
|  |     this.viewport = this.viewport.clone({ | ||
|  |       scale: 1, | ||
|  |       rotation: totalRotation | ||
|  |     }); | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   cancelRendering() { | ||
|  |     if (this.renderTask) { | ||
|  |       this.renderTask.cancel(); | ||
|  |       this.renderTask = null; | ||
|  |     } | ||
|  |     this.resume = null; | ||
|  |   } | ||
|  |   #getPageDrawContext(upscaleFactor = 1, enableHWA = this.enableHWA) { | ||
|  |     const canvas = document.createElement("canvas"); | ||
|  |     const ctx = canvas.getContext("2d", { | ||
|  |       alpha: false, | ||
|  |       willReadFrequently: !enableHWA | ||
|  |     }); | ||
|  |     const outputScale = new OutputScale(); | ||
|  |     canvas.width = upscaleFactor * this.canvasWidth * outputScale.sx | 0; | ||
|  |     canvas.height = upscaleFactor * this.canvasHeight * outputScale.sy | 0; | ||
|  |     const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; | ||
|  |     return { | ||
|  |       ctx, | ||
|  |       canvas, | ||
|  |       transform | ||
|  |     }; | ||
|  |   } | ||
|  |   #convertCanvasToImage(canvas) { | ||
|  |     if (this.renderingState !== RenderingStates.FINISHED) { | ||
|  |       throw new Error("#convertCanvasToImage: Rendering has not finished."); | ||
|  |     } | ||
|  |     const reducedCanvas = this.#reduceImage(canvas); | ||
|  |     const image = document.createElement("img"); | ||
|  |     image.className = "thumbnailImage"; | ||
|  |     image.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas"); | ||
|  |     image.setAttribute("data-l10n-args", this.#pageL10nArgs); | ||
|  |     image.src = reducedCanvas.toDataURL(); | ||
|  |     this.image = image; | ||
|  |     this.div.setAttribute("data-loaded", true); | ||
|  |     this._placeholderImg.replaceWith(image); | ||
|  |     reducedCanvas.width = 0; | ||
|  |     reducedCanvas.height = 0; | ||
|  |   } | ||
|  |   async #finishRenderTask(renderTask, canvas, error = null) { | ||
|  |     if (renderTask === this.renderTask) { | ||
|  |       this.renderTask = null; | ||
|  |     } | ||
|  |     if (error instanceof RenderingCancelledException) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.renderingState = RenderingStates.FINISHED; | ||
|  |     this.#convertCanvasToImage(canvas); | ||
|  |     if (error) { | ||
|  |       throw error; | ||
|  |     } | ||
|  |   } | ||
|  |   async draw() { | ||
|  |     if (this.renderingState !== RenderingStates.INITIAL) { | ||
|  |       console.error("Must be in new state before drawing"); | ||
|  |       return undefined; | ||
|  |     } | ||
|  |     const { | ||
|  |       pdfPage | ||
|  |     } = this; | ||
|  |     if (!pdfPage) { | ||
|  |       this.renderingState = RenderingStates.FINISHED; | ||
|  |       throw new Error("pdfPage is not loaded"); | ||
|  |     } | ||
|  |     this.renderingState = RenderingStates.RUNNING; | ||
|  |     const { | ||
|  |       ctx, | ||
|  |       canvas, | ||
|  |       transform | ||
|  |     } = this.#getPageDrawContext(DRAW_UPSCALE_FACTOR); | ||
|  |     const drawViewport = this.viewport.clone({ | ||
|  |       scale: DRAW_UPSCALE_FACTOR * this.scale | ||
|  |     }); | ||
|  |     const renderContinueCallback = cont => { | ||
|  |       if (!this.renderingQueue.isHighestPriority(this)) { | ||
|  |         this.renderingState = RenderingStates.PAUSED; | ||
|  |         this.resume = () => { | ||
|  |           this.renderingState = RenderingStates.RUNNING; | ||
|  |           cont(); | ||
|  |         }; | ||
|  |         return; | ||
|  |       } | ||
|  |       cont(); | ||
|  |     }; | ||
|  |     const renderContext = { | ||
|  |       canvasContext: ctx, | ||
|  |       transform, | ||
|  |       viewport: drawViewport, | ||
|  |       optionalContentConfigPromise: this._optionalContentConfigPromise, | ||
|  |       pageColors: this.pageColors | ||
|  |     }; | ||
|  |     const renderTask = this.renderTask = pdfPage.render(renderContext); | ||
|  |     renderTask.onContinue = renderContinueCallback; | ||
|  |     const resultPromise = renderTask.promise.then(() => this.#finishRenderTask(renderTask, canvas), error => this.#finishRenderTask(renderTask, canvas, error)); | ||
|  |     resultPromise.finally(() => { | ||
|  |       canvas.width = 0; | ||
|  |       canvas.height = 0; | ||
|  |       this.eventBus.dispatch("thumbnailrendered", { | ||
|  |         source: this, | ||
|  |         pageNumber: this.id, | ||
|  |         pdfPage: this.pdfPage | ||
|  |       }); | ||
|  |     }); | ||
|  |     return resultPromise; | ||
|  |   } | ||
|  |   setImage(pageView) { | ||
|  |     if (this.renderingState !== RenderingStates.INITIAL) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       thumbnailCanvas: canvas, | ||
|  |       pdfPage, | ||
|  |       scale | ||
|  |     } = pageView; | ||
|  |     if (!canvas) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this.pdfPage) { | ||
|  |       this.setPdfPage(pdfPage); | ||
|  |     } | ||
|  |     if (scale < this.scale) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.renderingState = RenderingStates.FINISHED; | ||
|  |     this.#convertCanvasToImage(canvas); | ||
|  |   } | ||
|  |   #reduceImage(img) { | ||
|  |     const { | ||
|  |       ctx, | ||
|  |       canvas | ||
|  |     } = this.#getPageDrawContext(1, true); | ||
|  |     if (img.width <= 2 * canvas.width) { | ||
|  |       ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); | ||
|  |       return canvas; | ||
|  |     } | ||
|  |     let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; | ||
|  |     let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; | ||
|  |     const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(reducedWidth, reducedHeight); | ||
|  |     while (reducedWidth > img.width || reducedHeight > img.height) { | ||
|  |       reducedWidth >>= 1; | ||
|  |       reducedHeight >>= 1; | ||
|  |     } | ||
|  |     reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight); | ||
|  |     while (reducedWidth > 2 * canvas.width) { | ||
|  |       reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1); | ||
|  |       reducedWidth >>= 1; | ||
|  |       reducedHeight >>= 1; | ||
|  |     } | ||
|  |     ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height); | ||
|  |     return canvas; | ||
|  |   } | ||
|  |   get #pageL10nArgs() { | ||
|  |     return JSON.stringify({ | ||
|  |       page: this.pageLabel ?? this.id | ||
|  |     }); | ||
|  |   } | ||
|  |   setPageLabel(label) { | ||
|  |     this.pageLabel = typeof label === "string" ? label : null; | ||
|  |     this.anchor.setAttribute("data-l10n-args", this.#pageL10nArgs); | ||
|  |     if (this.renderingState !== RenderingStates.FINISHED) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.image?.setAttribute("data-l10n-args", this.#pageL10nArgs); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_thumbnail_viewer.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const THUMBNAIL_SCROLL_MARGIN = -19; | ||
|  | const THUMBNAIL_SELECTED_CLASS = "selected"; | ||
|  | class PDFThumbnailViewer { | ||
|  |   constructor({ | ||
|  |     container, | ||
|  |     eventBus, | ||
|  |     linkService, | ||
|  |     renderingQueue, | ||
|  |     pageColors, | ||
|  |     abortSignal, | ||
|  |     enableHWA | ||
|  |   }) { | ||
|  |     this.container = container; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.linkService = linkService; | ||
|  |     this.renderingQueue = renderingQueue; | ||
|  |     this.pageColors = pageColors || null; | ||
|  |     this.enableHWA = enableHWA || false; | ||
|  |     this.scroll = watchScroll(this.container, this.#scrollUpdated.bind(this), abortSignal); | ||
|  |     this.#resetView(); | ||
|  |   } | ||
|  |   #scrollUpdated() { | ||
|  |     this.renderingQueue.renderHighestPriority(); | ||
|  |   } | ||
|  |   getThumbnail(index) { | ||
|  |     return this._thumbnails[index]; | ||
|  |   } | ||
|  |   #getVisibleThumbs() { | ||
|  |     return getVisibleElements({ | ||
|  |       scrollEl: this.container, | ||
|  |       views: this._thumbnails | ||
|  |     }); | ||
|  |   } | ||
|  |   scrollThumbnailIntoView(pageNumber) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const thumbnailView = this._thumbnails[pageNumber - 1]; | ||
|  |     if (!thumbnailView) { | ||
|  |       console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.'); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (pageNumber !== this._currentPageNumber) { | ||
|  |       const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1]; | ||
|  |       prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS); | ||
|  |       thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); | ||
|  |     } | ||
|  |     const { | ||
|  |       first, | ||
|  |       last, | ||
|  |       views | ||
|  |     } = this.#getVisibleThumbs(); | ||
|  |     if (views.length > 0) { | ||
|  |       let shouldScroll = false; | ||
|  |       if (pageNumber <= first.id || pageNumber >= last.id) { | ||
|  |         shouldScroll = true; | ||
|  |       } else { | ||
|  |         for (const { | ||
|  |           id, | ||
|  |           percent | ||
|  |         } of views) { | ||
|  |           if (id !== pageNumber) { | ||
|  |             continue; | ||
|  |           } | ||
|  |           shouldScroll = percent < 100; | ||
|  |           break; | ||
|  |         } | ||
|  |       } | ||
|  |       if (shouldScroll) { | ||
|  |         scrollIntoView(thumbnailView.div, { | ||
|  |           top: THUMBNAIL_SCROLL_MARGIN | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |     this._currentPageNumber = pageNumber; | ||
|  |   } | ||
|  |   get pagesRotation() { | ||
|  |     return this._pagesRotation; | ||
|  |   } | ||
|  |   set pagesRotation(rotation) { | ||
|  |     if (!isValidRotation(rotation)) { | ||
|  |       throw new Error("Invalid thumbnails rotation angle."); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._pagesRotation === rotation) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._pagesRotation = rotation; | ||
|  |     const updateArgs = { | ||
|  |       rotation | ||
|  |     }; | ||
|  |     for (const thumbnail of this._thumbnails) { | ||
|  |       thumbnail.update(updateArgs); | ||
|  |     } | ||
|  |   } | ||
|  |   cleanup() { | ||
|  |     for (const thumbnail of this._thumbnails) { | ||
|  |       if (thumbnail.renderingState !== RenderingStates.FINISHED) { | ||
|  |         thumbnail.reset(); | ||
|  |       } | ||
|  |     } | ||
|  |     TempImageFactory.destroyCanvas(); | ||
|  |   } | ||
|  |   #resetView() { | ||
|  |     this._thumbnails = []; | ||
|  |     this._currentPageNumber = 1; | ||
|  |     this._pageLabels = null; | ||
|  |     this._pagesRotation = 0; | ||
|  |     this.container.textContent = ""; | ||
|  |   } | ||
|  |   setDocument(pdfDocument) { | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.#cancelRendering(); | ||
|  |       this.#resetView(); | ||
|  |     } | ||
|  |     this.pdfDocument = pdfDocument; | ||
|  |     if (!pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const firstPagePromise = pdfDocument.getPage(1); | ||
|  |     const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ | ||
|  |       intent: "display" | ||
|  |     }); | ||
|  |     firstPagePromise.then(firstPdfPage => { | ||
|  |       const pagesCount = pdfDocument.numPages; | ||
|  |       const viewport = firstPdfPage.getViewport({ | ||
|  |         scale: 1 | ||
|  |       }); | ||
|  |       for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { | ||
|  |         const thumbnail = new PDFThumbnailView({ | ||
|  |           container: this.container, | ||
|  |           eventBus: this.eventBus, | ||
|  |           id: pageNum, | ||
|  |           defaultViewport: viewport.clone(), | ||
|  |           optionalContentConfigPromise, | ||
|  |           linkService: this.linkService, | ||
|  |           renderingQueue: this.renderingQueue, | ||
|  |           pageColors: this.pageColors, | ||
|  |           enableHWA: this.enableHWA | ||
|  |         }); | ||
|  |         this._thumbnails.push(thumbnail); | ||
|  |       } | ||
|  |       this._thumbnails[0]?.setPdfPage(firstPdfPage); | ||
|  |       const thumbnailView = this._thumbnails[this._currentPageNumber - 1]; | ||
|  |       thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); | ||
|  |     }).catch(reason => { | ||
|  |       console.error("Unable to initialize thumbnail viewer", reason); | ||
|  |     }); | ||
|  |   } | ||
|  |   #cancelRendering() { | ||
|  |     for (const thumbnail of this._thumbnails) { | ||
|  |       thumbnail.cancelRendering(); | ||
|  |     } | ||
|  |   } | ||
|  |   setPageLabels(labels) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!labels) { | ||
|  |       this._pageLabels = null; | ||
|  |     } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { | ||
|  |       this._pageLabels = null; | ||
|  |       console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels."); | ||
|  |     } else { | ||
|  |       this._pageLabels = labels; | ||
|  |     } | ||
|  |     for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { | ||
|  |       this._thumbnails[i].setPageLabel(this._pageLabels?.[i] ?? null); | ||
|  |     } | ||
|  |   } | ||
|  |   async #ensurePdfPageLoaded(thumbView) { | ||
|  |     if (thumbView.pdfPage) { | ||
|  |       return thumbView.pdfPage; | ||
|  |     } | ||
|  |     try { | ||
|  |       const pdfPage = await this.pdfDocument.getPage(thumbView.id); | ||
|  |       if (!thumbView.pdfPage) { | ||
|  |         thumbView.setPdfPage(pdfPage); | ||
|  |       } | ||
|  |       return pdfPage; | ||
|  |     } catch (reason) { | ||
|  |       console.error("Unable to get page for thumb view", reason); | ||
|  |       return null; | ||
|  |     } | ||
|  |   } | ||
|  |   #getScrollAhead(visible) { | ||
|  |     if (visible.first?.id === 1) { | ||
|  |       return true; | ||
|  |     } else if (visible.last?.id === this._thumbnails.length) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     return this.scroll.down; | ||
|  |   } | ||
|  |   forceRendering() { | ||
|  |     const visibleThumbs = this.#getVisibleThumbs(); | ||
|  |     const scrollAhead = this.#getScrollAhead(visibleThumbs); | ||
|  |     const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead); | ||
|  |     if (thumbView) { | ||
|  |       this.#ensurePdfPageLoaded(thumbView).then(() => { | ||
|  |         this.renderingQueue.renderView(thumbView); | ||
|  |       }); | ||
|  |       return true; | ||
|  |     } | ||
|  |     return false; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/annotation_editor_layer_builder.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class AnnotationEditorLayerBuilder { | ||
|  |   #annotationLayer = null; | ||
|  |   #drawLayer = null; | ||
|  |   #onAppend = null; | ||
|  |   #textLayer = null; | ||
|  |   #uiManager; | ||
|  |   constructor(options) { | ||
|  |     this.pdfPage = options.pdfPage; | ||
|  |     this.accessibilityManager = options.accessibilityManager; | ||
|  |     this.l10n = options.l10n; | ||
|  |     this.l10n ||= new genericl10n_GenericL10n(); | ||
|  |     this.annotationEditorLayer = null; | ||
|  |     this.div = null; | ||
|  |     this._cancelled = false; | ||
|  |     this.#uiManager = options.uiManager; | ||
|  |     this.#annotationLayer = options.annotationLayer || null; | ||
|  |     this.#textLayer = options.textLayer || null; | ||
|  |     this.#drawLayer = options.drawLayer || null; | ||
|  |     this.#onAppend = options.onAppend || null; | ||
|  |   } | ||
|  |   async render(viewport, intent = "display") { | ||
|  |     if (intent !== "display") { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._cancelled) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const clonedViewport = viewport.clone({ | ||
|  |       dontFlip: true | ||
|  |     }); | ||
|  |     if (this.div) { | ||
|  |       this.annotationEditorLayer.update({ | ||
|  |         viewport: clonedViewport | ||
|  |       }); | ||
|  |       this.show(); | ||
|  |       return; | ||
|  |     } | ||
|  |     const div = this.div = document.createElement("div"); | ||
|  |     div.className = "annotationEditorLayer"; | ||
|  |     div.hidden = true; | ||
|  |     div.dir = this.#uiManager.direction; | ||
|  |     this.#onAppend?.(div); | ||
|  |     this.annotationEditorLayer = new AnnotationEditorLayer({ | ||
|  |       uiManager: this.#uiManager, | ||
|  |       div, | ||
|  |       accessibilityManager: this.accessibilityManager, | ||
|  |       pageIndex: this.pdfPage.pageNumber - 1, | ||
|  |       l10n: this.l10n, | ||
|  |       viewport: clonedViewport, | ||
|  |       annotationLayer: this.#annotationLayer, | ||
|  |       textLayer: this.#textLayer, | ||
|  |       drawLayer: this.#drawLayer | ||
|  |     }); | ||
|  |     const parameters = { | ||
|  |       viewport: clonedViewport, | ||
|  |       div, | ||
|  |       annotations: null, | ||
|  |       intent | ||
|  |     }; | ||
|  |     this.annotationEditorLayer.render(parameters); | ||
|  |     this.show(); | ||
|  |   } | ||
|  |   cancel() { | ||
|  |     this._cancelled = true; | ||
|  |     if (!this.div) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.annotationEditorLayer.destroy(); | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (!this.div) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.div.hidden = true; | ||
|  |   } | ||
|  |   show() { | ||
|  |     if (!this.div || this.annotationEditorLayer.isInvisible) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.div.hidden = false; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/annotation_layer_builder.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class AnnotationLayerBuilder { | ||
|  |   #onAppend = null; | ||
|  |   #eventAbortController = null; | ||
|  |   constructor({ | ||
|  |     pdfPage, | ||
|  |     linkService, | ||
|  |     downloadManager, | ||
|  |     annotationStorage = null, | ||
|  |     imageResourcesPath = "", | ||
|  |     renderForms = true, | ||
|  |     enableScripting = false, | ||
|  |     hasJSActionsPromise = null, | ||
|  |     fieldObjectsPromise = null, | ||
|  |     annotationCanvasMap = null, | ||
|  |     accessibilityManager = null, | ||
|  |     annotationEditorUIManager = null, | ||
|  |     onAppend = null | ||
|  |   }) { | ||
|  |     this.pdfPage = pdfPage; | ||
|  |     this.linkService = linkService; | ||
|  |     this.downloadManager = downloadManager; | ||
|  |     this.imageResourcesPath = imageResourcesPath; | ||
|  |     this.renderForms = renderForms; | ||
|  |     this.annotationStorage = annotationStorage; | ||
|  |     this.enableScripting = enableScripting; | ||
|  |     this._hasJSActionsPromise = hasJSActionsPromise || Promise.resolve(false); | ||
|  |     this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null); | ||
|  |     this._annotationCanvasMap = annotationCanvasMap; | ||
|  |     this._accessibilityManager = accessibilityManager; | ||
|  |     this._annotationEditorUIManager = annotationEditorUIManager; | ||
|  |     this.#onAppend = onAppend; | ||
|  |     this.annotationLayer = null; | ||
|  |     this.div = null; | ||
|  |     this._cancelled = false; | ||
|  |     this._eventBus = linkService.eventBus; | ||
|  |   } | ||
|  |   async render(viewport, intent = "display") { | ||
|  |     if (this.div) { | ||
|  |       if (this._cancelled || !this.annotationLayer) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.annotationLayer.update({ | ||
|  |         viewport: viewport.clone({ | ||
|  |           dontFlip: true | ||
|  |         }) | ||
|  |       }); | ||
|  |       return; | ||
|  |     } | ||
|  |     const [annotations, hasJSActions, fieldObjects] = await Promise.all([this.pdfPage.getAnnotations({ | ||
|  |       intent | ||
|  |     }), this._hasJSActionsPromise, this._fieldObjectsPromise]); | ||
|  |     if (this._cancelled) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const div = this.div = document.createElement("div"); | ||
|  |     div.className = "annotationLayer"; | ||
|  |     this.#onAppend?.(div); | ||
|  |     if (annotations.length === 0) { | ||
|  |       this.hide(); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.annotationLayer = new AnnotationLayer({ | ||
|  |       div, | ||
|  |       accessibilityManager: this._accessibilityManager, | ||
|  |       annotationCanvasMap: this._annotationCanvasMap, | ||
|  |       annotationEditorUIManager: this._annotationEditorUIManager, | ||
|  |       page: this.pdfPage, | ||
|  |       viewport: viewport.clone({ | ||
|  |         dontFlip: true | ||
|  |       }) | ||
|  |     }); | ||
|  |     await this.annotationLayer.render({ | ||
|  |       annotations, | ||
|  |       imageResourcesPath: this.imageResourcesPath, | ||
|  |       renderForms: this.renderForms, | ||
|  |       linkService: this.linkService, | ||
|  |       downloadManager: this.downloadManager, | ||
|  |       annotationStorage: this.annotationStorage, | ||
|  |       enableScripting: this.enableScripting, | ||
|  |       hasJSActions, | ||
|  |       fieldObjects | ||
|  |     }); | ||
|  |     if (this.linkService.isInPresentationMode) { | ||
|  |       this.#updatePresentationModeState(PresentationModeState.FULLSCREEN); | ||
|  |     } | ||
|  |     if (!this.#eventAbortController) { | ||
|  |       this.#eventAbortController = new AbortController(); | ||
|  |       this._eventBus?._on("presentationmodechanged", evt => { | ||
|  |         this.#updatePresentationModeState(evt.state); | ||
|  |       }, { | ||
|  |         signal: this.#eventAbortController.signal | ||
|  |       }); | ||
|  |     } | ||
|  |   } | ||
|  |   cancel() { | ||
|  |     this._cancelled = true; | ||
|  |     this.#eventAbortController?.abort(); | ||
|  |     this.#eventAbortController = null; | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (!this.div) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.div.hidden = true; | ||
|  |   } | ||
|  |   hasEditableAnnotations() { | ||
|  |     return !!this.annotationLayer?.hasEditableAnnotations(); | ||
|  |   } | ||
|  |   #updatePresentationModeState(state) { | ||
|  |     if (!this.div) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let disableFormElements = false; | ||
|  |     switch (state) { | ||
|  |       case PresentationModeState.FULLSCREEN: | ||
|  |         disableFormElements = true; | ||
|  |         break; | ||
|  |       case PresentationModeState.NORMAL: | ||
|  |         break; | ||
|  |       default: | ||
|  |         return; | ||
|  |     } | ||
|  |     for (const section of this.div.childNodes) { | ||
|  |       if (section.hasAttribute("data-internal-link")) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       section.inert = disableFormElements; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/draw_layer_builder.js
 | ||
|  | 
 | ||
|  | class DrawLayerBuilder { | ||
|  |   #drawLayer = null; | ||
|  |   constructor(options) { | ||
|  |     this.pageIndex = options.pageIndex; | ||
|  |   } | ||
|  |   async render(intent = "display") { | ||
|  |     if (intent !== "display" || this.#drawLayer || this._cancelled) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#drawLayer = new DrawLayer({ | ||
|  |       pageIndex: this.pageIndex | ||
|  |     }); | ||
|  |   } | ||
|  |   cancel() { | ||
|  |     this._cancelled = true; | ||
|  |     if (!this.#drawLayer) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#drawLayer.destroy(); | ||
|  |     this.#drawLayer = null; | ||
|  |   } | ||
|  |   setParent(parent) { | ||
|  |     this.#drawLayer?.setParent(parent); | ||
|  |   } | ||
|  |   getDrawLayer() { | ||
|  |     return this.#drawLayer; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/struct_tree_layer_builder.js
 | ||
|  | 
 | ||
|  | const PDF_ROLE_TO_HTML_ROLE = { | ||
|  |   Document: null, | ||
|  |   DocumentFragment: null, | ||
|  |   Part: "group", | ||
|  |   Sect: "group", | ||
|  |   Div: "group", | ||
|  |   Aside: "note", | ||
|  |   NonStruct: "none", | ||
|  |   P: null, | ||
|  |   H: "heading", | ||
|  |   Title: null, | ||
|  |   FENote: "note", | ||
|  |   Sub: "group", | ||
|  |   Lbl: null, | ||
|  |   Span: null, | ||
|  |   Em: null, | ||
|  |   Strong: null, | ||
|  |   Link: "link", | ||
|  |   Annot: "note", | ||
|  |   Form: "form", | ||
|  |   Ruby: null, | ||
|  |   RB: null, | ||
|  |   RT: null, | ||
|  |   RP: null, | ||
|  |   Warichu: null, | ||
|  |   WT: null, | ||
|  |   WP: null, | ||
|  |   L: "list", | ||
|  |   LI: "listitem", | ||
|  |   LBody: null, | ||
|  |   Table: "table", | ||
|  |   TR: "row", | ||
|  |   TH: "columnheader", | ||
|  |   TD: "cell", | ||
|  |   THead: "columnheader", | ||
|  |   TBody: null, | ||
|  |   TFoot: null, | ||
|  |   Caption: null, | ||
|  |   Figure: "figure", | ||
|  |   Formula: null, | ||
|  |   Artifact: null | ||
|  | }; | ||
|  | const HEADING_PATTERN = /^H(\d+)$/; | ||
|  | class StructTreeLayerBuilder { | ||
|  |   #treeDom = undefined; | ||
|  |   get renderingDone() { | ||
|  |     return this.#treeDom !== undefined; | ||
|  |   } | ||
|  |   render(structTree) { | ||
|  |     if (this.#treeDom !== undefined) { | ||
|  |       return this.#treeDom; | ||
|  |     } | ||
|  |     const treeDom = this.#walk(structTree); | ||
|  |     treeDom?.classList.add("structTree"); | ||
|  |     return this.#treeDom = treeDom; | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (this.#treeDom && !this.#treeDom.hidden) { | ||
|  |       this.#treeDom.hidden = true; | ||
|  |     } | ||
|  |   } | ||
|  |   show() { | ||
|  |     if (this.#treeDom?.hidden) { | ||
|  |       this.#treeDom.hidden = false; | ||
|  |     } | ||
|  |   } | ||
|  |   #setAttributes(structElement, htmlElement) { | ||
|  |     const { | ||
|  |       alt, | ||
|  |       id, | ||
|  |       lang | ||
|  |     } = structElement; | ||
|  |     if (alt !== undefined) { | ||
|  |       htmlElement.setAttribute("aria-label", removeNullCharacters(alt)); | ||
|  |     } | ||
|  |     if (id !== undefined) { | ||
|  |       htmlElement.setAttribute("aria-owns", id); | ||
|  |     } | ||
|  |     if (lang !== undefined) { | ||
|  |       htmlElement.setAttribute("lang", removeNullCharacters(lang, true)); | ||
|  |     } | ||
|  |   } | ||
|  |   #walk(node) { | ||
|  |     if (!node) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     const element = document.createElement("span"); | ||
|  |     if ("role" in node) { | ||
|  |       const { | ||
|  |         role | ||
|  |       } = node; | ||
|  |       const match = role.match(HEADING_PATTERN); | ||
|  |       if (match) { | ||
|  |         element.setAttribute("role", "heading"); | ||
|  |         element.setAttribute("aria-level", match[1]); | ||
|  |       } else if (PDF_ROLE_TO_HTML_ROLE[role]) { | ||
|  |         element.setAttribute("role", PDF_ROLE_TO_HTML_ROLE[role]); | ||
|  |       } | ||
|  |     } | ||
|  |     this.#setAttributes(node, element); | ||
|  |     if (node.children) { | ||
|  |       if (node.children.length === 1 && "id" in node.children[0]) { | ||
|  |         this.#setAttributes(node.children[0], element); | ||
|  |       } else { | ||
|  |         for (const kid of node.children) { | ||
|  |           element.append(this.#walk(kid)); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     return element; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/text_accessibility.js
 | ||
|  | 
 | ||
|  | class TextAccessibilityManager { | ||
|  |   #enabled = false; | ||
|  |   #textChildren = null; | ||
|  |   #textNodes = new Map(); | ||
|  |   #waitingElements = new Map(); | ||
|  |   setTextMapping(textDivs) { | ||
|  |     this.#textChildren = textDivs; | ||
|  |   } | ||
|  |   static #compareElementPositions(e1, e2) { | ||
|  |     const rect1 = e1.getBoundingClientRect(); | ||
|  |     const rect2 = e2.getBoundingClientRect(); | ||
|  |     if (rect1.width === 0 && rect1.height === 0) { | ||
|  |       return +1; | ||
|  |     } | ||
|  |     if (rect2.width === 0 && rect2.height === 0) { | ||
|  |       return -1; | ||
|  |     } | ||
|  |     const top1 = rect1.y; | ||
|  |     const bot1 = rect1.y + rect1.height; | ||
|  |     const mid1 = rect1.y + rect1.height / 2; | ||
|  |     const top2 = rect2.y; | ||
|  |     const bot2 = rect2.y + rect2.height; | ||
|  |     const mid2 = rect2.y + rect2.height / 2; | ||
|  |     if (mid1 <= top2 && mid2 >= bot1) { | ||
|  |       return -1; | ||
|  |     } | ||
|  |     if (mid2 <= top1 && mid1 >= bot2) { | ||
|  |       return +1; | ||
|  |     } | ||
|  |     const centerX1 = rect1.x + rect1.width / 2; | ||
|  |     const centerX2 = rect2.x + rect2.width / 2; | ||
|  |     return centerX1 - centerX2; | ||
|  |   } | ||
|  |   enable() { | ||
|  |     if (this.#enabled) { | ||
|  |       throw new Error("TextAccessibilityManager is already enabled."); | ||
|  |     } | ||
|  |     if (!this.#textChildren) { | ||
|  |       throw new Error("Text divs and strings have not been set."); | ||
|  |     } | ||
|  |     this.#enabled = true; | ||
|  |     this.#textChildren = this.#textChildren.slice(); | ||
|  |     this.#textChildren.sort(TextAccessibilityManager.#compareElementPositions); | ||
|  |     if (this.#textNodes.size > 0) { | ||
|  |       const textChildren = this.#textChildren; | ||
|  |       for (const [id, nodeIndex] of this.#textNodes) { | ||
|  |         const element = document.getElementById(id); | ||
|  |         if (!element) { | ||
|  |           this.#textNodes.delete(id); | ||
|  |           continue; | ||
|  |         } | ||
|  |         this.#addIdToAriaOwns(id, textChildren[nodeIndex]); | ||
|  |       } | ||
|  |     } | ||
|  |     for (const [element, isRemovable] of this.#waitingElements) { | ||
|  |       this.addPointerInTextLayer(element, isRemovable); | ||
|  |     } | ||
|  |     this.#waitingElements.clear(); | ||
|  |   } | ||
|  |   disable() { | ||
|  |     if (!this.#enabled) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#waitingElements.clear(); | ||
|  |     this.#textChildren = null; | ||
|  |     this.#enabled = false; | ||
|  |   } | ||
|  |   removePointerInTextLayer(element) { | ||
|  |     if (!this.#enabled) { | ||
|  |       this.#waitingElements.delete(element); | ||
|  |       return; | ||
|  |     } | ||
|  |     const children = this.#textChildren; | ||
|  |     if (!children || children.length === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       id | ||
|  |     } = element; | ||
|  |     const nodeIndex = this.#textNodes.get(id); | ||
|  |     if (nodeIndex === undefined) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const node = children[nodeIndex]; | ||
|  |     this.#textNodes.delete(id); | ||
|  |     let owns = node.getAttribute("aria-owns"); | ||
|  |     if (owns?.includes(id)) { | ||
|  |       owns = owns.split(" ").filter(x => x !== id).join(" "); | ||
|  |       if (owns) { | ||
|  |         node.setAttribute("aria-owns", owns); | ||
|  |       } else { | ||
|  |         node.removeAttribute("aria-owns"); | ||
|  |         node.setAttribute("role", "presentation"); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   #addIdToAriaOwns(id, node) { | ||
|  |     const owns = node.getAttribute("aria-owns"); | ||
|  |     if (!owns?.includes(id)) { | ||
|  |       node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id); | ||
|  |     } | ||
|  |     node.removeAttribute("role"); | ||
|  |   } | ||
|  |   addPointerInTextLayer(element, isRemovable) { | ||
|  |     const { | ||
|  |       id | ||
|  |     } = element; | ||
|  |     if (!id) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     if (!this.#enabled) { | ||
|  |       this.#waitingElements.set(element, isRemovable); | ||
|  |       return null; | ||
|  |     } | ||
|  |     if (isRemovable) { | ||
|  |       this.removePointerInTextLayer(element); | ||
|  |     } | ||
|  |     const children = this.#textChildren; | ||
|  |     if (!children || children.length === 0) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0); | ||
|  |     const nodeIndex = Math.max(0, index - 1); | ||
|  |     const child = children[nodeIndex]; | ||
|  |     this.#addIdToAriaOwns(id, child); | ||
|  |     this.#textNodes.set(id, nodeIndex); | ||
|  |     const parent = child.parentNode; | ||
|  |     return parent?.classList.contains("markedContent") ? parent.id : null; | ||
|  |   } | ||
|  |   moveElementInDOM(container, element, contentElement, isRemovable) { | ||
|  |     const id = this.addPointerInTextLayer(contentElement, isRemovable); | ||
|  |     if (!container.hasChildNodes()) { | ||
|  |       container.append(element); | ||
|  |       return id; | ||
|  |     } | ||
|  |     const children = Array.from(container.childNodes).filter(node => node !== element); | ||
|  |     if (children.length === 0) { | ||
|  |       return id; | ||
|  |     } | ||
|  |     const elementToCompare = contentElement || element; | ||
|  |     const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(elementToCompare, node) < 0); | ||
|  |     if (index === 0) { | ||
|  |       children[0].before(element); | ||
|  |     } else { | ||
|  |       children[index - 1].after(element); | ||
|  |     } | ||
|  |     return id; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/text_highlighter.js
 | ||
|  | class TextHighlighter { | ||
|  |   #eventAbortController = null; | ||
|  |   constructor({ | ||
|  |     findController, | ||
|  |     eventBus, | ||
|  |     pageIndex | ||
|  |   }) { | ||
|  |     this.findController = findController; | ||
|  |     this.matches = []; | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.pageIdx = pageIndex; | ||
|  |     this.textDivs = null; | ||
|  |     this.textContentItemsStr = null; | ||
|  |     this.enabled = false; | ||
|  |   } | ||
|  |   setTextMapping(divs, texts) { | ||
|  |     this.textDivs = divs; | ||
|  |     this.textContentItemsStr = texts; | ||
|  |   } | ||
|  |   enable() { | ||
|  |     if (!this.textDivs || !this.textContentItemsStr) { | ||
|  |       throw new Error("Text divs and strings have not been set."); | ||
|  |     } | ||
|  |     if (this.enabled) { | ||
|  |       throw new Error("TextHighlighter is already enabled."); | ||
|  |     } | ||
|  |     this.enabled = true; | ||
|  |     if (!this.#eventAbortController) { | ||
|  |       this.#eventAbortController = new AbortController(); | ||
|  |       this.eventBus._on("updatetextlayermatches", evt => { | ||
|  |         if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) { | ||
|  |           this._updateMatches(); | ||
|  |         } | ||
|  |       }, { | ||
|  |         signal: this.#eventAbortController.signal | ||
|  |       }); | ||
|  |     } | ||
|  |     this._updateMatches(); | ||
|  |   } | ||
|  |   disable() { | ||
|  |     if (!this.enabled) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.enabled = false; | ||
|  |     this.#eventAbortController?.abort(); | ||
|  |     this.#eventAbortController = null; | ||
|  |     this._updateMatches(true); | ||
|  |   } | ||
|  |   _convertMatches(matches, matchesLength) { | ||
|  |     if (!matches) { | ||
|  |       return []; | ||
|  |     } | ||
|  |     const { | ||
|  |       textContentItemsStr | ||
|  |     } = this; | ||
|  |     let i = 0, | ||
|  |       iIndex = 0; | ||
|  |     const end = textContentItemsStr.length - 1; | ||
|  |     const result = []; | ||
|  |     for (let m = 0, mm = matches.length; m < mm; m++) { | ||
|  |       let matchIdx = matches[m]; | ||
|  |       while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) { | ||
|  |         iIndex += textContentItemsStr[i].length; | ||
|  |         i++; | ||
|  |       } | ||
|  |       if (i === textContentItemsStr.length) { | ||
|  |         console.error("Could not find a matching mapping"); | ||
|  |       } | ||
|  |       const match = { | ||
|  |         begin: { | ||
|  |           divIdx: i, | ||
|  |           offset: matchIdx - iIndex | ||
|  |         } | ||
|  |       }; | ||
|  |       matchIdx += matchesLength[m]; | ||
|  |       while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) { | ||
|  |         iIndex += textContentItemsStr[i].length; | ||
|  |         i++; | ||
|  |       } | ||
|  |       match.end = { | ||
|  |         divIdx: i, | ||
|  |         offset: matchIdx - iIndex | ||
|  |       }; | ||
|  |       result.push(match); | ||
|  |     } | ||
|  |     return result; | ||
|  |   } | ||
|  |   _renderMatches(matches) { | ||
|  |     if (matches.length === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       findController, | ||
|  |       pageIdx | ||
|  |     } = this; | ||
|  |     const { | ||
|  |       textContentItemsStr, | ||
|  |       textDivs | ||
|  |     } = this; | ||
|  |     const isSelectedPage = pageIdx === findController.selected.pageIdx; | ||
|  |     const selectedMatchIdx = findController.selected.matchIdx; | ||
|  |     const highlightAll = findController.state.highlightAll; | ||
|  |     let prevEnd = null; | ||
|  |     const infinity = { | ||
|  |       divIdx: -1, | ||
|  |       offset: undefined | ||
|  |     }; | ||
|  |     function beginText(begin, className) { | ||
|  |       const divIdx = begin.divIdx; | ||
|  |       textDivs[divIdx].textContent = ""; | ||
|  |       return appendTextToDiv(divIdx, 0, begin.offset, className); | ||
|  |     } | ||
|  |     function appendTextToDiv(divIdx, fromOffset, toOffset, className) { | ||
|  |       let div = textDivs[divIdx]; | ||
|  |       if (div.nodeType === Node.TEXT_NODE) { | ||
|  |         const span = document.createElement("span"); | ||
|  |         div.before(span); | ||
|  |         span.append(div); | ||
|  |         textDivs[divIdx] = span; | ||
|  |         div = span; | ||
|  |       } | ||
|  |       const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset); | ||
|  |       const node = document.createTextNode(content); | ||
|  |       if (className) { | ||
|  |         const span = document.createElement("span"); | ||
|  |         span.className = `${className} appended`; | ||
|  |         span.append(node); | ||
|  |         div.append(span); | ||
|  |         return className.includes("selected") ? span.offsetLeft : 0; | ||
|  |       } | ||
|  |       div.append(node); | ||
|  |       return 0; | ||
|  |     } | ||
|  |     let i0 = selectedMatchIdx, | ||
|  |       i1 = i0 + 1; | ||
|  |     if (highlightAll) { | ||
|  |       i0 = 0; | ||
|  |       i1 = matches.length; | ||
|  |     } else if (!isSelectedPage) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let lastDivIdx = -1; | ||
|  |     let lastOffset = -1; | ||
|  |     for (let i = i0; i < i1; i++) { | ||
|  |       const match = matches[i]; | ||
|  |       const begin = match.begin; | ||
|  |       if (begin.divIdx === lastDivIdx && begin.offset === lastOffset) { | ||
|  |         continue; | ||
|  |       } | ||
|  |       lastDivIdx = begin.divIdx; | ||
|  |       lastOffset = begin.offset; | ||
|  |       const end = match.end; | ||
|  |       const isSelected = isSelectedPage && i === selectedMatchIdx; | ||
|  |       const highlightSuffix = isSelected ? " selected" : ""; | ||
|  |       let selectedLeft = 0; | ||
|  |       if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { | ||
|  |         if (prevEnd !== null) { | ||
|  |           appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); | ||
|  |         } | ||
|  |         beginText(begin); | ||
|  |       } else { | ||
|  |         appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset); | ||
|  |       } | ||
|  |       if (begin.divIdx === end.divIdx) { | ||
|  |         selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix); | ||
|  |       } else { | ||
|  |         selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix); | ||
|  |         for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) { | ||
|  |           textDivs[n0].className = "highlight middle" + highlightSuffix; | ||
|  |         } | ||
|  |         beginText(end, "highlight end" + highlightSuffix); | ||
|  |       } | ||
|  |       prevEnd = end; | ||
|  |       if (isSelected) { | ||
|  |         findController.scrollMatchIntoView({ | ||
|  |           element: textDivs[begin.divIdx], | ||
|  |           selectedLeft, | ||
|  |           pageIndex: pageIdx, | ||
|  |           matchIndex: selectedMatchIdx | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |     if (prevEnd) { | ||
|  |       appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); | ||
|  |     } | ||
|  |   } | ||
|  |   _updateMatches(reset = false) { | ||
|  |     if (!this.enabled && !reset) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       findController, | ||
|  |       matches, | ||
|  |       pageIdx | ||
|  |     } = this; | ||
|  |     const { | ||
|  |       textContentItemsStr, | ||
|  |       textDivs | ||
|  |     } = this; | ||
|  |     let clearedUntilDivIdx = -1; | ||
|  |     for (const match of matches) { | ||
|  |       const begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); | ||
|  |       for (let n = begin, end = match.end.divIdx; n <= end; n++) { | ||
|  |         const div = textDivs[n]; | ||
|  |         div.textContent = textContentItemsStr[n]; | ||
|  |         div.className = ""; | ||
|  |       } | ||
|  |       clearedUntilDivIdx = match.end.divIdx + 1; | ||
|  |     } | ||
|  |     if (!findController?.highlightMatches || reset) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pageMatches = findController.pageMatches[pageIdx] || null; | ||
|  |     const pageMatchesLength = findController.pageMatchesLength[pageIdx] || null; | ||
|  |     this.matches = this._convertMatches(pageMatches, pageMatchesLength); | ||
|  |     this._renderMatches(this.matches); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/text_layer_builder.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class TextLayerBuilder { | ||
|  |   #enablePermissions = false; | ||
|  |   #onAppend = null; | ||
|  |   #renderingDone = false; | ||
|  |   #textLayer = null; | ||
|  |   static #textLayers = new Map(); | ||
|  |   static #selectionChangeAbortController = null; | ||
|  |   constructor({ | ||
|  |     pdfPage, | ||
|  |     highlighter = null, | ||
|  |     accessibilityManager = null, | ||
|  |     enablePermissions = false, | ||
|  |     onAppend = null | ||
|  |   }) { | ||
|  |     this.pdfPage = pdfPage; | ||
|  |     this.highlighter = highlighter; | ||
|  |     this.accessibilityManager = accessibilityManager; | ||
|  |     this.#enablePermissions = enablePermissions === true; | ||
|  |     this.#onAppend = onAppend; | ||
|  |     this.div = document.createElement("div"); | ||
|  |     this.div.tabIndex = 0; | ||
|  |     this.div.className = "textLayer"; | ||
|  |   } | ||
|  |   async render(viewport, textContentParams = null) { | ||
|  |     if (this.#renderingDone && this.#textLayer) { | ||
|  |       this.#textLayer.update({ | ||
|  |         viewport, | ||
|  |         onBefore: this.hide.bind(this) | ||
|  |       }); | ||
|  |       this.show(); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.cancel(); | ||
|  |     this.#textLayer = new TextLayer({ | ||
|  |       textContentSource: this.pdfPage.streamTextContent(textContentParams || { | ||
|  |         includeMarkedContent: true, | ||
|  |         disableNormalization: true | ||
|  |       }), | ||
|  |       container: this.div, | ||
|  |       viewport | ||
|  |     }); | ||
|  |     const { | ||
|  |       textDivs, | ||
|  |       textContentItemsStr | ||
|  |     } = this.#textLayer; | ||
|  |     this.highlighter?.setTextMapping(textDivs, textContentItemsStr); | ||
|  |     this.accessibilityManager?.setTextMapping(textDivs); | ||
|  |     await this.#textLayer.render(); | ||
|  |     this.#renderingDone = true; | ||
|  |     const endOfContent = document.createElement("div"); | ||
|  |     endOfContent.className = "endOfContent"; | ||
|  |     this.div.append(endOfContent); | ||
|  |     this.#bindMouse(endOfContent); | ||
|  |     this.#onAppend?.(this.div); | ||
|  |     this.highlighter?.enable(); | ||
|  |     this.accessibilityManager?.enable(); | ||
|  |   } | ||
|  |   hide() { | ||
|  |     if (!this.div.hidden && this.#renderingDone) { | ||
|  |       this.highlighter?.disable(); | ||
|  |       this.div.hidden = true; | ||
|  |     } | ||
|  |   } | ||
|  |   show() { | ||
|  |     if (this.div.hidden && this.#renderingDone) { | ||
|  |       this.div.hidden = false; | ||
|  |       this.highlighter?.enable(); | ||
|  |     } | ||
|  |   } | ||
|  |   cancel() { | ||
|  |     this.#textLayer?.cancel(); | ||
|  |     this.#textLayer = null; | ||
|  |     this.highlighter?.disable(); | ||
|  |     this.accessibilityManager?.disable(); | ||
|  |     TextLayerBuilder.#removeGlobalSelectionListener(this.div); | ||
|  |   } | ||
|  |   #bindMouse(end) { | ||
|  |     const { | ||
|  |       div | ||
|  |     } = this; | ||
|  |     div.addEventListener("mousedown", () => { | ||
|  |       div.classList.add("selecting"); | ||
|  |     }); | ||
|  |     div.addEventListener("copy", event => { | ||
|  |       if (!this.#enablePermissions) { | ||
|  |         const selection = document.getSelection(); | ||
|  |         event.clipboardData.setData("text/plain", removeNullCharacters(normalizeUnicode(selection.toString()))); | ||
|  |       } | ||
|  |       event.preventDefault(); | ||
|  |       event.stopPropagation(); | ||
|  |     }); | ||
|  |     TextLayerBuilder.#textLayers.set(div, end); | ||
|  |     TextLayerBuilder.#enableGlobalSelectionListener(); | ||
|  |   } | ||
|  |   static #removeGlobalSelectionListener(textLayerDiv) { | ||
|  |     this.#textLayers.delete(textLayerDiv); | ||
|  |     if (this.#textLayers.size === 0) { | ||
|  |       this.#selectionChangeAbortController?.abort(); | ||
|  |       this.#selectionChangeAbortController = null; | ||
|  |     } | ||
|  |   } | ||
|  |   static #enableGlobalSelectionListener() { | ||
|  |     if (this.#selectionChangeAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#selectionChangeAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       signal | ||
|  |     } = this.#selectionChangeAbortController; | ||
|  |     const reset = (end, textLayer) => { | ||
|  |       textLayer.append(end); | ||
|  |       end.style.width = ""; | ||
|  |       end.style.height = ""; | ||
|  |       textLayer.classList.remove("selecting"); | ||
|  |     }; | ||
|  |     let isPointerDown = false; | ||
|  |     document.addEventListener("pointerdown", () => { | ||
|  |       isPointerDown = true; | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     document.addEventListener("pointerup", () => { | ||
|  |       isPointerDown = false; | ||
|  |       this.#textLayers.forEach(reset); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("blur", () => { | ||
|  |       isPointerDown = false; | ||
|  |       this.#textLayers.forEach(reset); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     document.addEventListener("keyup", () => { | ||
|  |       if (!isPointerDown) { | ||
|  |         this.#textLayers.forEach(reset); | ||
|  |       } | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     var isFirefox, prevRange; | ||
|  |     document.addEventListener("selectionchange", () => { | ||
|  |       const selection = document.getSelection(); | ||
|  |       if (selection.rangeCount === 0) { | ||
|  |         this.#textLayers.forEach(reset); | ||
|  |         return; | ||
|  |       } | ||
|  |       const activeTextLayers = new Set(); | ||
|  |       for (let i = 0; i < selection.rangeCount; i++) { | ||
|  |         const range = selection.getRangeAt(i); | ||
|  |         for (const textLayerDiv of this.#textLayers.keys()) { | ||
|  |           if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) { | ||
|  |             activeTextLayers.add(textLayerDiv); | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |       for (const [textLayerDiv, endDiv] of this.#textLayers) { | ||
|  |         if (activeTextLayers.has(textLayerDiv)) { | ||
|  |           textLayerDiv.classList.add("selecting"); | ||
|  |         } else { | ||
|  |           reset(endDiv, textLayerDiv); | ||
|  |         } | ||
|  |       } | ||
|  |       isFirefox ??= getComputedStyle(this.#textLayers.values().next().value).getPropertyValue("-moz-user-select") === "none"; | ||
|  |       if (isFirefox) { | ||
|  |         return; | ||
|  |       } | ||
|  |       const range = selection.getRangeAt(0); | ||
|  |       const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0); | ||
|  |       let anchor = modifyStart ? range.startContainer : range.endContainer; | ||
|  |       if (anchor.nodeType === Node.TEXT_NODE) { | ||
|  |         anchor = anchor.parentNode; | ||
|  |       } | ||
|  |       const parentTextLayer = anchor.parentElement.closest(".textLayer"); | ||
|  |       const endDiv = this.#textLayers.get(parentTextLayer); | ||
|  |       if (endDiv) { | ||
|  |         endDiv.style.width = parentTextLayer.style.width; | ||
|  |         endDiv.style.height = parentTextLayer.style.height; | ||
|  |         anchor.parentElement.insertBefore(endDiv, modifyStart ? anchor : anchor.nextSibling); | ||
|  |       } | ||
|  |       prevRange = range.cloneRange(); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_page_view.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const DEFAULT_LAYER_PROPERTIES = null; | ||
|  | const LAYERS_ORDER = new Map([["canvasWrapper", 0], ["textLayer", 1], ["annotationLayer", 2], ["annotationEditorLayer", 3], ["xfaLayer", 3]]); | ||
|  | class PDFPageView { | ||
|  |   #annotationMode = AnnotationMode.ENABLE_FORMS; | ||
|  |   #enableHWA = false; | ||
|  |   #hasRestrictedScaling = false; | ||
|  |   #isEditing = false; | ||
|  |   #layerProperties = null; | ||
|  |   #loadingId = null; | ||
|  |   #previousRotation = null; | ||
|  |   #renderError = null; | ||
|  |   #renderingState = RenderingStates.INITIAL; | ||
|  |   #textLayerMode = TextLayerMode.ENABLE; | ||
|  |   #useThumbnailCanvas = { | ||
|  |     directDrawing: true, | ||
|  |     initialOptionalContent: true, | ||
|  |     regularAnnotations: true | ||
|  |   }; | ||
|  |   #viewportMap = new WeakMap(); | ||
|  |   #layers = [null, null, null, null]; | ||
|  |   constructor(options) { | ||
|  |     const container = options.container; | ||
|  |     const defaultViewport = options.defaultViewport; | ||
|  |     this.id = options.id; | ||
|  |     this.renderingId = "page" + this.id; | ||
|  |     this.#layerProperties = options.layerProperties || DEFAULT_LAYER_PROPERTIES; | ||
|  |     this.pdfPage = null; | ||
|  |     this.pageLabel = null; | ||
|  |     this.rotation = 0; | ||
|  |     this.scale = options.scale || DEFAULT_SCALE; | ||
|  |     this.viewport = defaultViewport; | ||
|  |     this.pdfPageRotate = defaultViewport.rotation; | ||
|  |     this._optionalContentConfigPromise = options.optionalContentConfigPromise || null; | ||
|  |     this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE; | ||
|  |     this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; | ||
|  |     this.imageResourcesPath = options.imageResourcesPath || ""; | ||
|  |     this.maxCanvasPixels = options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels"); | ||
|  |     this.pageColors = options.pageColors || null; | ||
|  |     this.#enableHWA = options.enableHWA || false; | ||
|  |     this.eventBus = options.eventBus; | ||
|  |     this.renderingQueue = options.renderingQueue; | ||
|  |     this.l10n = options.l10n; | ||
|  |     this.l10n ||= new genericl10n_GenericL10n(); | ||
|  |     this.renderTask = null; | ||
|  |     this.resume = null; | ||
|  |     this._isStandalone = !this.renderingQueue?.hasViewer(); | ||
|  |     this._container = container; | ||
|  |     this._annotationCanvasMap = null; | ||
|  |     this.annotationLayer = null; | ||
|  |     this.annotationEditorLayer = null; | ||
|  |     this.textLayer = null; | ||
|  |     this.zoomLayer = null; | ||
|  |     this.xfaLayer = null; | ||
|  |     this.structTreeLayer = null; | ||
|  |     this.drawLayer = null; | ||
|  |     const div = document.createElement("div"); | ||
|  |     div.className = "page"; | ||
|  |     div.setAttribute("data-page-number", this.id); | ||
|  |     div.setAttribute("role", "region"); | ||
|  |     div.setAttribute("data-l10n-id", "pdfjs-page-landmark"); | ||
|  |     div.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |       page: this.id | ||
|  |     })); | ||
|  |     this.div = div; | ||
|  |     this.#setDimensions(); | ||
|  |     container?.append(div); | ||
|  |     if (this._isStandalone) { | ||
|  |       container?.style.setProperty("--scale-factor", this.scale * PixelsPerInch.PDF_TO_CSS_UNITS); | ||
|  |       const { | ||
|  |         optionalContentConfigPromise | ||
|  |       } = options; | ||
|  |       if (optionalContentConfigPromise) { | ||
|  |         optionalContentConfigPromise.then(optionalContentConfig => { | ||
|  |           if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { | ||
|  |             return; | ||
|  |           } | ||
|  |           this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility; | ||
|  |         }); | ||
|  |       } | ||
|  |       if (!options.l10n) { | ||
|  |         this.l10n.translate(this.div); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   #addLayer(div, name) { | ||
|  |     const pos = LAYERS_ORDER.get(name); | ||
|  |     const oldDiv = this.#layers[pos]; | ||
|  |     this.#layers[pos] = div; | ||
|  |     if (oldDiv) { | ||
|  |       oldDiv.replaceWith(div); | ||
|  |       return; | ||
|  |     } | ||
|  |     for (let i = pos - 1; i >= 0; i--) { | ||
|  |       const layer = this.#layers[i]; | ||
|  |       if (layer) { | ||
|  |         layer.after(div); | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     this.div.prepend(div); | ||
|  |   } | ||
|  |   get renderingState() { | ||
|  |     return this.#renderingState; | ||
|  |   } | ||
|  |   set renderingState(state) { | ||
|  |     if (state === this.#renderingState) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#renderingState = state; | ||
|  |     if (this.#loadingId) { | ||
|  |       clearTimeout(this.#loadingId); | ||
|  |       this.#loadingId = null; | ||
|  |     } | ||
|  |     switch (state) { | ||
|  |       case RenderingStates.PAUSED: | ||
|  |         this.div.classList.remove("loading"); | ||
|  |         break; | ||
|  |       case RenderingStates.RUNNING: | ||
|  |         this.div.classList.add("loadingIcon"); | ||
|  |         this.#loadingId = setTimeout(() => { | ||
|  |           this.div.classList.add("loading"); | ||
|  |           this.#loadingId = null; | ||
|  |         }, 0); | ||
|  |         break; | ||
|  |       case RenderingStates.INITIAL: | ||
|  |       case RenderingStates.FINISHED: | ||
|  |         this.div.classList.remove("loadingIcon", "loading"); | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   #setDimensions() { | ||
|  |     const { | ||
|  |       viewport | ||
|  |     } = this; | ||
|  |     if (this.pdfPage) { | ||
|  |       if (this.#previousRotation === viewport.rotation) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#previousRotation = viewport.rotation; | ||
|  |     } | ||
|  |     setLayerDimensions(this.div, viewport, true, false); | ||
|  |   } | ||
|  |   setPdfPage(pdfPage) { | ||
|  |     if (this._isStandalone && (this.pageColors?.foreground === "CanvasText" || this.pageColors?.background === "Canvas")) { | ||
|  |       this._container?.style.setProperty("--hcm-highlight-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight")); | ||
|  |       this._container?.style.setProperty("--hcm-highlight-selected-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "Highlight")); | ||
|  |     } | ||
|  |     this.pdfPage = pdfPage; | ||
|  |     this.pdfPageRotate = pdfPage.rotate; | ||
|  |     const totalRotation = (this.rotation + this.pdfPageRotate) % 360; | ||
|  |     this.viewport = pdfPage.getViewport({ | ||
|  |       scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS, | ||
|  |       rotation: totalRotation | ||
|  |     }); | ||
|  |     this.#setDimensions(); | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   destroy() { | ||
|  |     this.reset(); | ||
|  |     this.pdfPage?.cleanup(); | ||
|  |   } | ||
|  |   hasEditableAnnotations() { | ||
|  |     return !!this.annotationLayer?.hasEditableAnnotations(); | ||
|  |   } | ||
|  |   get _textHighlighter() { | ||
|  |     return shadow(this, "_textHighlighter", new TextHighlighter({ | ||
|  |       pageIndex: this.id - 1, | ||
|  |       eventBus: this.eventBus, | ||
|  |       findController: this.#layerProperties.findController | ||
|  |     })); | ||
|  |   } | ||
|  |   #dispatchLayerRendered(name, error) { | ||
|  |     this.eventBus.dispatch(name, { | ||
|  |       source: this, | ||
|  |       pageNumber: this.id, | ||
|  |       error | ||
|  |     }); | ||
|  |   } | ||
|  |   async #renderAnnotationLayer() { | ||
|  |     let error = null; | ||
|  |     try { | ||
|  |       await this.annotationLayer.render(this.viewport, "display"); | ||
|  |     } catch (ex) { | ||
|  |       console.error(`#renderAnnotationLayer: "${ex}".`); | ||
|  |       error = ex; | ||
|  |     } finally { | ||
|  |       this.#dispatchLayerRendered("annotationlayerrendered", error); | ||
|  |     } | ||
|  |   } | ||
|  |   async #renderAnnotationEditorLayer() { | ||
|  |     let error = null; | ||
|  |     try { | ||
|  |       await this.annotationEditorLayer.render(this.viewport, "display"); | ||
|  |     } catch (ex) { | ||
|  |       console.error(`#renderAnnotationEditorLayer: "${ex}".`); | ||
|  |       error = ex; | ||
|  |     } finally { | ||
|  |       this.#dispatchLayerRendered("annotationeditorlayerrendered", error); | ||
|  |     } | ||
|  |   } | ||
|  |   async #renderDrawLayer() { | ||
|  |     try { | ||
|  |       await this.drawLayer.render("display"); | ||
|  |     } catch (ex) { | ||
|  |       console.error(`#renderDrawLayer: "${ex}".`); | ||
|  |     } | ||
|  |   } | ||
|  |   async #renderXfaLayer() { | ||
|  |     let error = null; | ||
|  |     try { | ||
|  |       const result = await this.xfaLayer.render(this.viewport, "display"); | ||
|  |       if (result?.textDivs && this._textHighlighter) { | ||
|  |         this.#buildXfaTextContentItems(result.textDivs); | ||
|  |       } | ||
|  |     } catch (ex) { | ||
|  |       console.error(`#renderXfaLayer: "${ex}".`); | ||
|  |       error = ex; | ||
|  |     } finally { | ||
|  |       if (this.xfaLayer?.div) { | ||
|  |         this.l10n.pause(); | ||
|  |         this.#addLayer(this.xfaLayer.div, "xfaLayer"); | ||
|  |         this.l10n.resume(); | ||
|  |       } | ||
|  |       this.#dispatchLayerRendered("xfalayerrendered", error); | ||
|  |     } | ||
|  |   } | ||
|  |   async #renderTextLayer() { | ||
|  |     if (!this.textLayer) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let error = null; | ||
|  |     try { | ||
|  |       await this.textLayer.render(this.viewport); | ||
|  |     } catch (ex) { | ||
|  |       if (ex instanceof AbortException) { | ||
|  |         return; | ||
|  |       } | ||
|  |       console.error(`#renderTextLayer: "${ex}".`); | ||
|  |       error = ex; | ||
|  |     } | ||
|  |     this.#dispatchLayerRendered("textlayerrendered", error); | ||
|  |     this.#renderStructTreeLayer(); | ||
|  |   } | ||
|  |   async #renderStructTreeLayer() { | ||
|  |     if (!this.textLayer) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.structTreeLayer ||= new StructTreeLayerBuilder(); | ||
|  |     const tree = await (!this.structTreeLayer.renderingDone ? this.pdfPage.getStructTree() : null); | ||
|  |     const treeDom = this.structTreeLayer?.render(tree); | ||
|  |     if (treeDom) { | ||
|  |       this.l10n.pause(); | ||
|  |       this.canvas?.append(treeDom); | ||
|  |       this.l10n.resume(); | ||
|  |     } | ||
|  |     this.structTreeLayer?.show(); | ||
|  |   } | ||
|  |   async #buildXfaTextContentItems(textDivs) { | ||
|  |     const text = await this.pdfPage.getTextContent(); | ||
|  |     const items = []; | ||
|  |     for (const item of text.items) { | ||
|  |       items.push(item.str); | ||
|  |     } | ||
|  |     this._textHighlighter.setTextMapping(textDivs, items); | ||
|  |     this._textHighlighter.enable(); | ||
|  |   } | ||
|  |   _resetZoomLayer(removeFromDOM = false) { | ||
|  |     if (!this.zoomLayer) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const zoomLayerCanvas = this.zoomLayer.firstChild; | ||
|  |     this.#viewportMap.delete(zoomLayerCanvas); | ||
|  |     zoomLayerCanvas.width = 0; | ||
|  |     zoomLayerCanvas.height = 0; | ||
|  |     if (removeFromDOM) { | ||
|  |       this.zoomLayer.remove(); | ||
|  |     } | ||
|  |     this.zoomLayer = null; | ||
|  |   } | ||
|  |   reset({ | ||
|  |     keepZoomLayer = false, | ||
|  |     keepAnnotationLayer = false, | ||
|  |     keepAnnotationEditorLayer = false, | ||
|  |     keepXfaLayer = false, | ||
|  |     keepTextLayer = false | ||
|  |   } = {}) { | ||
|  |     this.cancelRendering({ | ||
|  |       keepAnnotationLayer, | ||
|  |       keepAnnotationEditorLayer, | ||
|  |       keepXfaLayer, | ||
|  |       keepTextLayer | ||
|  |     }); | ||
|  |     this.renderingState = RenderingStates.INITIAL; | ||
|  |     const div = this.div; | ||
|  |     const childNodes = div.childNodes, | ||
|  |       zoomLayerNode = keepZoomLayer && this.zoomLayer || null, | ||
|  |       annotationLayerNode = keepAnnotationLayer && this.annotationLayer?.div || null, | ||
|  |       annotationEditorLayerNode = keepAnnotationEditorLayer && this.annotationEditorLayer?.div || null, | ||
|  |       xfaLayerNode = keepXfaLayer && this.xfaLayer?.div || null, | ||
|  |       textLayerNode = keepTextLayer && this.textLayer?.div || null; | ||
|  |     for (let i = childNodes.length - 1; i >= 0; i--) { | ||
|  |       const node = childNodes[i]; | ||
|  |       switch (node) { | ||
|  |         case zoomLayerNode: | ||
|  |         case annotationLayerNode: | ||
|  |         case annotationEditorLayerNode: | ||
|  |         case xfaLayerNode: | ||
|  |         case textLayerNode: | ||
|  |           continue; | ||
|  |       } | ||
|  |       node.remove(); | ||
|  |       const layerIndex = this.#layers.indexOf(node); | ||
|  |       if (layerIndex >= 0) { | ||
|  |         this.#layers[layerIndex] = null; | ||
|  |       } | ||
|  |     } | ||
|  |     div.removeAttribute("data-loaded"); | ||
|  |     if (annotationLayerNode) { | ||
|  |       this.annotationLayer.hide(); | ||
|  |     } | ||
|  |     if (annotationEditorLayerNode) { | ||
|  |       this.annotationEditorLayer.hide(); | ||
|  |     } | ||
|  |     if (xfaLayerNode) { | ||
|  |       this.xfaLayer.hide(); | ||
|  |     } | ||
|  |     if (textLayerNode) { | ||
|  |       this.textLayer.hide(); | ||
|  |     } | ||
|  |     this.structTreeLayer?.hide(); | ||
|  |     if (!zoomLayerNode) { | ||
|  |       if (this.canvas) { | ||
|  |         this.#viewportMap.delete(this.canvas); | ||
|  |         this.canvas.width = 0; | ||
|  |         this.canvas.height = 0; | ||
|  |         delete this.canvas; | ||
|  |       } | ||
|  |       this._resetZoomLayer(); | ||
|  |     } | ||
|  |   } | ||
|  |   toggleEditingMode(isEditing) { | ||
|  |     if (!this.hasEditableAnnotations()) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#isEditing = isEditing; | ||
|  |     this.reset({ | ||
|  |       keepZoomLayer: true, | ||
|  |       keepAnnotationLayer: true, | ||
|  |       keepAnnotationEditorLayer: true, | ||
|  |       keepXfaLayer: true, | ||
|  |       keepTextLayer: true | ||
|  |     }); | ||
|  |   } | ||
|  |   update({ | ||
|  |     scale = 0, | ||
|  |     rotation = null, | ||
|  |     optionalContentConfigPromise = null, | ||
|  |     drawingDelay = -1 | ||
|  |   }) { | ||
|  |     this.scale = scale || this.scale; | ||
|  |     if (typeof rotation === "number") { | ||
|  |       this.rotation = rotation; | ||
|  |     } | ||
|  |     if (optionalContentConfigPromise instanceof Promise) { | ||
|  |       this._optionalContentConfigPromise = optionalContentConfigPromise; | ||
|  |       optionalContentConfigPromise.then(optionalContentConfig => { | ||
|  |         if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility; | ||
|  |       }); | ||
|  |     } | ||
|  |     this.#useThumbnailCanvas.directDrawing = true; | ||
|  |     const totalRotation = (this.rotation + this.pdfPageRotate) % 360; | ||
|  |     this.viewport = this.viewport.clone({ | ||
|  |       scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS, | ||
|  |       rotation: totalRotation | ||
|  |     }); | ||
|  |     this.#setDimensions(); | ||
|  |     if (this._isStandalone) { | ||
|  |       this._container?.style.setProperty("--scale-factor", this.viewport.scale); | ||
|  |     } | ||
|  |     if (this.canvas) { | ||
|  |       let onlyCssZoom = false; | ||
|  |       if (this.#hasRestrictedScaling) { | ||
|  |         if (this.maxCanvasPixels === 0) { | ||
|  |           onlyCssZoom = true; | ||
|  |         } else if (this.maxCanvasPixels > 0) { | ||
|  |           const { | ||
|  |             width, | ||
|  |             height | ||
|  |           } = this.viewport; | ||
|  |           const { | ||
|  |             sx, | ||
|  |             sy | ||
|  |           } = this.outputScale; | ||
|  |           onlyCssZoom = (Math.floor(width) * sx | 0) * (Math.floor(height) * sy | 0) > this.maxCanvasPixels; | ||
|  |         } | ||
|  |       } | ||
|  |       const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000; | ||
|  |       if (postponeDrawing || onlyCssZoom) { | ||
|  |         if (postponeDrawing && !onlyCssZoom && this.renderingState !== RenderingStates.FINISHED) { | ||
|  |           this.cancelRendering({ | ||
|  |             keepZoomLayer: true, | ||
|  |             keepAnnotationLayer: true, | ||
|  |             keepAnnotationEditorLayer: true, | ||
|  |             keepXfaLayer: true, | ||
|  |             keepTextLayer: true, | ||
|  |             cancelExtraDelay: drawingDelay | ||
|  |           }); | ||
|  |           this.renderingState = RenderingStates.FINISHED; | ||
|  |           this.#useThumbnailCanvas.directDrawing = false; | ||
|  |         } | ||
|  |         this.cssTransform({ | ||
|  |           target: this.canvas, | ||
|  |           redrawAnnotationLayer: true, | ||
|  |           redrawAnnotationEditorLayer: true, | ||
|  |           redrawXfaLayer: true, | ||
|  |           redrawTextLayer: !postponeDrawing, | ||
|  |           hideTextLayer: postponeDrawing | ||
|  |         }); | ||
|  |         if (postponeDrawing) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this.eventBus.dispatch("pagerendered", { | ||
|  |           source: this, | ||
|  |           pageNumber: this.id, | ||
|  |           cssTransform: true, | ||
|  |           timestamp: performance.now(), | ||
|  |           error: this.#renderError | ||
|  |         }); | ||
|  |         return; | ||
|  |       } | ||
|  |       if (!this.zoomLayer && !this.canvas.hidden) { | ||
|  |         this.zoomLayer = this.canvas.parentNode; | ||
|  |         this.zoomLayer.style.position = "absolute"; | ||
|  |       } | ||
|  |     } | ||
|  |     if (this.zoomLayer) { | ||
|  |       this.cssTransform({ | ||
|  |         target: this.zoomLayer.firstChild | ||
|  |       }); | ||
|  |     } | ||
|  |     this.reset({ | ||
|  |       keepZoomLayer: true, | ||
|  |       keepAnnotationLayer: true, | ||
|  |       keepAnnotationEditorLayer: true, | ||
|  |       keepXfaLayer: true, | ||
|  |       keepTextLayer: true | ||
|  |     }); | ||
|  |   } | ||
|  |   cancelRendering({ | ||
|  |     keepAnnotationLayer = false, | ||
|  |     keepAnnotationEditorLayer = false, | ||
|  |     keepXfaLayer = false, | ||
|  |     keepTextLayer = false, | ||
|  |     cancelExtraDelay = 0 | ||
|  |   } = {}) { | ||
|  |     if (this.renderTask) { | ||
|  |       this.renderTask.cancel(cancelExtraDelay); | ||
|  |       this.renderTask = null; | ||
|  |     } | ||
|  |     this.resume = null; | ||
|  |     if (this.textLayer && (!keepTextLayer || !this.textLayer.div)) { | ||
|  |       this.textLayer.cancel(); | ||
|  |       this.textLayer = null; | ||
|  |     } | ||
|  |     if (this.structTreeLayer && !this.textLayer) { | ||
|  |       this.structTreeLayer = null; | ||
|  |     } | ||
|  |     if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) { | ||
|  |       this.annotationLayer.cancel(); | ||
|  |       this.annotationLayer = null; | ||
|  |       this._annotationCanvasMap = null; | ||
|  |     } | ||
|  |     if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)) { | ||
|  |       if (this.drawLayer) { | ||
|  |         this.drawLayer.cancel(); | ||
|  |         this.drawLayer = null; | ||
|  |       } | ||
|  |       this.annotationEditorLayer.cancel(); | ||
|  |       this.annotationEditorLayer = null; | ||
|  |     } | ||
|  |     if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) { | ||
|  |       this.xfaLayer.cancel(); | ||
|  |       this.xfaLayer = null; | ||
|  |       this._textHighlighter?.disable(); | ||
|  |     } | ||
|  |   } | ||
|  |   cssTransform({ | ||
|  |     target, | ||
|  |     redrawAnnotationLayer = false, | ||
|  |     redrawAnnotationEditorLayer = false, | ||
|  |     redrawXfaLayer = false, | ||
|  |     redrawTextLayer = false, | ||
|  |     hideTextLayer = false | ||
|  |   }) { | ||
|  |     if (!target.hasAttribute("zooming")) { | ||
|  |       target.setAttribute("zooming", true); | ||
|  |       const { | ||
|  |         style | ||
|  |       } = target; | ||
|  |       style.width = style.height = ""; | ||
|  |     } | ||
|  |     const originalViewport = this.#viewportMap.get(target); | ||
|  |     if (this.viewport !== originalViewport) { | ||
|  |       const relativeRotation = this.viewport.rotation - originalViewport.rotation; | ||
|  |       const absRotation = Math.abs(relativeRotation); | ||
|  |       let scaleX = 1, | ||
|  |         scaleY = 1; | ||
|  |       if (absRotation === 90 || absRotation === 270) { | ||
|  |         const { | ||
|  |           width, | ||
|  |           height | ||
|  |         } = this.viewport; | ||
|  |         scaleX = height / width; | ||
|  |         scaleY = width / height; | ||
|  |       } | ||
|  |       target.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX}, ${scaleY})`; | ||
|  |     } | ||
|  |     if (redrawAnnotationLayer && this.annotationLayer) { | ||
|  |       this.#renderAnnotationLayer(); | ||
|  |     } | ||
|  |     if (redrawAnnotationEditorLayer && this.annotationEditorLayer) { | ||
|  |       if (this.drawLayer) { | ||
|  |         this.#renderDrawLayer(); | ||
|  |       } | ||
|  |       this.#renderAnnotationEditorLayer(); | ||
|  |     } | ||
|  |     if (redrawXfaLayer && this.xfaLayer) { | ||
|  |       this.#renderXfaLayer(); | ||
|  |     } | ||
|  |     if (this.textLayer) { | ||
|  |       if (hideTextLayer) { | ||
|  |         this.textLayer.hide(); | ||
|  |         this.structTreeLayer?.hide(); | ||
|  |       } else if (redrawTextLayer) { | ||
|  |         this.#renderTextLayer(); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   get width() { | ||
|  |     return this.viewport.width; | ||
|  |   } | ||
|  |   get height() { | ||
|  |     return this.viewport.height; | ||
|  |   } | ||
|  |   getPagePoint(x, y) { | ||
|  |     return this.viewport.convertToPdfPoint(x, y); | ||
|  |   } | ||
|  |   async #finishRenderTask(renderTask, error = null) { | ||
|  |     if (renderTask === this.renderTask) { | ||
|  |       this.renderTask = null; | ||
|  |     } | ||
|  |     if (error instanceof RenderingCancelledException) { | ||
|  |       this.#renderError = null; | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#renderError = error; | ||
|  |     this.renderingState = RenderingStates.FINISHED; | ||
|  |     this._resetZoomLayer(true); | ||
|  |     this.#useThumbnailCanvas.regularAnnotations = !renderTask.separateAnnots; | ||
|  |     this.eventBus.dispatch("pagerendered", { | ||
|  |       source: this, | ||
|  |       pageNumber: this.id, | ||
|  |       cssTransform: false, | ||
|  |       timestamp: performance.now(), | ||
|  |       error: this.#renderError | ||
|  |     }); | ||
|  |     if (error) { | ||
|  |       throw error; | ||
|  |     } | ||
|  |   } | ||
|  |   async draw() { | ||
|  |     if (this.renderingState !== RenderingStates.INITIAL) { | ||
|  |       console.error("Must be in new state before drawing"); | ||
|  |       this.reset(); | ||
|  |     } | ||
|  |     const { | ||
|  |       div, | ||
|  |       l10n, | ||
|  |       pageColors, | ||
|  |       pdfPage, | ||
|  |       viewport | ||
|  |     } = this; | ||
|  |     if (!pdfPage) { | ||
|  |       this.renderingState = RenderingStates.FINISHED; | ||
|  |       throw new Error("pdfPage is not loaded"); | ||
|  |     } | ||
|  |     this.renderingState = RenderingStates.RUNNING; | ||
|  |     const canvasWrapper = document.createElement("div"); | ||
|  |     canvasWrapper.classList.add("canvasWrapper"); | ||
|  |     this.#addLayer(canvasWrapper, "canvasWrapper"); | ||
|  |     if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) { | ||
|  |       this._accessibilityManager ||= new TextAccessibilityManager(); | ||
|  |       this.textLayer = new TextLayerBuilder({ | ||
|  |         pdfPage, | ||
|  |         highlighter: this._textHighlighter, | ||
|  |         accessibilityManager: this._accessibilityManager, | ||
|  |         enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS, | ||
|  |         onAppend: textLayerDiv => { | ||
|  |           this.l10n.pause(); | ||
|  |           this.#addLayer(textLayerDiv, "textLayer"); | ||
|  |           this.l10n.resume(); | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |     if (!this.annotationLayer && this.#annotationMode !== AnnotationMode.DISABLE) { | ||
|  |       const { | ||
|  |         annotationStorage, | ||
|  |         annotationEditorUIManager, | ||
|  |         downloadManager, | ||
|  |         enableScripting, | ||
|  |         fieldObjectsPromise, | ||
|  |         hasJSActionsPromise, | ||
|  |         linkService | ||
|  |       } = this.#layerProperties; | ||
|  |       this._annotationCanvasMap ||= new Map(); | ||
|  |       this.annotationLayer = new AnnotationLayerBuilder({ | ||
|  |         pdfPage, | ||
|  |         annotationStorage, | ||
|  |         imageResourcesPath: this.imageResourcesPath, | ||
|  |         renderForms: this.#annotationMode === AnnotationMode.ENABLE_FORMS, | ||
|  |         linkService, | ||
|  |         downloadManager, | ||
|  |         enableScripting, | ||
|  |         hasJSActionsPromise, | ||
|  |         fieldObjectsPromise, | ||
|  |         annotationCanvasMap: this._annotationCanvasMap, | ||
|  |         accessibilityManager: this._accessibilityManager, | ||
|  |         annotationEditorUIManager, | ||
|  |         onAppend: annotationLayerDiv => { | ||
|  |           this.#addLayer(annotationLayerDiv, "annotationLayer"); | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |     const renderContinueCallback = cont => { | ||
|  |       showCanvas?.(false); | ||
|  |       if (this.renderingQueue && !this.renderingQueue.isHighestPriority(this)) { | ||
|  |         this.renderingState = RenderingStates.PAUSED; | ||
|  |         this.resume = () => { | ||
|  |           this.renderingState = RenderingStates.RUNNING; | ||
|  |           cont(); | ||
|  |         }; | ||
|  |         return; | ||
|  |       } | ||
|  |       cont(); | ||
|  |     }; | ||
|  |     const { | ||
|  |       width, | ||
|  |       height | ||
|  |     } = viewport; | ||
|  |     const canvas = document.createElement("canvas"); | ||
|  |     canvas.setAttribute("role", "presentation"); | ||
|  |     canvas.hidden = true; | ||
|  |     const hasHCM = !!(pageColors?.background && pageColors?.foreground); | ||
|  |     let showCanvas = isLastShow => { | ||
|  |       if (!hasHCM || isLastShow) { | ||
|  |         canvas.hidden = false; | ||
|  |         showCanvas = null; | ||
|  |       } | ||
|  |     }; | ||
|  |     canvasWrapper.append(canvas); | ||
|  |     this.canvas = canvas; | ||
|  |     const ctx = canvas.getContext("2d", { | ||
|  |       alpha: false, | ||
|  |       willReadFrequently: !this.#enableHWA | ||
|  |     }); | ||
|  |     const outputScale = this.outputScale = new OutputScale(); | ||
|  |     if (this.maxCanvasPixels === 0) { | ||
|  |       const invScale = 1 / this.scale; | ||
|  |       outputScale.sx *= invScale; | ||
|  |       outputScale.sy *= invScale; | ||
|  |       this.#hasRestrictedScaling = true; | ||
|  |     } else if (this.maxCanvasPixels > 0) { | ||
|  |       const pixelsInViewport = width * height; | ||
|  |       const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport); | ||
|  |       if (outputScale.sx > maxScale || outputScale.sy > maxScale) { | ||
|  |         outputScale.sx = maxScale; | ||
|  |         outputScale.sy = maxScale; | ||
|  |         this.#hasRestrictedScaling = true; | ||
|  |       } else { | ||
|  |         this.#hasRestrictedScaling = false; | ||
|  |       } | ||
|  |     } | ||
|  |     const sfx = approximateFraction(outputScale.sx); | ||
|  |     const sfy = approximateFraction(outputScale.sy); | ||
|  |     canvas.width = floorToDivide(width * outputScale.sx, sfx[0]); | ||
|  |     canvas.height = floorToDivide(height * outputScale.sy, sfy[0]); | ||
|  |     const { | ||
|  |       style | ||
|  |     } = canvas; | ||
|  |     style.width = floorToDivide(width, sfx[1]) + "px"; | ||
|  |     style.height = floorToDivide(height, sfy[1]) + "px"; | ||
|  |     this.#viewportMap.set(canvas, viewport); | ||
|  |     const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; | ||
|  |     const renderContext = { | ||
|  |       canvasContext: ctx, | ||
|  |       transform, | ||
|  |       viewport, | ||
|  |       annotationMode: this.#annotationMode, | ||
|  |       optionalContentConfigPromise: this._optionalContentConfigPromise, | ||
|  |       annotationCanvasMap: this._annotationCanvasMap, | ||
|  |       pageColors, | ||
|  |       isEditing: this.#isEditing | ||
|  |     }; | ||
|  |     const renderTask = this.renderTask = pdfPage.render(renderContext); | ||
|  |     renderTask.onContinue = renderContinueCallback; | ||
|  |     const resultPromise = renderTask.promise.then(async () => { | ||
|  |       showCanvas?.(true); | ||
|  |       await this.#finishRenderTask(renderTask); | ||
|  |       this.#renderTextLayer(); | ||
|  |       if (this.annotationLayer) { | ||
|  |         await this.#renderAnnotationLayer(); | ||
|  |       } | ||
|  |       const { | ||
|  |         annotationEditorUIManager | ||
|  |       } = this.#layerProperties; | ||
|  |       if (!annotationEditorUIManager) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.drawLayer ||= new DrawLayerBuilder({ | ||
|  |         pageIndex: this.id | ||
|  |       }); | ||
|  |       await this.#renderDrawLayer(); | ||
|  |       this.drawLayer.setParent(canvasWrapper); | ||
|  |       this.annotationEditorLayer ||= new AnnotationEditorLayerBuilder({ | ||
|  |         uiManager: annotationEditorUIManager, | ||
|  |         pdfPage, | ||
|  |         l10n, | ||
|  |         accessibilityManager: this._accessibilityManager, | ||
|  |         annotationLayer: this.annotationLayer?.annotationLayer, | ||
|  |         textLayer: this.textLayer, | ||
|  |         drawLayer: this.drawLayer.getDrawLayer(), | ||
|  |         onAppend: annotationEditorLayerDiv => { | ||
|  |           this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer"); | ||
|  |         } | ||
|  |       }); | ||
|  |       this.#renderAnnotationEditorLayer(); | ||
|  |     }, error => { | ||
|  |       if (!(error instanceof RenderingCancelledException)) { | ||
|  |         showCanvas?.(true); | ||
|  |       } | ||
|  |       return this.#finishRenderTask(renderTask, error); | ||
|  |     }); | ||
|  |     if (pdfPage.isPureXfa) { | ||
|  |       if (!this.xfaLayer) { | ||
|  |         const { | ||
|  |           annotationStorage, | ||
|  |           linkService | ||
|  |         } = this.#layerProperties; | ||
|  |         this.xfaLayer = new XfaLayerBuilder({ | ||
|  |           pdfPage, | ||
|  |           annotationStorage, | ||
|  |           linkService | ||
|  |         }); | ||
|  |       } | ||
|  |       this.#renderXfaLayer(); | ||
|  |     } | ||
|  |     div.setAttribute("data-loaded", true); | ||
|  |     this.eventBus.dispatch("pagerender", { | ||
|  |       source: this, | ||
|  |       pageNumber: this.id | ||
|  |     }); | ||
|  |     return resultPromise; | ||
|  |   } | ||
|  |   setPageLabel(label) { | ||
|  |     this.pageLabel = typeof label === "string" ? label : null; | ||
|  |     this.div.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |       page: this.pageLabel ?? this.id | ||
|  |     })); | ||
|  |     if (this.pageLabel !== null) { | ||
|  |       this.div.setAttribute("data-page-label", this.pageLabel); | ||
|  |     } else { | ||
|  |       this.div.removeAttribute("data-page-label"); | ||
|  |     } | ||
|  |   } | ||
|  |   get thumbnailCanvas() { | ||
|  |     const { | ||
|  |       directDrawing, | ||
|  |       initialOptionalContent, | ||
|  |       regularAnnotations | ||
|  |     } = this.#useThumbnailCanvas; | ||
|  |     return directDrawing && initialOptionalContent && regularAnnotations ? this.canvas : null; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/pdf_viewer.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const DEFAULT_CACHE_SIZE = 10; | ||
|  | const PagesCountLimit = { | ||
|  |   FORCE_SCROLL_MODE_PAGE: 10000, | ||
|  |   FORCE_LAZY_PAGE_INIT: 5000, | ||
|  |   PAUSE_EAGER_PAGE_INIT: 250 | ||
|  | }; | ||
|  | function isValidAnnotationEditorMode(mode) { | ||
|  |   return Object.values(AnnotationEditorType).includes(mode) && mode !== AnnotationEditorType.DISABLE; | ||
|  | } | ||
|  | class PDFPageViewBuffer { | ||
|  |   #buf = new Set(); | ||
|  |   #size = 0; | ||
|  |   constructor(size) { | ||
|  |     this.#size = size; | ||
|  |   } | ||
|  |   push(view) { | ||
|  |     const buf = this.#buf; | ||
|  |     if (buf.has(view)) { | ||
|  |       buf.delete(view); | ||
|  |     } | ||
|  |     buf.add(view); | ||
|  |     if (buf.size > this.#size) { | ||
|  |       this.#destroyFirstView(); | ||
|  |     } | ||
|  |   } | ||
|  |   resize(newSize, idsToKeep = null) { | ||
|  |     this.#size = newSize; | ||
|  |     const buf = this.#buf; | ||
|  |     if (idsToKeep) { | ||
|  |       const ii = buf.size; | ||
|  |       let i = 1; | ||
|  |       for (const view of buf) { | ||
|  |         if (idsToKeep.has(view.id)) { | ||
|  |           buf.delete(view); | ||
|  |           buf.add(view); | ||
|  |         } | ||
|  |         if (++i > ii) { | ||
|  |           break; | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     while (buf.size > this.#size) { | ||
|  |       this.#destroyFirstView(); | ||
|  |     } | ||
|  |   } | ||
|  |   has(view) { | ||
|  |     return this.#buf.has(view); | ||
|  |   } | ||
|  |   [Symbol.iterator]() { | ||
|  |     return this.#buf.keys(); | ||
|  |   } | ||
|  |   #destroyFirstView() { | ||
|  |     const firstView = this.#buf.keys().next().value; | ||
|  |     firstView?.destroy(); | ||
|  |     this.#buf.delete(firstView); | ||
|  |   } | ||
|  | } | ||
|  | class PDFViewer { | ||
|  |   #buffer = null; | ||
|  |   #altTextManager = null; | ||
|  |   #annotationEditorHighlightColors = null; | ||
|  |   #annotationEditorMode = AnnotationEditorType.NONE; | ||
|  |   #annotationEditorUIManager = null; | ||
|  |   #annotationMode = AnnotationMode.ENABLE_FORMS; | ||
|  |   #containerTopLeft = null; | ||
|  |   #enableHWA = false; | ||
|  |   #enableHighlightFloatingButton = false; | ||
|  |   #enablePermissions = false; | ||
|  |   #enableUpdatedAddImage = false; | ||
|  |   #enableNewAltTextWhenAddingImage = false; | ||
|  |   #eventAbortController = null; | ||
|  |   #mlManager = null; | ||
|  |   #onPageRenderedCallback = null; | ||
|  |   #switchAnnotationEditorModeTimeoutId = null; | ||
|  |   #getAllTextInProgress = false; | ||
|  |   #hiddenCopyElement = null; | ||
|  |   #interruptCopyCondition = false; | ||
|  |   #previousContainerHeight = 0; | ||
|  |   #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this)); | ||
|  |   #scrollModePageState = null; | ||
|  |   #scaleTimeoutId = null; | ||
|  |   #textLayerMode = TextLayerMode.ENABLE; | ||
|  |   constructor(options) { | ||
|  |     const viewerVersion = "4.6.82"; | ||
|  |     if (version !== viewerVersion) { | ||
|  |       throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); | ||
|  |     } | ||
|  |     this.container = options.container; | ||
|  |     this.viewer = options.viewer || options.container.firstElementChild; | ||
|  |     if (this.container?.tagName !== "DIV" || this.viewer?.tagName !== "DIV") { | ||
|  |       throw new Error("Invalid `container` and/or `viewer` option."); | ||
|  |     } | ||
|  |     if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") { | ||
|  |       throw new Error("The `container` must be absolutely positioned."); | ||
|  |     } | ||
|  |     this.#resizeObserver.observe(this.container); | ||
|  |     this.eventBus = options.eventBus; | ||
|  |     this.linkService = options.linkService || new SimpleLinkService(); | ||
|  |     this.downloadManager = options.downloadManager || null; | ||
|  |     this.findController = options.findController || null; | ||
|  |     this.#altTextManager = options.altTextManager || null; | ||
|  |     if (this.findController) { | ||
|  |       this.findController.onIsPageVisible = pageNumber => this._getVisiblePages().ids.has(pageNumber); | ||
|  |     } | ||
|  |     this._scriptingManager = options.scriptingManager || null; | ||
|  |     this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE; | ||
|  |     this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; | ||
|  |     this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE; | ||
|  |     this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null; | ||
|  |     this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true; | ||
|  |     this.#enableUpdatedAddImage = options.enableUpdatedAddImage === true; | ||
|  |     this.#enableNewAltTextWhenAddingImage = options.enableNewAltTextWhenAddingImage === true; | ||
|  |     this.imageResourcesPath = options.imageResourcesPath || ""; | ||
|  |     this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; | ||
|  |     this.removePageBorders = options.removePageBorders || false; | ||
|  |     this.maxCanvasPixels = options.maxCanvasPixels; | ||
|  |     this.l10n = options.l10n; | ||
|  |     this.l10n ||= new genericl10n_GenericL10n(); | ||
|  |     this.#enablePermissions = options.enablePermissions || false; | ||
|  |     this.pageColors = options.pageColors || null; | ||
|  |     this.#mlManager = options.mlManager || null; | ||
|  |     this.#enableHWA = options.enableHWA || false; | ||
|  |     this.defaultRenderingQueue = !options.renderingQueue; | ||
|  |     if (this.defaultRenderingQueue) { | ||
|  |       this.renderingQueue = new PDFRenderingQueue(); | ||
|  |       this.renderingQueue.setViewer(this); | ||
|  |     } else { | ||
|  |       this.renderingQueue = options.renderingQueue; | ||
|  |     } | ||
|  |     const { | ||
|  |       abortSignal | ||
|  |     } = options; | ||
|  |     abortSignal?.addEventListener("abort", () => { | ||
|  |       this.#resizeObserver.disconnect(); | ||
|  |       this.#resizeObserver = null; | ||
|  |     }, { | ||
|  |       once: true | ||
|  |     }); | ||
|  |     this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this), abortSignal); | ||
|  |     this.presentationModeState = PresentationModeState.UNKNOWN; | ||
|  |     this._resetView(); | ||
|  |     if (this.removePageBorders) { | ||
|  |       this.viewer.classList.add("removePageBorders"); | ||
|  |     } | ||
|  |     this.#updateContainerHeightCss(); | ||
|  |     this.eventBus._on("thumbnailrendered", ({ | ||
|  |       pageNumber, | ||
|  |       pdfPage | ||
|  |     }) => { | ||
|  |       const pageView = this._pages[pageNumber - 1]; | ||
|  |       if (!this.#buffer.has(pageView)) { | ||
|  |         pdfPage?.cleanup(); | ||
|  |       } | ||
|  |     }); | ||
|  |     if (!options.l10n) { | ||
|  |       this.l10n.translate(this.container); | ||
|  |     } | ||
|  |   } | ||
|  |   get pagesCount() { | ||
|  |     return this._pages.length; | ||
|  |   } | ||
|  |   getPageView(index) { | ||
|  |     return this._pages[index]; | ||
|  |   } | ||
|  |   getCachedPageViews() { | ||
|  |     return new Set(this.#buffer); | ||
|  |   } | ||
|  |   get pageViewsReady() { | ||
|  |     return this._pages.every(pageView => pageView?.pdfPage); | ||
|  |   } | ||
|  |   get renderForms() { | ||
|  |     return this.#annotationMode === AnnotationMode.ENABLE_FORMS; | ||
|  |   } | ||
|  |   get enableScripting() { | ||
|  |     return !!this._scriptingManager; | ||
|  |   } | ||
|  |   get currentPageNumber() { | ||
|  |     return this._currentPageNumber; | ||
|  |   } | ||
|  |   set currentPageNumber(val) { | ||
|  |     if (!Number.isInteger(val)) { | ||
|  |       throw new Error("Invalid page number."); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this._setCurrentPageNumber(val, true)) { | ||
|  |       console.error(`currentPageNumber: "${val}" is not a valid page.`); | ||
|  |     } | ||
|  |   } | ||
|  |   _setCurrentPageNumber(val, resetCurrentPageView = false) { | ||
|  |     if (this._currentPageNumber === val) { | ||
|  |       if (resetCurrentPageView) { | ||
|  |         this.#resetCurrentPageView(); | ||
|  |       } | ||
|  |       return true; | ||
|  |     } | ||
|  |     if (!(0 < val && val <= this.pagesCount)) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     const previous = this._currentPageNumber; | ||
|  |     this._currentPageNumber = val; | ||
|  |     this.eventBus.dispatch("pagechanging", { | ||
|  |       source: this, | ||
|  |       pageNumber: val, | ||
|  |       pageLabel: this._pageLabels?.[val - 1] ?? null, | ||
|  |       previous | ||
|  |     }); | ||
|  |     if (resetCurrentPageView) { | ||
|  |       this.#resetCurrentPageView(); | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  |   get currentPageLabel() { | ||
|  |     return this._pageLabels?.[this._currentPageNumber - 1] ?? null; | ||
|  |   } | ||
|  |   set currentPageLabel(val) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let page = val | 0; | ||
|  |     if (this._pageLabels) { | ||
|  |       const i = this._pageLabels.indexOf(val); | ||
|  |       if (i >= 0) { | ||
|  |         page = i + 1; | ||
|  |       } | ||
|  |     } | ||
|  |     if (!this._setCurrentPageNumber(page, true)) { | ||
|  |       console.error(`currentPageLabel: "${val}" is not a valid page.`); | ||
|  |     } | ||
|  |   } | ||
|  |   get currentScale() { | ||
|  |     return this._currentScale !== UNKNOWN_SCALE ? this._currentScale : DEFAULT_SCALE; | ||
|  |   } | ||
|  |   set currentScale(val) { | ||
|  |     if (isNaN(val)) { | ||
|  |       throw new Error("Invalid numeric scale."); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#setScale(val, { | ||
|  |       noScroll: false | ||
|  |     }); | ||
|  |   } | ||
|  |   get currentScaleValue() { | ||
|  |     return this._currentScaleValue; | ||
|  |   } | ||
|  |   set currentScaleValue(val) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.#setScale(val, { | ||
|  |       noScroll: false | ||
|  |     }); | ||
|  |   } | ||
|  |   get pagesRotation() { | ||
|  |     return this._pagesRotation; | ||
|  |   } | ||
|  |   set pagesRotation(rotation) { | ||
|  |     if (!isValidRotation(rotation)) { | ||
|  |       throw new Error("Invalid pages rotation angle."); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     rotation %= 360; | ||
|  |     if (rotation < 0) { | ||
|  |       rotation += 360; | ||
|  |     } | ||
|  |     if (this._pagesRotation === rotation) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._pagesRotation = rotation; | ||
|  |     const pageNumber = this._currentPageNumber; | ||
|  |     this.refresh(true, { | ||
|  |       rotation | ||
|  |     }); | ||
|  |     if (this._currentScaleValue) { | ||
|  |       this.#setScale(this._currentScaleValue, { | ||
|  |         noScroll: true | ||
|  |       }); | ||
|  |     } | ||
|  |     this.eventBus.dispatch("rotationchanging", { | ||
|  |       source: this, | ||
|  |       pagesRotation: rotation, | ||
|  |       pageNumber | ||
|  |     }); | ||
|  |     if (this.defaultRenderingQueue) { | ||
|  |       this.update(); | ||
|  |     } | ||
|  |   } | ||
|  |   get firstPagePromise() { | ||
|  |     return this.pdfDocument ? this._firstPageCapability.promise : null; | ||
|  |   } | ||
|  |   get onePageRendered() { | ||
|  |     return this.pdfDocument ? this._onePageRenderedCapability.promise : null; | ||
|  |   } | ||
|  |   get pagesPromise() { | ||
|  |     return this.pdfDocument ? this._pagesCapability.promise : null; | ||
|  |   } | ||
|  |   get _layerProperties() { | ||
|  |     const self = this; | ||
|  |     return shadow(this, "_layerProperties", { | ||
|  |       get annotationEditorUIManager() { | ||
|  |         return self.#annotationEditorUIManager; | ||
|  |       }, | ||
|  |       get annotationStorage() { | ||
|  |         return self.pdfDocument?.annotationStorage; | ||
|  |       }, | ||
|  |       get downloadManager() { | ||
|  |         return self.downloadManager; | ||
|  |       }, | ||
|  |       get enableScripting() { | ||
|  |         return !!self._scriptingManager; | ||
|  |       }, | ||
|  |       get fieldObjectsPromise() { | ||
|  |         return self.pdfDocument?.getFieldObjects(); | ||
|  |       }, | ||
|  |       get findController() { | ||
|  |         return self.findController; | ||
|  |       }, | ||
|  |       get hasJSActionsPromise() { | ||
|  |         return self.pdfDocument?.hasJSActions(); | ||
|  |       }, | ||
|  |       get linkService() { | ||
|  |         return self.linkService; | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   #initializePermissions(permissions) { | ||
|  |     const params = { | ||
|  |       annotationEditorMode: this.#annotationEditorMode, | ||
|  |       annotationMode: this.#annotationMode, | ||
|  |       textLayerMode: this.#textLayerMode | ||
|  |     }; | ||
|  |     if (!permissions) { | ||
|  |       return params; | ||
|  |     } | ||
|  |     if (!permissions.includes(PermissionFlag.COPY) && this.#textLayerMode === TextLayerMode.ENABLE) { | ||
|  |       params.textLayerMode = TextLayerMode.ENABLE_PERMISSIONS; | ||
|  |     } | ||
|  |     if (!permissions.includes(PermissionFlag.MODIFY_CONTENTS)) { | ||
|  |       params.annotationEditorMode = AnnotationEditorType.DISABLE; | ||
|  |     } | ||
|  |     if (!permissions.includes(PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.includes(PermissionFlag.FILL_INTERACTIVE_FORMS) && this.#annotationMode === AnnotationMode.ENABLE_FORMS) { | ||
|  |       params.annotationMode = AnnotationMode.ENABLE; | ||
|  |     } | ||
|  |     return params; | ||
|  |   } | ||
|  |   async #onePageRenderedOrForceFetch(signal) { | ||
|  |     if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const hiddenCapability = Promise.withResolvers(); | ||
|  |     function onVisibilityChange() { | ||
|  |       if (document.visibilityState === "hidden") { | ||
|  |         hiddenCapability.resolve(); | ||
|  |       } | ||
|  |     } | ||
|  |     document.addEventListener("visibilitychange", onVisibilityChange, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     await Promise.race([this._onePageRenderedCapability.promise, hiddenCapability.promise]); | ||
|  |     document.removeEventListener("visibilitychange", onVisibilityChange); | ||
|  |   } | ||
|  |   async getAllText() { | ||
|  |     const texts = []; | ||
|  |     const buffer = []; | ||
|  |     for (let pageNum = 1, pagesCount = this.pdfDocument.numPages; pageNum <= pagesCount; ++pageNum) { | ||
|  |       if (this.#interruptCopyCondition) { | ||
|  |         return null; | ||
|  |       } | ||
|  |       buffer.length = 0; | ||
|  |       const page = await this.pdfDocument.getPage(pageNum); | ||
|  |       const { | ||
|  |         items | ||
|  |       } = await page.getTextContent(); | ||
|  |       for (const item of items) { | ||
|  |         if (item.str) { | ||
|  |           buffer.push(item.str); | ||
|  |         } | ||
|  |         if (item.hasEOL) { | ||
|  |           buffer.push("\n"); | ||
|  |         } | ||
|  |       } | ||
|  |       texts.push(removeNullCharacters(buffer.join(""))); | ||
|  |     } | ||
|  |     return texts.join("\n"); | ||
|  |   } | ||
|  |   #copyCallback(textLayerMode, event) { | ||
|  |     const selection = document.getSelection(); | ||
|  |     const { | ||
|  |       focusNode, | ||
|  |       anchorNode | ||
|  |     } = selection; | ||
|  |     if (anchorNode && focusNode && selection.containsNode(this.#hiddenCopyElement)) { | ||
|  |       if (this.#getAllTextInProgress || textLayerMode === TextLayerMode.ENABLE_PERMISSIONS) { | ||
|  |         event.preventDefault(); | ||
|  |         event.stopPropagation(); | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#getAllTextInProgress = true; | ||
|  |       const { | ||
|  |         classList | ||
|  |       } = this.viewer; | ||
|  |       classList.add("copyAll"); | ||
|  |       const ac = new AbortController(); | ||
|  |       window.addEventListener("keydown", ev => this.#interruptCopyCondition = ev.key === "Escape", { | ||
|  |         signal: ac.signal | ||
|  |       }); | ||
|  |       this.getAllText().then(async text => { | ||
|  |         if (text !== null) { | ||
|  |           await navigator.clipboard.writeText(text); | ||
|  |         } | ||
|  |       }).catch(reason => { | ||
|  |         console.warn(`Something goes wrong when extracting the text: ${reason.message}`); | ||
|  |       }).finally(() => { | ||
|  |         this.#getAllTextInProgress = false; | ||
|  |         this.#interruptCopyCondition = false; | ||
|  |         ac.abort(); | ||
|  |         classList.remove("copyAll"); | ||
|  |       }); | ||
|  |       event.preventDefault(); | ||
|  |       event.stopPropagation(); | ||
|  |     } | ||
|  |   } | ||
|  |   setDocument(pdfDocument) { | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.eventBus.dispatch("pagesdestroy", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |       this._cancelRendering(); | ||
|  |       this._resetView(); | ||
|  |       this.findController?.setDocument(null); | ||
|  |       this._scriptingManager?.setDocument(null); | ||
|  |       this.#annotationEditorUIManager?.destroy(); | ||
|  |       this.#annotationEditorUIManager = null; | ||
|  |     } | ||
|  |     this.pdfDocument = pdfDocument; | ||
|  |     if (!pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pagesCount = pdfDocument.numPages; | ||
|  |     const firstPagePromise = pdfDocument.getPage(1); | ||
|  |     const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ | ||
|  |       intent: "display" | ||
|  |     }); | ||
|  |     const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve(); | ||
|  |     const { | ||
|  |       eventBus, | ||
|  |       pageColors, | ||
|  |       viewer | ||
|  |     } = this; | ||
|  |     this.#eventAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       signal | ||
|  |     } = this.#eventAbortController; | ||
|  |     if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { | ||
|  |       console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document."); | ||
|  |       const mode = this._scrollMode = ScrollMode.PAGE; | ||
|  |       eventBus.dispatch("scrollmodechanged", { | ||
|  |         source: this, | ||
|  |         mode | ||
|  |       }); | ||
|  |     } | ||
|  |     this._pagesCapability.promise.then(() => { | ||
|  |       eventBus.dispatch("pagesloaded", { | ||
|  |         source: this, | ||
|  |         pagesCount | ||
|  |       }); | ||
|  |     }, () => {}); | ||
|  |     const onBeforeDraw = evt => { | ||
|  |       const pageView = this._pages[evt.pageNumber - 1]; | ||
|  |       if (!pageView) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this.#buffer.push(pageView); | ||
|  |     }; | ||
|  |     eventBus._on("pagerender", onBeforeDraw, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     const onAfterDraw = evt => { | ||
|  |       if (evt.cssTransform) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this._onePageRenderedCapability.resolve({ | ||
|  |         timestamp: evt.timestamp | ||
|  |       }); | ||
|  |       eventBus._off("pagerendered", onAfterDraw); | ||
|  |     }; | ||
|  |     eventBus._on("pagerendered", onAfterDraw, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     Promise.all([firstPagePromise, permissionsPromise]).then(([firstPdfPage, permissions]) => { | ||
|  |       if (pdfDocument !== this.pdfDocument) { | ||
|  |         return; | ||
|  |       } | ||
|  |       this._firstPageCapability.resolve(firstPdfPage); | ||
|  |       this._optionalContentConfigPromise = optionalContentConfigPromise; | ||
|  |       const { | ||
|  |         annotationEditorMode, | ||
|  |         annotationMode, | ||
|  |         textLayerMode | ||
|  |       } = this.#initializePermissions(permissions); | ||
|  |       if (textLayerMode !== TextLayerMode.DISABLE) { | ||
|  |         const element = this.#hiddenCopyElement = document.createElement("div"); | ||
|  |         element.id = "hiddenCopyElement"; | ||
|  |         viewer.before(element); | ||
|  |       } | ||
|  |       if (typeof AbortSignal.any === "function" && annotationEditorMode !== AnnotationEditorType.DISABLE) { | ||
|  |         const mode = annotationEditorMode; | ||
|  |         if (pdfDocument.isPureXfa) { | ||
|  |           console.warn("Warning: XFA-editing is not implemented."); | ||
|  |         } else if (isValidAnnotationEditorMode(mode)) { | ||
|  |           this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, viewer, this.#altTextManager, eventBus, pdfDocument, pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#enableUpdatedAddImage, this.#enableNewAltTextWhenAddingImage, this.#mlManager); | ||
|  |           eventBus.dispatch("annotationeditoruimanager", { | ||
|  |             source: this, | ||
|  |             uiManager: this.#annotationEditorUIManager | ||
|  |           }); | ||
|  |           if (mode !== AnnotationEditorType.NONE) { | ||
|  |             if (mode === AnnotationEditorType.STAMP) { | ||
|  |               this.#mlManager?.loadModel("altText"); | ||
|  |             } | ||
|  |             this.#annotationEditorUIManager.updateMode(mode); | ||
|  |           } | ||
|  |         } else { | ||
|  |           console.error(`Invalid AnnotationEditor mode: ${mode}`); | ||
|  |         } | ||
|  |       } | ||
|  |       const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : viewer; | ||
|  |       const scale = this.currentScale; | ||
|  |       const viewport = firstPdfPage.getViewport({ | ||
|  |         scale: scale * PixelsPerInch.PDF_TO_CSS_UNITS | ||
|  |       }); | ||
|  |       viewer.style.setProperty("--scale-factor", viewport.scale); | ||
|  |       if (pageColors?.foreground === "CanvasText" || pageColors?.background === "Canvas") { | ||
|  |         viewer.style.setProperty("--hcm-highlight-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight")); | ||
|  |         viewer.style.setProperty("--hcm-highlight-selected-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "ButtonText")); | ||
|  |       } | ||
|  |       for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { | ||
|  |         const pageView = new PDFPageView({ | ||
|  |           container: viewerElement, | ||
|  |           eventBus, | ||
|  |           id: pageNum, | ||
|  |           scale, | ||
|  |           defaultViewport: viewport.clone(), | ||
|  |           optionalContentConfigPromise, | ||
|  |           renderingQueue: this.renderingQueue, | ||
|  |           textLayerMode, | ||
|  |           annotationMode, | ||
|  |           imageResourcesPath: this.imageResourcesPath, | ||
|  |           maxCanvasPixels: this.maxCanvasPixels, | ||
|  |           pageColors, | ||
|  |           l10n: this.l10n, | ||
|  |           layerProperties: this._layerProperties, | ||
|  |           enableHWA: this.#enableHWA | ||
|  |         }); | ||
|  |         this._pages.push(pageView); | ||
|  |       } | ||
|  |       this._pages[0]?.setPdfPage(firstPdfPage); | ||
|  |       if (this._scrollMode === ScrollMode.PAGE) { | ||
|  |         this.#ensurePageViewVisible(); | ||
|  |       } else if (this._spreadMode !== SpreadMode.NONE) { | ||
|  |         this._updateSpreadMode(); | ||
|  |       } | ||
|  |       this.#onePageRenderedOrForceFetch(signal).then(async () => { | ||
|  |         if (pdfDocument !== this.pdfDocument) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this.findController?.setDocument(pdfDocument); | ||
|  |         this._scriptingManager?.setDocument(pdfDocument); | ||
|  |         if (this.#hiddenCopyElement) { | ||
|  |           document.addEventListener("copy", this.#copyCallback.bind(this, textLayerMode), { | ||
|  |             signal | ||
|  |           }); | ||
|  |         } | ||
|  |         if (this.#annotationEditorUIManager) { | ||
|  |           eventBus.dispatch("annotationeditormodechanged", { | ||
|  |             source: this, | ||
|  |             mode: this.#annotationEditorMode | ||
|  |           }); | ||
|  |         } | ||
|  |         if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT) { | ||
|  |           this._pagesCapability.resolve(); | ||
|  |           return; | ||
|  |         } | ||
|  |         let getPagesLeft = pagesCount - 1; | ||
|  |         if (getPagesLeft <= 0) { | ||
|  |           this._pagesCapability.resolve(); | ||
|  |           return; | ||
|  |         } | ||
|  |         for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) { | ||
|  |           const promise = pdfDocument.getPage(pageNum).then(pdfPage => { | ||
|  |             const pageView = this._pages[pageNum - 1]; | ||
|  |             if (!pageView.pdfPage) { | ||
|  |               pageView.setPdfPage(pdfPage); | ||
|  |             } | ||
|  |             if (--getPagesLeft === 0) { | ||
|  |               this._pagesCapability.resolve(); | ||
|  |             } | ||
|  |           }, reason => { | ||
|  |             console.error(`Unable to get page ${pageNum} to initialize viewer`, reason); | ||
|  |             if (--getPagesLeft === 0) { | ||
|  |               this._pagesCapability.resolve(); | ||
|  |             } | ||
|  |           }); | ||
|  |           if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) { | ||
|  |             await promise; | ||
|  |           } | ||
|  |         } | ||
|  |       }); | ||
|  |       eventBus.dispatch("pagesinit", { | ||
|  |         source: this | ||
|  |       }); | ||
|  |       pdfDocument.getMetadata().then(({ | ||
|  |         info | ||
|  |       }) => { | ||
|  |         if (pdfDocument !== this.pdfDocument) { | ||
|  |           return; | ||
|  |         } | ||
|  |         if (info.Language) { | ||
|  |           viewer.lang = info.Language; | ||
|  |         } | ||
|  |       }); | ||
|  |       if (this.defaultRenderingQueue) { | ||
|  |         this.update(); | ||
|  |       } | ||
|  |     }).catch(reason => { | ||
|  |       console.error("Unable to initialize viewer", reason); | ||
|  |       this._pagesCapability.reject(reason); | ||
|  |     }); | ||
|  |   } | ||
|  |   setPageLabels(labels) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!labels) { | ||
|  |       this._pageLabels = null; | ||
|  |     } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { | ||
|  |       this._pageLabels = null; | ||
|  |       console.error(`setPageLabels: Invalid page labels.`); | ||
|  |     } else { | ||
|  |       this._pageLabels = labels; | ||
|  |     } | ||
|  |     for (let i = 0, ii = this._pages.length; i < ii; i++) { | ||
|  |       this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null); | ||
|  |     } | ||
|  |   } | ||
|  |   _resetView() { | ||
|  |     this._pages = []; | ||
|  |     this._currentPageNumber = 1; | ||
|  |     this._currentScale = UNKNOWN_SCALE; | ||
|  |     this._currentScaleValue = null; | ||
|  |     this._pageLabels = null; | ||
|  |     this.#buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); | ||
|  |     this._location = null; | ||
|  |     this._pagesRotation = 0; | ||
|  |     this._optionalContentConfigPromise = null; | ||
|  |     this._firstPageCapability = Promise.withResolvers(); | ||
|  |     this._onePageRenderedCapability = Promise.withResolvers(); | ||
|  |     this._pagesCapability = Promise.withResolvers(); | ||
|  |     this._scrollMode = ScrollMode.VERTICAL; | ||
|  |     this._previousScrollMode = ScrollMode.UNKNOWN; | ||
|  |     this._spreadMode = SpreadMode.NONE; | ||
|  |     this.#scrollModePageState = { | ||
|  |       previousPageNumber: 1, | ||
|  |       scrollDown: true, | ||
|  |       pages: [] | ||
|  |     }; | ||
|  |     this.#eventAbortController?.abort(); | ||
|  |     this.#eventAbortController = null; | ||
|  |     this.viewer.textContent = ""; | ||
|  |     this._updateScrollMode(); | ||
|  |     this.viewer.removeAttribute("lang"); | ||
|  |     this.#hiddenCopyElement?.remove(); | ||
|  |     this.#hiddenCopyElement = null; | ||
|  |     this.#cleanupSwitchAnnotationEditorMode(); | ||
|  |   } | ||
|  |   #ensurePageViewVisible() { | ||
|  |     if (this._scrollMode !== ScrollMode.PAGE) { | ||
|  |       throw new Error("#ensurePageViewVisible: Invalid scrollMode value."); | ||
|  |     } | ||
|  |     const pageNumber = this._currentPageNumber, | ||
|  |       state = this.#scrollModePageState, | ||
|  |       viewer = this.viewer; | ||
|  |     viewer.textContent = ""; | ||
|  |     state.pages.length = 0; | ||
|  |     if (this._spreadMode === SpreadMode.NONE && !this.isInPresentationMode) { | ||
|  |       const pageView = this._pages[pageNumber - 1]; | ||
|  |       viewer.append(pageView.div); | ||
|  |       state.pages.push(pageView); | ||
|  |     } else { | ||
|  |       const pageIndexSet = new Set(), | ||
|  |         parity = this._spreadMode - 1; | ||
|  |       if (parity === -1) { | ||
|  |         pageIndexSet.add(pageNumber - 1); | ||
|  |       } else if (pageNumber % 2 !== parity) { | ||
|  |         pageIndexSet.add(pageNumber - 1); | ||
|  |         pageIndexSet.add(pageNumber); | ||
|  |       } else { | ||
|  |         pageIndexSet.add(pageNumber - 2); | ||
|  |         pageIndexSet.add(pageNumber - 1); | ||
|  |       } | ||
|  |       const spread = document.createElement("div"); | ||
|  |       spread.className = "spread"; | ||
|  |       if (this.isInPresentationMode) { | ||
|  |         const dummyPage = document.createElement("div"); | ||
|  |         dummyPage.className = "dummyPage"; | ||
|  |         spread.append(dummyPage); | ||
|  |       } | ||
|  |       for (const i of pageIndexSet) { | ||
|  |         const pageView = this._pages[i]; | ||
|  |         if (!pageView) { | ||
|  |           continue; | ||
|  |         } | ||
|  |         spread.append(pageView.div); | ||
|  |         state.pages.push(pageView); | ||
|  |       } | ||
|  |       viewer.append(spread); | ||
|  |     } | ||
|  |     state.scrollDown = pageNumber >= state.previousPageNumber; | ||
|  |     state.previousPageNumber = pageNumber; | ||
|  |   } | ||
|  |   _scrollUpdate() { | ||
|  |     if (this.pagesCount === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.update(); | ||
|  |   } | ||
|  |   #scrollIntoView(pageView, pageSpot = null) { | ||
|  |     const { | ||
|  |       div, | ||
|  |       id | ||
|  |     } = pageView; | ||
|  |     if (this._currentPageNumber !== id) { | ||
|  |       this._setCurrentPageNumber(id); | ||
|  |     } | ||
|  |     if (this._scrollMode === ScrollMode.PAGE) { | ||
|  |       this.#ensurePageViewVisible(); | ||
|  |       this.update(); | ||
|  |     } | ||
|  |     if (!pageSpot && !this.isInPresentationMode) { | ||
|  |       const left = div.offsetLeft + div.clientLeft, | ||
|  |         right = left + div.clientWidth; | ||
|  |       const { | ||
|  |         scrollLeft, | ||
|  |         clientWidth | ||
|  |       } = this.container; | ||
|  |       if (this._scrollMode === ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) { | ||
|  |         pageSpot = { | ||
|  |           left: 0, | ||
|  |           top: 0 | ||
|  |         }; | ||
|  |       } | ||
|  |     } | ||
|  |     scrollIntoView(div, pageSpot); | ||
|  |     if (!this._currentScaleValue && this._location) { | ||
|  |       this._location = null; | ||
|  |     } | ||
|  |   } | ||
|  |   #isSameScale(newScale) { | ||
|  |     return newScale === this._currentScale || Math.abs(newScale - this._currentScale) < 1e-15; | ||
|  |   } | ||
|  |   #setScaleUpdatePages(newScale, newValue, { | ||
|  |     noScroll = false, | ||
|  |     preset = false, | ||
|  |     drawingDelay = -1, | ||
|  |     origin = null | ||
|  |   }) { | ||
|  |     this._currentScaleValue = newValue.toString(); | ||
|  |     if (this.#isSameScale(newScale)) { | ||
|  |       if (preset) { | ||
|  |         this.eventBus.dispatch("scalechanging", { | ||
|  |           source: this, | ||
|  |           scale: newScale, | ||
|  |           presetValue: newValue | ||
|  |         }); | ||
|  |       } | ||
|  |       return; | ||
|  |     } | ||
|  |     this.viewer.style.setProperty("--scale-factor", newScale * PixelsPerInch.PDF_TO_CSS_UNITS); | ||
|  |     const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000; | ||
|  |     this.refresh(true, { | ||
|  |       scale: newScale, | ||
|  |       drawingDelay: postponeDrawing ? drawingDelay : -1 | ||
|  |     }); | ||
|  |     if (postponeDrawing) { | ||
|  |       this.#scaleTimeoutId = setTimeout(() => { | ||
|  |         this.#scaleTimeoutId = null; | ||
|  |         this.refresh(); | ||
|  |       }, drawingDelay); | ||
|  |     } | ||
|  |     const previousScale = this._currentScale; | ||
|  |     this._currentScale = newScale; | ||
|  |     if (!noScroll) { | ||
|  |       let page = this._currentPageNumber, | ||
|  |         dest; | ||
|  |       if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) { | ||
|  |         page = this._location.pageNumber; | ||
|  |         dest = [null, { | ||
|  |           name: "XYZ" | ||
|  |         }, this._location.left, this._location.top, null]; | ||
|  |       } | ||
|  |       this.scrollPageIntoView({ | ||
|  |         pageNumber: page, | ||
|  |         destArray: dest, | ||
|  |         allowNegativeOffset: true | ||
|  |       }); | ||
|  |       if (Array.isArray(origin)) { | ||
|  |         const scaleDiff = newScale / previousScale - 1; | ||
|  |         const [top, left] = this.containerTopLeft; | ||
|  |         this.container.scrollLeft += (origin[0] - left) * scaleDiff; | ||
|  |         this.container.scrollTop += (origin[1] - top) * scaleDiff; | ||
|  |       } | ||
|  |     } | ||
|  |     this.eventBus.dispatch("scalechanging", { | ||
|  |       source: this, | ||
|  |       scale: newScale, | ||
|  |       presetValue: preset ? newValue : undefined | ||
|  |     }); | ||
|  |     if (this.defaultRenderingQueue) { | ||
|  |       this.update(); | ||
|  |     } | ||
|  |   } | ||
|  |   get #pageWidthScaleFactor() { | ||
|  |     if (this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL) { | ||
|  |       return 2; | ||
|  |     } | ||
|  |     return 1; | ||
|  |   } | ||
|  |   #setScale(value, options) { | ||
|  |     let scale = parseFloat(value); | ||
|  |     if (scale > 0) { | ||
|  |       options.preset = false; | ||
|  |       this.#setScaleUpdatePages(scale, value, options); | ||
|  |     } else { | ||
|  |       const currentPage = this._pages[this._currentPageNumber - 1]; | ||
|  |       if (!currentPage) { | ||
|  |         return; | ||
|  |       } | ||
|  |       let hPadding = SCROLLBAR_PADDING, | ||
|  |         vPadding = VERTICAL_PADDING; | ||
|  |       if (this.isInPresentationMode) { | ||
|  |         hPadding = vPadding = 4; | ||
|  |         if (this._spreadMode !== SpreadMode.NONE) { | ||
|  |           hPadding *= 2; | ||
|  |         } | ||
|  |       } else if (this.removePageBorders) { | ||
|  |         hPadding = vPadding = 0; | ||
|  |       } else if (this._scrollMode === ScrollMode.HORIZONTAL) { | ||
|  |         [hPadding, vPadding] = [vPadding, hPadding]; | ||
|  |       } | ||
|  |       const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this.#pageWidthScaleFactor; | ||
|  |       const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale; | ||
|  |       switch (value) { | ||
|  |         case "page-actual": | ||
|  |           scale = 1; | ||
|  |           break; | ||
|  |         case "page-width": | ||
|  |           scale = pageWidthScale; | ||
|  |           break; | ||
|  |         case "page-height": | ||
|  |           scale = pageHeightScale; | ||
|  |           break; | ||
|  |         case "page-fit": | ||
|  |           scale = Math.min(pageWidthScale, pageHeightScale); | ||
|  |           break; | ||
|  |         case "auto": | ||
|  |           const horizontalScale = isPortraitOrientation(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale); | ||
|  |           scale = Math.min(MAX_AUTO_SCALE, horizontalScale); | ||
|  |           break; | ||
|  |         default: | ||
|  |           console.error(`#setScale: "${value}" is an unknown zoom value.`); | ||
|  |           return; | ||
|  |       } | ||
|  |       options.preset = true; | ||
|  |       this.#setScaleUpdatePages(scale, value, options); | ||
|  |     } | ||
|  |   } | ||
|  |   #resetCurrentPageView() { | ||
|  |     const pageView = this._pages[this._currentPageNumber - 1]; | ||
|  |     if (this.isInPresentationMode) { | ||
|  |       this.#setScale(this._currentScaleValue, { | ||
|  |         noScroll: true | ||
|  |       }); | ||
|  |     } | ||
|  |     this.#scrollIntoView(pageView); | ||
|  |   } | ||
|  |   pageLabelToPageNumber(label) { | ||
|  |     if (!this._pageLabels) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     const i = this._pageLabels.indexOf(label); | ||
|  |     if (i < 0) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     return i + 1; | ||
|  |   } | ||
|  |   scrollPageIntoView({ | ||
|  |     pageNumber, | ||
|  |     destArray = null, | ||
|  |     allowNegativeOffset = false, | ||
|  |     ignoreDestinationZoom = false | ||
|  |   }) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1]; | ||
|  |     if (!pageView) { | ||
|  |       console.error(`scrollPageIntoView: "${pageNumber}" is not a valid pageNumber parameter.`); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.isInPresentationMode || !destArray) { | ||
|  |       this._setCurrentPageNumber(pageNumber, true); | ||
|  |       return; | ||
|  |     } | ||
|  |     let x = 0, | ||
|  |       y = 0; | ||
|  |     let width = 0, | ||
|  |       height = 0, | ||
|  |       widthScale, | ||
|  |       heightScale; | ||
|  |     const changeOrientation = pageView.rotation % 180 !== 0; | ||
|  |     const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS; | ||
|  |     const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS; | ||
|  |     let scale = 0; | ||
|  |     switch (destArray[1].name) { | ||
|  |       case "XYZ": | ||
|  |         x = destArray[2]; | ||
|  |         y = destArray[3]; | ||
|  |         scale = destArray[4]; | ||
|  |         x = x !== null ? x : 0; | ||
|  |         y = y !== null ? y : pageHeight; | ||
|  |         break; | ||
|  |       case "Fit": | ||
|  |       case "FitB": | ||
|  |         scale = "page-fit"; | ||
|  |         break; | ||
|  |       case "FitH": | ||
|  |       case "FitBH": | ||
|  |         y = destArray[2]; | ||
|  |         scale = "page-width"; | ||
|  |         if (y === null && this._location) { | ||
|  |           x = this._location.left; | ||
|  |           y = this._location.top; | ||
|  |         } else if (typeof y !== "number" || y < 0) { | ||
|  |           y = pageHeight; | ||
|  |         } | ||
|  |         break; | ||
|  |       case "FitV": | ||
|  |       case "FitBV": | ||
|  |         x = destArray[2]; | ||
|  |         width = pageWidth; | ||
|  |         height = pageHeight; | ||
|  |         scale = "page-height"; | ||
|  |         break; | ||
|  |       case "FitR": | ||
|  |         x = destArray[2]; | ||
|  |         y = destArray[3]; | ||
|  |         width = destArray[4] - x; | ||
|  |         height = destArray[5] - y; | ||
|  |         let hPadding = SCROLLBAR_PADDING, | ||
|  |           vPadding = VERTICAL_PADDING; | ||
|  |         if (this.removePageBorders) { | ||
|  |           hPadding = vPadding = 0; | ||
|  |         } | ||
|  |         widthScale = (this.container.clientWidth - hPadding) / width / PixelsPerInch.PDF_TO_CSS_UNITS; | ||
|  |         heightScale = (this.container.clientHeight - vPadding) / height / PixelsPerInch.PDF_TO_CSS_UNITS; | ||
|  |         scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); | ||
|  |         break; | ||
|  |       default: | ||
|  |         console.error(`scrollPageIntoView: "${destArray[1].name}" is not a valid destination type.`); | ||
|  |         return; | ||
|  |     } | ||
|  |     if (!ignoreDestinationZoom) { | ||
|  |       if (scale && scale !== this._currentScale) { | ||
|  |         this.currentScaleValue = scale; | ||
|  |       } else if (this._currentScale === UNKNOWN_SCALE) { | ||
|  |         this.currentScaleValue = DEFAULT_SCALE_VALUE; | ||
|  |       } | ||
|  |     } | ||
|  |     if (scale === "page-fit" && !destArray[4]) { | ||
|  |       this.#scrollIntoView(pageView); | ||
|  |       return; | ||
|  |     } | ||
|  |     const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)]; | ||
|  |     let left = Math.min(boundingRect[0][0], boundingRect[1][0]); | ||
|  |     let top = Math.min(boundingRect[0][1], boundingRect[1][1]); | ||
|  |     if (!allowNegativeOffset) { | ||
|  |       left = Math.max(left, 0); | ||
|  |       top = Math.max(top, 0); | ||
|  |     } | ||
|  |     this.#scrollIntoView(pageView, { | ||
|  |       left, | ||
|  |       top | ||
|  |     }); | ||
|  |   } | ||
|  |   _updateLocation(firstPage) { | ||
|  |     const currentScale = this._currentScale; | ||
|  |     const currentScaleValue = this._currentScaleValue; | ||
|  |     const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; | ||
|  |     const pageNumber = firstPage.id; | ||
|  |     const currentPageView = this._pages[pageNumber - 1]; | ||
|  |     const container = this.container; | ||
|  |     const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y); | ||
|  |     const intLeft = Math.round(topLeft[0]); | ||
|  |     const intTop = Math.round(topLeft[1]); | ||
|  |     let pdfOpenParams = `#page=${pageNumber}`; | ||
|  |     if (!this.isInPresentationMode) { | ||
|  |       pdfOpenParams += `&zoom=${normalizedScaleValue},${intLeft},${intTop}`; | ||
|  |     } | ||
|  |     this._location = { | ||
|  |       pageNumber, | ||
|  |       scale: normalizedScaleValue, | ||
|  |       top: intTop, | ||
|  |       left: intLeft, | ||
|  |       rotation: this._pagesRotation, | ||
|  |       pdfOpenParams | ||
|  |     }; | ||
|  |   } | ||
|  |   update() { | ||
|  |     const visible = this._getVisiblePages(); | ||
|  |     const visiblePages = visible.views, | ||
|  |       numVisiblePages = visiblePages.length; | ||
|  |     if (numVisiblePages === 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1); | ||
|  |     this.#buffer.resize(newCacheSize, visible.ids); | ||
|  |     this.renderingQueue.renderHighestPriority(visible); | ||
|  |     const isSimpleLayout = this._spreadMode === SpreadMode.NONE && (this._scrollMode === ScrollMode.PAGE || this._scrollMode === ScrollMode.VERTICAL); | ||
|  |     const currentId = this._currentPageNumber; | ||
|  |     let stillFullyVisible = false; | ||
|  |     for (const page of visiblePages) { | ||
|  |       if (page.percent < 100) { | ||
|  |         break; | ||
|  |       } | ||
|  |       if (page.id === currentId && isSimpleLayout) { | ||
|  |         stillFullyVisible = true; | ||
|  |         break; | ||
|  |       } | ||
|  |     } | ||
|  |     this._setCurrentPageNumber(stillFullyVisible ? currentId : visiblePages[0].id); | ||
|  |     this._updateLocation(visible.first); | ||
|  |     this.eventBus.dispatch("updateviewarea", { | ||
|  |       source: this, | ||
|  |       location: this._location | ||
|  |     }); | ||
|  |   } | ||
|  |   #switchToEditAnnotationMode() { | ||
|  |     const visible = this._getVisiblePages(); | ||
|  |     const pagesToRefresh = []; | ||
|  |     const { | ||
|  |       ids, | ||
|  |       views | ||
|  |     } = visible; | ||
|  |     for (const page of views) { | ||
|  |       const { | ||
|  |         view | ||
|  |       } = page; | ||
|  |       if (!view.hasEditableAnnotations()) { | ||
|  |         ids.delete(view.id); | ||
|  |         continue; | ||
|  |       } | ||
|  |       pagesToRefresh.push(page); | ||
|  |     } | ||
|  |     if (pagesToRefresh.length === 0) { | ||
|  |       return null; | ||
|  |     } | ||
|  |     this.renderingQueue.renderHighestPriority({ | ||
|  |       first: pagesToRefresh[0], | ||
|  |       last: pagesToRefresh.at(-1), | ||
|  |       views: pagesToRefresh, | ||
|  |       ids | ||
|  |     }); | ||
|  |     return ids; | ||
|  |   } | ||
|  |   containsElement(element) { | ||
|  |     return this.container.contains(element); | ||
|  |   } | ||
|  |   focus() { | ||
|  |     this.container.focus(); | ||
|  |   } | ||
|  |   get _isContainerRtl() { | ||
|  |     return getComputedStyle(this.container).direction === "rtl"; | ||
|  |   } | ||
|  |   get isInPresentationMode() { | ||
|  |     return this.presentationModeState === PresentationModeState.FULLSCREEN; | ||
|  |   } | ||
|  |   get isChangingPresentationMode() { | ||
|  |     return this.presentationModeState === PresentationModeState.CHANGING; | ||
|  |   } | ||
|  |   get isHorizontalScrollbarEnabled() { | ||
|  |     return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth; | ||
|  |   } | ||
|  |   get isVerticalScrollbarEnabled() { | ||
|  |     return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight; | ||
|  |   } | ||
|  |   _getVisiblePages() { | ||
|  |     const views = this._scrollMode === ScrollMode.PAGE ? this.#scrollModePageState.pages : this._pages, | ||
|  |       horizontal = this._scrollMode === ScrollMode.HORIZONTAL, | ||
|  |       rtl = horizontal && this._isContainerRtl; | ||
|  |     return getVisibleElements({ | ||
|  |       scrollEl: this.container, | ||
|  |       views, | ||
|  |       sortByVisibility: true, | ||
|  |       horizontal, | ||
|  |       rtl | ||
|  |     }); | ||
|  |   } | ||
|  |   cleanup() { | ||
|  |     for (const pageView of this._pages) { | ||
|  |       if (pageView.renderingState !== RenderingStates.FINISHED) { | ||
|  |         pageView.reset(); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   _cancelRendering() { | ||
|  |     for (const pageView of this._pages) { | ||
|  |       pageView.cancelRendering(); | ||
|  |     } | ||
|  |   } | ||
|  |   async #ensurePdfPageLoaded(pageView) { | ||
|  |     if (pageView.pdfPage) { | ||
|  |       return pageView.pdfPage; | ||
|  |     } | ||
|  |     try { | ||
|  |       const pdfPage = await this.pdfDocument.getPage(pageView.id); | ||
|  |       if (!pageView.pdfPage) { | ||
|  |         pageView.setPdfPage(pdfPage); | ||
|  |       } | ||
|  |       return pdfPage; | ||
|  |     } catch (reason) { | ||
|  |       console.error("Unable to get page for page view", reason); | ||
|  |       return null; | ||
|  |     } | ||
|  |   } | ||
|  |   #getScrollAhead(visible) { | ||
|  |     if (visible.first?.id === 1) { | ||
|  |       return true; | ||
|  |     } else if (visible.last?.id === this.pagesCount) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     switch (this._scrollMode) { | ||
|  |       case ScrollMode.PAGE: | ||
|  |         return this.#scrollModePageState.scrollDown; | ||
|  |       case ScrollMode.HORIZONTAL: | ||
|  |         return this.scroll.right; | ||
|  |     } | ||
|  |     return this.scroll.down; | ||
|  |   } | ||
|  |   forceRendering(currentlyVisiblePages) { | ||
|  |     const visiblePages = currentlyVisiblePages || this._getVisiblePages(); | ||
|  |     const scrollAhead = this.#getScrollAhead(visiblePages); | ||
|  |     const preRenderExtra = this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL; | ||
|  |     const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead, preRenderExtra); | ||
|  |     if (pageView) { | ||
|  |       this.#ensurePdfPageLoaded(pageView).then(() => { | ||
|  |         this.renderingQueue.renderView(pageView); | ||
|  |       }); | ||
|  |       return true; | ||
|  |     } | ||
|  |     return false; | ||
|  |   } | ||
|  |   get hasEqualPageSizes() { | ||
|  |     const firstPageView = this._pages[0]; | ||
|  |     for (let i = 1, ii = this._pages.length; i < ii; ++i) { | ||
|  |       const pageView = this._pages[i]; | ||
|  |       if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) { | ||
|  |         return false; | ||
|  |       } | ||
|  |     } | ||
|  |     return true; | ||
|  |   } | ||
|  |   getPagesOverview() { | ||
|  |     let initialOrientation; | ||
|  |     return this._pages.map(pageView => { | ||
|  |       const viewport = pageView.pdfPage.getViewport({ | ||
|  |         scale: 1 | ||
|  |       }); | ||
|  |       const orientation = isPortraitOrientation(viewport); | ||
|  |       if (initialOrientation === undefined) { | ||
|  |         initialOrientation = orientation; | ||
|  |       } else if (this.enablePrintAutoRotate && orientation !== initialOrientation) { | ||
|  |         return { | ||
|  |           width: viewport.height, | ||
|  |           height: viewport.width, | ||
|  |           rotation: (viewport.rotation - 90) % 360 | ||
|  |         }; | ||
|  |       } | ||
|  |       return { | ||
|  |         width: viewport.width, | ||
|  |         height: viewport.height, | ||
|  |         rotation: viewport.rotation | ||
|  |       }; | ||
|  |     }); | ||
|  |   } | ||
|  |   get optionalContentConfigPromise() { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return Promise.resolve(null); | ||
|  |     } | ||
|  |     if (!this._optionalContentConfigPromise) { | ||
|  |       console.error("optionalContentConfigPromise: Not initialized yet."); | ||
|  |       return this.pdfDocument.getOptionalContentConfig({ | ||
|  |         intent: "display" | ||
|  |       }); | ||
|  |     } | ||
|  |     return this._optionalContentConfigPromise; | ||
|  |   } | ||
|  |   set optionalContentConfigPromise(promise) { | ||
|  |     if (!(promise instanceof Promise)) { | ||
|  |       throw new Error(`Invalid optionalContentConfigPromise: ${promise}`); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this._optionalContentConfigPromise) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._optionalContentConfigPromise = promise; | ||
|  |     this.refresh(false, { | ||
|  |       optionalContentConfigPromise: promise | ||
|  |     }); | ||
|  |     this.eventBus.dispatch("optionalcontentconfigchanged", { | ||
|  |       source: this, | ||
|  |       promise | ||
|  |     }); | ||
|  |   } | ||
|  |   get scrollMode() { | ||
|  |     return this._scrollMode; | ||
|  |   } | ||
|  |   set scrollMode(mode) { | ||
|  |     if (this._scrollMode === mode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!isValidScrollMode(mode)) { | ||
|  |       throw new Error(`Invalid scroll mode: ${mode}`); | ||
|  |     } | ||
|  |     if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._previousScrollMode = this._scrollMode; | ||
|  |     this._scrollMode = mode; | ||
|  |     this.eventBus.dispatch("scrollmodechanged", { | ||
|  |       source: this, | ||
|  |       mode | ||
|  |     }); | ||
|  |     this._updateScrollMode(this._currentPageNumber); | ||
|  |   } | ||
|  |   _updateScrollMode(pageNumber = null) { | ||
|  |     const scrollMode = this._scrollMode, | ||
|  |       viewer = this.viewer; | ||
|  |     viewer.classList.toggle("scrollHorizontal", scrollMode === ScrollMode.HORIZONTAL); | ||
|  |     viewer.classList.toggle("scrollWrapped", scrollMode === ScrollMode.WRAPPED); | ||
|  |     if (!this.pdfDocument || !pageNumber) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (scrollMode === ScrollMode.PAGE) { | ||
|  |       this.#ensurePageViewVisible(); | ||
|  |     } else if (this._previousScrollMode === ScrollMode.PAGE) { | ||
|  |       this._updateSpreadMode(); | ||
|  |     } | ||
|  |     if (this._currentScaleValue && isNaN(this._currentScaleValue)) { | ||
|  |       this.#setScale(this._currentScaleValue, { | ||
|  |         noScroll: true | ||
|  |       }); | ||
|  |     } | ||
|  |     this._setCurrentPageNumber(pageNumber, true); | ||
|  |     this.update(); | ||
|  |   } | ||
|  |   get spreadMode() { | ||
|  |     return this._spreadMode; | ||
|  |   } | ||
|  |   set spreadMode(mode) { | ||
|  |     if (this._spreadMode === mode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!isValidSpreadMode(mode)) { | ||
|  |       throw new Error(`Invalid spread mode: ${mode}`); | ||
|  |     } | ||
|  |     this._spreadMode = mode; | ||
|  |     this.eventBus.dispatch("spreadmodechanged", { | ||
|  |       source: this, | ||
|  |       mode | ||
|  |     }); | ||
|  |     this._updateSpreadMode(this._currentPageNumber); | ||
|  |   } | ||
|  |   _updateSpreadMode(pageNumber = null) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const viewer = this.viewer, | ||
|  |       pages = this._pages; | ||
|  |     if (this._scrollMode === ScrollMode.PAGE) { | ||
|  |       this.#ensurePageViewVisible(); | ||
|  |     } else { | ||
|  |       viewer.textContent = ""; | ||
|  |       if (this._spreadMode === SpreadMode.NONE) { | ||
|  |         for (const pageView of this._pages) { | ||
|  |           viewer.append(pageView.div); | ||
|  |         } | ||
|  |       } else { | ||
|  |         const parity = this._spreadMode - 1; | ||
|  |         let spread = null; | ||
|  |         for (let i = 0, ii = pages.length; i < ii; ++i) { | ||
|  |           if (spread === null) { | ||
|  |             spread = document.createElement("div"); | ||
|  |             spread.className = "spread"; | ||
|  |             viewer.append(spread); | ||
|  |           } else if (i % 2 === parity) { | ||
|  |             spread = spread.cloneNode(false); | ||
|  |             viewer.append(spread); | ||
|  |           } | ||
|  |           spread.append(pages[i].div); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     if (!pageNumber) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this._currentScaleValue && isNaN(this._currentScaleValue)) { | ||
|  |       this.#setScale(this._currentScaleValue, { | ||
|  |         noScroll: true | ||
|  |       }); | ||
|  |     } | ||
|  |     this._setCurrentPageNumber(pageNumber, true); | ||
|  |     this.update(); | ||
|  |   } | ||
|  |   _getPageAdvance(currentPageNumber, previous = false) { | ||
|  |     switch (this._scrollMode) { | ||
|  |       case ScrollMode.WRAPPED: | ||
|  |         { | ||
|  |           const { | ||
|  |               views | ||
|  |             } = this._getVisiblePages(), | ||
|  |             pageLayout = new Map(); | ||
|  |           for (const { | ||
|  |             id, | ||
|  |             y, | ||
|  |             percent, | ||
|  |             widthPercent | ||
|  |           } of views) { | ||
|  |             if (percent === 0 || widthPercent < 100) { | ||
|  |               continue; | ||
|  |             } | ||
|  |             let yArray = pageLayout.get(y); | ||
|  |             if (!yArray) { | ||
|  |               pageLayout.set(y, yArray ||= []); | ||
|  |             } | ||
|  |             yArray.push(id); | ||
|  |           } | ||
|  |           for (const yArray of pageLayout.values()) { | ||
|  |             const currentIndex = yArray.indexOf(currentPageNumber); | ||
|  |             if (currentIndex === -1) { | ||
|  |               continue; | ||
|  |             } | ||
|  |             const numPages = yArray.length; | ||
|  |             if (numPages === 1) { | ||
|  |               break; | ||
|  |             } | ||
|  |             if (previous) { | ||
|  |               for (let i = currentIndex - 1, ii = 0; i >= ii; i--) { | ||
|  |                 const currentId = yArray[i], | ||
|  |                   expectedId = yArray[i + 1] - 1; | ||
|  |                 if (currentId < expectedId) { | ||
|  |                   return currentPageNumber - expectedId; | ||
|  |                 } | ||
|  |               } | ||
|  |             } else { | ||
|  |               for (let i = currentIndex + 1, ii = numPages; i < ii; i++) { | ||
|  |                 const currentId = yArray[i], | ||
|  |                   expectedId = yArray[i - 1] + 1; | ||
|  |                 if (currentId > expectedId) { | ||
|  |                   return expectedId - currentPageNumber; | ||
|  |                 } | ||
|  |               } | ||
|  |             } | ||
|  |             if (previous) { | ||
|  |               const firstId = yArray[0]; | ||
|  |               if (firstId < currentPageNumber) { | ||
|  |                 return currentPageNumber - firstId + 1; | ||
|  |               } | ||
|  |             } else { | ||
|  |               const lastId = yArray[numPages - 1]; | ||
|  |               if (lastId > currentPageNumber) { | ||
|  |                 return lastId - currentPageNumber + 1; | ||
|  |               } | ||
|  |             } | ||
|  |             break; | ||
|  |           } | ||
|  |           break; | ||
|  |         } | ||
|  |       case ScrollMode.HORIZONTAL: | ||
|  |         { | ||
|  |           break; | ||
|  |         } | ||
|  |       case ScrollMode.PAGE: | ||
|  |       case ScrollMode.VERTICAL: | ||
|  |         { | ||
|  |           if (this._spreadMode === SpreadMode.NONE) { | ||
|  |             break; | ||
|  |           } | ||
|  |           const parity = this._spreadMode - 1; | ||
|  |           if (previous && currentPageNumber % 2 !== parity) { | ||
|  |             break; | ||
|  |           } else if (!previous && currentPageNumber % 2 === parity) { | ||
|  |             break; | ||
|  |           } | ||
|  |           const { | ||
|  |               views | ||
|  |             } = this._getVisiblePages(), | ||
|  |             expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1; | ||
|  |           for (const { | ||
|  |             id, | ||
|  |             percent, | ||
|  |             widthPercent | ||
|  |           } of views) { | ||
|  |             if (id !== expectedId) { | ||
|  |               continue; | ||
|  |             } | ||
|  |             if (percent > 0 && widthPercent === 100) { | ||
|  |               return 2; | ||
|  |             } | ||
|  |             break; | ||
|  |           } | ||
|  |           break; | ||
|  |         } | ||
|  |     } | ||
|  |     return 1; | ||
|  |   } | ||
|  |   nextPage() { | ||
|  |     const currentPageNumber = this._currentPageNumber, | ||
|  |       pagesCount = this.pagesCount; | ||
|  |     if (currentPageNumber >= pagesCount) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     const advance = this._getPageAdvance(currentPageNumber, false) || 1; | ||
|  |     this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount); | ||
|  |     return true; | ||
|  |   } | ||
|  |   previousPage() { | ||
|  |     const currentPageNumber = this._currentPageNumber; | ||
|  |     if (currentPageNumber <= 1) { | ||
|  |       return false; | ||
|  |     } | ||
|  |     const advance = this._getPageAdvance(currentPageNumber, true) || 1; | ||
|  |     this.currentPageNumber = Math.max(currentPageNumber - advance, 1); | ||
|  |     return true; | ||
|  |   } | ||
|  |   updateScale({ | ||
|  |     drawingDelay, | ||
|  |     scaleFactor = null, | ||
|  |     steps = null, | ||
|  |     origin | ||
|  |   }) { | ||
|  |     if (steps === null && scaleFactor === null) { | ||
|  |       throw new Error("Invalid updateScale options: either `steps` or `scaleFactor` must be provided."); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let newScale = this._currentScale; | ||
|  |     if (scaleFactor > 0 && scaleFactor !== 1) { | ||
|  |       newScale = Math.round(newScale * scaleFactor * 100) / 100; | ||
|  |     } else if (steps) { | ||
|  |       const delta = steps > 0 ? DEFAULT_SCALE_DELTA : 1 / DEFAULT_SCALE_DELTA; | ||
|  |       const round = steps > 0 ? Math.ceil : Math.floor; | ||
|  |       steps = Math.abs(steps); | ||
|  |       do { | ||
|  |         newScale = round((newScale * delta).toFixed(2) * 10) / 10; | ||
|  |       } while (--steps > 0); | ||
|  |     } | ||
|  |     newScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale)); | ||
|  |     this.#setScale(newScale, { | ||
|  |       noScroll: false, | ||
|  |       drawingDelay, | ||
|  |       origin | ||
|  |     }); | ||
|  |   } | ||
|  |   increaseScale(options = {}) { | ||
|  |     this.updateScale({ | ||
|  |       ...options, | ||
|  |       steps: options.steps ?? 1 | ||
|  |     }); | ||
|  |   } | ||
|  |   decreaseScale(options = {}) { | ||
|  |     this.updateScale({ | ||
|  |       ...options, | ||
|  |       steps: -(options.steps ?? 1) | ||
|  |     }); | ||
|  |   } | ||
|  |   #updateContainerHeightCss(height = this.container.clientHeight) { | ||
|  |     if (height !== this.#previousContainerHeight) { | ||
|  |       this.#previousContainerHeight = height; | ||
|  |       docStyle.setProperty("--viewer-container-height", `${height}px`); | ||
|  |     } | ||
|  |   } | ||
|  |   #resizeObserverCallback(entries) { | ||
|  |     for (const entry of entries) { | ||
|  |       if (entry.target === this.container) { | ||
|  |         this.#updateContainerHeightCss(Math.floor(entry.borderBoxSize[0].blockSize)); | ||
|  |         this.#containerTopLeft = null; | ||
|  |         break; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   get containerTopLeft() { | ||
|  |     return this.#containerTopLeft ||= [this.container.offsetTop, this.container.offsetLeft]; | ||
|  |   } | ||
|  |   #cleanupSwitchAnnotationEditorMode() { | ||
|  |     if (this.#onPageRenderedCallback) { | ||
|  |       this.eventBus._off("pagerendered", this.#onPageRenderedCallback); | ||
|  |       this.#onPageRenderedCallback = null; | ||
|  |     } | ||
|  |     if (this.#switchAnnotationEditorModeTimeoutId !== null) { | ||
|  |       clearTimeout(this.#switchAnnotationEditorModeTimeoutId); | ||
|  |       this.#switchAnnotationEditorModeTimeoutId = null; | ||
|  |     } | ||
|  |   } | ||
|  |   get annotationEditorMode() { | ||
|  |     return this.#annotationEditorUIManager ? this.#annotationEditorMode : AnnotationEditorType.DISABLE; | ||
|  |   } | ||
|  |   set annotationEditorMode({ | ||
|  |     mode, | ||
|  |     editId = null, | ||
|  |     isFromKeyboard = false | ||
|  |   }) { | ||
|  |     if (!this.#annotationEditorUIManager) { | ||
|  |       throw new Error(`The AnnotationEditor is not enabled.`); | ||
|  |     } | ||
|  |     if (this.#annotationEditorMode === mode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!isValidAnnotationEditorMode(mode)) { | ||
|  |       throw new Error(`Invalid AnnotationEditor mode: ${mode}`); | ||
|  |     } | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (mode === AnnotationEditorType.STAMP) { | ||
|  |       this.#mlManager?.loadModel("altText"); | ||
|  |     } | ||
|  |     const { | ||
|  |       eventBus | ||
|  |     } = this; | ||
|  |     const updater = () => { | ||
|  |       this.#cleanupSwitchAnnotationEditorMode(); | ||
|  |       this.#annotationEditorMode = mode; | ||
|  |       this.#annotationEditorUIManager.updateMode(mode, editId, isFromKeyboard); | ||
|  |       eventBus.dispatch("annotationeditormodechanged", { | ||
|  |         source: this, | ||
|  |         mode | ||
|  |       }); | ||
|  |     }; | ||
|  |     if (mode === AnnotationEditorType.NONE || this.#annotationEditorMode === AnnotationEditorType.NONE) { | ||
|  |       const isEditing = mode !== AnnotationEditorType.NONE; | ||
|  |       if (!isEditing) { | ||
|  |         this.pdfDocument.annotationStorage.resetModifiedIds(); | ||
|  |       } | ||
|  |       for (const pageView of this._pages) { | ||
|  |         pageView.toggleEditingMode(isEditing); | ||
|  |       } | ||
|  |       const idsToRefresh = this.#switchToEditAnnotationMode(); | ||
|  |       if (isEditing && idsToRefresh) { | ||
|  |         this.#cleanupSwitchAnnotationEditorMode(); | ||
|  |         this.#onPageRenderedCallback = ({ | ||
|  |           pageNumber | ||
|  |         }) => { | ||
|  |           idsToRefresh.delete(pageNumber); | ||
|  |           if (idsToRefresh.size === 0) { | ||
|  |             this.#switchAnnotationEditorModeTimeoutId = setTimeout(updater, 0); | ||
|  |           } | ||
|  |         }; | ||
|  |         const { | ||
|  |           signal | ||
|  |         } = this.#eventAbortController; | ||
|  |         eventBus._on("pagerendered", this.#onPageRenderedCallback, { | ||
|  |           signal | ||
|  |         }); | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     updater(); | ||
|  |   } | ||
|  |   refresh(noUpdate = false, updateArgs = Object.create(null)) { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     for (const pageView of this._pages) { | ||
|  |       pageView.update(updateArgs); | ||
|  |     } | ||
|  |     if (this.#scaleTimeoutId !== null) { | ||
|  |       clearTimeout(this.#scaleTimeoutId); | ||
|  |       this.#scaleTimeoutId = null; | ||
|  |     } | ||
|  |     if (!noUpdate) { | ||
|  |       this.update(); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/secondary_toolbar.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class SecondaryToolbar { | ||
|  |   #opts; | ||
|  |   constructor(options, eventBus) { | ||
|  |     this.#opts = options; | ||
|  |     const buttons = [{ | ||
|  |       element: options.presentationModeButton, | ||
|  |       eventName: "presentationmode", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.printButton, | ||
|  |       eventName: "print", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.downloadButton, | ||
|  |       eventName: "download", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.viewBookmarkButton, | ||
|  |       eventName: null, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.firstPageButton, | ||
|  |       eventName: "firstpage", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.lastPageButton, | ||
|  |       eventName: "lastpage", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.pageRotateCwButton, | ||
|  |       eventName: "rotatecw", | ||
|  |       close: false | ||
|  |     }, { | ||
|  |       element: options.pageRotateCcwButton, | ||
|  |       eventName: "rotateccw", | ||
|  |       close: false | ||
|  |     }, { | ||
|  |       element: options.cursorSelectToolButton, | ||
|  |       eventName: "switchcursortool", | ||
|  |       eventDetails: { | ||
|  |         tool: CursorTool.SELECT | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.cursorHandToolButton, | ||
|  |       eventName: "switchcursortool", | ||
|  |       eventDetails: { | ||
|  |         tool: CursorTool.HAND | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.scrollPageButton, | ||
|  |       eventName: "switchscrollmode", | ||
|  |       eventDetails: { | ||
|  |         mode: ScrollMode.PAGE | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.scrollVerticalButton, | ||
|  |       eventName: "switchscrollmode", | ||
|  |       eventDetails: { | ||
|  |         mode: ScrollMode.VERTICAL | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.scrollHorizontalButton, | ||
|  |       eventName: "switchscrollmode", | ||
|  |       eventDetails: { | ||
|  |         mode: ScrollMode.HORIZONTAL | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.scrollWrappedButton, | ||
|  |       eventName: "switchscrollmode", | ||
|  |       eventDetails: { | ||
|  |         mode: ScrollMode.WRAPPED | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.spreadNoneButton, | ||
|  |       eventName: "switchspreadmode", | ||
|  |       eventDetails: { | ||
|  |         mode: SpreadMode.NONE | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.spreadOddButton, | ||
|  |       eventName: "switchspreadmode", | ||
|  |       eventDetails: { | ||
|  |         mode: SpreadMode.ODD | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.spreadEvenButton, | ||
|  |       eventName: "switchspreadmode", | ||
|  |       eventDetails: { | ||
|  |         mode: SpreadMode.EVEN | ||
|  |       }, | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.imageAltTextSettingsButton, | ||
|  |       eventName: "imagealttextsettings", | ||
|  |       close: true | ||
|  |     }, { | ||
|  |       element: options.documentPropertiesButton, | ||
|  |       eventName: "documentproperties", | ||
|  |       close: true | ||
|  |     }]; | ||
|  |     buttons.push({ | ||
|  |       element: options.openFileButton, | ||
|  |       eventName: "openfile", | ||
|  |       close: true | ||
|  |     }); | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.opened = false; | ||
|  |     this.#bindListeners(buttons); | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   get isOpen() { | ||
|  |     return this.opened; | ||
|  |   } | ||
|  |   setPageNumber(pageNumber) { | ||
|  |     this.pageNumber = pageNumber; | ||
|  |     this.#updateUIState(); | ||
|  |   } | ||
|  |   setPagesCount(pagesCount) { | ||
|  |     this.pagesCount = pagesCount; | ||
|  |     this.#updateUIState(); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this.pageNumber = 0; | ||
|  |     this.pagesCount = 0; | ||
|  |     this.#updateUIState(); | ||
|  |     this.eventBus.dispatch("switchcursortool", { | ||
|  |       source: this, | ||
|  |       reset: true | ||
|  |     }); | ||
|  |     this.#scrollModeChanged({ | ||
|  |       mode: ScrollMode.VERTICAL | ||
|  |     }); | ||
|  |     this.#spreadModeChanged({ | ||
|  |       mode: SpreadMode.NONE | ||
|  |     }); | ||
|  |   } | ||
|  |   #updateUIState() { | ||
|  |     const { | ||
|  |       firstPageButton, | ||
|  |       lastPageButton, | ||
|  |       pageRotateCwButton, | ||
|  |       pageRotateCcwButton | ||
|  |     } = this.#opts; | ||
|  |     firstPageButton.disabled = this.pageNumber <= 1; | ||
|  |     lastPageButton.disabled = this.pageNumber >= this.pagesCount; | ||
|  |     pageRotateCwButton.disabled = this.pagesCount === 0; | ||
|  |     pageRotateCcwButton.disabled = this.pagesCount === 0; | ||
|  |   } | ||
|  |   #bindListeners(buttons) { | ||
|  |     const { | ||
|  |       eventBus | ||
|  |     } = this; | ||
|  |     const { | ||
|  |       toggleButton | ||
|  |     } = this.#opts; | ||
|  |     toggleButton.addEventListener("click", this.toggle.bind(this)); | ||
|  |     for (const { | ||
|  |       element, | ||
|  |       eventName, | ||
|  |       close, | ||
|  |       eventDetails | ||
|  |     } of buttons) { | ||
|  |       element.addEventListener("click", evt => { | ||
|  |         if (eventName !== null) { | ||
|  |           eventBus.dispatch(eventName, { | ||
|  |             source: this, | ||
|  |             ...eventDetails | ||
|  |           }); | ||
|  |         } | ||
|  |         if (close) { | ||
|  |           this.close(); | ||
|  |         } | ||
|  |         eventBus.dispatch("reporttelemetry", { | ||
|  |           source: this, | ||
|  |           details: { | ||
|  |             type: "buttons", | ||
|  |             data: { | ||
|  |               id: element.id | ||
|  |             } | ||
|  |           } | ||
|  |         }); | ||
|  |       }); | ||
|  |     } | ||
|  |     eventBus._on("cursortoolchanged", this.#cursorToolChanged.bind(this)); | ||
|  |     eventBus._on("scrollmodechanged", this.#scrollModeChanged.bind(this)); | ||
|  |     eventBus._on("spreadmodechanged", this.#spreadModeChanged.bind(this)); | ||
|  |   } | ||
|  |   #cursorToolChanged({ | ||
|  |     tool | ||
|  |   }) { | ||
|  |     const { | ||
|  |       cursorSelectToolButton, | ||
|  |       cursorHandToolButton | ||
|  |     } = this.#opts; | ||
|  |     toggleCheckedBtn(cursorSelectToolButton, tool === CursorTool.SELECT); | ||
|  |     toggleCheckedBtn(cursorHandToolButton, tool === CursorTool.HAND); | ||
|  |   } | ||
|  |   #scrollModeChanged({ | ||
|  |     mode | ||
|  |   }) { | ||
|  |     const { | ||
|  |       scrollPageButton, | ||
|  |       scrollVerticalButton, | ||
|  |       scrollHorizontalButton, | ||
|  |       scrollWrappedButton, | ||
|  |       spreadNoneButton, | ||
|  |       spreadOddButton, | ||
|  |       spreadEvenButton | ||
|  |     } = this.#opts; | ||
|  |     toggleCheckedBtn(scrollPageButton, mode === ScrollMode.PAGE); | ||
|  |     toggleCheckedBtn(scrollVerticalButton, mode === ScrollMode.VERTICAL); | ||
|  |     toggleCheckedBtn(scrollHorizontalButton, mode === ScrollMode.HORIZONTAL); | ||
|  |     toggleCheckedBtn(scrollWrappedButton, mode === ScrollMode.WRAPPED); | ||
|  |     const forceScrollModePage = this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE; | ||
|  |     scrollPageButton.disabled = forceScrollModePage; | ||
|  |     scrollVerticalButton.disabled = forceScrollModePage; | ||
|  |     scrollHorizontalButton.disabled = forceScrollModePage; | ||
|  |     scrollWrappedButton.disabled = forceScrollModePage; | ||
|  |     const isHorizontal = mode === ScrollMode.HORIZONTAL; | ||
|  |     spreadNoneButton.disabled = isHorizontal; | ||
|  |     spreadOddButton.disabled = isHorizontal; | ||
|  |     spreadEvenButton.disabled = isHorizontal; | ||
|  |   } | ||
|  |   #spreadModeChanged({ | ||
|  |     mode | ||
|  |   }) { | ||
|  |     const { | ||
|  |       spreadNoneButton, | ||
|  |       spreadOddButton, | ||
|  |       spreadEvenButton | ||
|  |     } = this.#opts; | ||
|  |     toggleCheckedBtn(spreadNoneButton, mode === SpreadMode.NONE); | ||
|  |     toggleCheckedBtn(spreadOddButton, mode === SpreadMode.ODD); | ||
|  |     toggleCheckedBtn(spreadEvenButton, mode === SpreadMode.EVEN); | ||
|  |   } | ||
|  |   open() { | ||
|  |     if (this.opened) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.opened = true; | ||
|  |     const { | ||
|  |       toggleButton, | ||
|  |       toolbar | ||
|  |     } = this.#opts; | ||
|  |     toggleExpandedBtn(toggleButton, true, toolbar); | ||
|  |   } | ||
|  |   close() { | ||
|  |     if (!this.opened) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.opened = false; | ||
|  |     const { | ||
|  |       toggleButton, | ||
|  |       toolbar | ||
|  |     } = this.#opts; | ||
|  |     toggleExpandedBtn(toggleButton, false, toolbar); | ||
|  |   } | ||
|  |   toggle() { | ||
|  |     if (this.opened) { | ||
|  |       this.close(); | ||
|  |     } else { | ||
|  |       this.open(); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/toolbar.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class Toolbar { | ||
|  |   #opts; | ||
|  |   constructor(options, eventBus, toolbarDensity = 0) { | ||
|  |     this.#opts = options; | ||
|  |     this.eventBus = eventBus; | ||
|  |     const buttons = [{ | ||
|  |       element: options.previous, | ||
|  |       eventName: "previouspage" | ||
|  |     }, { | ||
|  |       element: options.next, | ||
|  |       eventName: "nextpage" | ||
|  |     }, { | ||
|  |       element: options.zoomIn, | ||
|  |       eventName: "zoomin" | ||
|  |     }, { | ||
|  |       element: options.zoomOut, | ||
|  |       eventName: "zoomout" | ||
|  |     }, { | ||
|  |       element: options.print, | ||
|  |       eventName: "print" | ||
|  |     }, { | ||
|  |       element: options.download, | ||
|  |       eventName: "download" | ||
|  |     }, { | ||
|  |       element: options.editorFreeTextButton, | ||
|  |       eventName: "switchannotationeditormode", | ||
|  |       eventDetails: { | ||
|  |         get mode() { | ||
|  |           const { | ||
|  |             classList | ||
|  |           } = options.editorFreeTextButton; | ||
|  |           return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.FREETEXT; | ||
|  |         } | ||
|  |       } | ||
|  |     }, { | ||
|  |       element: options.editorHighlightButton, | ||
|  |       eventName: "switchannotationeditormode", | ||
|  |       eventDetails: { | ||
|  |         get mode() { | ||
|  |           const { | ||
|  |             classList | ||
|  |           } = options.editorHighlightButton; | ||
|  |           return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.HIGHLIGHT; | ||
|  |         } | ||
|  |       } | ||
|  |     }, { | ||
|  |       element: options.editorInkButton, | ||
|  |       eventName: "switchannotationeditormode", | ||
|  |       eventDetails: { | ||
|  |         get mode() { | ||
|  |           const { | ||
|  |             classList | ||
|  |           } = options.editorInkButton; | ||
|  |           return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.INK; | ||
|  |         } | ||
|  |       } | ||
|  |     }, { | ||
|  |       element: options.editorStampButton, | ||
|  |       eventName: "switchannotationeditormode", | ||
|  |       eventDetails: { | ||
|  |         get mode() { | ||
|  |           const { | ||
|  |             classList | ||
|  |           } = options.editorStampButton; | ||
|  |           return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.STAMP; | ||
|  |         } | ||
|  |       }, | ||
|  |       telemetry: { | ||
|  |         type: "editing", | ||
|  |         data: { | ||
|  |           action: "pdfjs.image.icon_click" | ||
|  |         } | ||
|  |       } | ||
|  |     }]; | ||
|  |     this.#bindListeners(buttons); | ||
|  |     this.#updateToolbarDensity({ | ||
|  |       value: toolbarDensity | ||
|  |     }); | ||
|  |     this.reset(); | ||
|  |   } | ||
|  |   #updateToolbarDensity() {} | ||
|  |   #setAnnotationEditorUIManager(uiManager, parentContainer) { | ||
|  |     const colorPicker = new ColorPicker({ | ||
|  |       uiManager | ||
|  |     }); | ||
|  |     uiManager.setMainHighlightColorPicker(colorPicker); | ||
|  |     parentContainer.append(colorPicker.renderMainDropdown()); | ||
|  |   } | ||
|  |   setPageNumber(pageNumber, pageLabel) { | ||
|  |     this.pageNumber = pageNumber; | ||
|  |     this.pageLabel = pageLabel; | ||
|  |     this.#updateUIState(false); | ||
|  |   } | ||
|  |   setPagesCount(pagesCount, hasPageLabels) { | ||
|  |     this.pagesCount = pagesCount; | ||
|  |     this.hasPageLabels = hasPageLabels; | ||
|  |     this.#updateUIState(true); | ||
|  |   } | ||
|  |   setPageScale(pageScaleValue, pageScale) { | ||
|  |     this.pageScaleValue = (pageScaleValue || pageScale).toString(); | ||
|  |     this.pageScale = pageScale; | ||
|  |     this.#updateUIState(false); | ||
|  |   } | ||
|  |   reset() { | ||
|  |     this.pageNumber = 0; | ||
|  |     this.pageLabel = null; | ||
|  |     this.hasPageLabels = false; | ||
|  |     this.pagesCount = 0; | ||
|  |     this.pageScaleValue = DEFAULT_SCALE_VALUE; | ||
|  |     this.pageScale = DEFAULT_SCALE; | ||
|  |     this.#updateUIState(true); | ||
|  |     this.updateLoadingIndicatorState(); | ||
|  |     this.#editorModeChanged({ | ||
|  |       mode: AnnotationEditorType.DISABLE | ||
|  |     }); | ||
|  |   } | ||
|  |   #bindListeners(buttons) { | ||
|  |     const { | ||
|  |       eventBus | ||
|  |     } = this; | ||
|  |     const { | ||
|  |       editorHighlightColorPicker, | ||
|  |       editorHighlightButton, | ||
|  |       pageNumber, | ||
|  |       scaleSelect | ||
|  |     } = this.#opts; | ||
|  |     const self = this; | ||
|  |     for (const { | ||
|  |       element, | ||
|  |       eventName, | ||
|  |       eventDetails, | ||
|  |       telemetry | ||
|  |     } of buttons) { | ||
|  |       element.addEventListener("click", evt => { | ||
|  |         if (eventName !== null) { | ||
|  |           eventBus.dispatch(eventName, { | ||
|  |             source: this, | ||
|  |             ...eventDetails, | ||
|  |             isFromKeyboard: evt.detail === 0 | ||
|  |           }); | ||
|  |         } | ||
|  |         if (telemetry) { | ||
|  |           eventBus.dispatch("reporttelemetry", { | ||
|  |             source: this, | ||
|  |             details: telemetry | ||
|  |           }); | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |     pageNumber.addEventListener("click", function () { | ||
|  |       this.select(); | ||
|  |     }); | ||
|  |     pageNumber.addEventListener("change", function () { | ||
|  |       eventBus.dispatch("pagenumberchanged", { | ||
|  |         source: self, | ||
|  |         value: this.value | ||
|  |       }); | ||
|  |     }); | ||
|  |     scaleSelect.addEventListener("change", function () { | ||
|  |       if (this.value === "custom") { | ||
|  |         return; | ||
|  |       } | ||
|  |       eventBus.dispatch("scalechanged", { | ||
|  |         source: self, | ||
|  |         value: this.value | ||
|  |       }); | ||
|  |     }); | ||
|  |     scaleSelect.addEventListener("click", function ({ | ||
|  |       target | ||
|  |     }) { | ||
|  |       if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") { | ||
|  |         this.blur(); | ||
|  |       } | ||
|  |     }); | ||
|  |     scaleSelect.oncontextmenu = noContextMenu; | ||
|  |     eventBus._on("annotationeditormodechanged", this.#editorModeChanged.bind(this)); | ||
|  |     eventBus._on("showannotationeditorui", ({ | ||
|  |       mode | ||
|  |     }) => { | ||
|  |       switch (mode) { | ||
|  |         case AnnotationEditorType.HIGHLIGHT: | ||
|  |           editorHighlightButton.click(); | ||
|  |           break; | ||
|  |       } | ||
|  |     }); | ||
|  |     eventBus._on("toolbardensity", this.#updateToolbarDensity.bind(this)); | ||
|  |     if (editorHighlightColorPicker) { | ||
|  |       eventBus._on("annotationeditoruimanager", ({ | ||
|  |         uiManager | ||
|  |       }) => { | ||
|  |         this.#setAnnotationEditorUIManager(uiManager, editorHighlightColorPicker); | ||
|  |       }, { | ||
|  |         once: true | ||
|  |       }); | ||
|  |     } | ||
|  |   } | ||
|  |   #editorModeChanged({ | ||
|  |     mode | ||
|  |   }) { | ||
|  |     const { | ||
|  |       editorFreeTextButton, | ||
|  |       editorFreeTextParamsToolbar, | ||
|  |       editorHighlightButton, | ||
|  |       editorHighlightParamsToolbar, | ||
|  |       editorInkButton, | ||
|  |       editorInkParamsToolbar, | ||
|  |       editorStampButton, | ||
|  |       editorStampParamsToolbar | ||
|  |     } = this.#opts; | ||
|  |     toggleCheckedBtn(editorFreeTextButton, mode === AnnotationEditorType.FREETEXT, editorFreeTextParamsToolbar); | ||
|  |     toggleCheckedBtn(editorHighlightButton, mode === AnnotationEditorType.HIGHLIGHT, editorHighlightParamsToolbar); | ||
|  |     toggleCheckedBtn(editorInkButton, mode === AnnotationEditorType.INK, editorInkParamsToolbar); | ||
|  |     toggleCheckedBtn(editorStampButton, mode === AnnotationEditorType.STAMP, editorStampParamsToolbar); | ||
|  |     const isDisable = mode === AnnotationEditorType.DISABLE; | ||
|  |     editorFreeTextButton.disabled = isDisable; | ||
|  |     editorHighlightButton.disabled = isDisable; | ||
|  |     editorInkButton.disabled = isDisable; | ||
|  |     editorStampButton.disabled = isDisable; | ||
|  |   } | ||
|  |   #updateUIState(resetNumPages = false) { | ||
|  |     const { | ||
|  |       pageNumber, | ||
|  |       pagesCount, | ||
|  |       pageScaleValue, | ||
|  |       pageScale | ||
|  |     } = this; | ||
|  |     const opts = this.#opts; | ||
|  |     if (resetNumPages) { | ||
|  |       if (this.hasPageLabels) { | ||
|  |         opts.pageNumber.type = "text"; | ||
|  |         opts.numPages.setAttribute("data-l10n-id", "pdfjs-page-of-pages"); | ||
|  |       } else { | ||
|  |         opts.pageNumber.type = "number"; | ||
|  |         opts.numPages.setAttribute("data-l10n-id", "pdfjs-of-pages"); | ||
|  |         opts.numPages.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |           pagesCount | ||
|  |         })); | ||
|  |       } | ||
|  |       opts.pageNumber.max = pagesCount; | ||
|  |     } | ||
|  |     if (this.hasPageLabels) { | ||
|  |       opts.pageNumber.value = this.pageLabel; | ||
|  |       opts.numPages.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |         pageNumber, | ||
|  |         pagesCount | ||
|  |       })); | ||
|  |     } else { | ||
|  |       opts.pageNumber.value = pageNumber; | ||
|  |     } | ||
|  |     opts.previous.disabled = pageNumber <= 1; | ||
|  |     opts.next.disabled = pageNumber >= pagesCount; | ||
|  |     opts.zoomOut.disabled = pageScale <= MIN_SCALE; | ||
|  |     opts.zoomIn.disabled = pageScale >= MAX_SCALE; | ||
|  |     let predefinedValueFound = false; | ||
|  |     for (const option of opts.scaleSelect.options) { | ||
|  |       if (option.value !== pageScaleValue) { | ||
|  |         option.selected = false; | ||
|  |         continue; | ||
|  |       } | ||
|  |       option.selected = true; | ||
|  |       predefinedValueFound = true; | ||
|  |     } | ||
|  |     if (!predefinedValueFound) { | ||
|  |       opts.customScaleOption.selected = true; | ||
|  |       opts.customScaleOption.setAttribute("data-l10n-args", JSON.stringify({ | ||
|  |         scale: Math.round(pageScale * 10000) / 100 | ||
|  |       })); | ||
|  |     } | ||
|  |   } | ||
|  |   updateLoadingIndicatorState(loading = false) { | ||
|  |     const { | ||
|  |       pageNumber | ||
|  |     } = this.#opts; | ||
|  |     pageNumber.classList.toggle("loading", loading); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/view_history.js
 | ||
|  | const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20; | ||
|  | class ViewHistory { | ||
|  |   constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) { | ||
|  |     this.fingerprint = fingerprint; | ||
|  |     this.cacheSize = cacheSize; | ||
|  |     this._initializedPromise = this._readFromStorage().then(databaseStr => { | ||
|  |       const database = JSON.parse(databaseStr || "{}"); | ||
|  |       let index = -1; | ||
|  |       if (!Array.isArray(database.files)) { | ||
|  |         database.files = []; | ||
|  |       } else { | ||
|  |         while (database.files.length >= this.cacheSize) { | ||
|  |           database.files.shift(); | ||
|  |         } | ||
|  |         for (let i = 0, ii = database.files.length; i < ii; i++) { | ||
|  |           const branch = database.files[i]; | ||
|  |           if (branch.fingerprint === this.fingerprint) { | ||
|  |             index = i; | ||
|  |             break; | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |       if (index === -1) { | ||
|  |         index = database.files.push({ | ||
|  |           fingerprint: this.fingerprint | ||
|  |         }) - 1; | ||
|  |       } | ||
|  |       this.file = database.files[index]; | ||
|  |       this.database = database; | ||
|  |     }); | ||
|  |   } | ||
|  |   async _writeToStorage() { | ||
|  |     const databaseStr = JSON.stringify(this.database); | ||
|  |     localStorage.setItem("pdfjs.history", databaseStr); | ||
|  |   } | ||
|  |   async _readFromStorage() { | ||
|  |     return localStorage.getItem("pdfjs.history"); | ||
|  |   } | ||
|  |   async set(name, val) { | ||
|  |     await this._initializedPromise; | ||
|  |     this.file[name] = val; | ||
|  |     return this._writeToStorage(); | ||
|  |   } | ||
|  |   async setMultiple(properties) { | ||
|  |     await this._initializedPromise; | ||
|  |     for (const name in properties) { | ||
|  |       this.file[name] = properties[name]; | ||
|  |     } | ||
|  |     return this._writeToStorage(); | ||
|  |   } | ||
|  |   async get(name, defaultValue) { | ||
|  |     await this._initializedPromise; | ||
|  |     const val = this.file[name]; | ||
|  |     return val !== undefined ? val : defaultValue; | ||
|  |   } | ||
|  |   async getMultiple(properties) { | ||
|  |     await this._initializedPromise; | ||
|  |     const values = Object.create(null); | ||
|  |     for (const name in properties) { | ||
|  |       const val = this.file[name]; | ||
|  |       values[name] = val !== undefined ? val : properties[name]; | ||
|  |     } | ||
|  |     return values; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/app.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const FORCE_PAGES_LOADED_TIMEOUT = 10000; | ||
|  | const ViewOnLoad = { | ||
|  |   UNKNOWN: -1, | ||
|  |   PREVIOUS: 0, | ||
|  |   INITIAL: 1 | ||
|  | }; | ||
|  | const PDFViewerApplication = { | ||
|  |   initialBookmark: document.location.hash.substring(1), | ||
|  |   _initializedCapability: { | ||
|  |     ...Promise.withResolvers(), | ||
|  |     settled: false | ||
|  |   }, | ||
|  |   appConfig: null, | ||
|  |   pdfDocument: null, | ||
|  |   pdfLoadingTask: null, | ||
|  |   printService: null, | ||
|  |   pdfViewer: null, | ||
|  |   pdfThumbnailViewer: null, | ||
|  |   pdfRenderingQueue: null, | ||
|  |   pdfPresentationMode: null, | ||
|  |   pdfDocumentProperties: null, | ||
|  |   pdfLinkService: null, | ||
|  |   pdfHistory: null, | ||
|  |   pdfSidebar: null, | ||
|  |   pdfOutlineViewer: null, | ||
|  |   pdfAttachmentViewer: null, | ||
|  |   pdfLayerViewer: null, | ||
|  |   pdfCursorTools: null, | ||
|  |   pdfScriptingManager: null, | ||
|  |   store: null, | ||
|  |   downloadManager: null, | ||
|  |   overlayManager: null, | ||
|  |   preferences: new Preferences(), | ||
|  |   toolbar: null, | ||
|  |   secondaryToolbar: null, | ||
|  |   eventBus: null, | ||
|  |   l10n: null, | ||
|  |   annotationEditorParams: null, | ||
|  |   imageAltTextSettings: null, | ||
|  |   isInitialViewSet: false, | ||
|  |   isViewerEmbedded: window.parent !== window, | ||
|  |   url: "", | ||
|  |   baseUrl: "", | ||
|  |   mlManager: null, | ||
|  |   _downloadUrl: "", | ||
|  |   _eventBusAbortController: null, | ||
|  |   _windowAbortController: null, | ||
|  |   _globalAbortController: new AbortController(), | ||
|  |   documentInfo: null, | ||
|  |   metadata: null, | ||
|  |   _contentDispositionFilename: null, | ||
|  |   _contentLength: null, | ||
|  |   _saveInProgress: false, | ||
|  |   _wheelUnusedTicks: 0, | ||
|  |   _wheelUnusedFactor: 1, | ||
|  |   _touchUnusedTicks: 0, | ||
|  |   _touchUnusedFactor: 1, | ||
|  |   _PDFBug: null, | ||
|  |   _hasAnnotationEditors: false, | ||
|  |   _title: document.title, | ||
|  |   _printAnnotationStoragePromise: null, | ||
|  |   _touchInfo: null, | ||
|  |   _isCtrlKeyDown: false, | ||
|  |   _caretBrowsing: null, | ||
|  |   _isScrolling: false, | ||
|  |   async initialize(appConfig) { | ||
|  |     this.appConfig = appConfig; | ||
|  |     try { | ||
|  |       await this.preferences.initializedPromise; | ||
|  |     } catch (ex) { | ||
|  |       console.error(`initialize: "${ex.message}".`); | ||
|  |     } | ||
|  |     if (AppOptions.get("pdfBugEnabled")) { | ||
|  |       await this._parseHashParams(); | ||
|  |     } | ||
|  |     let mode; | ||
|  |     switch (AppOptions.get("viewerCssTheme")) { | ||
|  |       case 1: | ||
|  |         mode = "is-light"; | ||
|  |         break; | ||
|  |       case 2: | ||
|  |         mode = "is-dark"; | ||
|  |         break; | ||
|  |     } | ||
|  |     if (mode) { | ||
|  |       document.documentElement.classList.add(mode); | ||
|  |     } | ||
|  |     this.l10n = await this.externalServices.createL10n(); | ||
|  |     document.getElementsByTagName("html")[0].dir = this.l10n.getDirection(); | ||
|  |     this.l10n.translate(appConfig.appContainer || document.documentElement); | ||
|  |     if (this.isViewerEmbedded && AppOptions.get("externalLinkTarget") === LinkTarget.NONE) { | ||
|  |       AppOptions.set("externalLinkTarget", LinkTarget.TOP); | ||
|  |     } | ||
|  |     await this._initializeViewerComponents(); | ||
|  |     this.bindEvents(); | ||
|  |     this.bindWindowEvents(); | ||
|  |     this._initializedCapability.settled = true; | ||
|  |     this._initializedCapability.resolve(); | ||
|  |   }, | ||
|  |   async _parseHashParams() { | ||
|  |     const hash = document.location.hash.substring(1); | ||
|  |     if (!hash) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |         mainContainer, | ||
|  |         viewerContainer | ||
|  |       } = this.appConfig, | ||
|  |       params = parseQueryString(hash); | ||
|  |     const loadPDFBug = async () => { | ||
|  |       if (this._PDFBug) { | ||
|  |         return; | ||
|  |       } | ||
|  |       const { | ||
|  |         PDFBug | ||
|  |       } = await import( /*webpackIgnore: true*/AppOptions.get("debuggerSrc")); | ||
|  |       this._PDFBug = PDFBug; | ||
|  |     }; | ||
|  |     if (params.get("disableworker") === "true") { | ||
|  |       try { | ||
|  |         GlobalWorkerOptions.workerSrc ||= AppOptions.get("workerSrc"); | ||
|  |         await import( /*webpackIgnore: true*/PDFWorker.workerSrc); | ||
|  |       } catch (ex) { | ||
|  |         console.error(`_parseHashParams: "${ex.message}".`); | ||
|  |       } | ||
|  |     } | ||
|  |     if (params.has("textlayer")) { | ||
|  |       switch (params.get("textlayer")) { | ||
|  |         case "off": | ||
|  |           AppOptions.set("textLayerMode", TextLayerMode.DISABLE); | ||
|  |           break; | ||
|  |         case "visible": | ||
|  |         case "shadow": | ||
|  |         case "hover": | ||
|  |           viewerContainer.classList.add(`textLayer-${params.get("textlayer")}`); | ||
|  |           try { | ||
|  |             await loadPDFBug(); | ||
|  |             this._PDFBug.loadCSS(); | ||
|  |           } catch (ex) { | ||
|  |             console.error(`_parseHashParams: "${ex.message}".`); | ||
|  |           } | ||
|  |           break; | ||
|  |       } | ||
|  |     } | ||
|  |     if (params.has("pdfbug")) { | ||
|  |       AppOptions.setAll({ | ||
|  |         pdfBug: true, | ||
|  |         fontExtraProperties: true | ||
|  |       }); | ||
|  |       const enabled = params.get("pdfbug").split(","); | ||
|  |       try { | ||
|  |         await loadPDFBug(); | ||
|  |         this._PDFBug.init(mainContainer, enabled); | ||
|  |       } catch (ex) { | ||
|  |         console.error(`_parseHashParams: "${ex.message}".`); | ||
|  |       } | ||
|  |     } | ||
|  |     if (params.has("locale")) { | ||
|  |       AppOptions.set("localeProperties", { | ||
|  |         lang: params.get("locale") | ||
|  |       }); | ||
|  |     } | ||
|  |     const opts = { | ||
|  |       disableAutoFetch: x => x === "true", | ||
|  |       disableFontFace: x => x === "true", | ||
|  |       disableHistory: x => x === "true", | ||
|  |       disableRange: x => x === "true", | ||
|  |       disableStream: x => x === "true", | ||
|  |       verbosity: x => x | 0 | ||
|  |     }; | ||
|  |     for (const name in opts) { | ||
|  |       const check = opts[name], | ||
|  |         key = name.toLowerCase(); | ||
|  |       if (params.has(key)) { | ||
|  |         AppOptions.set(name, check(params.get(key))); | ||
|  |       } | ||
|  |     } | ||
|  |   }, | ||
|  |   async _initializeViewerComponents() { | ||
|  |     const { | ||
|  |       appConfig, | ||
|  |       externalServices, | ||
|  |       l10n | ||
|  |     } = this; | ||
|  |     let eventBus; | ||
|  |     eventBus = new EventBus(); | ||
|  |     this.mlManager?.setEventBus(eventBus, this._globalAbortController.signal); | ||
|  |     this.eventBus = eventBus; | ||
|  |     this.overlayManager = new OverlayManager(); | ||
|  |     const pdfRenderingQueue = new PDFRenderingQueue(); | ||
|  |     pdfRenderingQueue.onIdle = this._cleanup.bind(this); | ||
|  |     this.pdfRenderingQueue = pdfRenderingQueue; | ||
|  |     const pdfLinkService = new PDFLinkService({ | ||
|  |       eventBus, | ||
|  |       externalLinkTarget: AppOptions.get("externalLinkTarget"), | ||
|  |       externalLinkRel: AppOptions.get("externalLinkRel"), | ||
|  |       ignoreDestinationZoom: AppOptions.get("ignoreDestinationZoom") | ||
|  |     }); | ||
|  |     this.pdfLinkService = pdfLinkService; | ||
|  |     const downloadManager = this.downloadManager = new DownloadManager(); | ||
|  |     const findController = new PDFFindController({ | ||
|  |       linkService: pdfLinkService, | ||
|  |       eventBus, | ||
|  |       updateMatchesCountOnProgress: true | ||
|  |     }); | ||
|  |     this.findController = findController; | ||
|  |     const pdfScriptingManager = new PDFScriptingManager({ | ||
|  |       eventBus, | ||
|  |       externalServices, | ||
|  |       docProperties: this._scriptingDocProperties.bind(this) | ||
|  |     }); | ||
|  |     this.pdfScriptingManager = pdfScriptingManager; | ||
|  |     const container = appConfig.mainContainer, | ||
|  |       viewer = appConfig.viewerContainer; | ||
|  |     const annotationEditorMode = AppOptions.get("annotationEditorMode"); | ||
|  |     const pageColors = AppOptions.get("forcePageColors") || window.matchMedia("(forced-colors: active)").matches ? { | ||
|  |       background: AppOptions.get("pageColorsBackground"), | ||
|  |       foreground: AppOptions.get("pageColorsForeground") | ||
|  |     } : null; | ||
|  |     let altTextManager; | ||
|  |     if (AppOptions.get("enableUpdatedAddImage")) { | ||
|  |       altTextManager = appConfig.newAltTextDialog ? new NewAltTextManager(appConfig.newAltTextDialog, this.overlayManager, eventBus) : null; | ||
|  |     } else { | ||
|  |       altTextManager = appConfig.altTextDialog ? new AltTextManager(appConfig.altTextDialog, container, this.overlayManager, eventBus) : null; | ||
|  |     } | ||
|  |     const enableHWA = AppOptions.get("enableHWA"); | ||
|  |     const pdfViewer = new PDFViewer({ | ||
|  |       container, | ||
|  |       viewer, | ||
|  |       eventBus, | ||
|  |       renderingQueue: pdfRenderingQueue, | ||
|  |       linkService: pdfLinkService, | ||
|  |       downloadManager, | ||
|  |       altTextManager, | ||
|  |       findController, | ||
|  |       scriptingManager: AppOptions.get("enableScripting") && pdfScriptingManager, | ||
|  |       l10n, | ||
|  |       textLayerMode: AppOptions.get("textLayerMode"), | ||
|  |       annotationMode: AppOptions.get("annotationMode"), | ||
|  |       annotationEditorMode, | ||
|  |       annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"), | ||
|  |       enableHighlightFloatingButton: AppOptions.get("enableHighlightFloatingButton"), | ||
|  |       enableUpdatedAddImage: AppOptions.get("enableUpdatedAddImage"), | ||
|  |       enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage"), | ||
|  |       imageResourcesPath: AppOptions.get("imageResourcesPath"), | ||
|  |       enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"), | ||
|  |       maxCanvasPixels: AppOptions.get("maxCanvasPixels"), | ||
|  |       enablePermissions: AppOptions.get("enablePermissions"), | ||
|  |       pageColors, | ||
|  |       mlManager: this.mlManager, | ||
|  |       abortSignal: this._globalAbortController.signal, | ||
|  |       enableHWA | ||
|  |     }); | ||
|  |     this.pdfViewer = pdfViewer; | ||
|  |     pdfRenderingQueue.setViewer(pdfViewer); | ||
|  |     pdfLinkService.setViewer(pdfViewer); | ||
|  |     pdfScriptingManager.setViewer(pdfViewer); | ||
|  |     if (appConfig.sidebar?.thumbnailView) { | ||
|  |       this.pdfThumbnailViewer = new PDFThumbnailViewer({ | ||
|  |         container: appConfig.sidebar.thumbnailView, | ||
|  |         eventBus, | ||
|  |         renderingQueue: pdfRenderingQueue, | ||
|  |         linkService: pdfLinkService, | ||
|  |         pageColors, | ||
|  |         abortSignal: this._globalAbortController.signal, | ||
|  |         enableHWA | ||
|  |       }); | ||
|  |       pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); | ||
|  |     } | ||
|  |     if (!this.isViewerEmbedded && !AppOptions.get("disableHistory")) { | ||
|  |       this.pdfHistory = new PDFHistory({ | ||
|  |         linkService: pdfLinkService, | ||
|  |         eventBus | ||
|  |       }); | ||
|  |       pdfLinkService.setHistory(this.pdfHistory); | ||
|  |     } | ||
|  |     if (!this.supportsIntegratedFind && appConfig.findBar) { | ||
|  |       this.findBar = new PDFFindBar(appConfig.findBar, eventBus); | ||
|  |     } | ||
|  |     if (appConfig.annotationEditorParams) { | ||
|  |       if (typeof AbortSignal.any === "function" && annotationEditorMode !== AnnotationEditorType.DISABLE) { | ||
|  |         this.annotationEditorParams = new AnnotationEditorParams(appConfig.annotationEditorParams, eventBus); | ||
|  |       } else { | ||
|  |         for (const id of ["editorModeButtons", "editorModeSeparator"]) { | ||
|  |           document.getElementById(id)?.classList.add("hidden"); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     if (this.mlManager && appConfig.secondaryToolbar?.imageAltTextSettingsButton) { | ||
|  |       this.imageAltTextSettings = new ImageAltTextSettings(appConfig.altTextSettingsDialog, this.overlayManager, eventBus, this.mlManager); | ||
|  |     } | ||
|  |     if (appConfig.documentProperties) { | ||
|  |       this.pdfDocumentProperties = new PDFDocumentProperties(appConfig.documentProperties, this.overlayManager, eventBus, l10n, () => this._docFilename); | ||
|  |     } | ||
|  |     if (appConfig.secondaryToolbar?.cursorHandToolButton) { | ||
|  |       this.pdfCursorTools = new PDFCursorTools({ | ||
|  |         container, | ||
|  |         eventBus, | ||
|  |         cursorToolOnLoad: AppOptions.get("cursorToolOnLoad") | ||
|  |       }); | ||
|  |     } | ||
|  |     if (appConfig.toolbar) { | ||
|  |       this.toolbar = new Toolbar(appConfig.toolbar, eventBus, AppOptions.get("toolbarDensity")); | ||
|  |     } | ||
|  |     if (appConfig.secondaryToolbar) { | ||
|  |       if (AppOptions.get("enableAltText")) { | ||
|  |         appConfig.secondaryToolbar.imageAltTextSettingsButton?.classList.remove("hidden"); | ||
|  |         appConfig.secondaryToolbar.imageAltTextSettingsSeparator?.classList.remove("hidden"); | ||
|  |       } | ||
|  |       this.secondaryToolbar = new SecondaryToolbar(appConfig.secondaryToolbar, eventBus); | ||
|  |     } | ||
|  |     if (this.supportsFullscreen && appConfig.secondaryToolbar?.presentationModeButton) { | ||
|  |       this.pdfPresentationMode = new PDFPresentationMode({ | ||
|  |         container, | ||
|  |         pdfViewer, | ||
|  |         eventBus | ||
|  |       }); | ||
|  |     } | ||
|  |     if (appConfig.passwordOverlay) { | ||
|  |       this.passwordPrompt = new PasswordPrompt(appConfig.passwordOverlay, this.overlayManager, this.isViewerEmbedded); | ||
|  |     } | ||
|  |     if (appConfig.sidebar?.outlineView) { | ||
|  |       this.pdfOutlineViewer = new PDFOutlineViewer({ | ||
|  |         container: appConfig.sidebar.outlineView, | ||
|  |         eventBus, | ||
|  |         l10n, | ||
|  |         linkService: pdfLinkService, | ||
|  |         downloadManager | ||
|  |       }); | ||
|  |     } | ||
|  |     if (appConfig.sidebar?.attachmentsView) { | ||
|  |       this.pdfAttachmentViewer = new PDFAttachmentViewer({ | ||
|  |         container: appConfig.sidebar.attachmentsView, | ||
|  |         eventBus, | ||
|  |         l10n, | ||
|  |         downloadManager | ||
|  |       }); | ||
|  |     } | ||
|  |     if (appConfig.sidebar?.layersView) { | ||
|  |       this.pdfLayerViewer = new PDFLayerViewer({ | ||
|  |         container: appConfig.sidebar.layersView, | ||
|  |         eventBus, | ||
|  |         l10n | ||
|  |       }); | ||
|  |     } | ||
|  |     if (appConfig.sidebar) { | ||
|  |       this.pdfSidebar = new PDFSidebar({ | ||
|  |         elements: appConfig.sidebar, | ||
|  |         eventBus, | ||
|  |         l10n | ||
|  |       }); | ||
|  |       this.pdfSidebar.onToggled = this.forceRendering.bind(this); | ||
|  |       this.pdfSidebar.onUpdateThumbnails = () => { | ||
|  |         for (const pageView of pdfViewer.getCachedPageViews()) { | ||
|  |           if (pageView.renderingState === RenderingStates.FINISHED) { | ||
|  |             this.pdfThumbnailViewer.getThumbnail(pageView.id - 1)?.setImage(pageView); | ||
|  |           } | ||
|  |         } | ||
|  |         this.pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); | ||
|  |       }; | ||
|  |     } | ||
|  |   }, | ||
|  |   async run(config) { | ||
|  |     await this.initialize(config); | ||
|  |     const { | ||
|  |       appConfig, | ||
|  |       eventBus | ||
|  |     } = this; | ||
|  |     let file; | ||
|  |     const queryString = document.location.search.substring(1); | ||
|  |     const params = parseQueryString(queryString); | ||
|  |     file = params.get("file") ?? AppOptions.get("defaultUrl"); | ||
|  |     validateFileURL(file); | ||
|  |     const fileInput = this._openFileInput = document.createElement("input"); | ||
|  |     fileInput.id = "fileInput"; | ||
|  |     fileInput.hidden = true; | ||
|  |     fileInput.type = "file"; | ||
|  |     fileInput.value = null; | ||
|  |     document.body.append(fileInput); | ||
|  |     fileInput.addEventListener("change", function (evt) { | ||
|  |       const { | ||
|  |         files | ||
|  |       } = evt.target; | ||
|  |       if (!files || files.length === 0) { | ||
|  |         return; | ||
|  |       } | ||
|  |       eventBus.dispatch("fileinputchange", { | ||
|  |         source: this, | ||
|  |         fileInput: evt.target | ||
|  |       }); | ||
|  |     }); | ||
|  |     appConfig.mainContainer.addEventListener("dragover", function (evt) { | ||
|  |       for (const item of evt.dataTransfer.items) { | ||
|  |         if (item.type === "application/pdf") { | ||
|  |           evt.dataTransfer.dropEffect = evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move"; | ||
|  |           evt.preventDefault(); | ||
|  |           evt.stopPropagation(); | ||
|  |           return; | ||
|  |         } | ||
|  |       } | ||
|  |     }); | ||
|  |     appConfig.mainContainer.addEventListener("drop", function (evt) { | ||
|  |       if (evt.dataTransfer.files?.[0].type !== "application/pdf") { | ||
|  |         return; | ||
|  |       } | ||
|  |       evt.preventDefault(); | ||
|  |       evt.stopPropagation(); | ||
|  |       eventBus.dispatch("fileinputchange", { | ||
|  |         source: this, | ||
|  |         fileInput: evt.dataTransfer | ||
|  |       }); | ||
|  |     }); | ||
|  |     if (!AppOptions.get("supportsDocumentFonts")) { | ||
|  |       AppOptions.set("disableFontFace", true); | ||
|  |       this.l10n.get("pdfjs-web-fonts-disabled").then(msg => { | ||
|  |         console.warn(msg); | ||
|  |       }); | ||
|  |     } | ||
|  |     if (!this.supportsPrinting) { | ||
|  |       appConfig.toolbar?.print?.classList.add("hidden"); | ||
|  |       appConfig.secondaryToolbar?.printButton.classList.add("hidden"); | ||
|  |     } | ||
|  |     if (!this.supportsFullscreen) { | ||
|  |       appConfig.secondaryToolbar?.presentationModeButton.classList.add("hidden"); | ||
|  |     } | ||
|  |     if (this.supportsIntegratedFind) { | ||
|  |       appConfig.findBar?.toggleButton?.classList.add("hidden"); | ||
|  |     } | ||
|  |     if (file) { | ||
|  |       this.open({ | ||
|  |         url: file | ||
|  |       }); | ||
|  |     } else { | ||
|  |       this._hideViewBookmark(); | ||
|  |     } | ||
|  |   }, | ||
|  |   get externalServices() { | ||
|  |     return shadow(this, "externalServices", new ExternalServices()); | ||
|  |   }, | ||
|  |   get initialized() { | ||
|  |     return this._initializedCapability.settled; | ||
|  |   }, | ||
|  |   get initializedPromise() { | ||
|  |     return this._initializedCapability.promise; | ||
|  |   }, | ||
|  |   updateZoom(steps, scaleFactor, origin) { | ||
|  |     if (this.pdfViewer.isInPresentationMode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.pdfViewer.updateScale({ | ||
|  |       drawingDelay: AppOptions.get("defaultZoomDelay"), | ||
|  |       steps, | ||
|  |       scaleFactor, | ||
|  |       origin | ||
|  |     }); | ||
|  |   }, | ||
|  |   zoomIn() { | ||
|  |     this.updateZoom(1); | ||
|  |   }, | ||
|  |   zoomOut() { | ||
|  |     this.updateZoom(-1); | ||
|  |   }, | ||
|  |   zoomReset() { | ||
|  |     if (this.pdfViewer.isInPresentationMode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE; | ||
|  |   }, | ||
|  |   get pagesCount() { | ||
|  |     return this.pdfDocument ? this.pdfDocument.numPages : 0; | ||
|  |   }, | ||
|  |   get page() { | ||
|  |     return this.pdfViewer.currentPageNumber; | ||
|  |   }, | ||
|  |   set page(val) { | ||
|  |     this.pdfViewer.currentPageNumber = val; | ||
|  |   }, | ||
|  |   get supportsPrinting() { | ||
|  |     return PDFPrintServiceFactory.supportsPrinting; | ||
|  |   }, | ||
|  |   get supportsFullscreen() { | ||
|  |     return shadow(this, "supportsFullscreen", document.fullscreenEnabled); | ||
|  |   }, | ||
|  |   get supportsPinchToZoom() { | ||
|  |     return shadow(this, "supportsPinchToZoom", AppOptions.get("supportsPinchToZoom")); | ||
|  |   }, | ||
|  |   get supportsIntegratedFind() { | ||
|  |     return shadow(this, "supportsIntegratedFind", AppOptions.get("supportsIntegratedFind")); | ||
|  |   }, | ||
|  |   get loadingBar() { | ||
|  |     const barElement = document.getElementById("loadingBar"); | ||
|  |     const bar = barElement ? new ProgressBar(barElement) : null; | ||
|  |     return shadow(this, "loadingBar", bar); | ||
|  |   }, | ||
|  |   get supportsMouseWheelZoomCtrlKey() { | ||
|  |     return shadow(this, "supportsMouseWheelZoomCtrlKey", AppOptions.get("supportsMouseWheelZoomCtrlKey")); | ||
|  |   }, | ||
|  |   get supportsMouseWheelZoomMetaKey() { | ||
|  |     return shadow(this, "supportsMouseWheelZoomMetaKey", AppOptions.get("supportsMouseWheelZoomMetaKey")); | ||
|  |   }, | ||
|  |   get supportsCaretBrowsingMode() { | ||
|  |     return AppOptions.get("supportsCaretBrowsingMode"); | ||
|  |   }, | ||
|  |   moveCaret(isUp, select) { | ||
|  |     this._caretBrowsing ||= new CaretBrowsingMode(this.appConfig.mainContainer, this.appConfig.viewerContainer, this.appConfig.toolbar?.container); | ||
|  |     this._caretBrowsing.moveCaret(isUp, select); | ||
|  |   }, | ||
|  |   setTitleUsingUrl(url = "", downloadUrl = null) { | ||
|  |     this.url = url; | ||
|  |     this.baseUrl = url.split("#", 1)[0]; | ||
|  |     if (downloadUrl) { | ||
|  |       this._downloadUrl = downloadUrl === url ? this.baseUrl : downloadUrl.split("#", 1)[0]; | ||
|  |     } | ||
|  |     if (isDataScheme(url)) { | ||
|  |       this._hideViewBookmark(); | ||
|  |     } | ||
|  |     let title = pdfjs_getPdfFilenameFromUrl(url, ""); | ||
|  |     if (!title) { | ||
|  |       try { | ||
|  |         title = decodeURIComponent(getFilenameFromUrl(url)); | ||
|  |       } catch {} | ||
|  |     } | ||
|  |     this.setTitle(title || url); | ||
|  |   }, | ||
|  |   setTitle(title = this._title) { | ||
|  |     this._title = title; | ||
|  |     if (this.isViewerEmbedded) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const editorIndicator = this._hasAnnotationEditors && !this.pdfRenderingQueue.printing; | ||
|  |     document.title = `${editorIndicator ? "* " : ""}${title}`; | ||
|  |   }, | ||
|  |   get _docFilename() { | ||
|  |     return this._contentDispositionFilename || pdfjs_getPdfFilenameFromUrl(this.url); | ||
|  |   }, | ||
|  |   _hideViewBookmark() { | ||
|  |     const { | ||
|  |       secondaryToolbar | ||
|  |     } = this.appConfig; | ||
|  |     secondaryToolbar?.viewBookmarkButton.classList.add("hidden"); | ||
|  |     if (secondaryToolbar?.presentationModeButton.classList.contains("hidden")) { | ||
|  |       document.getElementById("viewBookmarkSeparator")?.classList.add("hidden"); | ||
|  |     } | ||
|  |   }, | ||
|  |   async close() { | ||
|  |     this._unblockDocumentLoadEvent(); | ||
|  |     this._hideViewBookmark(); | ||
|  |     if (!this.pdfLoadingTask) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (this.pdfDocument?.annotationStorage.size > 0 && this._annotationStorageModified) { | ||
|  |       try { | ||
|  |         await this.save(); | ||
|  |       } catch {} | ||
|  |     } | ||
|  |     const promises = []; | ||
|  |     promises.push(this.pdfLoadingTask.destroy()); | ||
|  |     this.pdfLoadingTask = null; | ||
|  |     if (this.pdfDocument) { | ||
|  |       this.pdfDocument = null; | ||
|  |       this.pdfThumbnailViewer?.setDocument(null); | ||
|  |       this.pdfViewer.setDocument(null); | ||
|  |       this.pdfLinkService.setDocument(null); | ||
|  |       this.pdfDocumentProperties?.setDocument(null); | ||
|  |     } | ||
|  |     this.pdfLinkService.externalLinkEnabled = true; | ||
|  |     this.store = null; | ||
|  |     this.isInitialViewSet = false; | ||
|  |     this.url = ""; | ||
|  |     this.baseUrl = ""; | ||
|  |     this._downloadUrl = ""; | ||
|  |     this.documentInfo = null; | ||
|  |     this.metadata = null; | ||
|  |     this._contentDispositionFilename = null; | ||
|  |     this._contentLength = null; | ||
|  |     this._saveInProgress = false; | ||
|  |     this._hasAnnotationEditors = false; | ||
|  |     promises.push(this.pdfScriptingManager.destroyPromise, this.passwordPrompt.close()); | ||
|  |     this.setTitle(); | ||
|  |     this.pdfSidebar?.reset(); | ||
|  |     this.pdfOutlineViewer?.reset(); | ||
|  |     this.pdfAttachmentViewer?.reset(); | ||
|  |     this.pdfLayerViewer?.reset(); | ||
|  |     this.pdfHistory?.reset(); | ||
|  |     this.findBar?.reset(); | ||
|  |     this.toolbar?.reset(); | ||
|  |     this.secondaryToolbar?.reset(); | ||
|  |     this._PDFBug?.cleanup(); | ||
|  |     await Promise.all(promises); | ||
|  |   }, | ||
|  |   async open(args) { | ||
|  |     if (this.pdfLoadingTask) { | ||
|  |       await this.close(); | ||
|  |     } | ||
|  |     const workerParams = AppOptions.getAll(OptionKind.WORKER); | ||
|  |     Object.assign(GlobalWorkerOptions, workerParams); | ||
|  |     if (args.url) { | ||
|  |       this.setTitleUsingUrl(args.originalUrl || args.url, args.url); | ||
|  |     } | ||
|  |     const apiParams = AppOptions.getAll(OptionKind.API); | ||
|  |     const loadingTask = getDocument({ | ||
|  |       ...apiParams, | ||
|  |       ...args | ||
|  |     }); | ||
|  |     this.pdfLoadingTask = loadingTask; | ||
|  |     loadingTask.onPassword = (updateCallback, reason) => { | ||
|  |       if (this.isViewerEmbedded) { | ||
|  |         this._unblockDocumentLoadEvent(); | ||
|  |       } | ||
|  |       this.pdfLinkService.externalLinkEnabled = false; | ||
|  |       this.passwordPrompt.setUpdateCallback(updateCallback, reason); | ||
|  |       this.passwordPrompt.open(); | ||
|  |     }; | ||
|  |     loadingTask.onProgress = ({ | ||
|  |       loaded, | ||
|  |       total | ||
|  |     }) => { | ||
|  |       this.progress(loaded / total); | ||
|  |     }; | ||
|  |     return loadingTask.promise.then(pdfDocument => { | ||
|  |       this.load(pdfDocument); | ||
|  |     }, reason => { | ||
|  |       if (loadingTask !== this.pdfLoadingTask) { | ||
|  |         return undefined; | ||
|  |       } | ||
|  |       let key = "pdfjs-loading-error"; | ||
|  |       if (reason instanceof InvalidPDFException) { | ||
|  |         key = "pdfjs-invalid-file-error"; | ||
|  |       } else if (reason instanceof MissingPDFException) { | ||
|  |         key = "pdfjs-missing-file-error"; | ||
|  |       } else if (reason instanceof UnexpectedResponseException) { | ||
|  |         key = "pdfjs-unexpected-response-error"; | ||
|  |       } | ||
|  |       return this._documentError(key, { | ||
|  |         message: reason.message | ||
|  |       }).then(() => { | ||
|  |         throw reason; | ||
|  |       }); | ||
|  |     }); | ||
|  |   }, | ||
|  |   async download() { | ||
|  |     let data; | ||
|  |     try { | ||
|  |       data = await this.pdfDocument.getData(); | ||
|  |     } catch {} | ||
|  |     this.downloadManager.download(data, this._downloadUrl, this._docFilename); | ||
|  |   }, | ||
|  |   async save() { | ||
|  |     if (this._saveInProgress) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._saveInProgress = true; | ||
|  |     await this.pdfScriptingManager.dispatchWillSave(); | ||
|  |     try { | ||
|  |       const data = await this.pdfDocument.saveDocument(); | ||
|  |       this.downloadManager.download(data, this._downloadUrl, this._docFilename); | ||
|  |     } catch (reason) { | ||
|  |       console.error(`Error when saving the document: ${reason.message}`); | ||
|  |       await this.download(); | ||
|  |     } finally { | ||
|  |       await this.pdfScriptingManager.dispatchDidSave(); | ||
|  |       this._saveInProgress = false; | ||
|  |     } | ||
|  |     if (this._hasAnnotationEditors) { | ||
|  |       this.externalServices.reportTelemetry({ | ||
|  |         type: "editing", | ||
|  |         data: { | ||
|  |           type: "save", | ||
|  |           stats: this.pdfDocument?.annotationStorage.editorStats | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |   }, | ||
|  |   async downloadOrSave() { | ||
|  |     const { | ||
|  |       classList | ||
|  |     } = this.appConfig.appContainer; | ||
|  |     classList.add("wait"); | ||
|  |     await (this.pdfDocument?.annotationStorage.size > 0 ? this.save() : this.download()); | ||
|  |     classList.remove("wait"); | ||
|  |   }, | ||
|  |   async _documentError(key, moreInfo = null) { | ||
|  |     this._unblockDocumentLoadEvent(); | ||
|  |     const message = await this._otherError(key || "pdfjs-loading-error", moreInfo); | ||
|  |     this.eventBus.dispatch("documenterror", { | ||
|  |       source: this, | ||
|  |       message, | ||
|  |       reason: moreInfo?.message ?? null | ||
|  |     }); | ||
|  |   }, | ||
|  |   async _otherError(key, moreInfo = null) { | ||
|  |     const message = await this.l10n.get(key); | ||
|  |     const moreInfoText = [`PDF.js v${version || "?"} (build: ${build || "?"})`]; | ||
|  |     if (moreInfo) { | ||
|  |       moreInfoText.push(`Message: ${moreInfo.message}`); | ||
|  |       if (moreInfo.stack) { | ||
|  |         moreInfoText.push(`Stack: ${moreInfo.stack}`); | ||
|  |       } else { | ||
|  |         if (moreInfo.filename) { | ||
|  |           moreInfoText.push(`File: ${moreInfo.filename}`); | ||
|  |         } | ||
|  |         if (moreInfo.lineNumber) { | ||
|  |           moreInfoText.push(`Line: ${moreInfo.lineNumber}`); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     console.error(`${message}\n\n${moreInfoText.join("\n")}`); | ||
|  |     return message; | ||
|  |   }, | ||
|  |   progress(level) { | ||
|  |     const percent = Math.round(level * 100); | ||
|  |     if (!this.loadingBar || percent <= this.loadingBar.percent) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.loadingBar.percent = percent; | ||
|  |     if (this.pdfDocument?.loadingParams.disableAutoFetch ?? AppOptions.get("disableAutoFetch")) { | ||
|  |       this.loadingBar.setDisableAutoFetch(); | ||
|  |     } | ||
|  |   }, | ||
|  |   load(pdfDocument) { | ||
|  |     this.pdfDocument = pdfDocument; | ||
|  |     pdfDocument.getDownloadInfo().then(({ | ||
|  |       length | ||
|  |     }) => { | ||
|  |       this._contentLength = length; | ||
|  |       this.loadingBar?.hide(); | ||
|  |       firstPagePromise.then(() => { | ||
|  |         this.eventBus.dispatch("documentloaded", { | ||
|  |           source: this | ||
|  |         }); | ||
|  |       }); | ||
|  |     }); | ||
|  |     const pageLayoutPromise = pdfDocument.getPageLayout().catch(() => {}); | ||
|  |     const pageModePromise = pdfDocument.getPageMode().catch(() => {}); | ||
|  |     const openActionPromise = pdfDocument.getOpenAction().catch(() => {}); | ||
|  |     this.toolbar?.setPagesCount(pdfDocument.numPages, false); | ||
|  |     this.secondaryToolbar?.setPagesCount(pdfDocument.numPages); | ||
|  |     this.pdfLinkService.setDocument(pdfDocument); | ||
|  |     this.pdfDocumentProperties?.setDocument(pdfDocument); | ||
|  |     const pdfViewer = this.pdfViewer; | ||
|  |     pdfViewer.setDocument(pdfDocument); | ||
|  |     const { | ||
|  |       firstPagePromise, | ||
|  |       onePageRendered, | ||
|  |       pagesPromise | ||
|  |     } = pdfViewer; | ||
|  |     this.pdfThumbnailViewer?.setDocument(pdfDocument); | ||
|  |     const storedPromise = (this.store = new ViewHistory(pdfDocument.fingerprints[0])).getMultiple({ | ||
|  |       page: null, | ||
|  |       zoom: DEFAULT_SCALE_VALUE, | ||
|  |       scrollLeft: "0", | ||
|  |       scrollTop: "0", | ||
|  |       rotation: null, | ||
|  |       sidebarView: SidebarView.UNKNOWN, | ||
|  |       scrollMode: ScrollMode.UNKNOWN, | ||
|  |       spreadMode: SpreadMode.UNKNOWN | ||
|  |     }).catch(() => {}); | ||
|  |     firstPagePromise.then(pdfPage => { | ||
|  |       this.loadingBar?.setWidth(this.appConfig.viewerContainer); | ||
|  |       this._initializeAnnotationStorageCallbacks(pdfDocument); | ||
|  |       Promise.all([animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => { | ||
|  |         const viewOnLoad = AppOptions.get("viewOnLoad"); | ||
|  |         this._initializePdfHistory({ | ||
|  |           fingerprint: pdfDocument.fingerprints[0], | ||
|  |           viewOnLoad, | ||
|  |           initialDest: openAction?.dest | ||
|  |         }); | ||
|  |         const initialBookmark = this.initialBookmark; | ||
|  |         const zoom = AppOptions.get("defaultZoomValue"); | ||
|  |         let hash = zoom ? `zoom=${zoom}` : null; | ||
|  |         let rotation = null; | ||
|  |         let sidebarView = AppOptions.get("sidebarViewOnLoad"); | ||
|  |         let scrollMode = AppOptions.get("scrollModeOnLoad"); | ||
|  |         let spreadMode = AppOptions.get("spreadModeOnLoad"); | ||
|  |         if (stored?.page && viewOnLoad !== ViewOnLoad.INITIAL) { | ||
|  |           hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`; | ||
|  |           rotation = parseInt(stored.rotation, 10); | ||
|  |           if (sidebarView === SidebarView.UNKNOWN) { | ||
|  |             sidebarView = stored.sidebarView | 0; | ||
|  |           } | ||
|  |           if (scrollMode === ScrollMode.UNKNOWN) { | ||
|  |             scrollMode = stored.scrollMode | 0; | ||
|  |           } | ||
|  |           if (spreadMode === SpreadMode.UNKNOWN) { | ||
|  |             spreadMode = stored.spreadMode | 0; | ||
|  |           } | ||
|  |         } | ||
|  |         if (pageMode && sidebarView === SidebarView.UNKNOWN) { | ||
|  |           sidebarView = apiPageModeToSidebarView(pageMode); | ||
|  |         } | ||
|  |         if (pageLayout && scrollMode === ScrollMode.UNKNOWN && spreadMode === SpreadMode.UNKNOWN) { | ||
|  |           const modes = apiPageLayoutToViewerModes(pageLayout); | ||
|  |           spreadMode = modes.spreadMode; | ||
|  |         } | ||
|  |         this.setInitialView(hash, { | ||
|  |           rotation, | ||
|  |           sidebarView, | ||
|  |           scrollMode, | ||
|  |           spreadMode | ||
|  |         }); | ||
|  |         this.eventBus.dispatch("documentinit", { | ||
|  |           source: this | ||
|  |         }); | ||
|  |         if (!this.isViewerEmbedded) { | ||
|  |           pdfViewer.focus(); | ||
|  |         } | ||
|  |         await Promise.race([pagesPromise, new Promise(resolve => { | ||
|  |           setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT); | ||
|  |         })]); | ||
|  |         if (!initialBookmark && !hash) { | ||
|  |           return; | ||
|  |         } | ||
|  |         if (pdfViewer.hasEqualPageSizes) { | ||
|  |           return; | ||
|  |         } | ||
|  |         this.initialBookmark = initialBookmark; | ||
|  |         pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; | ||
|  |         this.setInitialView(hash); | ||
|  |       }).catch(() => { | ||
|  |         this.setInitialView(); | ||
|  |       }).then(function () { | ||
|  |         pdfViewer.update(); | ||
|  |       }); | ||
|  |     }); | ||
|  |     pagesPromise.then(() => { | ||
|  |       this._unblockDocumentLoadEvent(); | ||
|  |       this._initializeAutoPrint(pdfDocument, openActionPromise); | ||
|  |     }, reason => { | ||
|  |       this._documentError("pdfjs-loading-error", { | ||
|  |         message: reason.message | ||
|  |       }); | ||
|  |     }); | ||
|  |     onePageRendered.then(data => { | ||
|  |       this.externalServices.reportTelemetry({ | ||
|  |         type: "pageInfo", | ||
|  |         timestamp: data.timestamp | ||
|  |       }); | ||
|  |       if (this.pdfOutlineViewer) { | ||
|  |         pdfDocument.getOutline().then(outline => { | ||
|  |           if (pdfDocument !== this.pdfDocument) { | ||
|  |             return; | ||
|  |           } | ||
|  |           this.pdfOutlineViewer.render({ | ||
|  |             outline, | ||
|  |             pdfDocument | ||
|  |           }); | ||
|  |         }); | ||
|  |       } | ||
|  |       if (this.pdfAttachmentViewer) { | ||
|  |         pdfDocument.getAttachments().then(attachments => { | ||
|  |           if (pdfDocument !== this.pdfDocument) { | ||
|  |             return; | ||
|  |           } | ||
|  |           this.pdfAttachmentViewer.render({ | ||
|  |             attachments | ||
|  |           }); | ||
|  |         }); | ||
|  |       } | ||
|  |       if (this.pdfLayerViewer) { | ||
|  |         pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => { | ||
|  |           if (pdfDocument !== this.pdfDocument) { | ||
|  |             return; | ||
|  |           } | ||
|  |           this.pdfLayerViewer.render({ | ||
|  |             optionalContentConfig, | ||
|  |             pdfDocument | ||
|  |           }); | ||
|  |         }); | ||
|  |       } | ||
|  |     }); | ||
|  |     this._initializePageLabels(pdfDocument); | ||
|  |     this._initializeMetadata(pdfDocument); | ||
|  |   }, | ||
|  |   async _scriptingDocProperties(pdfDocument) { | ||
|  |     if (!this.documentInfo) { | ||
|  |       await new Promise(resolve => { | ||
|  |         this.eventBus._on("metadataloaded", resolve, { | ||
|  |           once: true | ||
|  |         }); | ||
|  |       }); | ||
|  |       if (pdfDocument !== this.pdfDocument) { | ||
|  |         return null; | ||
|  |       } | ||
|  |     } | ||
|  |     if (!this._contentLength) { | ||
|  |       await new Promise(resolve => { | ||
|  |         this.eventBus._on("documentloaded", resolve, { | ||
|  |           once: true | ||
|  |         }); | ||
|  |       }); | ||
|  |       if (pdfDocument !== this.pdfDocument) { | ||
|  |         return null; | ||
|  |       } | ||
|  |     } | ||
|  |     return { | ||
|  |       ...this.documentInfo, | ||
|  |       baseURL: this.baseUrl, | ||
|  |       filesize: this._contentLength, | ||
|  |       filename: this._docFilename, | ||
|  |       metadata: this.metadata?.getRaw(), | ||
|  |       authors: this.metadata?.get("dc:creator"), | ||
|  |       numPages: this.pagesCount, | ||
|  |       URL: this.url | ||
|  |     }; | ||
|  |   }, | ||
|  |   async _initializeAutoPrint(pdfDocument, openActionPromise) { | ||
|  |     const [openAction, jsActions] = await Promise.all([openActionPromise, this.pdfViewer.enableScripting ? null : pdfDocument.getJSActions()]); | ||
|  |     if (pdfDocument !== this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     let triggerAutoPrint = openAction?.action === "Print"; | ||
|  |     if (jsActions) { | ||
|  |       console.warn("Warning: JavaScript support is not enabled"); | ||
|  |       for (const name in jsActions) { | ||
|  |         if (triggerAutoPrint) { | ||
|  |           break; | ||
|  |         } | ||
|  |         switch (name) { | ||
|  |           case "WillClose": | ||
|  |           case "WillSave": | ||
|  |           case "DidSave": | ||
|  |           case "WillPrint": | ||
|  |           case "DidPrint": | ||
|  |             continue; | ||
|  |         } | ||
|  |         triggerAutoPrint = jsActions[name].some(js => AutoPrintRegExp.test(js)); | ||
|  |       } | ||
|  |     } | ||
|  |     if (triggerAutoPrint) { | ||
|  |       this.triggerPrinting(); | ||
|  |     } | ||
|  |   }, | ||
|  |   async _initializeMetadata(pdfDocument) { | ||
|  |     const { | ||
|  |       info, | ||
|  |       metadata, | ||
|  |       contentDispositionFilename, | ||
|  |       contentLength | ||
|  |     } = await pdfDocument.getMetadata(); | ||
|  |     if (pdfDocument !== this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.documentInfo = info; | ||
|  |     this.metadata = metadata; | ||
|  |     this._contentDispositionFilename ??= contentDispositionFilename; | ||
|  |     this._contentLength ??= contentLength; | ||
|  |     console.log(`PDF ${pdfDocument.fingerprints[0]} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${version || "?"} [${build || "?"}])`); | ||
|  |     let pdfTitle = info.Title; | ||
|  |     const metadataTitle = metadata?.get("dc:title"); | ||
|  |     if (metadataTitle) { | ||
|  |       if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) { | ||
|  |         pdfTitle = metadataTitle; | ||
|  |       } | ||
|  |     } | ||
|  |     if (pdfTitle) { | ||
|  |       this.setTitle(`${pdfTitle} - ${this._contentDispositionFilename || this._title}`); | ||
|  |     } else if (this._contentDispositionFilename) { | ||
|  |       this.setTitle(this._contentDispositionFilename); | ||
|  |     } | ||
|  |     if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) { | ||
|  |       if (pdfDocument.loadingParams.enableXfa) { | ||
|  |         console.warn("Warning: XFA Foreground documents are not supported"); | ||
|  |       } else { | ||
|  |         console.warn("Warning: XFA support is not enabled"); | ||
|  |       } | ||
|  |     } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderForms) { | ||
|  |       console.warn("Warning: Interactive form support is not enabled"); | ||
|  |     } | ||
|  |     if (info.IsSignaturesPresent) { | ||
|  |       console.warn("Warning: Digital signatures validation is not supported"); | ||
|  |     } | ||
|  |     this.eventBus.dispatch("metadataloaded", { | ||
|  |       source: this | ||
|  |     }); | ||
|  |   }, | ||
|  |   async _initializePageLabels(pdfDocument) { | ||
|  |     const labels = await pdfDocument.getPageLabels(); | ||
|  |     if (pdfDocument !== this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!labels || AppOptions.get("disablePageLabels")) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const numLabels = labels.length; | ||
|  |     let standardLabels = 0, | ||
|  |       emptyLabels = 0; | ||
|  |     for (let i = 0; i < numLabels; i++) { | ||
|  |       const label = labels[i]; | ||
|  |       if (label === (i + 1).toString()) { | ||
|  |         standardLabels++; | ||
|  |       } else if (label === "") { | ||
|  |         emptyLabels++; | ||
|  |       } else { | ||
|  |         break; | ||
|  |       } | ||
|  |     } | ||
|  |     if (standardLabels >= numLabels || emptyLabels >= numLabels) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       pdfViewer, | ||
|  |       pdfThumbnailViewer, | ||
|  |       toolbar | ||
|  |     } = this; | ||
|  |     pdfViewer.setPageLabels(labels); | ||
|  |     pdfThumbnailViewer?.setPageLabels(labels); | ||
|  |     toolbar?.setPagesCount(numLabels, true); | ||
|  |     toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); | ||
|  |   }, | ||
|  |   _initializePdfHistory({ | ||
|  |     fingerprint, | ||
|  |     viewOnLoad, | ||
|  |     initialDest = null | ||
|  |   }) { | ||
|  |     if (!this.pdfHistory) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.pdfHistory.initialize({ | ||
|  |       fingerprint, | ||
|  |       resetHistory: viewOnLoad === ViewOnLoad.INITIAL, | ||
|  |       updateUrl: AppOptions.get("historyUpdateUrl") | ||
|  |     }); | ||
|  |     if (this.pdfHistory.initialBookmark) { | ||
|  |       this.initialBookmark = this.pdfHistory.initialBookmark; | ||
|  |       this.initialRotation = this.pdfHistory.initialRotation; | ||
|  |     } | ||
|  |     if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) { | ||
|  |       this.initialBookmark = JSON.stringify(initialDest); | ||
|  |       this.pdfHistory.push({ | ||
|  |         explicitDest: initialDest, | ||
|  |         pageNumber: null | ||
|  |       }); | ||
|  |     } | ||
|  |   }, | ||
|  |   _initializeAnnotationStorageCallbacks(pdfDocument) { | ||
|  |     if (pdfDocument !== this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const { | ||
|  |       annotationStorage | ||
|  |     } = pdfDocument; | ||
|  |     annotationStorage.onSetModified = () => { | ||
|  |       window.addEventListener("beforeunload", beforeUnload); | ||
|  |       this._annotationStorageModified = true; | ||
|  |     }; | ||
|  |     annotationStorage.onResetModified = () => { | ||
|  |       window.removeEventListener("beforeunload", beforeUnload); | ||
|  |       delete this._annotationStorageModified; | ||
|  |     }; | ||
|  |     annotationStorage.onAnnotationEditor = typeStr => { | ||
|  |       this._hasAnnotationEditors = !!typeStr; | ||
|  |       this.setTitle(); | ||
|  |     }; | ||
|  |   }, | ||
|  |   setInitialView(storedHash, { | ||
|  |     rotation, | ||
|  |     sidebarView, | ||
|  |     scrollMode, | ||
|  |     spreadMode | ||
|  |   } = {}) { | ||
|  |     const setRotation = angle => { | ||
|  |       if (isValidRotation(angle)) { | ||
|  |         this.pdfViewer.pagesRotation = angle; | ||
|  |       } | ||
|  |     }; | ||
|  |     const setViewerModes = (scroll, spread) => { | ||
|  |       if (isValidScrollMode(scroll)) { | ||
|  |         this.pdfViewer.scrollMode = scroll; | ||
|  |       } | ||
|  |       if (isValidSpreadMode(spread)) { | ||
|  |         this.pdfViewer.spreadMode = spread; | ||
|  |       } | ||
|  |     }; | ||
|  |     this.isInitialViewSet = true; | ||
|  |     this.pdfSidebar?.setInitialView(sidebarView); | ||
|  |     setViewerModes(scrollMode, spreadMode); | ||
|  |     if (this.initialBookmark) { | ||
|  |       setRotation(this.initialRotation); | ||
|  |       delete this.initialRotation; | ||
|  |       this.pdfLinkService.setHash(this.initialBookmark); | ||
|  |       this.initialBookmark = null; | ||
|  |     } else if (storedHash) { | ||
|  |       setRotation(rotation); | ||
|  |       this.pdfLinkService.setHash(storedHash); | ||
|  |     } | ||
|  |     this.toolbar?.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel); | ||
|  |     this.secondaryToolbar?.setPageNumber(this.pdfViewer.currentPageNumber); | ||
|  |     if (!this.pdfViewer.currentScaleValue) { | ||
|  |       this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE; | ||
|  |     } | ||
|  |   }, | ||
|  |   _cleanup() { | ||
|  |     if (!this.pdfDocument) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this.pdfViewer.cleanup(); | ||
|  |     this.pdfThumbnailViewer?.cleanup(); | ||
|  |     this.pdfDocument.cleanup(AppOptions.get("fontExtraProperties")); | ||
|  |   }, | ||
|  |   forceRendering() { | ||
|  |     this.pdfRenderingQueue.printing = !!this.printService; | ||
|  |     this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar?.visibleView === SidebarView.THUMBS; | ||
|  |     this.pdfRenderingQueue.renderHighestPriority(); | ||
|  |   }, | ||
|  |   beforePrint() { | ||
|  |     this._printAnnotationStoragePromise = this.pdfScriptingManager.dispatchWillPrint().catch(() => {}).then(() => this.pdfDocument?.annotationStorage.print); | ||
|  |     if (this.printService) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this.supportsPrinting) { | ||
|  |       this._otherError("pdfjs-printing-not-supported"); | ||
|  |       return; | ||
|  |     } | ||
|  |     if (!this.pdfViewer.pageViewsReady) { | ||
|  |       this.l10n.get("pdfjs-printing-not-ready").then(msg => { | ||
|  |         window.alert(msg); | ||
|  |       }); | ||
|  |       return; | ||
|  |     } | ||
|  |     this.printService = PDFPrintServiceFactory.createPrintService({ | ||
|  |       pdfDocument: this.pdfDocument, | ||
|  |       pagesOverview: this.pdfViewer.getPagesOverview(), | ||
|  |       printContainer: this.appConfig.printContainer, | ||
|  |       printResolution: AppOptions.get("printResolution"), | ||
|  |       printAnnotationStoragePromise: this._printAnnotationStoragePromise | ||
|  |     }); | ||
|  |     this.forceRendering(); | ||
|  |     this.setTitle(); | ||
|  |     this.printService.layout(); | ||
|  |     if (this._hasAnnotationEditors) { | ||
|  |       this.externalServices.reportTelemetry({ | ||
|  |         type: "editing", | ||
|  |         data: { | ||
|  |           type: "print", | ||
|  |           stats: this.pdfDocument?.annotationStorage.editorStats | ||
|  |         } | ||
|  |       }); | ||
|  |     } | ||
|  |   }, | ||
|  |   afterPrint() { | ||
|  |     if (this._printAnnotationStoragePromise) { | ||
|  |       this._printAnnotationStoragePromise.then(() => { | ||
|  |         this.pdfScriptingManager.dispatchDidPrint(); | ||
|  |       }); | ||
|  |       this._printAnnotationStoragePromise = null; | ||
|  |     } | ||
|  |     if (this.printService) { | ||
|  |       this.printService.destroy(); | ||
|  |       this.printService = null; | ||
|  |       this.pdfDocument?.annotationStorage.resetModified(); | ||
|  |     } | ||
|  |     this.forceRendering(); | ||
|  |     this.setTitle(); | ||
|  |   }, | ||
|  |   rotatePages(delta) { | ||
|  |     this.pdfViewer.pagesRotation += delta; | ||
|  |   }, | ||
|  |   requestPresentationMode() { | ||
|  |     this.pdfPresentationMode?.request(); | ||
|  |   }, | ||
|  |   triggerPrinting() { | ||
|  |     if (this.supportsPrinting) { | ||
|  |       window.print(); | ||
|  |     } | ||
|  |   }, | ||
|  |   bindEvents() { | ||
|  |     if (this._eventBusAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._eventBusAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       eventBus, | ||
|  |       externalServices, | ||
|  |       pdfDocumentProperties, | ||
|  |       pdfViewer, | ||
|  |       preferences, | ||
|  |       _eventBusAbortController: { | ||
|  |         signal | ||
|  |       } | ||
|  |     } = this; | ||
|  |     eventBus._on("resize", onResize.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("hashchange", onHashchange.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("beforeprint", this.beforePrint.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("afterprint", this.afterPrint.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagerender", onPageRender.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagerendered", onPageRendered.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("updateviewarea", onUpdateViewarea.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagechanging", onPageChanging.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("scalechanging", onScaleChanging.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("rotationchanging", onRotationChanging.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("sidebarviewchanged", onSidebarViewChanged.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagemode", onPageMode.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("namedaction", onNamedAction.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("presentationmodechanged", evt => pdfViewer.presentationModeState = evt.state, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("presentationmode", this.requestPresentationMode.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("switchannotationeditormode", evt => pdfViewer.annotationEditorMode = evt, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("print", this.triggerPrinting.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("download", this.downloadOrSave.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("firstpage", () => this.page = 1, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("lastpage", () => this.page = this.pagesCount, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("nextpage", () => pdfViewer.nextPage(), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("previouspage", () => pdfViewer.previousPage(), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("zoomin", this.zoomIn.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("zoomout", this.zoomOut.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("zoomreset", this.zoomReset.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("pagenumberchanged", onPageNumberChanged.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("scalechanged", evt => pdfViewer.currentScaleValue = evt.value, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("rotatecw", this.rotatePages.bind(this, 90), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("rotateccw", this.rotatePages.bind(this, -90), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("optionalcontentconfig", evt => pdfViewer.optionalContentConfigPromise = evt.promise, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("switchscrollmode", evt => pdfViewer.scrollMode = evt.mode, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("scrollmodechanged", onViewerModesChanged.bind(this, "scrollMode"), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("switchspreadmode", evt => pdfViewer.spreadMode = evt.mode, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("spreadmodechanged", onViewerModesChanged.bind(this, "spreadMode"), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("imagealttextsettings", onImageAltTextSettings.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("documentproperties", () => pdfDocumentProperties?.open(), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("findfromurlhash", onFindFromUrlHash.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("updatefindmatchescount", onUpdateFindMatchesCount.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("updatefindcontrolstate", onUpdateFindControlState.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("fileinputchange", onFileInputChange.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     eventBus._on("openfile", onOpenFile.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |   }, | ||
|  |   bindWindowEvents() { | ||
|  |     if (this._windowAbortController) { | ||
|  |       return; | ||
|  |     } | ||
|  |     this._windowAbortController = new AbortController(); | ||
|  |     const { | ||
|  |       eventBus, | ||
|  |       appConfig: { | ||
|  |         mainContainer | ||
|  |       }, | ||
|  |       pdfViewer, | ||
|  |       _windowAbortController: { | ||
|  |         signal | ||
|  |       } | ||
|  |     } = this; | ||
|  |     function addWindowResolutionChange(evt = null) { | ||
|  |       if (evt) { | ||
|  |         pdfViewer.refresh(); | ||
|  |       } | ||
|  |       const mediaQueryList = window.matchMedia(`(resolution: ${window.devicePixelRatio || 1}dppx)`); | ||
|  |       mediaQueryList.addEventListener("change", addWindowResolutionChange, { | ||
|  |         once: true, | ||
|  |         signal | ||
|  |       }); | ||
|  |     } | ||
|  |     addWindowResolutionChange(); | ||
|  |     window.addEventListener("wheel", onWheel.bind(this), { | ||
|  |       passive: false, | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchstart", onTouchStart.bind(this), { | ||
|  |       passive: false, | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchmove", onTouchMove.bind(this), { | ||
|  |       passive: false, | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("touchend", onTouchEnd.bind(this), { | ||
|  |       passive: false, | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("click", onClick.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("keydown", onKeyDown.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("keyup", onKeyUp.bind(this), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("resize", () => eventBus.dispatch("resize", { | ||
|  |       source: window | ||
|  |     }), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("hashchange", () => { | ||
|  |       eventBus.dispatch("hashchange", { | ||
|  |         source: window, | ||
|  |         hash: document.location.hash.substring(1) | ||
|  |       }); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("beforeprint", () => eventBus.dispatch("beforeprint", { | ||
|  |       source: window | ||
|  |     }), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("afterprint", () => eventBus.dispatch("afterprint", { | ||
|  |       source: window | ||
|  |     }), { | ||
|  |       signal | ||
|  |     }); | ||
|  |     window.addEventListener("updatefromsandbox", evt => { | ||
|  |       eventBus.dispatch("updatefromsandbox", { | ||
|  |         source: window, | ||
|  |         detail: evt.detail | ||
|  |       }); | ||
|  |     }, { | ||
|  |       signal | ||
|  |     }); | ||
|  |     if (!("onscrollend" in document.documentElement)) { | ||
|  |       return; | ||
|  |     } | ||
|  |     ({ | ||
|  |       scrollTop: this._lastScrollTop, | ||
|  |       scrollLeft: this._lastScrollLeft | ||
|  |     } = mainContainer); | ||
|  |     const scrollend = () => { | ||
|  |       ({ | ||
|  |         scrollTop: this._lastScrollTop, | ||
|  |         scrollLeft: this._lastScrollLeft | ||
|  |       } = mainContainer); | ||
|  |       this._isScrolling = false; | ||
|  |       mainContainer.addEventListener("scroll", scroll, { | ||
|  |         passive: true, | ||
|  |         signal | ||
|  |       }); | ||
|  |       mainContainer.removeEventListener("scrollend", scrollend); | ||
|  |       mainContainer.removeEventListener("blur", scrollend); | ||
|  |     }; | ||
|  |     const scroll = () => { | ||
|  |       if (this._isCtrlKeyDown) { | ||
|  |         return; | ||
|  |       } | ||
|  |       if (this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) { | ||
|  |         return; | ||
|  |       } | ||
|  |       mainContainer.removeEventListener("scroll", scroll, { | ||
|  |         passive: true | ||
|  |       }); | ||
|  |       this._isScrolling = true; | ||
|  |       mainContainer.addEventListener("scrollend", scrollend, { | ||
|  |         signal | ||
|  |       }); | ||
|  |       mainContainer.addEventListener("blur", scrollend, { | ||
|  |         signal | ||
|  |       }); | ||
|  |     }; | ||
|  |     mainContainer.addEventListener("scroll", scroll, { | ||
|  |       passive: true, | ||
|  |       signal | ||
|  |     }); | ||
|  |   }, | ||
|  |   unbindEvents() { | ||
|  |     this._eventBusAbortController?.abort(); | ||
|  |     this._eventBusAbortController = null; | ||
|  |   }, | ||
|  |   unbindWindowEvents() { | ||
|  |     this._windowAbortController?.abort(); | ||
|  |     this._windowAbortController = null; | ||
|  |   }, | ||
|  |   async testingClose() { | ||
|  |     this.unbindEvents(); | ||
|  |     this.unbindWindowEvents(); | ||
|  |     this._globalAbortController?.abort(); | ||
|  |     this._globalAbortController = null; | ||
|  |     this.findBar?.close(); | ||
|  |     await Promise.all([this.l10n?.destroy(), this.close()]); | ||
|  |   }, | ||
|  |   _accumulateTicks(ticks, prop) { | ||
|  |     if (this[prop] > 0 && ticks < 0 || this[prop] < 0 && ticks > 0) { | ||
|  |       this[prop] = 0; | ||
|  |     } | ||
|  |     this[prop] += ticks; | ||
|  |     const wholeTicks = Math.trunc(this[prop]); | ||
|  |     this[prop] -= wholeTicks; | ||
|  |     return wholeTicks; | ||
|  |   }, | ||
|  |   _accumulateFactor(previousScale, factor, prop) { | ||
|  |     if (factor === 1) { | ||
|  |       return 1; | ||
|  |     } | ||
|  |     if (this[prop] > 1 && factor < 1 || this[prop] < 1 && factor > 1) { | ||
|  |       this[prop] = 1; | ||
|  |     } | ||
|  |     const newFactor = Math.floor(previousScale * factor * this[prop] * 100) / (100 * previousScale); | ||
|  |     this[prop] = factor / newFactor; | ||
|  |     return newFactor; | ||
|  |   }, | ||
|  |   _unblockDocumentLoadEvent() { | ||
|  |     document.blockUnblockOnload?.(false); | ||
|  |     this._unblockDocumentLoadEvent = () => {}; | ||
|  |   }, | ||
|  |   get scriptingReady() { | ||
|  |     return this.pdfScriptingManager.ready; | ||
|  |   } | ||
|  | }; | ||
|  | initCom(PDFViewerApplication); | ||
|  | { | ||
|  |   PDFPrintServiceFactory.initGlobals(PDFViewerApplication); | ||
|  | } | ||
|  | { | ||
|  |   const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"]; | ||
|  |   var validateFileURL = function (file) { | ||
|  |     if (!file) { | ||
|  |       return; | ||
|  |     } | ||
|  |     try { | ||
|  |       const viewerOrigin = new URL(window.location.href).origin || "null"; | ||
|  |       if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { | ||
|  |         return; | ||
|  |       } | ||
|  |       const fileOrigin = new URL(file, window.location.href).origin; | ||
|  |       if (fileOrigin !== viewerOrigin) { | ||
|  |         throw new Error("file origin does not match viewer's"); | ||
|  |       } | ||
|  |     } catch (ex) { | ||
|  |       PDFViewerApplication._documentError("pdfjs-loading-error", { | ||
|  |         message: ex.message | ||
|  |       }); | ||
|  |       throw ex; | ||
|  |     } | ||
|  |   }; | ||
|  |   var onFileInputChange = function (evt) { | ||
|  |     if (this.pdfViewer?.isInPresentationMode) { | ||
|  |       return; | ||
|  |     } | ||
|  |     const file = evt.fileInput.files[0]; | ||
|  |     this.open({ | ||
|  |       url: URL.createObjectURL(file), | ||
|  |       originalUrl: file.name | ||
|  |     }); | ||
|  |   }; | ||
|  |   var onOpenFile = function (evt) { | ||
|  |     this._openFileInput?.click(); | ||
|  |   }; | ||
|  | } | ||
|  | function onPageRender({ | ||
|  |   pageNumber | ||
|  | }) { | ||
|  |   if (pageNumber === this.page) { | ||
|  |     this.toolbar?.updateLoadingIndicatorState(true); | ||
|  |   } | ||
|  | } | ||
|  | function onPageRendered({ | ||
|  |   pageNumber, | ||
|  |   error | ||
|  | }) { | ||
|  |   if (pageNumber === this.page) { | ||
|  |     this.toolbar?.updateLoadingIndicatorState(false); | ||
|  |   } | ||
|  |   if (this.pdfSidebar?.visibleView === SidebarView.THUMBS) { | ||
|  |     const pageView = this.pdfViewer.getPageView(pageNumber - 1); | ||
|  |     const thumbnailView = this.pdfThumbnailViewer?.getThumbnail(pageNumber - 1); | ||
|  |     if (pageView) { | ||
|  |       thumbnailView?.setImage(pageView); | ||
|  |     } | ||
|  |   } | ||
|  |   if (error) { | ||
|  |     this._otherError("pdfjs-rendering-error", error); | ||
|  |   } | ||
|  | } | ||
|  | function onPageMode({ | ||
|  |   mode | ||
|  | }) { | ||
|  |   let view; | ||
|  |   switch (mode) { | ||
|  |     case "thumbs": | ||
|  |       view = SidebarView.THUMBS; | ||
|  |       break; | ||
|  |     case "bookmarks": | ||
|  |     case "outline": | ||
|  |       view = SidebarView.OUTLINE; | ||
|  |       break; | ||
|  |     case "attachments": | ||
|  |       view = SidebarView.ATTACHMENTS; | ||
|  |       break; | ||
|  |     case "layers": | ||
|  |       view = SidebarView.LAYERS; | ||
|  |       break; | ||
|  |     case "none": | ||
|  |       view = SidebarView.NONE; | ||
|  |       break; | ||
|  |     default: | ||
|  |       console.error('Invalid "pagemode" hash parameter: ' + mode); | ||
|  |       return; | ||
|  |   } | ||
|  |   this.pdfSidebar?.switchView(view, true); | ||
|  | } | ||
|  | function onNamedAction(evt) { | ||
|  |   switch (evt.action) { | ||
|  |     case "GoToPage": | ||
|  |       this.appConfig.toolbar?.pageNumber.select(); | ||
|  |       break; | ||
|  |     case "Find": | ||
|  |       if (!this.supportsIntegratedFind) { | ||
|  |         this.findBar?.toggle(); | ||
|  |       } | ||
|  |       break; | ||
|  |     case "Print": | ||
|  |       this.triggerPrinting(); | ||
|  |       break; | ||
|  |     case "SaveAs": | ||
|  |       this.downloadOrSave(); | ||
|  |       break; | ||
|  |   } | ||
|  | } | ||
|  | function onSidebarViewChanged({ | ||
|  |   view | ||
|  | }) { | ||
|  |   this.pdfRenderingQueue.isThumbnailViewEnabled = view === SidebarView.THUMBS; | ||
|  |   if (this.isInitialViewSet) { | ||
|  |     this.store?.set("sidebarView", view).catch(() => {}); | ||
|  |   } | ||
|  | } | ||
|  | function onUpdateViewarea({ | ||
|  |   location | ||
|  | }) { | ||
|  |   if (this.isInitialViewSet) { | ||
|  |     this.store?.setMultiple({ | ||
|  |       page: location.pageNumber, | ||
|  |       zoom: location.scale, | ||
|  |       scrollLeft: location.left, | ||
|  |       scrollTop: location.top, | ||
|  |       rotation: location.rotation | ||
|  |     }).catch(() => {}); | ||
|  |   } | ||
|  |   if (this.appConfig.secondaryToolbar) { | ||
|  |     this.appConfig.secondaryToolbar.viewBookmarkButton.href = this.pdfLinkService.getAnchorUrl(location.pdfOpenParams); | ||
|  |   } | ||
|  | } | ||
|  | function onViewerModesChanged(name, evt) { | ||
|  |   if (this.isInitialViewSet && !this.pdfViewer.isInPresentationMode) { | ||
|  |     this.store?.set(name, evt.mode).catch(() => {}); | ||
|  |   } | ||
|  | } | ||
|  | function onResize() { | ||
|  |   const { | ||
|  |     pdfDocument, | ||
|  |     pdfViewer, | ||
|  |     pdfRenderingQueue | ||
|  |   } = this; | ||
|  |   if (pdfRenderingQueue.printing && window.matchMedia("print").matches) { | ||
|  |     return; | ||
|  |   } | ||
|  |   if (!pdfDocument) { | ||
|  |     return; | ||
|  |   } | ||
|  |   const currentScaleValue = pdfViewer.currentScaleValue; | ||
|  |   if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") { | ||
|  |     pdfViewer.currentScaleValue = currentScaleValue; | ||
|  |   } | ||
|  |   pdfViewer.update(); | ||
|  | } | ||
|  | function onHashchange(evt) { | ||
|  |   const hash = evt.hash; | ||
|  |   if (!hash) { | ||
|  |     return; | ||
|  |   } | ||
|  |   if (!this.isInitialViewSet) { | ||
|  |     this.initialBookmark = hash; | ||
|  |   } else if (!this.pdfHistory?.popStateInProgress) { | ||
|  |     this.pdfLinkService.setHash(hash); | ||
|  |   } | ||
|  | } | ||
|  | function onPageNumberChanged(evt) { | ||
|  |   const { | ||
|  |     pdfViewer | ||
|  |   } = this; | ||
|  |   if (evt.value !== "") { | ||
|  |     this.pdfLinkService.goToPage(evt.value); | ||
|  |   } | ||
|  |   if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) { | ||
|  |     this.toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); | ||
|  |   } | ||
|  | } | ||
|  | function onImageAltTextSettings() { | ||
|  |   this.imageAltTextSettings?.open({ | ||
|  |     enableGuessAltText: AppOptions.get("enableGuessAltText"), | ||
|  |     enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage") | ||
|  |   }); | ||
|  | } | ||
|  | function onFindFromUrlHash(evt) { | ||
|  |   this.eventBus.dispatch("find", { | ||
|  |     source: evt.source, | ||
|  |     type: "", | ||
|  |     query: evt.query, | ||
|  |     caseSensitive: false, | ||
|  |     entireWord: false, | ||
|  |     highlightAll: true, | ||
|  |     findPrevious: false, | ||
|  |     matchDiacritics: true | ||
|  |   }); | ||
|  | } | ||
|  | function onUpdateFindMatchesCount({ | ||
|  |   matchesCount | ||
|  | }) { | ||
|  |   if (this.supportsIntegratedFind) { | ||
|  |     this.externalServices.updateFindMatchesCount(matchesCount); | ||
|  |   } else { | ||
|  |     this.findBar?.updateResultsCount(matchesCount); | ||
|  |   } | ||
|  | } | ||
|  | function onUpdateFindControlState({ | ||
|  |   state, | ||
|  |   previous, | ||
|  |   entireWord, | ||
|  |   matchesCount, | ||
|  |   rawQuery | ||
|  | }) { | ||
|  |   if (this.supportsIntegratedFind) { | ||
|  |     this.externalServices.updateFindControlState({ | ||
|  |       result: state, | ||
|  |       findPrevious: previous, | ||
|  |       entireWord, | ||
|  |       matchesCount, | ||
|  |       rawQuery | ||
|  |     }); | ||
|  |   } else { | ||
|  |     this.findBar?.updateUIState(state, previous, matchesCount); | ||
|  |   } | ||
|  | } | ||
|  | function onScaleChanging(evt) { | ||
|  |   this.toolbar?.setPageScale(evt.presetValue, evt.scale); | ||
|  |   this.pdfViewer.update(); | ||
|  | } | ||
|  | function onRotationChanging(evt) { | ||
|  |   if (this.pdfThumbnailViewer) { | ||
|  |     this.pdfThumbnailViewer.pagesRotation = evt.pagesRotation; | ||
|  |   } | ||
|  |   this.forceRendering(); | ||
|  |   this.pdfViewer.currentPageNumber = evt.pageNumber; | ||
|  | } | ||
|  | function onPageChanging({ | ||
|  |   pageNumber, | ||
|  |   pageLabel | ||
|  | }) { | ||
|  |   this.toolbar?.setPageNumber(pageNumber, pageLabel); | ||
|  |   this.secondaryToolbar?.setPageNumber(pageNumber); | ||
|  |   if (this.pdfSidebar?.visibleView === SidebarView.THUMBS) { | ||
|  |     this.pdfThumbnailViewer?.scrollThumbnailIntoView(pageNumber); | ||
|  |   } | ||
|  |   const currentPage = this.pdfViewer.getPageView(pageNumber - 1); | ||
|  |   this.toolbar?.updateLoadingIndicatorState(currentPage?.renderingState === RenderingStates.RUNNING); | ||
|  | } | ||
|  | function onWheel(evt) { | ||
|  |   const { | ||
|  |     pdfViewer, | ||
|  |     supportsMouseWheelZoomCtrlKey, | ||
|  |     supportsMouseWheelZoomMetaKey, | ||
|  |     supportsPinchToZoom | ||
|  |   } = this; | ||
|  |   if (pdfViewer.isInPresentationMode) { | ||
|  |     return; | ||
|  |   } | ||
|  |   const deltaMode = evt.deltaMode; | ||
|  |   let scaleFactor = Math.exp(-evt.deltaY / 100); | ||
|  |   const isBuiltInMac = false; | ||
|  |   const isPinchToZoom = evt.ctrlKey && !this._isCtrlKeyDown && deltaMode === WheelEvent.DOM_DELTA_PIXEL && evt.deltaX === 0 && (Math.abs(scaleFactor - 1) < 0.05 || isBuiltInMac) && evt.deltaZ === 0; | ||
|  |   const origin = [evt.clientX, evt.clientY]; | ||
|  |   if (isPinchToZoom || evt.ctrlKey && supportsMouseWheelZoomCtrlKey || evt.metaKey && supportsMouseWheelZoomMetaKey) { | ||
|  |     evt.preventDefault(); | ||
|  |     if (this._isScrolling || document.visibilityState === "hidden" || this.overlayManager.active) { | ||
|  |       return; | ||
|  |     } | ||
|  |     if (isPinchToZoom && supportsPinchToZoom) { | ||
|  |       scaleFactor = this._accumulateFactor(pdfViewer.currentScale, scaleFactor, "_wheelUnusedFactor"); | ||
|  |       this.updateZoom(null, scaleFactor, origin); | ||
|  |     } else { | ||
|  |       const delta = normalizeWheelEventDirection(evt); | ||
|  |       let ticks = 0; | ||
|  |       if (deltaMode === WheelEvent.DOM_DELTA_LINE || deltaMode === WheelEvent.DOM_DELTA_PAGE) { | ||
|  |         ticks = Math.abs(delta) >= 1 ? Math.sign(delta) : this._accumulateTicks(delta, "_wheelUnusedTicks"); | ||
|  |       } else { | ||
|  |         const PIXELS_PER_LINE_SCALE = 30; | ||
|  |         ticks = this._accumulateTicks(delta / PIXELS_PER_LINE_SCALE, "_wheelUnusedTicks"); | ||
|  |       } | ||
|  |       this.updateZoom(ticks, null, origin); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | function onTouchStart(evt) { | ||
|  |   if (this.pdfViewer.isInPresentationMode || evt.touches.length < 2) { | ||
|  |     return; | ||
|  |   } | ||
|  |   evt.preventDefault(); | ||
|  |   if (evt.touches.length !== 2 || this.overlayManager.active) { | ||
|  |     this._touchInfo = null; | ||
|  |     return; | ||
|  |   } | ||
|  |   let [touch0, touch1] = evt.touches; | ||
|  |   if (touch0.identifier > touch1.identifier) { | ||
|  |     [touch0, touch1] = [touch1, touch0]; | ||
|  |   } | ||
|  |   this._touchInfo = { | ||
|  |     touch0X: touch0.pageX, | ||
|  |     touch0Y: touch0.pageY, | ||
|  |     touch1X: touch1.pageX, | ||
|  |     touch1Y: touch1.pageY | ||
|  |   }; | ||
|  | } | ||
|  | function onTouchMove(evt) { | ||
|  |   if (!this._touchInfo || evt.touches.length !== 2) { | ||
|  |     return; | ||
|  |   } | ||
|  |   const { | ||
|  |     pdfViewer, | ||
|  |     _touchInfo, | ||
|  |     supportsPinchToZoom | ||
|  |   } = this; | ||
|  |   let [touch0, touch1] = evt.touches; | ||
|  |   if (touch0.identifier > touch1.identifier) { | ||
|  |     [touch0, touch1] = [touch1, touch0]; | ||
|  |   } | ||
|  |   const { | ||
|  |     pageX: page0X, | ||
|  |     pageY: page0Y | ||
|  |   } = touch0; | ||
|  |   const { | ||
|  |     pageX: page1X, | ||
|  |     pageY: page1Y | ||
|  |   } = touch1; | ||
|  |   const { | ||
|  |     touch0X: pTouch0X, | ||
|  |     touch0Y: pTouch0Y, | ||
|  |     touch1X: pTouch1X, | ||
|  |     touch1Y: pTouch1Y | ||
|  |   } = _touchInfo; | ||
|  |   if (Math.abs(pTouch0X - page0X) <= 1 && Math.abs(pTouch0Y - page0Y) <= 1 && Math.abs(pTouch1X - page1X) <= 1 && Math.abs(pTouch1Y - page1Y) <= 1) { | ||
|  |     return; | ||
|  |   } | ||
|  |   _touchInfo.touch0X = page0X; | ||
|  |   _touchInfo.touch0Y = page0Y; | ||
|  |   _touchInfo.touch1X = page1X; | ||
|  |   _touchInfo.touch1Y = page1Y; | ||
|  |   if (pTouch0X === page0X && pTouch0Y === page0Y) { | ||
|  |     const v1X = pTouch1X - page0X; | ||
|  |     const v1Y = pTouch1Y - page0Y; | ||
|  |     const v2X = page1X - page0X; | ||
|  |     const v2Y = page1Y - page0Y; | ||
|  |     const det = v1X * v2Y - v1Y * v2X; | ||
|  |     if (Math.abs(det) > 0.02 * Math.hypot(v1X, v1Y) * Math.hypot(v2X, v2Y)) { | ||
|  |       return; | ||
|  |     } | ||
|  |   } else if (pTouch1X === page1X && pTouch1Y === page1Y) { | ||
|  |     const v1X = pTouch0X - page1X; | ||
|  |     const v1Y = pTouch0Y - page1Y; | ||
|  |     const v2X = page0X - page1X; | ||
|  |     const v2Y = page0Y - page1Y; | ||
|  |     const det = v1X * v2Y - v1Y * v2X; | ||
|  |     if (Math.abs(det) > 0.02 * Math.hypot(v1X, v1Y) * Math.hypot(v2X, v2Y)) { | ||
|  |       return; | ||
|  |     } | ||
|  |   } else { | ||
|  |     const diff0X = page0X - pTouch0X; | ||
|  |     const diff1X = page1X - pTouch1X; | ||
|  |     const diff0Y = page0Y - pTouch0Y; | ||
|  |     const diff1Y = page1Y - pTouch1Y; | ||
|  |     const dotProduct = diff0X * diff1X + diff0Y * diff1Y; | ||
|  |     if (dotProduct >= 0) { | ||
|  |       return; | ||
|  |     } | ||
|  |   } | ||
|  |   evt.preventDefault(); | ||
|  |   const origin = [(page0X + page1X) / 2, (page0Y + page1Y) / 2]; | ||
|  |   const distance = Math.hypot(page0X - page1X, page0Y - page1Y) || 1; | ||
|  |   const pDistance = Math.hypot(pTouch0X - pTouch1X, pTouch0Y - pTouch1Y) || 1; | ||
|  |   if (supportsPinchToZoom) { | ||
|  |     const newScaleFactor = this._accumulateFactor(pdfViewer.currentScale, distance / pDistance, "_touchUnusedFactor"); | ||
|  |     this.updateZoom(null, newScaleFactor, origin); | ||
|  |   } else { | ||
|  |     const PIXELS_PER_LINE_SCALE = 30; | ||
|  |     const ticks = this._accumulateTicks((distance - pDistance) / PIXELS_PER_LINE_SCALE, "_touchUnusedTicks"); | ||
|  |     this.updateZoom(ticks, null, origin); | ||
|  |   } | ||
|  | } | ||
|  | function onTouchEnd(evt) { | ||
|  |   if (!this._touchInfo) { | ||
|  |     return; | ||
|  |   } | ||
|  |   evt.preventDefault(); | ||
|  |   this._touchInfo = null; | ||
|  |   this._touchUnusedTicks = 0; | ||
|  |   this._touchUnusedFactor = 1; | ||
|  | } | ||
|  | function onClick(evt) { | ||
|  |   if (!this.secondaryToolbar?.isOpen) { | ||
|  |     return; | ||
|  |   } | ||
|  |   const appConfig = this.appConfig; | ||
|  |   if (this.pdfViewer.containsElement(evt.target) || appConfig.toolbar?.container.contains(evt.target) && evt.target !== appConfig.secondaryToolbar?.toggleButton) { | ||
|  |     this.secondaryToolbar.close(); | ||
|  |   } | ||
|  | } | ||
|  | function onKeyUp(evt) { | ||
|  |   if (evt.key === "Control") { | ||
|  |     this._isCtrlKeyDown = false; | ||
|  |   } | ||
|  | } | ||
|  | function onKeyDown(evt) { | ||
|  |   this._isCtrlKeyDown = evt.key === "Control"; | ||
|  |   if (this.overlayManager.active) { | ||
|  |     return; | ||
|  |   } | ||
|  |   const { | ||
|  |     eventBus, | ||
|  |     pdfViewer | ||
|  |   } = this; | ||
|  |   const isViewerInPresentationMode = pdfViewer.isInPresentationMode; | ||
|  |   let handled = false, | ||
|  |     ensureViewerFocused = false; | ||
|  |   const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); | ||
|  |   if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { | ||
|  |     switch (evt.keyCode) { | ||
|  |       case 70: | ||
|  |         if (!this.supportsIntegratedFind && !evt.shiftKey) { | ||
|  |           this.findBar?.open(); | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 71: | ||
|  |         if (!this.supportsIntegratedFind) { | ||
|  |           const { | ||
|  |             state | ||
|  |           } = this.findController; | ||
|  |           if (state) { | ||
|  |             const newState = { | ||
|  |               source: window, | ||
|  |               type: "again", | ||
|  |               findPrevious: cmd === 5 || cmd === 12 | ||
|  |             }; | ||
|  |             eventBus.dispatch("find", { | ||
|  |               ...state, | ||
|  |               ...newState | ||
|  |             }); | ||
|  |           } | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 61: | ||
|  |       case 107: | ||
|  |       case 187: | ||
|  |       case 171: | ||
|  |         this.zoomIn(); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 173: | ||
|  |       case 109: | ||
|  |       case 189: | ||
|  |         this.zoomOut(); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 48: | ||
|  |       case 96: | ||
|  |         if (!isViewerInPresentationMode) { | ||
|  |           setTimeout(() => { | ||
|  |             this.zoomReset(); | ||
|  |           }); | ||
|  |           handled = false; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 38: | ||
|  |         if (isViewerInPresentationMode || this.page > 1) { | ||
|  |           this.page = 1; | ||
|  |           handled = true; | ||
|  |           ensureViewerFocused = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 40: | ||
|  |         if (isViewerInPresentationMode || this.page < this.pagesCount) { | ||
|  |           this.page = this.pagesCount; | ||
|  |           handled = true; | ||
|  |           ensureViewerFocused = true; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   if (cmd === 1 || cmd === 8) { | ||
|  |     switch (evt.keyCode) { | ||
|  |       case 83: | ||
|  |         eventBus.dispatch("download", { | ||
|  |           source: window | ||
|  |         }); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 79: | ||
|  |         { | ||
|  |           eventBus.dispatch("openfile", { | ||
|  |             source: window | ||
|  |           }); | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   if (cmd === 3 || cmd === 10) { | ||
|  |     switch (evt.keyCode) { | ||
|  |       case 80: | ||
|  |         this.requestPresentationMode(); | ||
|  |         handled = true; | ||
|  |         this.externalServices.reportTelemetry({ | ||
|  |           type: "buttons", | ||
|  |           data: { | ||
|  |             id: "presentationModeKeyboard" | ||
|  |           } | ||
|  |         }); | ||
|  |         break; | ||
|  |       case 71: | ||
|  |         if (this.appConfig.toolbar) { | ||
|  |           this.appConfig.toolbar.pageNumber.select(); | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   if (handled) { | ||
|  |     if (ensureViewerFocused && !isViewerInPresentationMode) { | ||
|  |       pdfViewer.focus(); | ||
|  |     } | ||
|  |     evt.preventDefault(); | ||
|  |     return; | ||
|  |   } | ||
|  |   const curElement = getActiveOrFocusedElement(); | ||
|  |   const curElementTagName = curElement?.tagName.toUpperCase(); | ||
|  |   if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElementTagName === "BUTTON" && (evt.keyCode === 13 || evt.keyCode === 32) || curElement?.isContentEditable) { | ||
|  |     if (evt.keyCode !== 27) { | ||
|  |       return; | ||
|  |     } | ||
|  |   } | ||
|  |   if (cmd === 0) { | ||
|  |     let turnPage = 0, | ||
|  |       turnOnlyIfPageFit = false; | ||
|  |     switch (evt.keyCode) { | ||
|  |       case 38: | ||
|  |         if (this.supportsCaretBrowsingMode) { | ||
|  |           this.moveCaret(true, false); | ||
|  |           handled = true; | ||
|  |           break; | ||
|  |         } | ||
|  |       case 33: | ||
|  |         if (pdfViewer.isVerticalScrollbarEnabled) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |         turnPage = -1; | ||
|  |         break; | ||
|  |       case 8: | ||
|  |         if (!isViewerInPresentationMode) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |         turnPage = -1; | ||
|  |         break; | ||
|  |       case 37: | ||
|  |         if (this.supportsCaretBrowsingMode) { | ||
|  |           return; | ||
|  |         } | ||
|  |         if (pdfViewer.isHorizontalScrollbarEnabled) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |       case 75: | ||
|  |       case 80: | ||
|  |         turnPage = -1; | ||
|  |         break; | ||
|  |       case 27: | ||
|  |         if (this.secondaryToolbar?.isOpen) { | ||
|  |           this.secondaryToolbar.close(); | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         if (!this.supportsIntegratedFind && this.findBar?.opened) { | ||
|  |           this.findBar.close(); | ||
|  |           handled = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 40: | ||
|  |         if (this.supportsCaretBrowsingMode) { | ||
|  |           this.moveCaret(false, false); | ||
|  |           handled = true; | ||
|  |           break; | ||
|  |         } | ||
|  |       case 34: | ||
|  |         if (pdfViewer.isVerticalScrollbarEnabled) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |         turnPage = 1; | ||
|  |         break; | ||
|  |       case 13: | ||
|  |       case 32: | ||
|  |         if (!isViewerInPresentationMode) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |         turnPage = 1; | ||
|  |         break; | ||
|  |       case 39: | ||
|  |         if (this.supportsCaretBrowsingMode) { | ||
|  |           return; | ||
|  |         } | ||
|  |         if (pdfViewer.isHorizontalScrollbarEnabled) { | ||
|  |           turnOnlyIfPageFit = true; | ||
|  |         } | ||
|  |       case 74: | ||
|  |       case 78: | ||
|  |         turnPage = 1; | ||
|  |         break; | ||
|  |       case 36: | ||
|  |         if (isViewerInPresentationMode || this.page > 1) { | ||
|  |           this.page = 1; | ||
|  |           handled = true; | ||
|  |           ensureViewerFocused = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 35: | ||
|  |         if (isViewerInPresentationMode || this.page < this.pagesCount) { | ||
|  |           this.page = this.pagesCount; | ||
|  |           handled = true; | ||
|  |           ensureViewerFocused = true; | ||
|  |         } | ||
|  |         break; | ||
|  |       case 83: | ||
|  |         this.pdfCursorTools?.switchTool(CursorTool.SELECT); | ||
|  |         break; | ||
|  |       case 72: | ||
|  |         this.pdfCursorTools?.switchTool(CursorTool.HAND); | ||
|  |         break; | ||
|  |       case 82: | ||
|  |         this.rotatePages(90); | ||
|  |         break; | ||
|  |       case 115: | ||
|  |         this.pdfSidebar?.toggle(); | ||
|  |         break; | ||
|  |     } | ||
|  |     if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) { | ||
|  |       if (turnPage > 0) { | ||
|  |         pdfViewer.nextPage(); | ||
|  |       } else { | ||
|  |         pdfViewer.previousPage(); | ||
|  |       } | ||
|  |       handled = true; | ||
|  |     } | ||
|  |   } | ||
|  |   if (cmd === 4) { | ||
|  |     switch (evt.keyCode) { | ||
|  |       case 13: | ||
|  |       case 32: | ||
|  |         if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") { | ||
|  |           break; | ||
|  |         } | ||
|  |         pdfViewer.previousPage(); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 38: | ||
|  |         this.moveCaret(true, true); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 40: | ||
|  |         this.moveCaret(false, true); | ||
|  |         handled = true; | ||
|  |         break; | ||
|  |       case 82: | ||
|  |         this.rotatePages(-90); | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  |   if (!handled && !isViewerInPresentationMode) { | ||
|  |     if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") { | ||
|  |       ensureViewerFocused = true; | ||
|  |     } | ||
|  |   } | ||
|  |   if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { | ||
|  |     pdfViewer.focus(); | ||
|  |   } | ||
|  |   if (handled) { | ||
|  |     evt.preventDefault(); | ||
|  |   } | ||
|  | } | ||
|  | function beforeUnload(evt) { | ||
|  |   evt.preventDefault(); | ||
|  |   evt.returnValue = ""; | ||
|  |   return false; | ||
|  | } | ||
|  | 
 | ||
|  | ;// CONCATENATED MODULE: ./web/viewer.js
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | const pdfjsVersion = "4.6.82"; | ||
|  | const pdfjsBuild = "9b541910f"; | ||
|  | const AppConstants = { | ||
|  |   LinkTarget: LinkTarget, | ||
|  |   RenderingStates: RenderingStates, | ||
|  |   ScrollMode: ScrollMode, | ||
|  |   SpreadMode: SpreadMode | ||
|  | }; | ||
|  | window.PDFViewerApplication = PDFViewerApplication; | ||
|  | window.PDFViewerApplicationConstants = AppConstants; | ||
|  | window.PDFViewerApplicationOptions = AppOptions; | ||
|  | function getViewerConfiguration() { | ||
|  |   return { | ||
|  |     appContainer: document.body, | ||
|  |     mainContainer: document.getElementById("viewerContainer"), | ||
|  |     viewerContainer: document.getElementById("viewer"), | ||
|  |     toolbar: { | ||
|  |       container: document.getElementById("toolbarViewer"), | ||
|  |       numPages: document.getElementById("numPages"), | ||
|  |       pageNumber: document.getElementById("pageNumber"), | ||
|  |       scaleSelect: document.getElementById("scaleSelect"), | ||
|  |       customScaleOption: document.getElementById("customScaleOption"), | ||
|  |       previous: document.getElementById("previous"), | ||
|  |       next: document.getElementById("next"), | ||
|  |       zoomIn: document.getElementById("zoomIn"), | ||
|  |       zoomOut: document.getElementById("zoomOut"), | ||
|  |       print: document.getElementById("print"), | ||
|  |       editorFreeTextButton: document.getElementById("editorFreeText"), | ||
|  |       editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"), | ||
|  |       editorHighlightButton: document.getElementById("editorHighlight"), | ||
|  |       editorHighlightParamsToolbar: document.getElementById("editorHighlightParamsToolbar"), | ||
|  |       editorHighlightColorPicker: document.getElementById("editorHighlightColorPicker"), | ||
|  |       editorInkButton: document.getElementById("editorInk"), | ||
|  |       editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"), | ||
|  |       editorStampButton: document.getElementById("editorStamp"), | ||
|  |       editorStampParamsToolbar: document.getElementById("editorStampParamsToolbar"), | ||
|  |       download: document.getElementById("download") | ||
|  |     }, | ||
|  |     secondaryToolbar: { | ||
|  |       toolbar: document.getElementById("secondaryToolbar"), | ||
|  |       toggleButton: document.getElementById("secondaryToolbarToggle"), | ||
|  |       presentationModeButton: document.getElementById("presentationMode"), | ||
|  |       openFileButton: document.getElementById("secondaryOpenFile"), | ||
|  |       printButton: document.getElementById("secondaryPrint"), | ||
|  |       downloadButton: document.getElementById("secondaryDownload"), | ||
|  |       viewBookmarkButton: document.getElementById("viewBookmark"), | ||
|  |       firstPageButton: document.getElementById("firstPage"), | ||
|  |       lastPageButton: document.getElementById("lastPage"), | ||
|  |       pageRotateCwButton: document.getElementById("pageRotateCw"), | ||
|  |       pageRotateCcwButton: document.getElementById("pageRotateCcw"), | ||
|  |       cursorSelectToolButton: document.getElementById("cursorSelectTool"), | ||
|  |       cursorHandToolButton: document.getElementById("cursorHandTool"), | ||
|  |       scrollPageButton: document.getElementById("scrollPage"), | ||
|  |       scrollVerticalButton: document.getElementById("scrollVertical"), | ||
|  |       scrollHorizontalButton: document.getElementById("scrollHorizontal"), | ||
|  |       scrollWrappedButton: document.getElementById("scrollWrapped"), | ||
|  |       spreadNoneButton: document.getElementById("spreadNone"), | ||
|  |       spreadOddButton: document.getElementById("spreadOdd"), | ||
|  |       spreadEvenButton: document.getElementById("spreadEven"), | ||
|  |       imageAltTextSettingsButton: document.getElementById("imageAltTextSettings"), | ||
|  |       imageAltTextSettingsSeparator: document.getElementById("imageAltTextSettingsSeparator"), | ||
|  |       documentPropertiesButton: document.getElementById("documentProperties") | ||
|  |     }, | ||
|  |     sidebar: { | ||
|  |       outerContainer: document.getElementById("outerContainer"), | ||
|  |       sidebarContainer: document.getElementById("sidebarContainer"), | ||
|  |       toggleButton: document.getElementById("sidebarToggle"), | ||
|  |       resizer: document.getElementById("sidebarResizer"), | ||
|  |       thumbnailButton: document.getElementById("viewThumbnail"), | ||
|  |       outlineButton: document.getElementById("viewOutline"), | ||
|  |       attachmentsButton: document.getElementById("viewAttachments"), | ||
|  |       layersButton: document.getElementById("viewLayers"), | ||
|  |       thumbnailView: document.getElementById("thumbnailView"), | ||
|  |       outlineView: document.getElementById("outlineView"), | ||
|  |       attachmentsView: document.getElementById("attachmentsView"), | ||
|  |       layersView: document.getElementById("layersView"), | ||
|  |       currentOutlineItemButton: document.getElementById("currentOutlineItem") | ||
|  |     }, | ||
|  |     findBar: { | ||
|  |       bar: document.getElementById("findbar"), | ||
|  |       toggleButton: document.getElementById("viewFind"), | ||
|  |       findField: document.getElementById("findInput"), | ||
|  |       highlightAllCheckbox: document.getElementById("findHighlightAll"), | ||
|  |       caseSensitiveCheckbox: document.getElementById("findMatchCase"), | ||
|  |       matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"), | ||
|  |       entireWordCheckbox: document.getElementById("findEntireWord"), | ||
|  |       findMsg: document.getElementById("findMsg"), | ||
|  |       findResultsCount: document.getElementById("findResultsCount"), | ||
|  |       findPreviousButton: document.getElementById("findPrevious"), | ||
|  |       findNextButton: document.getElementById("findNext") | ||
|  |     }, | ||
|  |     passwordOverlay: { | ||
|  |       dialog: document.getElementById("passwordDialog"), | ||
|  |       label: document.getElementById("passwordText"), | ||
|  |       input: document.getElementById("password"), | ||
|  |       submitButton: document.getElementById("passwordSubmit"), | ||
|  |       cancelButton: document.getElementById("passwordCancel") | ||
|  |     }, | ||
|  |     documentProperties: { | ||
|  |       dialog: document.getElementById("documentPropertiesDialog"), | ||
|  |       closeButton: document.getElementById("documentPropertiesClose"), | ||
|  |       fields: { | ||
|  |         fileName: document.getElementById("fileNameField"), | ||
|  |         fileSize: document.getElementById("fileSizeField"), | ||
|  |         title: document.getElementById("titleField"), | ||
|  |         author: document.getElementById("authorField"), | ||
|  |         subject: document.getElementById("subjectField"), | ||
|  |         keywords: document.getElementById("keywordsField"), | ||
|  |         creationDate: document.getElementById("creationDateField"), | ||
|  |         modificationDate: document.getElementById("modificationDateField"), | ||
|  |         creator: document.getElementById("creatorField"), | ||
|  |         producer: document.getElementById("producerField"), | ||
|  |         version: document.getElementById("versionField"), | ||
|  |         pageCount: document.getElementById("pageCountField"), | ||
|  |         pageSize: document.getElementById("pageSizeField"), | ||
|  |         linearized: document.getElementById("linearizedField") | ||
|  |       } | ||
|  |     }, | ||
|  |     altTextDialog: { | ||
|  |       dialog: document.getElementById("altTextDialog"), | ||
|  |       optionDescription: document.getElementById("descriptionButton"), | ||
|  |       optionDecorative: document.getElementById("decorativeButton"), | ||
|  |       textarea: document.getElementById("descriptionTextarea"), | ||
|  |       cancelButton: document.getElementById("altTextCancel"), | ||
|  |       saveButton: document.getElementById("altTextSave") | ||
|  |     }, | ||
|  |     newAltTextDialog: { | ||
|  |       dialog: document.getElementById("newAltTextDialog"), | ||
|  |       title: document.getElementById("newAltTextTitle"), | ||
|  |       descriptionContainer: document.getElementById("newAltTextDescriptionContainer"), | ||
|  |       textarea: document.getElementById("newAltTextDescriptionTextarea"), | ||
|  |       disclaimer: document.getElementById("newAltTextDisclaimer"), | ||
|  |       learnMore: document.getElementById("newAltTextLearnMore"), | ||
|  |       imagePreview: document.getElementById("newAltTextImagePreview"), | ||
|  |       createAutomatically: document.getElementById("newAltTextCreateAutomatically"), | ||
|  |       createAutomaticallyButton: document.getElementById("newAltTextCreateAutomaticallyButton"), | ||
|  |       downloadModel: document.getElementById("newAltTextDownloadModel"), | ||
|  |       downloadModelDescription: document.getElementById("newAltTextDownloadModelDescription"), | ||
|  |       error: document.getElementById("newAltTextError"), | ||
|  |       errorCloseButton: document.getElementById("newAltTextCloseButton"), | ||
|  |       cancelButton: document.getElementById("newAltTextCancel"), | ||
|  |       notNowButton: document.getElementById("newAltTextNotNow"), | ||
|  |       saveButton: document.getElementById("newAltTextSave") | ||
|  |     }, | ||
|  |     altTextSettingsDialog: { | ||
|  |       dialog: document.getElementById("altTextSettingsDialog"), | ||
|  |       createModelButton: document.getElementById("createModelButton"), | ||
|  |       aiModelSettings: document.getElementById("aiModelSettings"), | ||
|  |       learnMore: document.getElementById("altTextSettingsLearnMore"), | ||
|  |       deleteModelButton: document.getElementById("deleteModelButton"), | ||
|  |       downloadModelButton: document.getElementById("downloadModelButton"), | ||
|  |       showAltTextDialogButton: document.getElementById("showAltTextDialogButton"), | ||
|  |       altTextSettingsCloseButton: document.getElementById("altTextSettingsCloseButton"), | ||
|  |       closeButton: document.getElementById("altTextSettingsCloseButton") | ||
|  |     }, | ||
|  |     annotationEditorParams: { | ||
|  |       editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"), | ||
|  |       editorFreeTextColor: document.getElementById("editorFreeTextColor"), | ||
|  |       editorInkColor: document.getElementById("editorInkColor"), | ||
|  |       editorInkThickness: document.getElementById("editorInkThickness"), | ||
|  |       editorInkOpacity: document.getElementById("editorInkOpacity"), | ||
|  |       editorStampAddImage: document.getElementById("editorStampAddImage"), | ||
|  |       editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness"), | ||
|  |       editorHighlightShowAll: document.getElementById("editorHighlightShowAll") | ||
|  |     }, | ||
|  |     printContainer: document.getElementById("printContainer") | ||
|  |   }; | ||
|  | } | ||
|  | function webViewerLoad() { | ||
|  |   const config = getViewerConfiguration(); | ||
|  |   const event = new CustomEvent("webviewerloaded", { | ||
|  |     bubbles: true, | ||
|  |     cancelable: true, | ||
|  |     detail: { | ||
|  |       source: window | ||
|  |     } | ||
|  |   }); | ||
|  |   try { | ||
|  |     parent.document.dispatchEvent(event); | ||
|  |   } catch (ex) { | ||
|  |     console.error(`webviewerloaded: ${ex}`); | ||
|  |     document.dispatchEvent(event); | ||
|  |   } | ||
|  |   PDFViewerApplication.run(config); | ||
|  | } | ||
|  | document.blockUnblockOnload?.(true); | ||
|  | if (document.readyState === "interactive" || document.readyState === "complete") { | ||
|  |   webViewerLoad(); | ||
|  | } else { | ||
|  |   document.addEventListener("DOMContentLoaded", webViewerLoad, true); | ||
|  | } | ||
|  | 
 | ||
|  | var __webpack_exports__PDFViewerApplication = __webpack_exports__.PDFViewerApplication; | ||
|  | var __webpack_exports__PDFViewerApplicationConstants = __webpack_exports__.PDFViewerApplicationConstants; | ||
|  | var __webpack_exports__PDFViewerApplicationOptions = __webpack_exports__.PDFViewerApplicationOptions; | ||
|  | export { __webpack_exports__PDFViewerApplication as PDFViewerApplication, __webpack_exports__PDFViewerApplicationConstants as PDFViewerApplicationConstants, __webpack_exports__PDFViewerApplicationOptions as PDFViewerApplicationOptions }; | ||
|  | 
 | ||
|  | //# sourceMappingURL=viewer.mjs.map
 |