UNPKG

15.4 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.animationStarted = exports.VERTICAL_PADDING = exports.UNKNOWN_SCALE = exports.TextLayerMode = exports.SpreadMode = exports.SidebarView = exports.ScrollMode = exports.SCROLLBAR_PADDING = exports.RenderingStates = exports.RendererType = exports.ProgressBar = exports.PresentationModeState = exports.OutputScale = exports.MIN_SCALE = exports.MAX_SCALE = exports.MAX_AUTO_SCALE = exports.DEFAULT_SCALE_VALUE = exports.DEFAULT_SCALE_DELTA = exports.DEFAULT_SCALE = exports.AutoPrintRegExp = void 0;
28exports.apiPageLayoutToViewerModes = apiPageLayoutToViewerModes;
29exports.apiPageModeToSidebarView = apiPageModeToSidebarView;
30exports.approximateFraction = approximateFraction;
31exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements;
32exports.docStyle = void 0;
33exports.getActiveOrFocusedElement = getActiveOrFocusedElement;
34exports.getPageSizeInches = getPageSizeInches;
35exports.getVisibleElements = getVisibleElements;
36exports.isPortraitOrientation = isPortraitOrientation;
37exports.isValidRotation = isValidRotation;
38exports.isValidScrollMode = isValidScrollMode;
39exports.isValidSpreadMode = isValidSpreadMode;
40exports.noContextMenuHandler = noContextMenuHandler;
41exports.normalizeWheelEventDelta = normalizeWheelEventDelta;
42exports.normalizeWheelEventDirection = normalizeWheelEventDirection;
43exports.parseQueryString = parseQueryString;
44exports.removeNullCharacters = removeNullCharacters;
45exports.roundToDivide = roundToDivide;
46exports.scrollIntoView = scrollIntoView;
47exports.watchScroll = watchScroll;
48
49var _pdf = require("../pdf");
50
51const DEFAULT_SCALE_VALUE = "auto";
52exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE;
53const DEFAULT_SCALE = 1.0;
54exports.DEFAULT_SCALE = DEFAULT_SCALE;
55const DEFAULT_SCALE_DELTA = 1.1;
56exports.DEFAULT_SCALE_DELTA = DEFAULT_SCALE_DELTA;
57const MIN_SCALE = 0.1;
58exports.MIN_SCALE = MIN_SCALE;
59const MAX_SCALE = 10.0;
60exports.MAX_SCALE = MAX_SCALE;
61const UNKNOWN_SCALE = 0;
62exports.UNKNOWN_SCALE = UNKNOWN_SCALE;
63const MAX_AUTO_SCALE = 1.25;
64exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE;
65const SCROLLBAR_PADDING = 40;
66exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING;
67const VERTICAL_PADDING = 5;
68exports.VERTICAL_PADDING = VERTICAL_PADDING;
69const RenderingStates = {
70 INITIAL: 0,
71 RUNNING: 1,
72 PAUSED: 2,
73 FINISHED: 3
74};
75exports.RenderingStates = RenderingStates;
76const PresentationModeState = {
77 UNKNOWN: 0,
78 NORMAL: 1,
79 CHANGING: 2,
80 FULLSCREEN: 3
81};
82exports.PresentationModeState = PresentationModeState;
83const SidebarView = {
84 UNKNOWN: -1,
85 NONE: 0,
86 THUMBS: 1,
87 OUTLINE: 2,
88 ATTACHMENTS: 3,
89 LAYERS: 4
90};
91exports.SidebarView = SidebarView;
92const RendererType = {
93 CANVAS: "canvas",
94 SVG: "svg"
95};
96exports.RendererType = RendererType;
97const TextLayerMode = {
98 DISABLE: 0,
99 ENABLE: 1,
100 ENABLE_ENHANCE: 2
101};
102exports.TextLayerMode = TextLayerMode;
103const ScrollMode = {
104 UNKNOWN: -1,
105 VERTICAL: 0,
106 HORIZONTAL: 1,
107 WRAPPED: 2,
108 PAGE: 3
109};
110exports.ScrollMode = ScrollMode;
111const SpreadMode = {
112 UNKNOWN: -1,
113 NONE: 0,
114 ODD: 1,
115 EVEN: 2
116};
117exports.SpreadMode = SpreadMode;
118const AutoPrintRegExp = /\bprint\s*\(/;
119exports.AutoPrintRegExp = AutoPrintRegExp;
120
121class OutputScale {
122 constructor() {
123 const pixelRatio = window.devicePixelRatio || 1;
124 this.sx = pixelRatio;
125 this.sy = pixelRatio;
126 }
127
128 get scaled() {
129 return this.sx !== 1 || this.sy !== 1;
130 }
131
132}
133
134exports.OutputScale = OutputScale;
135
136function scrollIntoView(element, spot, scrollMatches = false) {
137 let parent = element.offsetParent;
138
139 if (!parent) {
140 console.error("offsetParent is not set -- cannot scroll");
141 return;
142 }
143
144 let offsetY = element.offsetTop + element.clientTop;
145 let offsetX = element.offsetLeft + element.clientLeft;
146
147 while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || scrollMatches && (parent.classList.contains("markedContent") || getComputedStyle(parent).overflow === "hidden")) {
148 offsetY += parent.offsetTop;
149 offsetX += parent.offsetLeft;
150 parent = parent.offsetParent;
151
152 if (!parent) {
153 return;
154 }
155 }
156
157 if (spot) {
158 if (spot.top !== undefined) {
159 offsetY += spot.top;
160 }
161
162 if (spot.left !== undefined) {
163 offsetX += spot.left;
164 parent.scrollLeft = offsetX;
165 }
166 }
167
168 parent.scrollTop = offsetY;
169}
170
171function watchScroll(viewAreaElement, callback) {
172 const debounceScroll = function (evt) {
173 if (rAF) {
174 return;
175 }
176
177 rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
178 rAF = null;
179 const currentX = viewAreaElement.scrollLeft;
180 const lastX = state.lastX;
181
182 if (currentX !== lastX) {
183 state.right = currentX > lastX;
184 }
185
186 state.lastX = currentX;
187 const currentY = viewAreaElement.scrollTop;
188 const lastY = state.lastY;
189
190 if (currentY !== lastY) {
191 state.down = currentY > lastY;
192 }
193
194 state.lastY = currentY;
195 callback(state);
196 });
197 };
198
199 const state = {
200 right: true,
201 down: true,
202 lastX: viewAreaElement.scrollLeft,
203 lastY: viewAreaElement.scrollTop,
204 _eventHandler: debounceScroll
205 };
206 let rAF = null;
207 viewAreaElement.addEventListener("scroll", debounceScroll, true);
208 return state;
209}
210
211function parseQueryString(query) {
212 const params = new Map();
213
214 for (const [key, value] of new URLSearchParams(query)) {
215 params.set(key.toLowerCase(), value);
216 }
217
218 return params;
219}
220
221const NullCharactersRegExp = /\x00/g;
222const InvisibleCharactersRegExp = /[\x01-\x1F]/g;
223
224function removeNullCharacters(str, replaceInvisible = false) {
225 if (typeof str !== "string") {
226 console.error(`The argument must be a string.`);
227 return str;
228 }
229
230 if (replaceInvisible) {
231 str = str.replace(InvisibleCharactersRegExp, " ");
232 }
233
234 return str.replace(NullCharactersRegExp, "");
235}
236
237function approximateFraction(x) {
238 if (Math.floor(x) === x) {
239 return [x, 1];
240 }
241
242 const xinv = 1 / x;
243 const limit = 8;
244
245 if (xinv > limit) {
246 return [1, limit];
247 } else if (Math.floor(xinv) === xinv) {
248 return [1, xinv];
249 }
250
251 const x_ = x > 1 ? xinv : x;
252 let a = 0,
253 b = 1,
254 c = 1,
255 d = 1;
256
257 while (true) {
258 const p = a + c,
259 q = b + d;
260
261 if (q > limit) {
262 break;
263 }
264
265 if (x_ <= p / q) {
266 c = p;
267 d = q;
268 } else {
269 a = p;
270 b = q;
271 }
272 }
273
274 let result;
275
276 if (x_ - a / b < c / d - x_) {
277 result = x_ === x ? [a, b] : [b, a];
278 } else {
279 result = x_ === x ? [c, d] : [d, c];
280 }
281
282 return result;
283}
284
285function roundToDivide(x, div) {
286 const r = x % div;
287 return r === 0 ? x : Math.round(x - r + div);
288}
289
290function getPageSizeInches({
291 view,
292 userUnit,
293 rotate
294}) {
295 const [x1, y1, x2, y2] = view;
296 const changeOrientation = rotate % 180 !== 0;
297 const width = (x2 - x1) / 72 * userUnit;
298 const height = (y2 - y1) / 72 * userUnit;
299 return {
300 width: changeOrientation ? height : width,
301 height: changeOrientation ? width : height
302 };
303}
304
305function backtrackBeforeAllVisibleElements(index, views, top) {
306 if (index < 2) {
307 return index;
308 }
309
310 let elt = views[index].div;
311 let pageTop = elt.offsetTop + elt.clientTop;
312
313 if (pageTop >= top) {
314 elt = views[index - 1].div;
315 pageTop = elt.offsetTop + elt.clientTop;
316 }
317
318 for (let i = index - 2; i >= 0; --i) {
319 elt = views[i].div;
320
321 if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) {
322 break;
323 }
324
325 index = i;
326 }
327
328 return index;
329}
330
331function getVisibleElements({
332 scrollEl,
333 views,
334 sortByVisibility = false,
335 horizontal = false,
336 rtl = false
337}) {
338 const top = scrollEl.scrollTop,
339 bottom = top + scrollEl.clientHeight;
340 const left = scrollEl.scrollLeft,
341 right = left + scrollEl.clientWidth;
342
343 function isElementBottomAfterViewTop(view) {
344 const element = view.div;
345 const elementBottom = element.offsetTop + element.clientTop + element.clientHeight;
346 return elementBottom > top;
347 }
348
349 function isElementNextAfterViewHorizontally(view) {
350 const element = view.div;
351 const elementLeft = element.offsetLeft + element.clientLeft;
352 const elementRight = elementLeft + element.clientWidth;
353 return rtl ? elementLeft < right : elementRight > left;
354 }
355
356 const visible = [],
357 ids = new Set(),
358 numViews = views.length;
359 let firstVisibleElementInd = (0, _pdf.binarySearchFirstItem)(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop);
360
361 if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) {
362 firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top);
363 }
364
365 let lastEdge = horizontal ? right : -1;
366
367 for (let i = firstVisibleElementInd; i < numViews; i++) {
368 const view = views[i],
369 element = view.div;
370 const currentWidth = element.offsetLeft + element.clientLeft;
371 const currentHeight = element.offsetTop + element.clientTop;
372 const viewWidth = element.clientWidth,
373 viewHeight = element.clientHeight;
374 const viewRight = currentWidth + viewWidth;
375 const viewBottom = currentHeight + viewHeight;
376
377 if (lastEdge === -1) {
378 if (viewBottom >= bottom) {
379 lastEdge = viewBottom;
380 }
381 } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) {
382 break;
383 }
384
385 if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) {
386 continue;
387 }
388
389 const hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom);
390 const hiddenWidth = Math.max(0, left - currentWidth) + Math.max(0, viewRight - right);
391 const fractionHeight = (viewHeight - hiddenHeight) / viewHeight,
392 fractionWidth = (viewWidth - hiddenWidth) / viewWidth;
393 const percent = fractionHeight * fractionWidth * 100 | 0;
394 visible.push({
395 id: view.id,
396 x: currentWidth,
397 y: currentHeight,
398 view,
399 percent,
400 widthPercent: fractionWidth * 100 | 0
401 });
402 ids.add(view.id);
403 }
404
405 const first = visible[0],
406 last = visible.at(-1);
407
408 if (sortByVisibility) {
409 visible.sort(function (a, b) {
410 const pc = a.percent - b.percent;
411
412 if (Math.abs(pc) > 0.001) {
413 return -pc;
414 }
415
416 return a.id - b.id;
417 });
418 }
419
420 return {
421 first,
422 last,
423 views: visible,
424 ids
425 };
426}
427
428function noContextMenuHandler(evt) {
429 evt.preventDefault();
430}
431
432function normalizeWheelEventDirection(evt) {
433 let delta = Math.hypot(evt.deltaX, evt.deltaY);
434 const angle = Math.atan2(evt.deltaY, evt.deltaX);
435
436 if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {
437 delta = -delta;
438 }
439
440 return delta;
441}
442
443function normalizeWheelEventDelta(evt) {
444 let delta = normalizeWheelEventDirection(evt);
445 const MOUSE_DOM_DELTA_PIXEL_MODE = 0;
446 const MOUSE_DOM_DELTA_LINE_MODE = 1;
447 const MOUSE_PIXELS_PER_LINE = 30;
448 const MOUSE_LINES_PER_PAGE = 30;
449
450 if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) {
451 delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;
452 } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) {
453 delta /= MOUSE_LINES_PER_PAGE;
454 }
455
456 return delta;
457}
458
459function isValidRotation(angle) {
460 return Number.isInteger(angle) && angle % 90 === 0;
461}
462
463function isValidScrollMode(mode) {
464 return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN;
465}
466
467function isValidSpreadMode(mode) {
468 return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN;
469}
470
471function isPortraitOrientation(size) {
472 return size.width <= size.height;
473}
474
475const animationStarted = new Promise(function (resolve) {
476 if (typeof window === "undefined") {
477 setTimeout(resolve, 20);
478 return;
479 }
480
481 window.requestAnimationFrame(resolve);
482});
483exports.animationStarted = animationStarted;
484const docStyle = typeof document === "undefined" ? null : document.documentElement.style;
485exports.docStyle = docStyle;
486
487function clamp(v, min, max) {
488 return Math.min(Math.max(v, min), max);
489}
490
491class ProgressBar {
492 #classList = null;
493 #percent = 0;
494 #visible = true;
495
496 constructor(id) {
497 if (arguments.length > 1) {
498 throw new Error("ProgressBar no longer accepts any additional options, " + "please use CSS rules to modify its appearance instead.");
499 }
500
501 const bar = document.getElementById(id);
502 this.#classList = bar.classList;
503 }
504
505 get percent() {
506 return this.#percent;
507 }
508
509 set percent(val) {
510 this.#percent = clamp(val, 0, 100);
511
512 if (isNaN(val)) {
513 this.#classList.add("indeterminate");
514 return;
515 }
516
517 this.#classList.remove("indeterminate");
518 docStyle.setProperty("--progressBar-percent", `${this.#percent}%`);
519 }
520
521 setWidth(viewer) {
522 if (!viewer) {
523 return;
524 }
525
526 const container = viewer.parentNode;
527 const scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
528
529 if (scrollbarWidth > 0) {
530 docStyle.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`);
531 }
532 }
533
534 hide() {
535 if (!this.#visible) {
536 return;
537 }
538
539 this.#visible = false;
540 this.#classList.add("hidden");
541 }
542
543 show() {
544 if (this.#visible) {
545 return;
546 }
547
548 this.#visible = true;
549 this.#classList.remove("hidden");
550 }
551
552}
553
554exports.ProgressBar = ProgressBar;
555
556function getActiveOrFocusedElement() {
557 let curRoot = document;
558 let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
559
560 while (curActiveOrFocused?.shadowRoot) {
561 curRoot = curActiveOrFocused.shadowRoot;
562 curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
563 }
564
565 return curActiveOrFocused;
566}
567
568function apiPageLayoutToViewerModes(layout) {
569 let scrollMode = ScrollMode.VERTICAL,
570 spreadMode = SpreadMode.NONE;
571
572 switch (layout) {
573 case "SinglePage":
574 scrollMode = ScrollMode.PAGE;
575 break;
576
577 case "OneColumn":
578 break;
579
580 case "TwoPageLeft":
581 scrollMode = ScrollMode.PAGE;
582
583 case "TwoColumnLeft":
584 spreadMode = SpreadMode.ODD;
585 break;
586
587 case "TwoPageRight":
588 scrollMode = ScrollMode.PAGE;
589
590 case "TwoColumnRight":
591 spreadMode = SpreadMode.EVEN;
592 break;
593 }
594
595 return {
596 scrollMode,
597 spreadMode
598 };
599}
600
601function apiPageModeToSidebarView(mode) {
602 switch (mode) {
603 case "UseNone":
604 return SidebarView.NONE;
605
606 case "UseThumbs":
607 return SidebarView.THUMBS;
608
609 case "UseOutlines":
610 return SidebarView.OUTLINE;
611
612 case "UseAttachments":
613 return SidebarView.ATTACHMENTS;
614
615 case "UseOC":
616 return SidebarView.LAYERS;
617 }
618
619 return SidebarView.NONE;
620}
\No newline at end of file