/** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2020 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * Javascript code in this page */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.approximateFraction = approximateFraction; exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements; exports.binarySearchFirstItem = binarySearchFirstItem; exports.getActiveOrFocusedElement = getActiveOrFocusedElement; exports.getOutputScale = getOutputScale; exports.getPageSizeInches = getPageSizeInches; exports.getPDFFileNameFromURL = getPDFFileNameFromURL; exports.getVisibleElements = getVisibleElements; exports.isPortraitOrientation = isPortraitOrientation; exports.isValidRotation = isValidRotation; exports.isValidScrollMode = isValidScrollMode; exports.isValidSpreadMode = isValidSpreadMode; exports.moveToEndOfArray = moveToEndOfArray; exports.noContextMenuHandler = noContextMenuHandler; exports.normalizeWheelEventDelta = normalizeWheelEventDelta; exports.normalizeWheelEventDirection = normalizeWheelEventDirection; exports.parseQueryString = parseQueryString; exports.roundToDivide = roundToDivide; exports.scrollIntoView = scrollIntoView; exports.waitOnEventOrTimeout = waitOnEventOrTimeout; exports.watchScroll = watchScroll; exports.WaitOnType = exports.VERTICAL_PADDING = exports.UNKNOWN_SCALE = exports.TextLayerMode = exports.SpreadMode = exports.SidebarView = exports.ScrollMode = exports.SCROLLBAR_PADDING = exports.RendererType = exports.ProgressBar = exports.PresentationModeState = exports.NullL10n = exports.MIN_SCALE = exports.MAX_SCALE = exports.MAX_AUTO_SCALE = exports.EventBus = exports.DEFAULT_SCALE_VALUE = exports.DEFAULT_SCALE = exports.CSS_UNITS = exports.AutoPrintRegExp = exports.animationStarted = void 0; const CSS_UNITS = 96.0 / 72.0; exports.CSS_UNITS = CSS_UNITS; const DEFAULT_SCALE_VALUE = "auto"; exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; const DEFAULT_SCALE = 1.0; exports.DEFAULT_SCALE = DEFAULT_SCALE; const MIN_SCALE = 0.1; exports.MIN_SCALE = MIN_SCALE; const MAX_SCALE = 10.0; exports.MAX_SCALE = MAX_SCALE; const UNKNOWN_SCALE = 0; exports.UNKNOWN_SCALE = UNKNOWN_SCALE; const MAX_AUTO_SCALE = 1.25; exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE; const SCROLLBAR_PADDING = 40; exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; const VERTICAL_PADDING = 5; exports.VERTICAL_PADDING = VERTICAL_PADDING; const LOADINGBAR_END_OFFSET_VAR = "--loadingBar-end-offset"; const PresentationModeState = { UNKNOWN: 0, NORMAL: 1, CHANGING: 2, FULLSCREEN: 3 }; exports.PresentationModeState = PresentationModeState; const SidebarView = { UNKNOWN: -1, NONE: 0, THUMBS: 1, OUTLINE: 2, ATTACHMENTS: 3, LAYERS: 4 }; exports.SidebarView = SidebarView; const RendererType = { CANVAS: "canvas", SVG: "svg" }; exports.RendererType = RendererType; const TextLayerMode = { DISABLE: 0, ENABLE: 1, ENABLE_ENHANCE: 2 }; exports.TextLayerMode = TextLayerMode; const ScrollMode = { UNKNOWN: -1, VERTICAL: 0, HORIZONTAL: 1, WRAPPED: 2 }; exports.ScrollMode = ScrollMode; const SpreadMode = { UNKNOWN: -1, NONE: 0, ODD: 1, EVEN: 2 }; exports.SpreadMode = SpreadMode; const AutoPrintRegExp = /\bprint\s*\(/; exports.AutoPrintRegExp = AutoPrintRegExp; function formatL10nValue(text, args) { if (!args) { return text; } return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => { return name in args ? args[name] : "{{" + name + "}}"; }); } const NullL10n = { async getLanguage() { return "en-us"; }, async getDirection() { return "ltr"; }, async get(property, args, fallback) { return formatL10nValue(fallback, args); }, async translate(element) {} }; exports.NullL10n = NullL10n; function getOutputScale(ctx) { const devicePixelRatio = window.devicePixelRatio || 1; const backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; const pixelRatio = devicePixelRatio / backingStoreRatio; return { sx: pixelRatio, sy: pixelRatio, scaled: pixelRatio !== 1 }; } function scrollIntoView(element, spot, skipOverflowHiddenElements = 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 || skipOverflowHiddenElements && getComputedStyle(parent).overflow === "hidden") { if (parent.dataset._scaleY) { offsetY /= parent.dataset._scaleY; offsetX /= parent.dataset._scaleX; } 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) { 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, true); return state; } function parseQueryString(query) { const parts = query.split("&"); const params = Object.create(null); for (let i = 0, ii = parts.length; i < ii; ++i) { const param = parts[i].split("="); const key = param[0].toLowerCase(); const value = param.length > 1 ? param[1] : null; params[decodeURIComponent(key)] = decodeURIComponent(value); } return params; } function binarySearchFirstItem(items, condition) { let minIndex = 0; 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 roundToDivide(x, div) { const r = x % div; return r === 0 ? x : Math.round(x - r + 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 = [], 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 }); } const first = visible[0], last = visible[visible.length - 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 }; } function noContextMenuHandler(evt) { evt.preventDefault(); } function isDataSchema(url) { let i = 0; const ii = url.length; while (i < ii && url[i].trim() === "") { i++; } return url.substring(i, i + 5).toLowerCase() === "data:"; } function getPDFFileNameFromURL(url, defaultFilename = "document.pdf") { if (typeof url !== "string") { return defaultFilename; } if (isDataSchema(url)) { console.warn("getPDFFileNameFromURL: " + 'ignoring "data:" URL for performance reasons.'); return defaultFilename; } const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i; const splitURI = reURI.exec(url); let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]); if (suggestedFilename) { suggestedFilename = suggestedFilename[0]; if (suggestedFilename.includes("%")) { try { suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0]; } catch (ex) {} } } return suggestedFilename || defaultFilename; } function normalizeWheelEventDirection(evt) { let delta = Math.sqrt(evt.deltaX * evt.deltaX + evt.deltaY * 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) { let delta = normalizeWheelEventDirection(evt); const MOUSE_DOM_DELTA_PIXEL_MODE = 0; const MOUSE_DOM_DELTA_LINE_MODE = 1; const MOUSE_PIXELS_PER_LINE = 30; const MOUSE_LINES_PER_PAGE = 30; if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) { delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE; } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) { 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 WaitOnType = { EVENT: "event", TIMEOUT: "timeout" }; exports.WaitOnType = WaitOnType; function waitOnEventOrTimeout({ target, name, delay = 0 }) { return new Promise(function (resolve, reject) { if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) { throw new Error("waitOnEventOrTimeout - invalid parameters."); } function handler(type) { if (target instanceof EventBus) { target._off(name, eventHandler); } else { target.removeEventListener(name, eventHandler); } if (timeout) { clearTimeout(timeout); } resolve(type); } const eventHandler = handler.bind(null, WaitOnType.EVENT); if (target instanceof EventBus) { target._on(name, eventHandler); } else { target.addEventListener(name, eventHandler); } const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT); const timeout = setTimeout(timeoutHandler, delay); }); } const animationStarted = new Promise(function (resolve) { window.requestAnimationFrame(resolve); }); exports.animationStarted = animationStarted; function dispatchDOMEvent(eventName, args = null) { throw new Error("Not implemented: dispatchDOMEvent"); } class EventBus { constructor(options) { this._listeners = Object.create(null); } on(eventName, listener, options = null) { this._on(eventName, listener, { external: true, once: options?.once }); } off(eventName, listener, options = null) { this._off(eventName, listener, { external: true, once: options?.once }); } dispatch(eventName) { const eventListeners = this._listeners[eventName]; if (!eventListeners || eventListeners.length === 0) { return; } const args = Array.prototype.slice.call(arguments, 1); let externalListeners; eventListeners.slice(0).forEach(({ listener, external, once }) => { if (once) { this._off(eventName, listener); } if (external) { (externalListeners || (externalListeners = [])).push(listener); return; } listener.apply(null, args); }); if (externalListeners) { externalListeners.forEach(listener => { listener.apply(null, args); }); externalListeners = null; } } _on(eventName, listener, options = null) { var _this$_listeners; const eventListeners = (_this$_listeners = this._listeners)[eventName] || (_this$_listeners[eventName] = []); eventListeners.push({ listener, external: options?.external === true, once: options?.once === true }); } _off(eventName, listener, options = null) { const eventListeners = this._listeners[eventName]; if (!eventListeners) { return; } for (let i = 0, ii = eventListeners.length; i < ii; i++) { if (eventListeners[i].listener === listener) { eventListeners.splice(i, 1); return; } } } } exports.EventBus = EventBus; function clamp(v, min, max) { return Math.min(Math.max(v, min), max); } class ProgressBar { constructor(id, { height, width, units } = {}) { this.visible = true; this.div = document.querySelector(id + " .progress"); this.bar = this.div.parentNode; this.height = height || 100; this.width = width || 100; this.units = units || "%"; this.div.style.height = this.height + this.units; this.percent = 0; } _updateBar() { if (this._indeterminate) { this.div.classList.add("indeterminate"); this.div.style.width = this.width + this.units; return; } this.div.classList.remove("indeterminate"); const progressSize = this.width * this._percent / 100; this.div.style.width = progressSize + this.units; } get percent() { return this._percent; } set percent(val) { this._indeterminate = isNaN(val); this._percent = clamp(val, 0, 100); this._updateBar(); } setWidth(viewer) { if (!viewer) { return; } const container = viewer.parentNode; const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; if (scrollbarWidth > 0) { const doc = document.documentElement; doc.style.setProperty(LOADINGBAR_END_OFFSET_VAR, `${scrollbarWidth}px`); } } hide() { if (!this.visible) { return; } this.visible = false; this.bar.classList.add("hidden"); } show() { if (this.visible) { return; } this.visible = true; this.bar.classList.remove("hidden"); } } exports.ProgressBar = ProgressBar; function moveToEndOfArray(arr, condition) { const moved = [], len = arr.length; let write = 0; for (let read = 0; read < len; ++read) { if (condition(arr[read])) { moved.push(arr[read]); } else { arr[write] = arr[read]; ++write; } } for (let read = 0; write < len; ++read, ++write) { arr[write] = moved[read]; } } function getActiveOrFocusedElement() { let curRoot = document; let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); while (curActiveOrFocused && curActiveOrFocused.shadowRoot) { curRoot = curActiveOrFocused.shadowRoot; curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); } return curActiveOrFocused; }