2019-04-13 13:02:01 +00:00
/ * *
* @ licstart The following is the entire license notice for the
2022-09-05 17:42:02 +00:00
* JavaScript code in this page
2019-04-13 13:02:01 +00:00
*
2024-08-07 13:16:38 +00:00
* Copyright 2024 Mozilla Foundation
2016-07-09 08:54:13 +00:00
*
* 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 .
2019-04-13 13:02:01 +00:00
*
* @ licend The above is the entire license notice for the
2022-09-05 17:42:02 +00:00
* JavaScript code in this page
2016-07-09 08:54:13 +00:00
* /
2024-06-09 09:59:38 +00:00
/******/ // 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 _ _ = { } ;
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
// EXPORTS
_ _webpack _require _ _ . d ( _ _webpack _exports _ _ , {
PDFViewerApplication : ( ) => ( /* reexport */ PDFViewerApplication ) ,
PDFViewerApplicationConstants : ( ) => ( /* binding */ AppConstants ) ,
PDFViewerApplicationOptions : ( ) => ( /* reexport */ AppOptions )
} ) ;
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/ui_utils.js
2022-09-05 17:42:02 +00:00
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 ,
2024-06-09 09:59:38 +00:00
ENABLE _PERMISSIONS : 2
2022-09-05 17:42:02 +00:00
} ;
const ScrollMode = {
UNKNOWN : - 1 ,
VERTICAL : 0 ,
HORIZONTAL : 1 ,
WRAPPED : 2 ,
PAGE : 3
} ;
const SpreadMode = {
UNKNOWN : - 1 ,
NONE : 0 ,
ODD : 1 ,
EVEN : 2
} ;
2024-06-09 09:59:38 +00:00
const CursorTool = {
SELECT : 0 ,
HAND : 1 ,
ZOOM : 2
} ;
2022-09-05 17:42:02 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
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 ;
}
2024-07-13 08:49:47 +00:00
function watchScroll ( viewAreaElement , callback , abortSignal = undefined ) {
2022-09-05 17:42:02 +00:00
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 ;
2024-07-13 08:49:47 +00:00
viewAreaElement . addEventListener ( "scroll" , debounceScroll , {
useCapture : true ,
signal : abortSignal
} ) ;
abortSignal ? . addEventListener ( "abort" , ( ) => window . cancelAnimationFrame ( rAF ) , {
once : true
} ) ;
2022-09-05 17:42:02 +00:00
return state ;
}
function parseQueryString ( query ) {
const params = new Map ( ) ;
for ( const [ key , value ] of new URLSearchParams ( query ) ) {
params . set ( key . toLowerCase ( ) , value ) ;
}
return params ;
}
2024-06-09 09:59:38 +00:00
const InvisibleCharsRegExp = /[\x00-\x1F]/g ;
2022-09-05 17:42:02 +00:00
function removeNullCharacters ( str , replaceInvisible = false ) {
2024-06-09 09:59:38 +00:00
if ( ! InvisibleCharsRegExp . test ( str ) ) {
2022-09-05 17:42:02 +00:00
return str ;
}
if ( replaceInvisible ) {
2024-06-09 09:59:38 +00:00
return str . replaceAll ( InvisibleCharsRegExp , m => m === "\x00" ? "" : " " ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return str . replaceAll ( "\x00" , "" ) ;
2022-09-05 17:42:02 +00:00
}
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 ] ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
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 ,
2024-06-09 09:59:38 +00:00
b = 1 ,
c = 1 ,
d = 1 ;
2022-09-05 17:42:02 +00:00
while ( true ) {
const p = a + c ,
2024-06-09 09:59:38 +00:00
q = b + d ;
2022-09-05 17:42:02 +00:00
if ( q > limit ) {
break ;
}
if ( x _ <= p / q ) {
c = p ;
d = q ;
} else {
a = p ;
b = q ;
}
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
let result ;
if ( x _ - a / b < c / d - x _ ) {
result = x _ === x ? [ a , b ] : [ b , a ] ;
} else {
result = x _ === x ? [ c , d ] : [ d , c ] ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
return result ;
}
2024-07-13 08:49:47 +00:00
function floorToDivide ( x , div ) {
return x - x % div ;
2022-09-05 17:42:02 +00:00
}
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 ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
index = i ;
}
return index ;
}
function getVisibleElements ( {
scrollEl ,
views ,
sortByVisibility = false ,
horizontal = false ,
rtl = false
} ) {
const top = scrollEl . scrollTop ,
2024-06-09 09:59:38 +00:00
bottom = top + scrollEl . clientHeight ;
2022-09-05 17:42:02 +00:00
const left = scrollEl . scrollLeft ,
2024-06-09 09:59:38 +00:00
right = left + scrollEl . clientWidth ;
2022-09-05 17:42:02 +00:00
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 = [ ] ,
2024-06-09 09:59:38 +00:00
ids = new Set ( ) ,
numViews = views . length ;
2022-09-05 17:42:02 +00:00
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 ] ,
2024-06-09 09:59:38 +00:00
element = view . div ;
2022-09-05 17:42:02 +00:00
const currentWidth = element . offsetLeft + element . clientLeft ;
const currentHeight = element . offsetTop + element . clientTop ;
const viewWidth = element . clientWidth ,
2024-06-09 09:59:38 +00:00
viewHeight = element . clientHeight ;
2022-09-05 17:42:02 +00:00
const viewRight = currentWidth + viewWidth ;
const viewBottom = currentHeight + viewHeight ;
if ( lastEdge === - 1 ) {
if ( viewBottom >= bottom ) {
lastEdge = viewBottom ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
} else if ( ( horizontal ? currentWidth : currentHeight ) > lastEdge ) {
break ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
if ( viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right ) {
continue ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
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 ,
2024-06-09 09:59:38 +00:00
fractionWidth = ( viewWidth - hiddenWidth ) / viewWidth ;
2022-09-05 17:42:02 +00:00
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 ] ,
2024-06-09 09:59:38 +00:00
last = visible . at ( - 1 ) ;
2022-09-05 17:42:02 +00:00
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 ) {
2024-06-09 09:59:38 +00:00
const deltaMode = evt . deltaMode ;
2022-09-05 17:42:02 +00:00
let delta = normalizeWheelEventDirection ( evt ) ;
const MOUSE _PIXELS _PER _LINE = 30 ;
const MOUSE _LINES _PER _PAGE = 30 ;
2024-06-09 09:59:38 +00:00
if ( deltaMode === WheelEvent . DOM _DELTA _PIXEL ) {
2022-09-05 17:42:02 +00:00
delta /= MOUSE _PIXELS _PER _LINE * MOUSE _LINES _PER _PAGE ;
2024-06-09 09:59:38 +00:00
} else if ( deltaMode === WheelEvent . DOM _DELTA _LINE ) {
2022-09-05 17:42:02 +00:00
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 ;
2024-06-09 09:59:38 +00:00
# disableAutoFetchTimeout = null ;
2022-09-05 17:42:02 +00:00
# percent = 0 ;
2024-06-09 09:59:38 +00:00
# style = null ;
2022-09-05 17:42:02 +00:00
# visible = true ;
2024-06-09 09:59:38 +00:00
constructor ( bar ) {
2022-09-05 17:42:02 +00:00
this . # classList = bar . classList ;
2024-06-09 09:59:38 +00:00
this . # style = bar . style ;
2022-09-05 17:42:02 +00:00
}
get percent ( ) {
return this . # percent ;
}
set percent ( val ) {
this . # percent = clamp ( val , 0 , 100 ) ;
if ( isNaN ( val ) ) {
this . # classList . add ( "indeterminate" ) ;
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
this . # classList . remove ( "indeterminate" ) ;
2024-06-09 09:59:38 +00:00
this . # style . setProperty ( "--progressBar-percent" , ` ${ this . # percent } % ` ) ;
2022-09-05 17:42:02 +00:00
}
setWidth ( viewer ) {
if ( ! viewer ) {
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
const container = viewer . parentNode ;
const scrollbarWidth = container . offsetWidth - viewer . offsetWidth ;
if ( scrollbarWidth > 0 ) {
2024-06-09 09:59:38 +00:00
this . # style . setProperty ( "--progressBar-end-offset" , ` ${ scrollbarWidth } px ` ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
setDisableAutoFetch ( delay = 5000 ) {
2024-08-07 13:16:38 +00:00
if ( this . # percent === 100 || isNaN ( this . # percent ) ) {
2024-06-09 09:59:38 +00:00
return ;
}
if ( this . # disableAutoFetchTimeout ) {
clearTimeout ( this . # disableAutoFetchTimeout ) ;
}
this . show ( ) ;
this . # disableAutoFetchTimeout = setTimeout ( ( ) => {
this . # disableAutoFetchTimeout = null ;
this . hide ( ) ;
} , delay ) ;
}
2022-09-05 17:42:02 +00:00
hide ( ) {
if ( ! this . # visible ) {
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
this . # visible = false ;
this . # classList . add ( "hidden" ) ;
}
show ( ) {
if ( this . # visible ) {
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
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 ,
2024-06-09 09:59:38 +00:00
spreadMode = SpreadMode . NONE ;
2022-09-05 17:42:02 +00:00
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 ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/app_options.js
2022-09-05 17:42:02 +00:00
{
2024-08-07 13:16:38 +00:00
var compatParams = new Map ( ) ;
2022-09-05 17:42:02 +00:00
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 ;
2024-08-07 13:16:38 +00:00
( function ( ) {
2022-09-05 17:42:02 +00:00
if ( isIOS || isAndroid ) {
2024-08-07 13:16:38 +00:00
compatParams . set ( "maxCanvasPixels" , 5242880 ) ;
}
} ) ( ) ;
( function ( ) {
if ( isAndroid ) {
compatParams . set ( "useSystemFonts" , false ) ;
2022-09-05 17:42:02 +00:00
}
} ) ( ) ;
}
const OptionKind = {
2024-06-09 09:59:38 +00:00
BROWSER : 0x01 ,
2022-09-05 17:42:02 +00:00
VIEWER : 0x02 ,
API : 0x04 ,
WORKER : 0x08 ,
2024-08-07 13:16:38 +00:00
EVENT _DISPATCH : 0x10 ,
2022-09-05 17:42:02 +00:00
PREFERENCE : 0x80
} ;
2024-08-07 13:16:38 +00:00
const Type = {
BOOLEAN : 0x01 ,
NUMBER : 0x02 ,
OBJECT : 0x04 ,
STRING : 0x08 ,
UNDEFINED : 0x10
} ;
2022-09-05 17:42:02 +00:00
const defaultOptions = {
2024-08-07 13:16:38 +00:00
allowedGlobalEvents : {
value : null ,
kind : OptionKind . BROWSER
} ,
2024-06-09 09:59:38 +00:00
canvasMaxAreaInBytes : {
2022-09-05 17:42:02 +00:00
value : - 1 ,
2024-06-09 09:59:38 +00:00
kind : OptionKind . BROWSER + OptionKind . API
} ,
isInAutomation : {
value : false ,
kind : OptionKind . BROWSER
} ,
2024-08-07 13:16:38 +00:00
localeProperties : {
value : {
lang : navigator . language || "en-US"
} ,
kind : OptionKind . BROWSER
} ,
nimbusDataStr : {
value : "" ,
kind : OptionKind . BROWSER
} ,
2024-06-09 09:59:38 +00:00
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
} ,
2024-08-07 13:16:38 +00:00
toolbarDensity : {
value : 0 ,
kind : OptionKind . BROWSER + OptionKind . EVENT _DISPATCH
} ,
altTextLearnMoreUrl : {
value : "" ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-06-09 09:59:38 +00:00
annotationEditorMode : {
value : 0 ,
2022-09-05 17:42:02 +00:00
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
annotationMode : {
value : 2 ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
cursorToolOnLoad : {
value : 0 ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-06-09 09:59:38 +00:00
debuggerSrc : {
value : "./debugger.mjs" ,
kind : OptionKind . VIEWER
} ,
defaultZoomDelay : {
value : 400 ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2022-09-05 17:42:02 +00:00
defaultZoomValue : {
value : "" ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
disableHistory : {
value : false ,
kind : OptionKind . VIEWER
} ,
disablePageLabels : {
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-08-07 13:16:38 +00:00
enableAltText : {
2024-06-09 09:59:38 +00:00
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-08-07 13:16:38 +00:00
enableGuessAltText : {
value : true ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
enableHighlightEditor : {
2024-06-09 09:59:38 +00:00
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-08-07 13:16:38 +00:00
enableHighlightFloatingButton : {
2024-06-09 09:59:38 +00:00
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2022-09-05 17:42:02 +00:00
enablePermissions : {
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
enablePrintAutoRotate : {
value : true ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
enableScripting : {
value : true ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-08-07 13:16:38 +00:00
enableUpdatedAddImage : {
value : false ,
2024-06-09 09:59:38 +00:00
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2022-09-05 17:42:02 +00:00
externalLinkRel : {
value : "noopener noreferrer nofollow" ,
kind : OptionKind . VIEWER
} ,
externalLinkTarget : {
value : 0 ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2024-06-09 09:59:38 +00:00
highlightEditorColors : {
value : "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F" ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2022-09-05 17:42:02 +00:00
historyUpdateUrl : {
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
ignoreDestinationZoom : {
value : false ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
imageResourcesPath : {
value : "./images/" ,
kind : OptionKind . VIEWER
} ,
maxCanvasPixels : {
2024-06-09 09:59:38 +00:00
value : 2 * * 25 ,
2022-09-05 17:42:02 +00:00
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
} ,
2024-07-13 08:49:47 +00:00
enableHWA : {
value : true ,
kind : OptionKind . API + OptionKind . VIEWER + OptionKind . PREFERENCE
} ,
2022-09-05 17:42:02 +00:00
enableXfa : {
value : true ,
kind : OptionKind . API + OptionKind . PREFERENCE
} ,
fontExtraProperties : {
value : false ,
kind : OptionKind . API
} ,
isEvalSupported : {
value : true ,
kind : OptionKind . API
} ,
2024-06-09 09:59:38 +00:00
isOffscreenCanvasSupported : {
value : true ,
kind : OptionKind . API
} ,
2022-09-05 17:42:02 +00:00
maxImageSize : {
value : - 1 ,
kind : OptionKind . API
} ,
pdfBug : {
value : false ,
kind : OptionKind . API
} ,
standardFontDataUrl : {
value : "../web/standard_fonts/" ,
kind : OptionKind . API
} ,
2024-08-07 13:16:38 +00:00
useSystemFonts : {
value : undefined ,
kind : OptionKind . API ,
type : Type . BOOLEAN + Type . UNDEFINED
} ,
2022-09-05 17:42:02 +00:00
verbosity : {
value : 1 ,
kind : OptionKind . API
} ,
workerPort : {
value : null ,
kind : OptionKind . WORKER
} ,
workerSrc : {
2024-06-09 09:59:38 +00:00
value : "../build/pdf.worker.mjs" ,
2022-09-05 17:42:02 +00:00
kind : OptionKind . WORKER
}
} ;
{
defaultOptions . defaultUrl = {
value : "compressed.tracemonkey-pldi-09.pdf" ,
kind : OptionKind . VIEWER
} ;
2024-06-09 09:59:38 +00:00
defaultOptions . sandboxBundleSrc = {
value : "../build/pdf.sandbox.mjs" ,
kind : OptionKind . VIEWER
} ;
defaultOptions . viewerCssTheme = {
value : 0 ,
kind : OptionKind . VIEWER + OptionKind . PREFERENCE
} ;
}
{
2022-09-05 17:42:02 +00:00
defaultOptions . disablePreferences = {
value : false ,
kind : OptionKind . VIEWER
} ;
}
2024-08-07 13:16:38 +00:00
const userOptions = new Map ( ) ;
2024-06-09 09:59:38 +00:00
{
2024-08-07 13:16:38 +00:00
for ( const [ name , value ] of compatParams ) {
userOptions . set ( name , value ) ;
2024-06-09 09:59:38 +00:00
}
}
2022-09-05 17:42:02 +00:00
class AppOptions {
2024-08-07 13:16:38 +00:00
static eventBus ;
2022-09-05 17:42:02 +00:00
constructor ( ) {
throw new Error ( "Cannot initialize AppOptions." ) ;
}
static get ( name ) {
2024-08-07 13:16:38 +00:00
return userOptions . has ( name ) ? userOptions . get ( name ) : defaultOptions [ name ] ? . value ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
static getAll ( kind = null , defaultOnly = false ) {
2022-09-05 17:42:02 +00:00
const options = Object . create ( null ) ;
for ( const name in defaultOptions ) {
2024-08-07 13:16:38 +00:00
const defaultOpt = defaultOptions [ name ] ;
if ( kind && ! ( kind & defaultOpt . kind ) ) {
2024-06-09 09:59:38 +00:00
continue ;
2022-09-05 17:42:02 +00:00
}
2024-08-07 13:16:38 +00:00
options [ name ] = ! defaultOnly && userOptions . has ( name ) ? userOptions . get ( name ) : defaultOpt . value ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
return options ;
}
static set ( name , value ) {
2024-08-07 13:16:38 +00:00
this . setAll ( {
[ name ] : value
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-08-07 13:16:38 +00:00
static setAll ( options , prefs = false ) {
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 ;
2024-06-09 09:59:38 +00:00
}
2024-08-07 13:16:38 +00:00
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 ) ;
2024-06-09 09:59:38 +00:00
}
2024-08-07 13:16:38 +00:00
userOptions . set ( name , userOpt ) ;
2024-06-09 09:59:38 +00:00
}
2024-08-07 13:16:38 +00:00
if ( events ) {
for ( const [ name , value ] of events ) {
this . eventBus . dispatch ( name . toLowerCase ( ) , {
source : this ,
value
} ) ;
}
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-08-07 13:16:38 +00:00
}
{
AppOptions . _checkDisablePreferences = ( ) => {
if ( AppOptions . get ( "disablePreferences" ) ) {
return true ;
2024-06-09 09:59:38 +00:00
}
2024-08-07 13:16:38 +00:00
for ( const [ name ] of userOptions ) {
if ( compatParams . has ( name ) ) {
continue ;
}
console . warn ( "The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option to prevent that.' ) ;
break ;
}
return false ;
} ;
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_link_service.js
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
const DEFAULT _LINK _REL = "noopener noreferrer nofollow" ;
const LinkTarget = {
NONE : 0 ,
SELF : 1 ,
BLANK : 2 ,
PARENT : 3 ,
TOP : 4
} ;
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
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 ( ) {
2024-06-09 09:59:38 +00:00
return this . pdfDocument ? this . pdfViewer . currentPageNumber : 1 ;
2022-09-05 17:42:02 +00:00
}
set page ( value ) {
2024-06-09 09:59:38 +00:00
if ( this . pdfDocument ) {
this . pdfViewer . currentPageNumber = value ;
}
2022-09-05 17:42:02 +00:00
}
get rotation ( ) {
2024-06-09 09:59:38 +00:00
return this . pdfDocument ? this . pdfViewer . pagesRotation : 0 ;
2022-09-05 17:42:02 +00:00
}
set rotation ( value ) {
2024-06-09 09:59:38 +00:00
if ( this . pdfDocument ) {
this . pdfViewer . pagesRotation = value ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
if ( ! pageNumber ) {
2024-06-09 09:59:38 +00:00
try {
pageNumber = ( await this . pdfDocument . getPageIndex ( destRef ) ) + 1 ;
} catch {
console . error ( ` goToDestination: " ${ destRef } " is not a valid page reference, for dest=" ${ dest } ". ` ) ;
return ;
}
2022-09-05 17:42:02 +00:00
}
} else if ( Number . isInteger ( destRef ) ) {
pageNumber = destRef + 1 ;
}
if ( ! pageNumber || pageNumber < 1 || pageNumber > this . pagesCount ) {
2024-06-09 09:59:38 +00:00
console . error ( ` goToDestination: " ${ pageNumber } " is not a valid page number, for dest=" ${ dest } ". ` ) ;
2019-04-13 13:02:01 +00:00
return ;
}
2022-09-05 17:42:02 +00:00
if ( this . pdfHistory ) {
this . pdfHistory . pushCurrentPosition ( ) ;
this . pdfHistory . push ( {
namedDest ,
explicitDest ,
pageNumber
2021-03-25 17:57:25 +00:00
} ) ;
2022-09-05 17:42:02 +00:00
}
this . pdfViewer . scrollPageIntoView ( {
pageNumber ,
destArray : explicitDest ,
ignoreDestinationZoom : this . _ignoreDestinationZoom
} ) ;
}
goToPage ( val ) {
if ( ! this . pdfDocument ) {
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
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. ` ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2022-09-05 17:42:02 +00:00
if ( this . pdfHistory ) {
this . pdfHistory . pushCurrentPosition ( ) ;
this . pdfHistory . pushPage ( pageNumber ) ;
}
this . pdfViewer . scrollPageIntoView ( {
pageNumber
2021-03-25 17:57:25 +00:00
} ) ;
2022-09-05 17:42:02 +00:00
}
addLinkAttributes ( link , url , newWindow = false ) {
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
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 ) ) ;
2019-04-13 13:02:01 +00:00
}
}
2022-09-05 17:42:02 +00:00
return this . getAnchorUrl ( "" ) ;
}
getAnchorUrl ( anchor ) {
2024-06-09 09:59:38 +00:00
return this . baseUrl ? this . baseUrl + anchor : anchor ;
2022-09-05 17:42:02 +00:00
}
setHash ( hash ) {
if ( ! this . pdfDocument ) {
return ;
}
let pageNumber , dest ;
if ( hash . includes ( "=" ) ) {
2024-06-09 09:59:38 +00:00
const params = parseQueryString ( hash ) ;
2022-09-05 17:42:02 +00:00
if ( params . has ( "search" ) ) {
2024-06-09 09:59:38 +00:00
const query = params . get ( "search" ) . replaceAll ( '"' , "" ) ,
phrase = params . get ( "phrase" ) === "true" ;
2022-09-05 17:42:02 +00:00
this . eventBus . dispatch ( "findfromurlhash" , {
source : this ,
2024-06-09 09:59:38 +00:00
query : phrase ? query : query . match ( /\S+/g )
2022-09-05 17:42:02 +00:00
} ) ;
}
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 ] ;
2024-06-09 09:59:38 +00:00
} 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 {
2022-09-05 17:42:02 +00:00
dest = [ null , {
name : zoomArg
2024-06-09 09:59:38 +00:00
} , zoomArgs [ 1 ] | 0 , zoomArgs [ 2 ] | 0 , zoomArgs [ 3 ] | 0 , zoomArgs [ 4 ] | 0 ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} else {
console . error ( ` PDFLinkService.setHash: " ${ zoomArg } " is not a valid zoom value. ` ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
if ( dest ) {
this . pdfViewer . scrollPageIntoView ( {
pageNumber : pageNumber || this . page ,
destArray : dest ,
allowNegativeOffset : true
} ) ;
} else if ( pageNumber ) {
this . page = pageNumber ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
if ( params . has ( "pagemode" ) ) {
this . eventBus . dispatch ( "pagemode" , {
source : this ,
mode : params . get ( "pagemode" )
2019-04-13 13:02:01 +00:00
} ) ;
2022-09-05 17:42:02 +00:00
}
if ( params . has ( "nameddest" ) ) {
this . goToDestination ( params . get ( "nameddest" ) ) ;
}
2024-06-09 09:59:38 +00:00
return ;
}
dest = unescape ( hash ) ;
try {
dest = JSON . parse ( dest ) ;
if ( ! Array . isArray ( dest ) ) {
dest = dest . toString ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} catch { }
if ( typeof dest === "string" || PDFLinkService . # isValidExplicitDest ( dest ) ) {
this . goToDestination ( dest ) ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
console . error ( ` PDFLinkService.setHash: " ${ unescape ( hash ) } " is not a valid destination. ` ) ;
2022-09-05 17:42:02 +00:00
}
executeNamedAction ( action ) {
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
return ;
}
2022-09-05 17:42:02 +00:00
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
} ) ;
}
2024-06-09 09:59:38 +00:00
async executeSetOCGState ( action ) {
if ( ! this . pdfDocument ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const pdfDocument = this . pdfDocument ,
optionalContentConfig = await this . pdfViewer . optionalContentConfigPromise ;
if ( pdfDocument !== this . pdfDocument ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
optionalContentConfig . setOCGState ( action ) ;
this . pdfViewer . optionalContentConfigPromise = Promise . resolve ( optionalContentConfig ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
static # isValidExplicitDest ( dest ) {
if ( ! Array . isArray ( dest ) || dest . length < 2 ) {
2022-09-05 17:42:02 +00:00
return false ;
}
2024-06-09 09:59:38 +00:00
const [ page , zoom , ... args ] = dest ;
if ( ! ( typeof page === "object" && Number . isInteger ( page ? . num ) && Number . isInteger ( page ? . gen ) ) && ! Number . isInteger ( page ) ) {
2022-09-05 17:42:02 +00:00
return false ;
}
2024-06-09 09:59:38 +00:00
if ( ! ( typeof zoom === "object" && typeof zoom ? . name === "string" ) ) {
2022-09-05 17:42:02 +00:00
return false ;
}
2024-08-07 13:16:38 +00:00
const argsLen = args . length ;
2022-09-05 17:42:02 +00:00
let allowNull = true ;
switch ( zoom . name ) {
case "XYZ" :
2024-08-07 13:16:38 +00:00
if ( argsLen < 2 || argsLen > 3 ) {
2022-09-05 17:42:02 +00:00
return false ;
}
break ;
case "Fit" :
case "FitB" :
2024-08-07 13:16:38 +00:00
return argsLen === 0 ;
2022-09-05 17:42:02 +00:00
case "FitH" :
case "FitBH" :
case "FitV" :
case "FitBV" :
2024-08-07 13:16:38 +00:00
if ( argsLen > 1 ) {
2022-09-05 17:42:02 +00:00
return false ;
}
break ;
case "FitR" :
2024-08-07 13:16:38 +00:00
if ( argsLen !== 4 ) {
2021-03-25 17:57:25 +00:00
return false ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
allowNull = false ;
break ;
default :
return false ;
}
2024-06-09 09:59:38 +00:00
for ( const arg of args ) {
if ( ! ( typeof arg === "number" || allowNull && arg === null ) ) {
2022-09-05 17:42:02 +00:00
return false ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
return true ;
}
}
2024-06-09 09:59:38 +00:00
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." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
off ( eventName , listener , options = null ) {
this . _off ( eventName , listener ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
_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
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
_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 ;
}
}
}
}
2024-07-13 08:49:47 +00:00
class FirefoxEventBus extends EventBus {
# externalServices ;
# globalEventNames ;
# isInAutomation ;
constructor ( globalEventNames , externalServices , isInAutomation ) {
super ( ) ;
this . # globalEventNames = globalEventNames ;
this . # externalServices = externalServices ;
this . # isInAutomation = isInAutomation ;
}
2024-06-09 09:59:38 +00:00
dispatch ( eventName , data ) {
2024-07-13 08:49:47 +00:00
throw new Error ( "Not implemented: FirefoxEventBus.dispatch" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/external_services.js
class BaseExternalServices {
constructor ( ) {
if ( this . constructor === BaseExternalServices ) {
throw new Error ( "Cannot initialize BaseExternalServices." ) ;
}
}
updateFindControlState ( data ) { }
updateFindMatchesCount ( data ) { }
initPassiveLoading ( ) { }
reportTelemetry ( data ) { }
async createL10n ( ) {
2022-09-05 17:42:02 +00:00
throw new Error ( "Not implemented: createL10n" ) ;
}
2024-06-09 09:59:38 +00:00
createScripting ( ) {
2022-09-05 17:42:02 +00:00
throw new Error ( "Not implemented: createScripting" ) ;
}
2024-06-09 09:59:38 +00:00
updateEditorStates ( data ) {
throw new Error ( "Not implemented: updateEditorStates" ) ;
2022-09-05 17:42:02 +00:00
}
2024-07-13 08:49:47 +00:00
dispatchGlobalEvent ( _event ) { }
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/preferences.js
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
class BasePreferences {
# defaults = Object . freeze ( {
2024-08-07 13:16:38 +00:00
altTextLearnMoreUrl : "" ,
2024-06-09 09:59:38 +00:00
annotationEditorMode : 0 ,
annotationMode : 2 ,
cursorToolOnLoad : 0 ,
defaultZoomDelay : 400 ,
defaultZoomValue : "" ,
disablePageLabels : false ,
2024-08-07 13:16:38 +00:00
enableAltText : false ,
enableGuessAltText : true ,
2024-06-09 09:59:38 +00:00
enableHighlightEditor : false ,
enableHighlightFloatingButton : false ,
enablePermissions : false ,
enablePrintAutoRotate : true ,
enableScripting : true ,
2024-08-07 13:16:38 +00:00
enableUpdatedAddImage : false ,
2024-06-09 09:59:38 +00:00
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 ,
2024-07-13 08:49:47 +00:00
enableHWA : true ,
2024-06-09 09:59:38 +00:00
enableXfa : true ,
viewerCssTheme : 0
} ) ;
# initializedPromise = null ;
constructor ( ) {
if ( this . constructor === BasePreferences ) {
throw new Error ( "Cannot initialize BasePreferences." ) ;
}
this . # initializedPromise = this . _readFromStorage ( this . # defaults ) . then ( ( {
browserPrefs ,
prefs
} ) => {
2024-08-07 13:16:38 +00:00
if ( AppOptions . _checkDisablePreferences ( ) ) {
return ;
2024-06-09 09:59:38 +00:00
}
2024-08-07 13:16:38 +00:00
AppOptions . setAll ( {
... browserPrefs ,
... prefs
} , true ) ;
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
async _writeToStorage ( prefObj ) {
throw new Error ( "Not implemented: _writeToStorage" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async _readFromStorage ( prefObj ) {
throw new Error ( "Not implemented: _readFromStorage" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async reset ( ) {
await this . # initializedPromise ;
2024-08-07 13:16:38 +00:00
AppOptions . setAll ( this . # defaults , true ) ;
await this . _writeToStorage ( this . # defaults ) ;
2024-06-09 09:59:38 +00:00
}
async set ( name , value ) {
await this . # initializedPromise ;
2024-08-07 13:16:38 +00:00
AppOptions . setAll ( {
[ name ] : value
} , true ) ;
await this . _writeToStorage ( AppOptions . getAll ( OptionKind . PREFERENCE ) ) ;
2024-06-09 09:59:38 +00:00
}
async get ( name ) {
await this . # initializedPromise ;
2024-08-07 13:16:38 +00:00
return AppOptions . get ( name ) ;
2024-06-09 09:59:38 +00:00
}
get initializedPromise ( ) {
return this . # initializedPromise ;
}
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // 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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
}
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
}
; // CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/resolver.js
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 } ` ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} 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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
return errors ;
}
formatPattern ( pattern , args = null , errors = null ) {
if ( typeof pattern === "string" ) {
return this . _transform ( pattern ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let scope = new Scope ( this , errors , args ) ;
2022-09-05 17:42:02 +00:00
try {
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
throw err ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
function test ( re ) {
re . lastIndex = cursor ;
return re . test ( source ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function consumeChar ( char , errorClass ) {
if ( source [ cursor ] === char ) {
cursor ++ ;
return true ;
}
if ( errorClass ) {
throw new errorClass ( ` Expected ${ char } ` ) ;
}
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function consumeToken ( re , errorClass ) {
if ( test ( re ) ) {
cursor = re . lastIndex ;
return true ;
}
if ( errorClass ) {
throw new errorClass ( ` Expected ${ re . toString ( ) } ` ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function match1 ( re ) {
return match ( re ) [ 1 ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function parsePattern ( ) {
let first ;
if ( test ( RE _TEXT _RUN ) ) {
first = match1 ( RE _TEXT _RUN ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
function parseLiteral ( ) {
if ( test ( RE _NUMBER _LITERAL ) ) {
return parseNumberLiteral ( ) ;
}
if ( source [ cursor ] === '"' ) {
return parseStringLiteral ( ) ;
}
throw new SyntaxError ( "Invalid expression" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
function parseNumberLiteral ( ) {
let [ , value , fraction = "" ] = match ( RE _NUMBER _LITERAL ) ;
let precision = fraction . length ;
return {
type : "num" ,
value : parseFloat ( value ) ,
precision
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function parseEscapeSequence ( ) {
if ( test ( RE _STRING _ESCAPE ) ) {
return match1 ( RE _STRING _ESCAPE ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) : "<22> " ;
}
throw new SyntaxError ( "Unknown escape sequence" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( source [ cursor - 1 ] === " " ) {
return makeIndent ( source . slice ( start , cursor ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return false ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
function trim ( text , re ) {
return text . replace ( re , "" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function makeIndent ( blank ) {
let value = blank . replace ( RE _BLANK _LINES , "\n" ) ;
let length = RE _INDENT . exec ( blank ) [ 1 ] . length ;
return new Indent ( value , length ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
}
class Indent {
constructor ( value , length ) {
this . value = value ;
this . length = length ;
}
}
; // CONCATENATED MODULE: ./node_modules/@fluent/bundle/esm/index.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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" ]
2022-09-05 17:42:02 +00:00
} ,
2024-06-09 09:59:38 +00:00
"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 ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
const templateElement = element . ownerDocument . createElementNS ( "http://www.w3.org/1999/xhtml" , "template" ) ;
templateElement . innerHTML = value ;
overlayChildNodes ( templateElement . content , element ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ( ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ( ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . push ( this . iterator . next ( ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return this [ this . length - 1 ] ;
}
}
; // CONCATENATED MODULE: ./node_modules/cached-iterable/src/index.mjs
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./node_modules/@fluent/dom/esm/localization.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ]
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
}
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 )
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
}
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." ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2024-07-13 08:49:47 +00:00
if ( this . windowElement && this . pendingrAF ) {
this . windowElement . cancelAnimationFrame ( this . pendingrAF ) ;
}
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . translateMutations ( this . mutationObserver . takeRecords ( ) ) ;
this . mutationObserver . disconnect ( ) ;
}
resumeObserving ( ) {
if ( ! this . mutationObserver ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
for ( const root of this . roots ) {
this . mutationObserver . observe ( root , this . observerConfig ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
}
}
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
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/l10n.js
class L10n {
# dir ;
2024-07-13 08:49:47 +00:00
# elements = new Set ( ) ;
2024-06-09 09:59:38 +00:00
# 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 ) {
2024-07-13 08:49:47 +00:00
this . # elements . add ( element ) ;
2024-06-09 09:59:38 +00:00
try {
this . # l10n . connectRoot ( element ) ;
await this . # l10n . translateRoots ( ) ;
} catch { }
}
2024-07-13 08:49:47 +00:00
async destroy ( ) {
for ( const element of this . # elements ) {
this . # l10n . disconnectRoot ( element ) ;
}
this . # elements . clear ( ) ;
this . # l10n . pauseObserving ( ) ;
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/genericl10n.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
langs . push ( defaultLang ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
for ( const lang of langs ) {
const bundle = await this . # createBundle ( lang , baseURL , paths ) ;
if ( bundle ) {
yield bundle ;
2024-07-13 08:49:47 +00:00
} else if ( lang === "en-us" ) {
2024-06-09 09:59:38 +00:00
yield this . # createBundleFallback ( lang ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
}
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 )
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
}
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 - kb = { $size _kb } KB ( { $size _b } bytes ) \ npdfjs - document - properties - mb = { $size _mb } MB ( { $size _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 - string = { $date } , { $time } \ 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 - document - properties - page - size - orientation - landscape = landscape \ npdfjs - document - properties - page - size - name - a - three =
return createBundle ( lang , text ) ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/generic_scripting.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
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 ( ) ;
}
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/genericcom.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ( ) {
2024-08-07 13:16:38 +00:00
return new genericl10n _GenericL10n ( AppOptions . get ( "localeProperties" ) ? . lang ) ;
2024-06-09 09:59:38 +00:00
}
createScripting ( ) {
return new GenericScripting ( AppOptions . get ( "sandboxBundleSrc" ) ) ;
}
}
class MLManager {
2024-08-07 13:16:38 +00:00
async isEnabledFor ( _name ) {
return false ;
}
async deleteModel ( _service ) {
return null ;
}
2024-06-09 09:59:38 +00:00
async guess ( ) {
return null ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/alt_text_manager.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
const {
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ` ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
style . top = ` ${ top } px ` ;
} else {
dialog . classList . remove ( "positioned" ) ;
style . left = "" ;
style . top = "" ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
# finish ( ) {
if ( this . # overlayManager . active === this . # dialog ) {
this . # overlayManager . close ( this . # dialog ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
# 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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # hasUsedPointer = true ;
this . # removeOnClickListeners ( ) ;
}
# removeOnClickListeners ( ) {
for ( const element of this . _elements ) {
element . removeEventListener ( "click" , this . # boundOnClick ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
destroy ( ) {
this . # uiManager = null ;
this . # finish ( ) ;
this . # svgElement ? . remove ( ) ;
this . # svgElement = this . # rectElement = null ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/annotation_editor_params.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
} ;
editorFreeTextFontSize . addEventListener ( "input" , function ( ) {
dispatchEvent ( "FREETEXT_SIZE" , this . valueAsNumber ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
editorFreeTextColor . addEventListener ( "input" , function ( ) {
dispatchEvent ( "FREETEXT_COLOR" , this . value ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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" , ( ) => {
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 ;
}
}
} ) ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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
} ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( rect . right - PRECISION <= caretX ) {
const {
lastChild
} = element ;
if ( select ) {
selection . extend ( lastChild , lastChild . length ) ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
selection . setPosition ( lastChild , lastChild . length ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . # mainContainer . addEventListener ( "scrollend" , this . # setCaretPositionHelper . bind ( this , selection , caretX , select , newLineElement , null ) , {
once : true
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
moveCaret ( isUp , select ) {
const selection = document . getSelection ( ) ;
if ( selection . rangeCount === 0 ) {
2022-09-05 17:42:02 +00:00
return ;
}
const {
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
if ( ! newLineElement ) {
const node = this . # getNodeOnNextPage ( root , isUp ) ;
if ( ! node ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const [ caretX ] = this . # getCaretPosition ( selection , isUp ) ;
const {
parentElement
} = node ;
this . # setCaretPosition ( select , selection , parentElement , parentElement . getBoundingClientRect ( ) , caretX ) ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/download_manager.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . downloadData ( data , filename , contentType ) ;
return false ;
}
2024-07-13 08:49:47 +00:00
download ( data , url , filename , _options ) {
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" ;
}
2024-06-09 09:59:38 +00:00
download ( blobUrl , filename ) ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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." ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . # overlays . set ( dialog , {
canForceClose
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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." ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/password_prompt.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const passwordIncorrect = this . # reason === PasswordResponses . INCORRECT _PASSWORD ;
if ( ! this . _isViewerEmbedded || passwordIncorrect ) {
this . input . focus ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . label . setAttribute ( "data-l10n-id" , ` pdfjs-password- ${ passwordIncorrect ? "invalid" : "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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . close ( ) ;
this . input . value = "" ;
this . # updateCallback ( password ) ;
this . # updateCallback = null ;
}
async setUpdateCallback ( updateCallback , reason ) {
if ( this . # activeCapability ) {
await this . # activeCapability . promise ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # updateCallback = updateCallback ;
this . # reason = reason ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/base_tree_viewer.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
const TREEITEM _OFFSET _TOP = - 100 ;
const TREEITEM _SELECTED _CLASS = "selected" ;
class BaseTreeViewer {
constructor ( options ) {
if ( this . constructor === BaseTreeViewer ) {
throw new Error ( "Cannot initialize BaseTreeViewer." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
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 ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
_scrollToCurrentTreeItem ( treeItem ) {
if ( ! treeItem ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
currentNode = currentNode . parentNode ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _l10n . resume ( ) ;
this . _updateCurrentTreeItem ( treeItem ) ;
this . container . scrollTo ( treeItem . offsetLeft , treeItem . offsetTop + TREEITEM _OFFSET _TOP ) ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_attachment_viewer.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
class PDFAttachmentViewer extends BaseTreeViewer {
constructor ( options ) {
super ( options ) ;
this . downloadManager = options . downloadManager ;
this . eventBus . _on ( "fileattachmentannotation" , this . # appendAttachment . bind ( this ) ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
reset ( keepRenderedCapability = false ) {
super . reset ( ) ;
this . _attachments = null ;
if ( ! keepRenderedCapability ) {
this . _renderedCapability = Promise . withResolvers ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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" , {
2022-09-05 17:42:02 +00:00
source : this ,
2024-06-09 09:59:38 +00:00
attachmentsCount
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
_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 ) ;
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
# 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
} ) ;
} ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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" ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
activate ( ) {
if ( ! this . active ) {
this . active = true ;
this . element . addEventListener ( "mousedown" , this . _onMouseDown , true ) ;
this . element . classList . add ( CSS _CLASS _GRAB ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
deactivate ( ) {
if ( this . active ) {
this . active = false ;
this . element . removeEventListener ( "mousedown" , this . _onMouseDown , true ) ;
this . _endPan ( ) ;
this . element . classList . remove ( CSS _CLASS _GRAB ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
toggle ( ) {
if ( this . active ) {
this . deactivate ( ) ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
this . activate ( ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
ignoreTarget ( node ) {
return node . matches ( "a[href], a[href] *, input, textarea, button, button *, select, option" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ( ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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"
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_cursor_tools.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
2024-06-09 09:59:38 +00:00
}
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
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} ;
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
} ) ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_document_properties.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
const DEFAULT _FIELD _CONTENT = "-" ;
const NON _METRIC _LOCALES = [ "en-us" , "en-lr" , "my" ] ;
const US _PAGE _NAMES = {
"8.5x11" : "letter" ,
"8.5x14" : "legal"
} ;
const METRIC _PAGE _NAMES = {
"297x420" : "a-three" ,
"210x297" : "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 } ` ] ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
} ) ;
this . _isNonMetricLocale = NON _METRIC _LOCALES . includes ( l10n . getLanguage ( ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async close ( ) {
this . overlayManager . close ( this . dialog ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
setDocument ( pdfDocument ) {
if ( this . pdfDocument ) {
this . # reset ( ) ;
this . # updateUI ( true ) ;
}
if ( ! pdfDocument ) {
return ;
}
this . pdfDocument = pdfDocument ;
this . _dataAvailableCapability . resolve ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# reset ( ) {
this . pdfDocument = null ;
this . # fieldData = null ;
this . _dataAvailableCapability = Promise . withResolvers ( ) ;
this . _currentPageNumber = 1 ;
this . _pagesRotation = 0 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# updateUI ( reset = false ) {
if ( reset || ! this . # fieldData ) {
for ( const id in this . fields ) {
this . fields [ id ] . textContent = DEFAULT _FIELD _CONTENT ;
}
return ;
}
if ( 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 : DEFAULT _FIELD _CONTENT ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async # parseFileSize ( fileSize = 0 ) {
const kb = fileSize / 1024 ,
mb = kb / 1024 ;
if ( ! kb ) {
return undefined ;
}
return this . l10n . get ( ` pdfjs-document-properties- ${ mb >= 1 ? "mb" : "kb" } ` , {
size _mb : mb >= 1 && ( + mb . toPrecision ( 3 ) ) . toLocaleString ( ) ,
size _kb : mb < 1 && ( + kb . toPrecision ( 3 ) ) . toLocaleString ( ) ,
size _b : fileSize . toLocaleString ( )
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async # parsePageSize ( pageSizeInches , pagesRotation ) {
if ( ! pageSizeInches ) {
return undefined ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( pagesRotation % 180 !== 0 ) {
pageSizeInches = {
width : pageSizeInches . height ,
height : pageSizeInches . width
2022-09-05 17:42:02 +00:00
} ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
const isPortrait = isPortraitOrientation ( pageSizeInches ) ;
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 rawName = getPageName ( sizeInches , isPortrait , US _PAGE _NAMES ) || getPageName ( sizeMillimeters , isPortrait , METRIC _PAGE _NAMES ) ;
if ( ! rawName && ! ( 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 ) {
rawName = getPageName ( intMillimeters , isPortrait , METRIC _PAGE _NAMES ) ;
if ( rawName ) {
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 ( [ this . _isNonMetricLocale ? sizeInches : sizeMillimeters , this . l10n . get ( ` pdfjs-document-properties-page-size-unit- ${ this . _isNonMetricLocale ? "inches" : "millimeters" } ` ) , rawName && this . l10n . get ( ` pdfjs-document-properties-page-size-name- ${ rawName } ` ) , this . l10n . get ( ` pdfjs-document-properties-page-size-orientation- ${ isPortrait ? "portrait" : "landscape" } ` ) ] ) ;
return this . l10n . get ( ` pdfjs-document-properties-page-size-dimension- ${ name ? "name-" : "" } string ` , {
width : width . toLocaleString ( ) ,
height : height . toLocaleString ( ) ,
unit ,
name ,
orientation
} ) ;
}
async # parseDate ( inputDate ) {
const dateObject = PDFDateString . toDateObject ( inputDate ) ;
if ( ! dateObject ) {
return undefined ;
}
return this . l10n . get ( "pdfjs-document-properties-date-string" , {
date : dateObject . toLocaleDateString ( ) ,
time : dateObject . toLocaleTimeString ( )
} ) ;
}
# parseLinearization ( isLinearized ) {
return this . l10n . get ( ` pdfjs-document-properties-linearized- ${ isLinearized ? "yes" : "no" } ` ) ;
}
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
function isAscii ( charCode ) {
return ( charCode & 0xff80 ) === 0 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isAsciiAlpha ( charCode ) {
return charCode >= 0x61 && charCode <= 0x7a || charCode >= 0x41 && charCode <= 0x5a ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isAsciiDigit ( charCode ) {
return charCode >= 0x30 && charCode <= 0x39 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isAsciiSpace ( charCode ) {
return charCode === 0x20 || charCode === 0x09 || charCode === 0x0d || charCode === 0x0a ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
function isHan ( charCode ) {
return charCode >= 0x3400 && charCode <= 0x9fff || charCode >= 0xf900 && charCode <= 0xfaff ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isKatakana ( charCode ) {
return charCode >= 0x30a0 && charCode <= 0x30ff ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isHiragana ( charCode ) {
return charCode >= 0x3040 && charCode <= 0x309f ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isHalfwidthKatakana ( charCode ) {
return charCode >= 0xff60 && charCode <= 0xff9f ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function isThai ( charCode ) {
return ( charCode & 0xff80 ) === 0x0e00 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2020-02-09 16:02:28 +00:00
}
2024-06-09 09:59:38 +00:00
return CharacterType . ALPHA _LETTER ;
2020-02-09 16:02:28 +00:00
}
2024-06-09 09:59:38 +00:00
let NormalizeWithNFKC ;
function getNormalizeWithNFKC ( ) {
NormalizeWithNFKC || = ` ¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓ ℕ -№ℙ-ℝ℠-™ℤΩℨK-ℭ ℯ -ℱ ℳ -ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰꟲ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩ ` ;
return NormalizeWithNFKC ;
2022-09-05 17:42:02 +00:00
}
2020-02-09 16:02:28 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_find_controller.js
2020-02-09 16:02:28 +00:00
2024-06-09 09:59:38 +00:00
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 ++ ] ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let normalizationRegex ;
if ( syllablePositions . length === 0 && noSyllablesRegExp ) {
normalizationRegex = noSyllablesRegExp ;
} else if ( syllablePositions . length > 0 && withSyllablesRegExp ) {
normalizationRegex = withSyllablesRegExp ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
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" ) ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
const rawDiacriticsPositions = [ ] ;
while ( ( m = DIACRITICS _REG _EXP . exec ( text ) ) !== null ) {
rawDiacriticsPositions . push ( [ m [ 0 ] . length , m . index ] ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
positions . push ( [ i - 1 - shift + 1 , shift - 1 ] ) ;
shift -= 1 ;
shiftOrigin += 1 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
positions . push ( [ i - shift + 1 , shift ] ) ;
shiftOrigin += 1 ;
eol += 1 ;
return p3 . charAt ( 0 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2020-02-09 16:02:28 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function getOriginalIndex ( diffs , pos , len ) {
if ( ! diffs ) {
return [ pos , len ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const start = pos ;
const end = pos + len - 1 ;
let i = binarySearchFirstItem ( diffs , x => x [ 0 ] >= start ) ;
if ( diffs [ i ] [ 0 ] > start ) {
-- i ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let j = binarySearchFirstItem ( diffs , x => x [ 0 ] >= end , i ) ;
if ( diffs [ j ] [ 0 ] > end ) {
-- j ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const oldStart = start + diffs [ i ] [ 1 ] ;
const oldEnd = end + diffs [ j ] [ 1 ] ;
const oldLen = oldEnd + 1 - oldStart ;
return [ oldStart , oldLen ] ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
class PDFFindController {
# state = null ;
# updateMatchesCountOnProgress = true ;
# visitedPagesCount = 0 ;
constructor ( {
linkService ,
2022-09-05 17:42:02 +00:00
eventBus ,
2024-06-09 09:59:38 +00:00
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 ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get highlightMatches ( ) {
return this . _highlightMatches ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get pageMatches ( ) {
return this . _pageMatches ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get pageMatchesLength ( ) {
return this . _pageMatchesLength ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get selected ( ) {
return this . _selected ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get state ( ) {
return this . # state ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
setDocument ( pdfDocument ) {
if ( this . _pdfDocument ) {
this . # reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! pdfDocument ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _pdfDocument = pdfDocument ;
this . _firstPageCapability . resolve ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# onFind ( state ) {
if ( ! state ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const pdfDocument = this . _pdfDocument ;
const {
type
} = state ;
if ( this . # state === null || this . # shouldDirtyMatch ( state ) ) {
this . _dirtyMatch = true ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . # state = state ;
if ( type !== "highlightallchange" ) {
this . # updateUIState ( FindState . PENDING ) ;
}
this . _firstPageCapability . promise . then ( ( ) => {
if ( ! this . _pdfDocument || pdfDocument && this . _pdfDocument !== pdfDocument ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return this . _normalizedQuery ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} 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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return true ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# calculateRegExpMatch ( query , entireWord , pageIndex , pageContent ) {
const matches = this . _pageMatches [ pageIndex ] = [ ] ;
const matchesLength = this . _pageMatchesLength [ pageIndex ] = [ ] ;
if ( ! query ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const diffs = this . _pageDiffs [ pageIndex ] ;
let match ;
while ( ( match = query . exec ( pageContent ) ) !== null ) {
if ( entireWord && ! this . # isEntireWord ( pageContent , match . index , match [ 0 ] . length ) ) {
continue ;
}
const [ matchPos , matchLen ] = getOriginalIndex ( diffs , match . index , match [ 0 ] . length ) ;
if ( matchLen ) {
matches . push ( matchPos ) ;
matchesLength . push ( matchLen ) ;
2022-09-05 17:42:02 +00:00
}
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# calculateMatch ( pageIndex ) {
let query = this . # query ;
if ( query . length === 0 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const {
caseSensitive ,
entireWord
} = this . # state ;
const pageContent = this . _pageContents [ 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 ( "|" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const flags = ` g ${ isUnicode ? "u" : "" } ${ caseSensitive ? "" : "i" } ` ;
query = query ? new RegExp ( query , flags ) : null ;
this . # calculateRegExpMatch ( query , entireWord , pageIndex , pageContent ) ;
if ( this . # state . highlightAll ) {
this . # updatePage ( pageIndex ) ;
}
if ( this . _resumePageIdx === pageIndex ) {
this . _resumePageIdx = null ;
this . # nextPageMatch ( ) ;
}
const pageMatchesCount = this . _pageMatches [ pageIndex ] . length ;
this . _matchesCountTotal += pageMatchesCount ;
if ( this . # updateMatchesCountOnProgress ) {
if ( pageMatchesCount > 0 ) {
this . # updateUIResultsCount ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} else if ( ++ this . # visitedPagesCount === this . _linkService . pagesCount ) {
this . # updateUIResultsCount ( ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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" ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
[ 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 ( ) ;
} ) ;
} ) ;
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# updatePage ( index ) {
if ( this . _scrollMatches && this . _selected . pageIdx === index ) {
this . _linkService . page = index + 1 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _eventBus . dispatch ( "updatetextlayermatches" , {
source : this ,
pageIndex : index
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# updateAllPages ( ) {
this . _eventBus . dispatch ( "updatetextlayermatches" , {
source : this ,
pageIndex : - 1
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ) ;
} ) ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
const query = this . # query ;
if ( query . length === 0 ) {
this . # updateUIState ( FindState . FOUND ) ;
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . # advanceOffsetPage ( previous ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . # nextPageMatch ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . # advanceOffsetPage ( previous ) ;
if ( offset . wrapped ) {
offset . matchIdx = null ;
if ( this . _pagesToSearch < 0 ) {
this . # updateMatch ( false ) ;
return true ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return false ;
}
# nextPageMatch ( ) {
if ( this . _resumePageIdx !== null ) {
console . error ( "There can only be one pending page." ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
let matches = null ;
do {
const pageIdx = this . _offset . pageIdx ;
matches = this . _pageMatches [ pageIdx ] ;
if ( ! matches ) {
this . _resumePageIdx = pageIdx ;
break ;
}
} while ( ! this . # matchesReady ( matches ) ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ) ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ( ) ;
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
# 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 ( )
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
# updateUIState ( state , previous = false ) {
if ( ! this . # updateMatchesCountOnProgress && ( this . # visitedPagesCount !== this . _linkService . pagesCount || state === FindState . PENDING ) ) {
return ;
}
this . _eventBus . dispatch ( "updatefindcontrolstate" , {
source : this ,
state ,
previous ,
2024-07-13 08:49:47 +00:00
entireWord : this . # state ? . entireWord ? ? null ,
2024-06-09 09:59:38 +00:00
matchesCount : this . # requestMatchesCount ( ) ,
rawQuery : this . # state ? . query ? ? null
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_find_bar.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
} ) ;
2024-06-09 09:59:38 +00:00
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" ) ;
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
reset ( ) {
this . updateUIState ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 = ` pdfjs-find-reached- ${ previous ? "top" : "bottom" } ` ;
break ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
updateResultsCount ( {
current = 0 ,
total = 0
} = { } ) {
const {
findResultsCount
} = this ;
if ( total > 0 ) {
const limit = MATCHES _COUNT _LIMIT ;
findResultsCount . setAttribute ( "data-l10n-id" , ` pdfjs-find-match-count ${ total > limit ? "-limit" : "" } ` ) ;
findResultsCount . setAttribute ( "data-l10n-args" , JSON . stringify ( {
limit ,
current ,
total
} ) ) ;
} else {
findResultsCount . removeAttribute ( "data-l10n-id" ) ;
findResultsCount . textContent = "" ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
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" ) ;
2021-03-25 17:57:25 +00:00
}
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_history.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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
} ) ;
2019-04-13 13:02:01 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
initialize ( {
fingerprint ,
resetHistory = false ,
updateUrl = false
} ) {
if ( ! fingerprint || typeof fingerprint !== "string" ) {
console . error ( 'PDFHistory.initialize: The "fingerprint" must be a non-empty string.' ) ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . _initialized ) {
this . reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const destination = state . destination ;
this . # updateInternalState ( destination , state . uid , true ) ;
if ( destination . rotation !== undefined ) {
this . _initialRotation = destination . rotation ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 } ` ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
push ( {
namedDest = null ,
explicitDest ,
pageNumber
} ) {
if ( ! this . _initialized ) {
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const hash = namedDest || JSON . stringify ( explicitDest ) ;
if ( ! hash ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
let forceReplace = false ;
if ( this . _destination && ( isDestHashesEqual ( this . _destination . hash , hash ) || isDestArraysEqual ( this . _destination . dest , explicitDest ) ) ) {
if ( this . _destination . page ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
} ) ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
pushPage ( pageNumber ) {
if ( ! this . _initialized ) {
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . # isValidPage ( pageNumber ) ) {
console . error ( ` PDFHistory.pushPage: " ${ pageNumber } " is not a valid page number. ` ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( this . _destination ? . page === pageNumber ) {
return ;
}
if ( this . _popStateInProgress ) {
return ;
}
this . # pushOrReplaceState ( {
dest : null ,
hash : ` page= ${ pageNumber } ` ,
page : pageNumber ,
rotation : this . linkService . rotation
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( ! this . _popStateInProgress ) {
this . _popStateInProgress = true ;
Promise . resolve ( ) . then ( ( ) => {
this . _popStateInProgress = false ;
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
pushCurrentPosition ( ) {
if ( ! this . _initialized || this . _popStateInProgress ) {
return ;
}
this . # tryPushCurrentPosition ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
back ( ) {
if ( ! this . _initialized || this . _popStateInProgress ) {
return ;
}
const state = window . history . state ;
if ( this . # isValidState ( state ) && state . uid > 0 ) {
window . history . back ( ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
forward ( ) {
if ( ! this . _initialized || this . _popStateInProgress ) {
return ;
}
const state = window . history . state ;
if ( this . # isValidState ( state ) && state . uid < this . _maxUid ) {
window . history . forward ( ) ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get popStateInProgress ( ) {
return this . _initialized && ( this . _popStateInProgress || this . _blockHashChange > 0 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get initialBookmark ( ) {
return this . _initialized ? this . _initialBookmark : null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get initialRotation ( ) {
return this . _initialized ? this . _initialRotation : null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# pushOrReplaceState ( destination , forceReplace = false ) {
const shouldReplace = forceReplace || ! this . _destination ;
const newState = {
fingerprint : this . _fingerprint ,
uid : shouldReplace ? this . _uid : this . _uid + 1 ,
destination
2021-03-25 17:57:25 +00:00
} ;
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
# tryPushCurrentPosition ( temporary = false ) {
if ( ! this . _position ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# isValidPage ( val ) {
return Number . isInteger ( val ) && val > 0 && val <= this . linkService . pagesCount ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# isValidState ( state , checkReload = false ) {
if ( ! state ) {
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( state . destination === null || typeof state . destination !== "object" ) {
return false ;
}
return true ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# updateInternalState ( destination , uid , removeTemporary = false ) {
if ( this . _updateViewareaTimeout ) {
clearTimeout ( this . _updateViewareaTimeout ) ;
this . _updateViewareaTimeout = null ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( removeTemporary && destination ? . temporary ) {
delete destination . temporary ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _destination = destination ;
this . _uid = uid ;
this . _maxUid = Math . max ( this . _maxUid , uid ) ;
this . _numPositionUpdates = 0 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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
} ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
# updateViewarea ( {
location
} ) {
if ( this . _updateViewareaTimeout ) {
clearTimeout ( this . _updateViewareaTimeout ) ;
this . _updateViewareaTimeout = null ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _position = {
hash : location . pdfOpenParams . substring ( 1 ) ,
page : this . linkService . page ,
first : location . pageNumber ,
rotation : location . rotation
} ;
if ( this . _popStateInProgress ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( POSITION _UPDATED _THRESHOLD > 0 && this . _isPagesLoaded && this . _destination && ! this . _destination . page ) {
this . _numPositionUpdates ++ ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( UPDATE _VIEWAREA _TIMEOUT > 0 ) {
this . _updateViewareaTimeout = setTimeout ( ( ) => {
if ( ! this . _popStateInProgress ) {
this . # tryPushCurrentPosition ( true ) ;
}
this . _updateViewareaTimeout = null ;
} , UPDATE _VIEWAREA _TIMEOUT ) ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( ! this . # isValidState ( state ) ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
# bindEvents ( ) {
if ( this . # eventAbortController ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( Array . isArray ( first ) || Array . isArray ( second ) ) {
return false ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
return true ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return first === second || Number . isNaN ( first ) && Number . isNaN ( second ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! ( Array . isArray ( firstDest ) && Array . isArray ( secondDest ) ) ) {
return false ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( firstDest . length !== secondDest . length ) {
return false ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
for ( let i = 0 , ii = firstDest . length ; i < ii ; i ++ ) {
if ( ! isEntryEqual ( firstDest [ i ] , secondDest [ i ] ) ) {
return false ;
}
}
return true ;
2021-03-25 17:57:25 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_layer_viewer.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
class PDFLayerViewer extends BaseTreeViewer {
constructor ( options ) {
super ( options ) ;
this . eventBus . _on ( "optionalcontentconfigchanged" , evt => {
this . # updateLayers ( evt . promise ) ;
2019-04-13 13:02:01 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . eventBus . _on ( "resetlayers" , ( ) => {
this . # updateLayers ( ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . eventBus . _on ( "togglelayerstree" , this . _toggleAllTreeItems . bind ( this ) ) ;
2021-03-25 17:57:25 +00:00
}
reset ( ) {
2024-06-09 09:59:38 +00:00
super . reset ( ) ;
this . _optionalContentConfig = null ;
this . _optionalContentHash = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_dispatchEvent ( layersCount ) {
this . eventBus . dispatch ( "layersloaded" , {
2021-03-25 17:57:25 +00:00
source : this ,
2024-06-09 09:59:38 +00:00
layersCount
2021-03-25 17:57:25 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
_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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
input . checked = ! input . checked ;
setVisibility ( ) ;
return false ;
} ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async _setNestedName ( element , {
name = null
} ) {
if ( typeof name === "string" ) {
element . textContent = this . _normalizeTextContent ( name ) ;
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
element . textContent = await this . _l10n . get ( "pdfjs-additional-layers" ) ;
element . style . fontStyle = "italic" ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_addToggleButton ( div , {
name = null
} ) {
super . _addToggleButton ( div , name === null ) ;
}
_toggleAllTreeItems ( ) {
if ( ! this . _optionalContentConfig ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
super . _toggleAllTreeItems ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
render ( {
optionalContentConfig ,
pdfDocument
} ) {
if ( this . _optionalContentConfig ) {
this . reset ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . _optionalContentConfig = optionalContentConfig || null ;
this . _pdfDocument = pdfDocument || null ;
const groups = optionalContentConfig ? . getOrder ( ) ;
if ( ! groups ) {
this . _dispatchEvent ( 0 ) ;
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
this . _finishRendering ( fragment , layersCount , hasAnyNesting ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "optionalcontentconfig" , {
source : this ,
promise : Promise . resolve ( optionalContentConfig )
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . render ( {
optionalContentConfig ,
pdfDocument : this . _pdfDocument
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_outline_viewer.js
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( action ) {
element . href = linkService . getAnchorUrl ( "" ) ;
element . onclick = ( ) => {
linkService . executeNamedAction ( action ) ;
return false ;
} ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( attachment ) {
element . href = linkService . getAnchorUrl ( "" ) ;
element . onclick = ( ) => {
this . downloadManager . openOrDownloadData ( attachment . content , attachment . filename ) ;
return false ;
} ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return false ;
} ;
}
_setStyles ( element , {
bold ,
italic
} ) {
if ( bold ) {
element . style . fontWeight = "bold" ;
}
if ( italic ) {
element . style . fontStyle = "italic" ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
_addToggleButton ( div , {
count ,
items
2021-03-25 17:57:25 +00:00
} ) {
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_toggleAllTreeItems ( ) {
if ( ! this . _outline ) {
return ;
}
super . _toggleAllTreeItems ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
render ( {
outline ,
pdfDocument
} ) {
if ( this . _outline ) {
this . reset ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . _outline = outline || null ;
this . _pdfDocument = pdfDocument || null ;
if ( ! outline ) {
this . _dispatchEvent ( 0 ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async _currentOutlineItem ( ) {
if ( ! this . _isPagesLoaded ) {
throw new Error ( "_currentOutlineItem: All pages have not been loaded." ) ;
}
if ( ! this . _outline || ! this . _pdfDocument ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const pageNumberToDestHash = await this . _getPageNumberToDestHash ( this . _pdfDocument ) ;
if ( ! pageNumberToDestHash ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _updateCurrentTreeItem ( null ) ;
if ( this . _sidebarView !== SidebarView . OUTLINE ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
for ( let i = this . _currentPageNumber ; i > 0 ; i -- ) {
const destHash = pageNumberToDestHash . get ( i ) ;
if ( ! destHash ) {
continue ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
const linkElement = this . container . querySelector ( ` a[href=" ${ destHash } "] ` ) ;
if ( ! linkElement ) {
continue ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2019-04-13 13:02:01 +00:00
} else {
2024-06-09 09:59:38 +00:00
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
} ) ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
}
this . _pageNumberToDestHashCapability . resolve ( pageNumberToDestHash . size > 0 ? pageNumberToDestHash : null ) ;
return this . _pageNumberToDestHashCapability . promise ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_presentation_mode.js
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async request ( ) {
const {
container ,
pdfViewer
} = this ;
if ( this . active || ! pdfViewer . pagesCount || ! container . requestFullscreen ) {
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( pdfViewer . annotationEditorMode !== AnnotationEditorType . DISABLE ) {
this . # args . annotationEditorMode = pdfViewer . annotationEditorMode ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
try {
await promise ;
pdfViewer . focus ( ) ;
return true ;
} catch {
this . # removeFullscreenChangeListeners ( ) ;
this . # notifyStateChange ( PresentationModeState . NORMAL ) ;
}
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get active ( ) {
return this . # state === PresentationModeState . CHANGING || this . # state === PresentationModeState . FULLSCREEN ;
}
# mouseWheel ( evt ) {
if ( ! this . active ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
evt . preventDefault ( ) ;
const delta = normalizeWheelEventDelta ( evt ) ;
const currentTime = Date . now ( ) ;
const storedTime = this . mouseScrollTimeStamp ;
if ( currentTime > storedTime && currentTime - storedTime < MOUSE _SCROLL _COOLDOWN _TIME ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
}
}
2024-06-09 09:59:38 +00:00
# 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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . pdfViewer . currentPageNumber = this . # args . pageNumber ;
this . pdfViewer . currentScaleValue = "page-fit" ;
if ( this . # args . annotationEditorMode !== null ) {
this . pdfViewer . annotationEditorMode = {
mode : AnnotationEditorType . NONE
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} , 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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . pdfViewer . currentScaleValue = this . # args . scaleValue ;
this . pdfViewer . currentPageNumber = pageNumber ;
if ( this . # args . annotationEditorMode !== null ) {
this . pdfViewer . annotationEditorMode = {
mode : this . # args . annotationEditorMode
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # args = null ;
} , 0 ) ;
this . # removeWindowListeners ( ) ;
this . # hideControls ( ) ;
this . # resetMouseScrollState ( ) ;
this . contextMenuOpen = false ;
}
# mouseDown ( evt ) {
if ( this . contextMenuOpen ) {
this . contextMenuOpen = false ;
evt . preventDefault ( ) ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( evt . button !== 0 ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( evt . target . href && evt . target . parentNode ? . hasAttribute ( "data-internal-link" ) ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
evt . preventDefault ( ) ;
if ( evt . shiftKey ) {
this . pdfViewer . previousPage ( ) ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
this . pdfViewer . nextPage ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
# contextMenu ( ) {
this . contextMenuOpen = true ;
}
# showControls ( ) {
if ( this . controlsTimeout ) {
clearTimeout ( this . controlsTimeout ) ;
} else {
this . container . classList . add ( CONTROLS _SELECTOR ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . controlsTimeout = setTimeout ( ( ) => {
this . container . classList . remove ( CONTROLS _SELECTOR ) ;
delete this . controlsTimeout ;
} , DELAY _BEFORE _HIDING _CONTROLS ) ;
}
# hideControls ( ) {
if ( ! this . controlsTimeout ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
clearTimeout ( this . controlsTimeout ) ;
this . container . classList . remove ( CONTROLS _SELECTOR ) ;
delete this . controlsTimeout ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# resetMouseScrollState ( ) {
this . mouseScrollTimeStamp = 0 ;
this . mouseScrollDelta = 0 ;
}
# touchSwipe ( evt ) {
if ( ! this . active ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
# addWindowListeners ( ) {
if ( this . # windowAbortController ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
# 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
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
# removeFullscreenChangeListeners ( ) {
this . # fullscreenChangeAbortController ? . abort ( ) ;
this . # fullscreenChangeAbortController = null ;
}
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/xfa_layer_builder.js
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const xfaHtml = await this . pdfPage . getXfa ( ) ;
if ( this . _cancelled || ! xfaHtml ) {
return {
textDivs : [ ]
} ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . div . hidden = true ;
}
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/print_utils.js
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_print_service.js
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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!" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . pageStyleSheet = document . createElement ( "style" ) ;
this . pageStyleSheet . textContent = ` @page { size: ${ width } pt ${ height } pt;} ` ;
body . append ( this . pageStyleSheet ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
destroy ( ) {
if ( activeService !== this ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . printContainer . textContent = "" ;
const body = document . querySelector ( "body" ) ;
body . removeAttribute ( "data-pdfjsprinting" ) ;
if ( this . pageStyleSheet ) {
this . pageStyleSheet . remove ( ) ;
this . pageStyleSheet = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . scratchCanvas . width = this . scratchCanvas . height = 0 ;
this . scratchCanvas = null ;
activeService = null ;
ensureOverlay ( ) . then ( function ( ) {
if ( overlayManager . active === dialog ) {
overlayManager . close ( dialog ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
renderPages ( ) {
if ( this . pdfDocument . isPureXfa ) {
getXfaHtmlForPrinting ( this . printContainer , this . pdfDocument ) ;
return Promise . resolve ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
return new Promise ( renderNextPage ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
useRenderedPage ( ) {
this . throwIfInactive ( ) ;
const img = document . createElement ( "img" ) ;
const scratchCanvas = this . scratchCanvas ;
if ( "toBlob" in scratchCanvas ) {
scratchCanvas . toBlob ( function ( blob ) {
img . src = URL . createObjectURL ( blob ) ;
} ) ;
} else {
img . src = scratchCanvas . toDataURL ( ) ;
}
const wrapper = document . createElement ( "div" ) ;
wrapper . className = "printedPage" ;
wrapper . append ( img ) ;
this . printContainer . append ( wrapper ) ;
return new Promise ( function ( resolve , reject ) {
img . onload = resolve ;
img . onerror = reject ;
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
performPrint ( ) {
this . throwIfInactive ( ) ;
return new Promise ( resolve => {
setTimeout ( ( ) => {
if ( ! this . active ) {
resolve ( ) ;
return ;
}
print . call ( window ) ;
setTimeout ( resolve , 20 ) ;
} , 0 ) ;
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
get active ( ) {
return this === activeService ;
}
throwIfInactive ( ) {
if ( ! this . active ) {
throw new Error ( "This print request was cancelled or completed." ) ;
}
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function abort ( ) {
if ( activeService ) {
activeService . destroy ( ) ;
dispatchEvent ( "afterprint" ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let overlayPromise ;
function ensureOverlay ( ) {
if ( ! overlayPromise ) {
overlayManager = viewerApp . overlayManager ;
if ( ! overlayManager ) {
throw new Error ( "The overlay manager has not yet been initialized." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
dialog || = document . getElementById ( "printServiceDialog" ) ;
overlayPromise = overlayManager . register ( dialog , true ) ;
document . getElementById ( "printCancel" ) . onclick = abort ;
dialog . addEventListener ( "close" , abort ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return overlayPromise ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_rendering_queue.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
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 ) ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( this . isThumbnailViewEnabled && this . pdfThumbnailViewer ? . forceRendering ( ) ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . printing ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( this . onIdle ) {
this . idleTimeout = setTimeout ( this . onIdle . bind ( this ) , CLEANUP _TIMEOUT ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
getHighestPriority ( visible , views , scrolledDown , preRenderExtra = false ) {
const visibleViews = visible . views ,
numVisible = visibleViews . length ;
if ( numVisible === 0 ) {
return null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
for ( let i = 0 ; i < numVisible ; i ++ ) {
const view = visibleViews [ i ] . view ;
if ( ! this . isViewFinished ( view ) ) {
return view ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let preRenderIndex = scrolledDown ? lastId : firstId - 2 ;
let preRenderView = views [ preRenderIndex ] ;
if ( preRenderView && ! this . isViewFinished ( preRenderView ) ) {
return preRenderView ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( preRenderExtra ) {
preRenderIndex += scrolledDown ? 1 : - 1 ;
preRenderView = views [ preRenderIndex ] ;
if ( preRenderView && ! this . isViewFinished ( preRenderView ) ) {
return preRenderView ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return true ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_scripting_manager.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const [ objects , calculationOrder , docActions ] = await Promise . all ( [ pdfDocument . getFieldObjects ( ) , pdfDocument . getCalculationOrderIds ( ) , pdfDocument . getJSActions ( ) ] ) ;
if ( ! objects && ! docActions ) {
await this . # destroyScripting ( ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( pdfDocument !== this . # pdfDocument ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
try {
this . # scripting = this . # initScripting ( ) ;
} catch ( error ) {
console . error ( ` setDocument: " ${ error . message } ". ` ) ;
await this . # destroyScripting ( ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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"
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
}
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async dispatchWillSave ( ) {
return this . # scripting ? . dispatchEventInSandbox ( {
id : "doc" ,
name : "WillSave"
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async dispatchDidSave ( ) {
return this . # scripting ? . dispatchEventInSandbox ( {
id : "doc" ,
name : "DidSave"
} ) ;
}
async dispatchWillPrint ( ) {
if ( ! this . # scripting ) {
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
await this . # willPrintCapability . promise ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async dispatchDidPrint ( ) {
return this . # scripting ? . dispatchEventInSandbox ( {
id : "doc" ,
name : "DidPrint"
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get destroyPromise ( ) {
return this . # destroyCapability ? . promise || null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get ready ( ) {
return this . # ready ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get _pageOpenPending ( ) {
return shadow ( this , "_pageOpenPending" , new Set ( ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( isInPresentationMode && detail . focus ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
async # dispatchPageOpen ( pageNumber , initialize = false ) {
const pdfDocument = this . # pdfDocument ,
visitedPages = this . _visitedPages ;
if ( initialize ) {
this . # closeCapability = Promise . withResolvers ( ) ;
}
if ( ! this . # closeCapability ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const pageView = this . # pdfViewer . getPageView ( pageNumber - 1 ) ;
if ( pageView ? . renderingState !== RenderingStates . FINISHED ) {
this . _pageOpenPending . add ( pageNumber ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . _pageOpenPending . delete ( pageNumber ) ;
const actionsPromise = ( async ( ) => {
const actions = await ( ! visitedPages . has ( pageNumber ) ? pageView . pdfPage ? . getJSActions ( ) : null ) ;
if ( pdfDocument !== this . # pdfDocument ) {
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
await this . # scripting ? . dispatchEventInSandbox ( {
id : "page" ,
name : "PageOpen" ,
pageNumber ,
actions
} ) ;
} ) ( ) ;
visitedPages . set ( pageNumber , actionsPromise ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
async # dispatchPageClose ( pageNumber ) {
const pdfDocument = this . # pdfDocument ,
visitedPages = this . _visitedPages ;
if ( ! this . # closeCapability ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . _pageOpenPending . has ( pageNumber ) ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const actionsPromise = visitedPages . get ( pageNumber ) ;
if ( ! actionsPromise ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
visitedPages . set ( pageNumber , null ) ;
await actionsPromise ;
if ( pdfDocument !== this . # pdfDocument ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
await this . # scripting ? . dispatchEventInSandbox ( {
id : "page" ,
name : "PageClose" ,
pageNumber
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# initScripting ( ) {
this . # destroyCapability = Promise . withResolvers ( ) ;
if ( this . # scripting ) {
throw new Error ( "#initScripting: Scripting already exists." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return this . # externalServices . createScripting ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async # destroyScripting ( ) {
if ( ! this . # scripting ) {
this . # pdfDocument = null ;
this . # destroyCapability ? . resolve ( ) ;
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // 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 ;
# mouseMoveBound = this . # mouseMove . bind ( this ) ;
# mouseUpBound = this . # mouseUp . bind ( this ) ;
# outerContainerWidth = null ;
# width = null ;
constructor ( {
elements ,
eventBus ,
l10n
2021-03-25 17:57:25 +00:00
} ) {
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . isInitialViewSet = true ;
if ( view === SidebarView . NONE || view === SidebarView . UNKNOWN ) {
this . # dispatchEvent ( ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . switchView ( view , true ) ;
if ( ! this . isInitialEventDispatched ) {
this . # dispatchEvent ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
switchView ( view , forceOpen = false ) {
const isViewChanged = view !== this . active ;
let forceRendering = false ;
switch ( view ) {
case SidebarView . NONE :
if ( this . isOpen ) {
this . close ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
open ( ) {
if ( this . isOpen ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
toggle ( evt = null ) {
if ( this . isOpen ) {
this . close ( evt ) ;
} else {
this . open ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
# dispatchEvent ( ) {
if ( this . isInitialViewSet ) {
this . isInitialEventDispatched || = true ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "sidebarviewchanged" , {
source : this ,
view : this . visibleView
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
# showUINotification ( ) {
this . toggleButton . setAttribute ( "data-l10n-id" , "pdfjs-toggle-sidebar-notification-button" ) ;
if ( ! this . isOpen ) {
this . toggleButton . classList . add ( UI _NOTIFICATION _CLASS ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# hideUINotification ( reset = false ) {
if ( this . isOpen || reset ) {
this . toggleButton . classList . remove ( UI _NOTIFICATION _CLASS ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( reset ) {
this . toggleButton . setAttribute ( "data-l10n-id" , "pdfjs-toggle-sidebar-button" ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# addEventListeners ( ) {
this . sidebarContainer . addEventListener ( "transitionend" , evt => {
if ( evt . target === this . sidebarContainer ) {
this . outerContainer . classList . remove ( "sidebarMoving" ) ;
this . 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" , ( ) => {
this . 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" , ( ) => {
this . eventBus . dispatch ( "resetlayers" , {
source : this
} ) ;
} ) ;
this . _currentOutlineItemButton . addEventListener ( "click" , ( ) => {
this . 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 ) ;
}
} ;
this . eventBus . _on ( "outlineloaded" , evt => {
onTreeLoaded ( evt . outlineCount , this . outlineButton , SidebarView . OUTLINE ) ;
evt . currentOutlineItemPromise . then ( enabled => {
if ( ! this . isInitialViewSet ) {
return ;
}
this . _currentOutlineItemButton . disabled = ! enabled ;
} ) ;
} ) ;
this . eventBus . _on ( "attachmentsloaded" , evt => {
onTreeLoaded ( evt . attachmentsCount , this . attachmentsButton , SidebarView . ATTACHMENTS ) ;
} ) ;
this . eventBus . _on ( "layersloaded" , evt => {
onTreeLoaded ( evt . layersCount , this . layersButton , SidebarView . LAYERS ) ;
} ) ;
this . 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 ;
}
this . outerContainer . classList . add ( SIDEBAR _RESIZING _CLASS ) ;
window . addEventListener ( "mousemove" , this . # mouseMoveBound ) ;
window . addEventListener ( "mouseup" , this . # mouseUpBound ) ;
} ) ;
this . eventBus . _on ( "resize" , evt => {
if ( evt . source !== window ) {
return ;
}
this . # outerContainerWidth = null ;
if ( ! this . # width ) {
return ;
}
if ( ! this . isOpen ) {
this . # updateWidth ( this . # width ) ;
return ;
}
this . outerContainer . classList . add ( SIDEBAR _RESIZING _CLASS ) ;
const updated = this . # updateWidth ( this . # width ) ;
Promise . resolve ( ) . then ( ( ) => {
this . outerContainer . classList . remove ( SIDEBAR _RESIZING _CLASS ) ;
if ( updated ) {
this . eventBus . dispatch ( "resize" , {
source : this
} ) ;
}
} ) ;
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get outerContainerWidth ( ) {
return this . # outerContainerWidth || = this . outerContainer . clientWidth ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ` ) ;
2022-09-05 17:42:02 +00:00
return true ;
}
2024-06-09 09:59:38 +00:00
# mouseMove ( evt ) {
let width = evt . clientX ;
if ( this . # isRTL ) {
width = this . outerContainerWidth - width ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # updateWidth ( width ) ;
}
# mouseUp ( evt ) {
this . outerContainer . classList . remove ( SIDEBAR _RESIZING _CLASS ) ;
this . eventBus . dispatch ( "resize" , {
source : this
} ) ;
window . removeEventListener ( "mousemove" , this . # mouseMoveBound ) ;
window . removeEventListener ( "mouseup" , this . # mouseUpBound ) ;
}
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_thumbnail_view.js
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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" ) ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
static destroyCanvas ( ) {
const tempCanvas = this . # tempCanvas ;
if ( tempCanvas ) {
tempCanvas . width = 0 ;
tempCanvas . height = 0 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . # tempCanvas = null ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
class PDFThumbnailView {
constructor ( {
container ,
eventBus ,
id ,
defaultViewport ,
optionalContentConfigPromise ,
linkService ,
renderingQueue ,
2024-07-13 08:49:47 +00:00
pageColors ,
enableHWA
2024-06-09 09:59:38 +00:00
} ) {
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 ;
2024-07-13 08:49:47 +00:00
this . enableHWA = enableHWA || false ;
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ` ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
setPdfPage ( pdfPage ) {
this . pdfPage = pdfPage ;
this . pdfPageRotate = pdfPage . rotate ;
const totalRotation = ( this . rotation + this . pdfPageRotate ) % 360 ;
this . viewport = pdfPage . getViewport ( {
scale : 1 ,
rotation : totalRotation
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
update ( {
rotation = null
2022-09-05 17:42:02 +00:00
} ) {
2024-06-09 09:59:38 +00:00
if ( typeof rotation === "number" ) {
this . rotation = rotation ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
const totalRotation = ( this . rotation + this . pdfPageRotate ) % 360 ;
this . viewport = this . viewport . clone ( {
scale : 1 ,
rotation : totalRotation
} ) ;
this . reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
cancelRendering ( ) {
if ( this . renderTask ) {
this . renderTask . cancel ( ) ;
this . renderTask = null ;
}
this . resume = null ;
2021-03-25 17:57:25 +00:00
}
2024-07-13 08:49:47 +00:00
# getPageDrawContext ( upscaleFactor = 1 , enableHWA = this . enableHWA ) {
2024-06-09 09:59:38 +00:00
const canvas = document . createElement ( "canvas" ) ;
const ctx = canvas . getContext ( "2d" , {
2024-07-13 08:49:47 +00:00
alpha : false ,
willReadFrequently : ! enableHWA
2024-06-09 09:59:38 +00:00
} ) ;
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." ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
async # finishRenderTask ( renderTask , canvas , error = null ) {
if ( renderTask === this . renderTask ) {
this . renderTask = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( error instanceof RenderingCancelledException ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . renderingState = RenderingStates . FINISHED ;
this . # convertCanvasToImage ( canvas ) ;
if ( error ) {
throw error ;
2021-03-25 17:57:25 +00:00
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
async draw ( ) {
if ( this . renderingState !== RenderingStates . INITIAL ) {
console . error ( "Must be in new state before drawing" ) ;
return undefined ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
const renderContinueCallback = cont => {
if ( ! this . renderingQueue . isHighestPriority ( this ) ) {
this . renderingState = RenderingStates . PAUSED ;
this . resume = ( ) => {
this . renderingState = RenderingStates . RUNNING ;
cont ( ) ;
} ;
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
return resultPromise ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
setImage ( pageView ) {
if ( this . renderingState !== RenderingStates . INITIAL ) {
return ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
const {
2024-06-09 09:59:38 +00:00
thumbnailCanvas : canvas ,
pdfPage ,
scale
} = pageView ;
if ( ! canvas ) {
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfPage ) {
this . setPdfPage ( pdfPage ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( scale < this . scale ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . renderingState = RenderingStates . FINISHED ;
this . # convertCanvasToImage ( canvas ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# reduceImage ( img ) {
const {
ctx ,
canvas
2024-07-13 08:49:47 +00:00
} = this . # getPageDrawContext ( 1 , true ) ;
2024-06-09 09:59:38 +00:00
if ( img . width <= 2 * canvas . width ) {
ctx . drawImage ( img , 0 , 0 , img . width , img . height , 0 , 0 , canvas . width , canvas . height ) ;
return canvas ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . image ? . setAttribute ( "data-l10n-args" , this . # pageL10nArgs ) ;
}
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_thumbnail_viewer.js
2021-03-25 17:57:25 +00:00
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
const THUMBNAIL _SCROLL _MARGIN = - 19 ;
const THUMBNAIL _SELECTED _CLASS = "selected" ;
class PDFThumbnailViewer {
constructor ( {
container ,
eventBus ,
linkService ,
renderingQueue ,
2024-07-13 08:49:47 +00:00
pageColors ,
abortSignal ,
enableHWA
2024-06-09 09:59:38 +00:00
} ) {
this . container = container ;
this . eventBus = eventBus ;
this . linkService = linkService ;
this . renderingQueue = renderingQueue ;
this . pageColors = pageColors || null ;
2024-07-13 08:49:47 +00:00
this . enableHWA = enableHWA || false ;
this . scroll = watchScroll ( this . container , this . # scrollUpdated . bind ( this ) , abortSignal ) ;
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
if ( shouldScroll ) {
scrollIntoView ( thumbnailView . div , {
top : THUMBNAIL _SCROLL _MARGIN
} ) ;
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _currentPageNumber = pageNumber ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get pagesRotation ( ) {
return this . _pagesRotation ;
}
set pagesRotation ( rotation ) {
if ( ! isValidRotation ( rotation ) ) {
throw new Error ( "Invalid thumbnails rotation angle." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( this . _pagesRotation === rotation ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ,
2024-07-13 08:49:47 +00:00
pageColors : this . pageColors ,
enableHWA : this . enableHWA
2024-06-09 09:59:38 +00:00
} ) ;
this . _thumbnails . push ( thumbnail ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return pdfPage ;
} catch ( reason ) {
console . error ( "Unable to get page for thumb view" , reason ) ;
return null ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# getScrollAhead ( visible ) {
if ( visible . first ? . id === 1 ) {
return true ;
} else if ( visible . last ? . id === this . _thumbnails . length ) {
return false ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/annotation_editor_layer_builder.js
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/annotation_layer_builder.js
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
class AnnotationLayerBuilder {
# onAppend = null ;
# eventAbortController = null ;
2022-09-05 17:42:02 +00:00
constructor ( {
2024-06-09 09:59:38 +00:00
pdfPage ,
linkService ,
downloadManager ,
annotationStorage = null ,
imageResourcesPath = "" ,
renderForms = true ,
enableScripting = false ,
hasJSActionsPromise = null ,
fieldObjectsPromise = null ,
annotationCanvasMap = null ,
accessibilityManager = null ,
annotationEditorUIManager = null ,
onAppend = null
2022-09-05 17:42:02 +00:00
} ) {
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async render ( viewport , intent = "display" ) {
if ( this . div ) {
if ( this . _cancelled || ! this . annotationLayer ) {
return ;
}
this . annotationLayer . update ( {
viewport : viewport . clone ( {
dontFlip : true
} )
} ) ;
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
const [ annotations , hasJSActions , fieldObjects ] = await Promise . all ( [ this . pdfPage . getAnnotations ( {
intent
} ) , this . _hasJSActionsPromise , this . _fieldObjectsPromise ] ) ;
if ( this . _cancelled ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const div = this . div = document . createElement ( "div" ) ;
div . className = "annotationLayer" ;
this . # onAppend ? . ( div ) ;
if ( annotations . length === 0 ) {
this . hide ( ) ;
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
cancel ( ) {
this . _cancelled = true ;
this . # eventAbortController ? . abort ( ) ;
this . # eventAbortController = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
hide ( ) {
if ( ! this . div ) {
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . div . hidden = true ;
}
2024-08-07 13:16:38 +00:00
hasEditableAnnotations ( ) {
return ! ! this . annotationLayer ? . hasEditableAnnotations ( ) ;
}
2024-06-09 09:59:38 +00:00
# updatePresentationModeState ( state ) {
if ( ! this . div ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
let disableFormElements = false ;
switch ( state ) {
case PresentationModeState . FULLSCREEN :
disableFormElements = true ;
break ;
case PresentationModeState . NORMAL :
break ;
default :
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
for ( const section of this . div . childNodes ) {
if ( section . hasAttribute ( "data-internal-link" ) ) {
continue ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
section . inert = disableFormElements ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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
2022-09-05 17:42:02 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
cancel ( ) {
this . _cancelled = true ;
if ( ! this . # drawLayer ) {
return ;
}
this . # drawLayer . destroy ( ) ;
this . # drawLayer = null ;
}
setParent ( parent ) {
this . # drawLayer ? . setParent ( parent ) ;
}
getDrawLayer ( ) {
return this . # drawLayer ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/struct_tree_layer_builder.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
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 ] ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 ) ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
return element ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/text_accessibility.js
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
class TextAccessibilityManager {
# enabled = false ;
# textChildren = null ;
# textNodes = new Map ( ) ;
# waitingElements = new Map ( ) ;
setTextMapping ( textDivs ) {
this . # textChildren = textDivs ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
static # compareElementPositions ( e1 , e2 ) {
const rect1 = e1 . getBoundingClientRect ( ) ;
const rect2 = e2 . getBoundingClientRect ( ) ;
if ( rect1 . width === 0 && rect1 . height === 0 ) {
return + 1 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # addIdToAriaOwns ( id , textChildren [ nodeIndex ] ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
for ( const [ element , isRemovable ] of this . # waitingElements ) {
this . addPointerInTextLayer ( element , isRemovable ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . # waitingElements . clear ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
disable ( ) {
if ( ! this . # enabled ) {
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . # waitingElements . clear ( ) ;
this . # textChildren = null ;
this . # enabled = false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
removePointerInTextLayer ( element ) {
if ( ! this . # enabled ) {
this . # waitingElements . delete ( element ) ;
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const children = this . # textChildren ;
if ( ! children || children . length === 0 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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" ) ;
}
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# addIdToAriaOwns ( id , node ) {
const owns = node . getAttribute ( "aria-owns" ) ;
if ( ! owns ? . includes ( id ) ) {
node . setAttribute ( "aria-owns" , owns ? ` ${ owns } ${ id } ` : id ) ;
}
node . removeAttribute ( "role" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
children [ index - 1 ] . after ( element ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return id ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
; // 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
setTextMapping ( divs , texts ) {
this . textDivs = divs ;
this . textContentItemsStr = texts ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
enable ( ) {
if ( ! this . textDivs || ! this . textContentItemsStr ) {
throw new Error ( "Text divs and strings have not been set." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . enabled ) {
throw new Error ( "TextHighlighter is already enabled." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _updateMatches ( ) ;
}
disable ( ) {
if ( ! this . enabled ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . enabled = false ;
this . # eventAbortController ? . abort ( ) ;
this . # eventAbortController = null ;
this . _updateMatches ( true ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_convertMatches ( matches , matchesLength ) {
if ( ! matches ) {
return [ ] ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ++ ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( i === textContentItemsStr . length ) {
console . error ( "Could not find a matching mapping" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
const match = {
begin : {
divIdx : i ,
offset : matchIdx - iIndex
}
} ;
matchIdx += matchesLength [ m ] ;
while ( i !== end && matchIdx > iIndex + textContentItemsStr [ i ] . length ) {
iIndex += textContentItemsStr [ i ] . length ;
i ++ ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
match . end = {
divIdx : i ,
offset : matchIdx - iIndex
} ;
result . push ( match ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
return result ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_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
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
}
if ( prevEnd ) {
appendTextToDiv ( prevEnd . divIdx , prevEnd . offset , infinity . offset ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
_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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/text_layer_builder.js
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
class TextLayerBuilder {
# enablePermissions = false ;
# onAppend = null ;
# renderingDone = false ;
# textLayer = null ;
static # textLayers = new Map ( ) ;
static # selectionChangeAbortController = null ;
2022-09-05 17:42:02 +00:00
constructor ( {
2024-06-09 09:59:38 +00:00
pdfPage ,
highlighter = null ,
accessibilityManager = null ,
enablePermissions = false ,
onAppend = null
2022-09-05 17:42:02 +00:00
} ) {
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2024-07-13 08:49:47 +00:00
this . # renderingDone = true ;
const endOfContent = document . createElement ( "div" ) ;
endOfContent . className = "endOfContent" ;
this . div . append ( endOfContent ) ;
this . # bindMouse ( endOfContent ) ;
2024-06-09 09:59:38 +00:00
this . # onAppend ? . ( this . div ) ;
this . highlighter ? . enable ( ) ;
this . accessibilityManager ? . enable ( ) ;
}
hide ( ) {
if ( ! this . div . hidden && this . # renderingDone ) {
this . highlighter ? . disable ( ) ;
this . div . hidden = true ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
show ( ) {
if ( this . div . hidden && this . # renderingDone ) {
this . div . hidden = false ;
this . highlighter ? . enable ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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" , evt => {
end . classList . add ( "active" ) ;
} ) ;
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . # selectionChangeAbortController = new AbortController ( ) ;
const {
signal
} = this . # selectionChangeAbortController ;
const reset = ( end , textLayer ) => {
textLayer . append ( end ) ;
end . style . width = "" ;
end . style . height = "" ;
end . classList . remove ( "active" ) ;
} ;
document . addEventListener ( "pointerup" , ( ) => {
this . # textLayers . forEach ( reset ) ;
} , {
signal
} ) ;
var isFirefox , prevRange ;
document . addEventListener ( "selectionchange" , ( ) => {
const selection = document . getSelection ( ) ;
if ( selection . rangeCount === 0 ) {
this . # textLayers . forEach ( reset ) ;
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ) {
endDiv . classList . add ( "active" ) ;
} else {
reset ( endDiv , textLayerDiv ) ;
}
}
isFirefox ? ? = getComputedStyle ( this . # textLayers . values ( ) . next ( ) . value ) . getPropertyValue ( "-moz-user-select" ) === "none" ;
if ( isFirefox ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
}
}
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_page_view.js
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2024-06-09 09:59:38 +00:00
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 ;
2024-07-13 08:49:47 +00:00
# enableHWA = false ;
2024-06-09 09:59:38 +00:00
# hasRestrictedScaling = false ;
2024-08-07 13:16:38 +00:00
# isEditing = false ;
2024-06-09 09:59:38 +00:00
# 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 ;
2024-07-13 08:49:47 +00:00
this . # enableHWA = options . enableHWA || false ;
2024-06-09 09:59:38 +00:00
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 ) ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
# 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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
this . div . prepend ( div ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get renderingState ( ) {
return this . # renderingState ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# setDimensions ( ) {
const {
viewport
} = this ;
if ( this . pdfPage ) {
if ( this . # previousRotation === viewport . rotation ) {
return ;
}
this . # previousRotation = viewport . rotation ;
}
setLayerDimensions ( this . div , viewport , true , false ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . # setDimensions ( ) ;
this . reset ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
destroy ( ) {
this . reset ( ) ;
this . pdfPage ? . cleanup ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-08-07 13:16:38 +00:00
hasEditableAnnotations ( ) {
return ! ! this . annotationLayer ? . hasEditableAnnotations ( ) ;
}
2024-06-09 09:59:38 +00:00
get _textHighlighter ( ) {
return shadow ( this , "_textHighlighter" , new TextHighlighter ( {
pageIndex : this . id - 1 ,
eventBus : this . eventBus ,
findController : this . # layerProperties . findController
} ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
# dispatchLayerRendered ( name , error ) {
this . eventBus . dispatch ( name , {
source : this ,
pageNumber : this . id ,
error
} ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async # renderDrawLayer ( ) {
try {
await this . drawLayer . render ( "display" ) ;
} catch ( ex ) {
console . error ( ` #renderDrawLayer: " ${ ex } ". ` ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async # renderXfaLayer ( ) {
let error = null ;
try {
const result = await this . xfaLayer . render ( this . viewport , "display" ) ;
if ( result ? . textDivs && this . _textHighlighter ) {
this . # buildXfaTextContentItems ( result . textDivs ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} 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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
let error = null ;
try {
await this . textLayer . render ( this . viewport ) ;
} catch ( ex ) {
if ( ex instanceof AbortException ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
console . error ( ` #renderTextLayer: " ${ ex } ". ` ) ;
error = ex ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . # dispatchLayerRendered ( "textlayerrendered" , error ) ;
this . # renderStructTreeLayer ( ) ;
}
async # renderStructTreeLayer ( ) {
if ( ! this . textLayer ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async # buildXfaTextContentItems ( textDivs ) {
const text = await this . pdfPage . getTextContent ( ) ;
const items = [ ] ;
for ( const item of text . items ) {
items . push ( item . str ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . _textHighlighter . setTextMapping ( textDivs , items ) ;
this . _textHighlighter . enable ( ) ;
}
_resetZoomLayer ( removeFromDOM = false ) {
if ( ! this . zoomLayer ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const zoomLayerCanvas = this . zoomLayer . firstChild ;
this . # viewportMap . delete ( zoomLayerCanvas ) ;
zoomLayerCanvas . width = 0 ;
zoomLayerCanvas . height = 0 ;
if ( removeFromDOM ) {
this . zoomLayer . remove ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . zoomLayer = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
reset ( {
keepZoomLayer = false ,
keepAnnotationLayer = false ,
keepAnnotationEditorLayer = false ,
keepXfaLayer = false ,
keepTextLayer = false
} = { } ) {
this . cancelRendering ( {
keepAnnotationLayer ,
keepAnnotationEditorLayer ,
keepXfaLayer ,
keepTextLayer
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
div . removeAttribute ( "data-loaded" ) ;
if ( annotationLayerNode ) {
this . annotationLayer . hide ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( annotationEditorLayerNode ) {
this . annotationEditorLayer . hide ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( xfaLayerNode ) {
this . xfaLayer . hide ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( textLayerNode ) {
this . textLayer . hide ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-08-07 13:16:38 +00:00
toggleEditingMode ( isEditing ) {
if ( ! this . hasEditableAnnotations ( ) ) {
return ;
}
this . # isEditing = isEditing ;
this . reset ( {
keepZoomLayer : true ,
keepAnnotationLayer : true ,
keepAnnotationEditorLayer : true ,
keepXfaLayer : true ,
keepTextLayer : true
} ) ;
}
2024-06-09 09:59:38 +00:00
update ( {
scale = 0 ,
rotation = null ,
optionalContentConfigPromise = null ,
drawingDelay = - 1
2021-03-25 17:57:25 +00:00
} ) {
2024-06-09 09:59:38 +00:00
this . scale = scale || this . scale ;
if ( typeof rotation === "number" ) {
this . rotation = rotation ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( optionalContentConfigPromise instanceof Promise ) {
this . _optionalContentConfigPromise = optionalContentConfigPromise ;
optionalContentConfigPromise . then ( optionalContentConfig => {
if ( optionalContentConfigPromise !== this . _optionalContentConfigPromise ) {
return ;
}
this . # useThumbnailCanvas . initialOptionalContent = optionalContentConfig . hasInitialVisibility ;
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . cssTransform ( {
target : this . canvas ,
redrawAnnotationLayer : true ,
redrawAnnotationEditorLayer : true ,
redrawXfaLayer : true ,
redrawTextLayer : ! postponeDrawing ,
hideTextLayer : postponeDrawing
} ) ;
if ( postponeDrawing ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "pagerendered" , {
source : this ,
pageNumber : this . id ,
cssTransform : true ,
timestamp : performance . now ( ) ,
error : this . # renderError
} ) ;
2022-09-05 17:42:02 +00:00
return ;
2024-06-09 09:59:38 +00:00
}
if ( ! this . zoomLayer && ! this . canvas . hidden ) {
this . zoomLayer = this . canvas . parentNode ;
this . zoomLayer . style . position = "absolute" ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . zoomLayer ) {
this . cssTransform ( {
target : this . zoomLayer . firstChild
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 } ) ` ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
}
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
async draw ( ) {
if ( this . renderingState !== RenderingStates . INITIAL ) {
console . error ( "Must be in new state before drawing" ) ;
this . reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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" , {
2024-07-13 08:49:47 +00:00
alpha : false ,
willReadFrequently : ! this . # enableHWA
2024-06-09 09:59:38 +00:00
} ) ;
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 ) ;
2024-07-13 08:49:47 +00:00
canvas . width = floorToDivide ( width * outputScale . sx , sfx [ 0 ] ) ;
canvas . height = floorToDivide ( height * outputScale . sy , sfy [ 0 ] ) ;
2024-06-09 09:59:38 +00:00
const {
style
} = canvas ;
2024-07-13 08:49:47 +00:00
style . width = floorToDivide ( width , sfx [ 1 ] ) + "px" ;
style . height = floorToDivide ( height , sfy [ 1 ] ) + "px" ;
2024-06-09 09:59:38 +00:00
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 ,
2024-08-07 13:16:38 +00:00
pageColors ,
isEditing : this . # isEditing
2024-06-09 09:59:38 +00:00
} ;
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 ) ;
if ( ! this . annotationEditorLayer ) {
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" , {
2022-09-05 17:42:02 +00:00
source : this ,
2024-06-09 09:59:38 +00:00
pageNumber : this . id
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
return resultPromise ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
} else {
2024-06-09 09:59:38 +00:00
this . div . removeAttribute ( "data-page-label" ) ;
2019-04-13 13:02:01 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get thumbnailCanvas ( ) {
2022-09-05 17:42:02 +00:00
const {
2024-06-09 09:59:38 +00:00
directDrawing ,
initialOptionalContent ,
regularAnnotations
} = this . # useThumbnailCanvas ;
return directDrawing && initialOptionalContent && regularAnnotations ? this . canvas : null ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/pdf_viewer.js
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
const DEFAULT _CACHE _SIZE = 10 ;
const PagesCountLimit = {
2024-07-13 08:49:47 +00:00
FORCE _SCROLL _MODE _PAGE : 10000 ,
FORCE _LAZY _PAGE _INIT : 5000 ,
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
while ( buf . size > this . # size ) {
this . # destroyFirstView ( ) ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
has ( view ) {
return this . # buf . has ( view ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
[ Symbol . iterator ] ( ) {
return this . # buf . keys ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ;
2024-07-13 08:49:47 +00:00
# enableHWA = false ;
2024-06-09 09:59:38 +00:00
# enableHighlightFloatingButton = false ;
# enablePermissions = false ;
2024-08-07 13:16:38 +00:00
# enableUpdatedAddImage = false ;
2024-06-09 09:59:38 +00:00
# eventAbortController = null ;
# mlManager = null ;
2024-08-07 13:16:38 +00:00
# onPageRenderedCallback = null ;
# switchAnnotationEditorModeTimeoutId = null ;
2024-06-09 09:59:38 +00:00
# getAllTextInProgress = false ;
# hiddenCopyElement = null ;
# interruptCopyCondition = false ;
# previousContainerHeight = 0 ;
# resizeObserver = new ResizeObserver ( this . # resizeObserverCallback . bind ( this ) ) ;
# scrollModePageState = null ;
# scaleTimeoutId = null ;
# textLayerMode = TextLayerMode . ENABLE ;
constructor ( options ) {
2024-08-07 13:16:38 +00:00
const viewerVersion = "4.5.136" ;
2024-06-09 09:59:38 +00:00
if ( version !== viewerVersion ) {
throw new Error ( ` The API version " ${ version } " does not match the Viewer version " ${ viewerVersion } ". ` ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . container . offsetParent && getComputedStyle ( this . container ) . position !== "absolute" ) {
throw new Error ( "The `container` must be absolutely positioned." ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2024-08-07 13:16:38 +00:00
this . # enableUpdatedAddImage = options . enableUpdatedAddImage === true ;
2024-06-09 09:59:38 +00:00
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 ;
2024-07-13 08:49:47 +00:00
this . # enableHWA = options . enableHWA || false ;
2024-06-09 09:59:38 +00:00
this . defaultRenderingQueue = ! options . renderingQueue ;
if ( this . defaultRenderingQueue ) {
this . renderingQueue = new PDFRenderingQueue ( ) ;
this . renderingQueue . setViewer ( this ) ;
} else {
this . renderingQueue = options . renderingQueue ;
}
2024-07-13 08:49:47 +00:00
const {
abortSignal
} = options ;
abortSignal ? . addEventListener ( "abort" , ( ) => {
this . # resizeObserver . disconnect ( ) ;
this . # resizeObserver = null ;
} , {
once : true
} ) ;
this . scroll = watchScroll ( this . container , this . _scrollUpdate . bind ( this ) , abortSignal ) ;
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
} ) ;
2024-06-09 09:59:38 +00:00
if ( ! options . l10n ) {
this . l10n . translate ( this . container ) ;
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
get pagesCount ( ) {
return this . _pages . length ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
getPageView ( index ) {
return this . _pages [ index ] ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
getCachedPageViews ( ) {
return new Set ( this . # buffer ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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." ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( ! this . _setCurrentPageNumber ( val , true ) ) {
console . error ( ` currentPageNumber: " ${ val } " is not a valid page. ` ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
_setCurrentPageNumber ( val , resetCurrentPageView = false ) {
if ( this . _currentPageNumber === val ) {
if ( resetCurrentPageView ) {
this . # resetCurrentPageView ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
2021-03-25 17:57:25 +00:00
}
get pagesRotation ( ) {
return this . _pagesRotation ;
}
set pagesRotation ( rotation ) {
2024-06-09 09:59:38 +00:00
if ( ! isValidRotation ( rotation ) ) {
throw new Error ( "Invalid pages rotation angle." ) ;
2017-05-13 12:01:52 +00:00
}
2021-03-25 17:57:25 +00:00
if ( ! this . pdfDocument ) {
return ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
rotation %= 360 ;
if ( rotation < 0 ) {
rotation += 360 ;
}
2021-03-25 17:57:25 +00:00
if ( this . _pagesRotation === rotation ) {
return ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
this . _pagesRotation = rotation ;
2024-06-09 09:59:38 +00:00
const pageNumber = this . _currentPageNumber ;
this . refresh ( true , {
2022-09-05 17:42:02 +00:00
rotation
2024-06-09 09:59:38 +00:00
} ) ;
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
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return params ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
document . addEventListener ( "visibilitychange" , onVisibilityChange , {
signal
} ) ;
await Promise . race ( [ this . _onePageRenderedCapability . promise , hiddenCapability . promise ] ) ;
document . removeEventListener ( "visibilitychange" , onVisibilityChange ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2024-07-13 08:49:47 +00:00
const {
classList
} = this . viewer ;
classList . add ( "copyAll" ) ;
const ac = new AbortController ( ) ;
window . addEventListener ( "keydown" , ev => this . # interruptCopyCondition = ev . key === "Escape" , {
signal : ac . signal
} ) ;
2024-06-09 09:59:38 +00:00
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 ;
2024-07-13 08:49:47 +00:00
ac . abort ( ) ;
classList . remove ( "copyAll" ) ;
2024-06-09 09:59:38 +00:00
} ) ;
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
}
2021-03-25 17:57:25 +00:00
}
setDocument ( pdfDocument ) {
if ( this . pdfDocument ) {
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "pagesdestroy" , {
source : this
} ) ;
2021-03-25 17:57:25 +00:00
this . _cancelRendering ( ) ;
this . _resetView ( ) ;
2024-06-09 09:59:38 +00:00
this . findController ? . setDocument ( null ) ;
this . _scriptingManager ? . setDocument ( null ) ;
if ( this . # annotationEditorUIManager ) {
this . # annotationEditorUIManager . destroy ( ) ;
this . # annotationEditorUIManager = null ;
}
2021-03-25 17:57:25 +00:00
}
this . pdfDocument = pdfDocument ;
if ( ! pdfDocument ) {
return ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
const pagesCount = pdfDocument . numPages ;
2021-03-25 17:57:25 +00:00
const firstPagePromise = pdfDocument . getPage ( 1 ) ;
2024-06-09 09:59:38 +00:00
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
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
this . _pagesCapability . promise . then ( ( ) => {
eventBus . dispatch ( "pagesloaded" , {
source : this ,
pagesCount
} ) ;
} , ( ) => { } ) ;
const onBeforeDraw = evt => {
const pageView = this . _pages [ evt . pageNumber - 1 ] ;
if ( ! pageView ) {
return ;
2016-07-09 08:54:13 +00:00
}
2024-06-09 09:59:38 +00:00
this . # buffer . push ( pageView ) ;
} ;
eventBus . _on ( "pagerender" , onBeforeDraw , {
signal
} ) ;
const onAfterDraw = evt => {
if ( evt . cssTransform ) {
return ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
this . _onePageRenderedCapability . resolve ( {
timestamp : evt . timestamp
} ) ;
eventBus . _off ( "pagerendered" , onAfterDraw ) ;
} ;
eventBus . _on ( "pagerendered" , onAfterDraw , {
signal
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ( annotationEditorMode !== AnnotationEditorType . DISABLE ) {
const mode = annotationEditorMode ;
if ( pdfDocument . isPureXfa ) {
console . warn ( "Warning: XFA-editing is not implemented." ) ;
} else if ( isValidAnnotationEditorMode ( mode ) ) {
2024-08-07 13:16:38 +00:00
this . # annotationEditorUIManager = new AnnotationEditorUIManager ( this . container , viewer , this . # altTextManager , eventBus , pdfDocument , pageColors , this . # annotationEditorHighlightColors , this . # enableHighlightFloatingButton , this . # enableUpdatedAddImage , this . # mlManager ) ;
2024-06-09 09:59:38 +00:00
eventBus . dispatch ( "annotationeditoruimanager" , {
source : this ,
uiManager : this . # annotationEditorUIManager
} ) ;
if ( mode !== AnnotationEditorType . NONE ) {
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 ,
2024-07-13 08:49:47 +00:00
layerProperties : this . _layerProperties ,
enableHWA : this . # enableHWA
2024-06-09 09:59:38 +00:00
} ) ;
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 ) ;
} ) ;
}
2021-03-25 17:57:25 +00:00
setPageLabels ( labels ) {
if ( ! this . pdfDocument ) {
return ;
2017-05-13 12:01:52 +00:00
}
2021-03-25 17:57:25 +00:00
if ( ! labels ) {
this . _pageLabels = null ;
} else if ( ! ( Array . isArray ( labels ) && this . pdfDocument . numPages === labels . length ) ) {
this . _pageLabels = null ;
2024-06-09 09:59:38 +00:00
console . error ( ` setPageLabels: Invalid page labels. ` ) ;
2021-03-25 17:57:25 +00:00
} else {
this . _pageLabels = labels ;
}
2024-06-09 09:59:38 +00:00
for ( let i = 0 , ii = this . _pages . length ; i < ii ; i ++ ) {
this . _pages [ i ] . setPageLabel ( this . _pageLabels ? . [ i ] ? ? null ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
_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 ;
2024-08-07 13:16:38 +00:00
this . # cleanupSwitchAnnotationEditorMode ( ) ;
2024-06-09 09:59:38 +00:00
}
# ensurePageViewVisible ( ) {
if ( this . _scrollMode !== ScrollMode . PAGE ) {
throw new Error ( "#ensurePageViewVisible: Invalid scrollMode value." ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
state . scrollDown = pageNumber >= state . previousPageNumber ;
state . previousPageNumber = pageNumber ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
_scrollUpdate ( ) {
if ( this . pagesCount === 0 ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . update ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# scrollIntoView ( pageView , pageSpot = null ) {
const {
div ,
id
} = pageView ;
if ( this . _currentPageNumber !== id ) {
this . _setCurrentPageNumber ( id ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . _scrollMode === ScrollMode . PAGE ) {
this . # ensurePageViewVisible ( ) ;
this . update ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
scrollIntoView ( div , pageSpot ) ;
if ( ! this . _currentScaleValue && this . _location ) {
this . _location = null ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# isSameScale ( newScale ) {
return newScale === this . _currentScale || Math . abs ( newScale - this . _currentScale ) < 1e-15 ;
}
# setScaleUpdatePages ( newScale , newValue , {
noScroll = false ,
preset = false ,
drawingDelay = - 1 ,
origin = null
2022-09-05 17:42:02 +00:00
} ) {
2024-06-09 09:59:38 +00:00
this . _currentScaleValue = newValue . toString ( ) ;
if ( this . # isSameScale ( newScale ) ) {
if ( preset ) {
this . eventBus . dispatch ( "scalechanging" , {
source : this ,
scale : newScale ,
presetValue : newValue
} ) ;
}
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( postponeDrawing ) {
this . # scaleTimeoutId = setTimeout ( ( ) => {
this . # scaleTimeoutId = null ;
this . refresh ( ) ;
} , drawingDelay ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "scalechanging" , {
source : this ,
scale : newScale ,
presetValue : preset ? newValue : undefined
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( this . defaultRenderingQueue ) {
this . update ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
get # pageWidthScaleFactor ( ) {
if ( this . _spreadMode !== SpreadMode . NONE && this . _scrollMode !== ScrollMode . HORIZONTAL ) {
return 2 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
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 ] ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
options . preset = true ;
this . # setScaleUpdatePages ( scale , value , options ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
# 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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
const pageView = Number . isInteger ( pageNumber ) && this . _pages [ pageNumber - 1 ] ;
if ( ! pageView ) {
console . error ( ` scrollPageIntoView: " ${ pageNumber } " is not a valid pageNumber parameter. ` ) ;
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . isInPresentationMode || ! destArray ) {
this . _setCurrentPageNumber ( pageNumber , true ) ;
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! ignoreDestinationZoom ) {
if ( scale && scale !== this . _currentScale ) {
this . currentScaleValue = scale ;
} else if ( this . _currentScale === UNKNOWN _SCALE ) {
this . currentScaleValue = DEFAULT _SCALE _VALUE ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( scale === "page-fit" && ! destArray [ 4 ] ) {
this . # scrollIntoView ( pageView ) ;
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_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
} ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
update ( ) {
const visible = this . _getVisiblePages ( ) ;
const visiblePages = visible . views ,
numVisiblePages = visiblePages . length ;
if ( numVisiblePages === 0 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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
2021-03-25 17:57:25 +00:00
} ) ;
}
2024-08-07 13:16:38 +00:00
# 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 ;
}
2024-06-09 09:59:38 +00:00
containsElement ( element ) {
return this . container . contains ( element ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
focus ( ) {
this . container . focus ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get _isContainerRtl ( ) {
return getComputedStyle ( this . container ) . direction === "rtl" ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get isInPresentationMode ( ) {
return this . presentationModeState === PresentationModeState . FULLSCREEN ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get isChangingPresentationMode ( ) {
return this . presentationModeState === PresentationModeState . CHANGING ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
get isHorizontalScrollbarEnabled ( ) {
return this . isInPresentationMode ? false : this . container . scrollWidth > this . container . clientWidth ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
get isVerticalScrollbarEnabled ( ) {
return this . isInPresentationMode ? false : this . container . scrollHeight > this . container . clientHeight ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
_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 ( ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
_cancelRendering ( ) {
for ( const pageView of this . _pages ) {
pageView . cancelRendering ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
async # ensurePdfPageLoaded ( pageView ) {
if ( pageView . pdfPage ) {
return pageView . pdfPage ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
try {
const pdfPage = await this . pdfDocument . getPage ( pageView . id ) ;
if ( ! pageView . pdfPage ) {
pageView . setPdfPage ( pdfPage ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
return pdfPage ;
} catch ( reason ) {
console . error ( "Unable to get page for page view" , reason ) ;
return null ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# getScrollAhead ( visible ) {
if ( visible . first ? . id === 1 ) {
return true ;
} else if ( visible . last ? . id === this . pagesCount ) {
2021-03-25 17:57:25 +00:00
return false ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
switch ( this . _scrollMode ) {
case ScrollMode . PAGE :
return this . # scrollModePageState . scrollDown ;
case ScrollMode . HORIZONTAL :
return this . scroll . right ;
}
return this . scroll . down ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ;
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get optionalContentConfigPromise ( ) {
2021-03-25 17:57:25 +00:00
if ( ! this . pdfDocument ) {
2024-06-09 09:59:38 +00:00
return Promise . resolve ( null ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . _optionalContentConfigPromise ) {
console . error ( "optionalContentConfigPromise: Not initialized yet." ) ;
return this . pdfDocument . getOptionalContentConfig ( {
intent : "display"
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return this . _optionalContentConfigPromise ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
set optionalContentConfigPromise ( promise ) {
if ( ! ( promise instanceof Promise ) ) {
throw new Error ( ` Invalid optionalContentConfigPromise: ${ promise } ` ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . _optionalContentConfigPromise ) {
return ;
}
this . _optionalContentConfigPromise = promise ;
this . refresh ( false , {
optionalContentConfigPromise : promise
} ) ;
this . eventBus . dispatch ( "optionalcontentconfigchanged" , {
2021-03-25 17:57:25 +00:00
source : this ,
2024-06-09 09:59:38 +00:00
promise
2021-03-25 17:57:25 +00:00
} ) ;
}
2024-06-09 09:59:38 +00:00
get scrollMode ( ) {
return this . _scrollMode ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
set scrollMode ( mode ) {
if ( this . _scrollMode === mode ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( ! isValidScrollMode ( mode ) ) {
throw new Error ( ` Invalid scroll mode: ${ mode } ` ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . pagesCount > PagesCountLimit . FORCE _SCROLL _MODE _PAGE ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _previousScrollMode = this . _scrollMode ;
this . _scrollMode = mode ;
this . eventBus . dispatch ( "scrollmodechanged" , {
source : this ,
mode
} ) ;
this . _updateScrollMode ( this . _currentPageNumber ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
get spreadMode ( ) {
return this . _spreadMode ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
set spreadMode ( mode ) {
if ( this . _spreadMode === mode ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( ! isValidSpreadMode ( mode ) ) {
throw new Error ( ` Invalid spread mode: ${ mode } ` ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _spreadMode = mode ;
this . eventBus . dispatch ( "spreadmodechanged" , {
source : this ,
mode
} ) ;
this . _updateSpreadMode ( this . _currentPageNumber ) ;
}
_updateSpreadMode ( pageNumber = null ) {
2021-03-25 17:57:25 +00:00
if ( ! this . pdfDocument ) {
return ;
}
2024-06-09 09:59:38 +00:00
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 ) ;
}
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! pageNumber ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( this . _currentScaleValue && isNaN ( this . _currentScaleValue ) ) {
this . # setScale ( this . _currentScaleValue , {
noScroll : true
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _setCurrentPageNumber ( pageNumber , true ) ;
this . update ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
_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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
previousPage ( ) {
const currentPageNumber = this . _currentPageNumber ;
if ( currentPageNumber <= 1 ) {
return false ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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." ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
newScale = Math . max ( MIN _SCALE , Math . min ( MAX _SCALE , newScale ) ) ;
this . # setScale ( newScale , {
noScroll : false ,
drawingDelay ,
origin
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
increaseScale ( options = { } ) {
this . updateScale ( {
... options ,
steps : options . steps ? ? 1
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
get containerTopLeft ( ) {
return this . # containerTopLeft || = [ this . container . offsetTop , this . container . offsetLeft ] ;
}
2024-08-07 13:16:38 +00:00
# cleanupSwitchAnnotationEditorMode ( ) {
if ( this . # onPageRenderedCallback ) {
this . eventBus . _off ( "pagerendered" , this . # onPageRenderedCallback ) ;
this . # onPageRenderedCallback = null ;
}
if ( this . # switchAnnotationEditorModeTimeoutId !== null ) {
clearTimeout ( this . # switchAnnotationEditorModeTimeoutId ) ;
this . # switchAnnotationEditorModeTimeoutId = null ;
}
}
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( ! isValidAnnotationEditorMode ( mode ) ) {
throw new Error ( ` Invalid AnnotationEditor mode: ${ mode } ` ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfDocument ) {
return ;
}
2024-08-07 13:16:38 +00:00
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 ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
set annotationEditorParams ( {
type ,
value
} ) {
if ( ! this . # annotationEditorUIManager ) {
throw new Error ( ` The AnnotationEditor is not enabled. ` ) ;
}
this . # annotationEditorUIManager . updateParams ( type , value ) ;
}
refresh ( noUpdate = false , updateArgs = Object . create ( null ) ) {
2021-03-25 17:57:25 +00:00
if ( ! this . pdfDocument ) {
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
for ( const pageView of this . _pages ) {
pageView . update ( updateArgs ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . # scaleTimeoutId !== null ) {
clearTimeout ( this . # scaleTimeoutId ) ;
this . # scaleTimeoutId = null ;
}
if ( ! noUpdate ) {
this . update ( ) ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/secondary_toolbar.js
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 . 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 ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
if ( element !== null ) {
2024-07-13 08:49:47 +00:00
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
2024-06-09 09:59:38 +00:00
}
2024-07-13 08:49:47 +00:00
}
2024-06-09 09:59:38 +00:00
} ) ;
2024-07-13 08:49:47 +00:00
} ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
eventBus . _on ( "cursortoolchanged" , this . # cursorToolChanged . bind ( this ) ) ;
eventBus . _on ( "scrollmodechanged" , this . # scrollModeChanged . bind ( this ) ) ;
eventBus . _on ( "spreadmodechanged" , this . # spreadModeChanged . bind ( this ) ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
# 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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
this . opened = true ;
const {
toggleButton ,
toolbar
} = this . # opts ;
toggleExpandedBtn ( toggleButton , true , toolbar ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
close ( ) {
if ( ! this . opened ) {
return ;
}
this . opened = false ;
2022-09-05 17:42:02 +00:00
const {
2024-06-09 09:59:38 +00:00
toggleButton ,
toolbar
} = this . # opts ;
toggleExpandedBtn ( toggleButton , false , toolbar ) ;
}
toggle ( ) {
if ( this . opened ) {
this . close ( ) ;
} else {
this . open ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/toolbar.js
2022-09-05 17:42:02 +00:00
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
class Toolbar {
# opts ;
2024-08-07 13:16:38 +00:00
constructor ( options , eventBus , toolbarDensity = 0 ) {
2024-06-09 09:59:38 +00:00
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 ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} , {
element : options . editorHighlightButton ,
eventName : "switchannotationeditormode" ,
eventDetails : {
get mode ( ) {
const {
classList
} = options . editorHighlightButton ;
return classList . contains ( "toggled" ) ? AnnotationEditorType . NONE : AnnotationEditorType . HIGHLIGHT ;
}
2016-07-09 08:54:13 +00:00
}
2024-06-09 09:59:38 +00:00
} , {
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 ;
}
}
} ] ;
this . # bindListeners ( buttons ) ;
if ( options . editorHighlightColorPicker ) {
eventBus . _on ( "annotationeditoruimanager" , ( {
uiManager
} ) => {
this . # setAnnotationEditorUIManager ( uiManager , options . editorHighlightColorPicker ) ;
} , {
once : true
2021-03-25 17:57:25 +00:00
} ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
eventBus . _on ( "showannotationeditorui" , ( {
mode
} ) => {
switch ( mode ) {
case AnnotationEditorType . HIGHLIGHT :
options . editorHighlightButton . click ( ) ;
break ;
}
2021-03-25 17:57:25 +00:00
} ) ;
2024-08-07 13:16:38 +00:00
eventBus . _on ( "toolbardensity" , this . # updateToolbarDensity . bind ( this ) ) ;
this . # updateToolbarDensity ( {
value : toolbarDensity
} ) ;
2024-06-09 09:59:38 +00:00
this . reset ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-08-07 13:16:38 +00:00
# updateToolbarDensity ( ) { }
2024-06-09 09:59:38 +00:00
# setAnnotationEditorUIManager ( uiManager , parentContainer ) {
const colorPicker = new ColorPicker ( {
uiManager
} ) ;
uiManager . setMainHighlightColorPicker ( colorPicker ) ;
parentContainer . append ( colorPicker . renderMainDropdown ( ) ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 {
pageNumber ,
scaleSelect
} = this . # opts ;
const self = this ;
for ( const {
element ,
eventName ,
eventDetails
} of buttons ) {
if ( element !== null ) {
element . addEventListener ( "click" , evt => {
if ( eventName !== null ) {
eventBus . dispatch ( eventName , {
source : this ,
... eventDetails ,
isFromKeyboard : evt . detail === 0
} ) ;
}
} ) ;
}
}
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" ) {
2017-05-13 12:01:52 +00:00
return ;
2016-07-09 08:54:13 +00:00
}
2024-06-09 09:59:38 +00:00
eventBus . dispatch ( "scalechanged" , {
source : self ,
value : this . value
} ) ;
} ) ;
scaleSelect . addEventListener ( "click" , function ( {
target
} ) {
if ( this . value === self . pageScaleValue && target . tagName . toUpperCase ( ) === "OPTION" ) {
this . blur ( ) ;
2016-07-09 08:54:13 +00:00
}
2024-06-09 09:59:38 +00:00
} ) ;
scaleSelect . oncontextmenu = noContextMenu ;
eventBus . _on ( "annotationeditormodechanged" , this . # editorModeChanged . bind ( this ) ) ;
}
# 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
} ) ) ;
2016-07-09 08:54:13 +00:00
}
2024-06-09 09:59:38 +00:00
opts . pageNumber . max = pagesCount ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // 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 ;
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
async _writeToStorage ( ) {
const databaseStr = JSON . stringify ( this . database ) ;
localStorage . setItem ( "pdfjs.history" , databaseStr ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ] ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ] ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
return values ;
}
}
2019-04-13 13:02:01 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/app.js
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2019-04-13 13:02:01 +00:00
2021-03-25 17:57:25 +00:00
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
2019-04-13 13:02:01 +00:00
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
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 ,
2024-08-07 13:16:38 +00:00
preferences : new Preferences ( ) ,
2024-06-09 09:59:38 +00:00
toolbar : null ,
secondaryToolbar : null ,
eventBus : null ,
l10n : null ,
annotationEditorParams : null ,
isInitialViewSet : false ,
isViewerEmbedded : window . parent !== window ,
url : "" ,
baseUrl : "" ,
2024-08-07 13:16:38 +00:00
mlManager : null ,
2024-06-09 09:59:38 +00:00
_downloadUrl : "" ,
_eventBusAbortController : null ,
_windowAbortController : null ,
2024-07-13 08:49:47 +00:00
_globalAbortController : new AbortController ( ) ,
2024-06-09 09:59:38 +00:00
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 } ". ` ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( AppOptions . get ( "pdfBugEnabled" ) ) {
await this . _parseHashParams ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
let mode ;
switch ( AppOptions . get ( "viewerCssTheme" ) ) {
case 1 :
mode = "is-light" ;
break ;
case 2 :
mode = "is-dark" ;
break ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( mode ) {
document . documentElement . classList . add ( mode ) ;
2022-09-05 17:42:02 +00:00
}
2024-08-07 13:16:38 +00:00
this . l10n = await this . externalServices . createL10n ( ) ;
2024-06-09 09:59:38 +00:00
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 ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 } ". ` ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "disablerange" ) ) {
AppOptions . set ( "disableRange" , params . get ( "disablerange" ) === "true" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "disablestream" ) ) {
AppOptions . set ( "disableStream" , params . get ( "disablestream" ) === "true" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "disableautofetch" ) ) {
AppOptions . set ( "disableAutoFetch" , params . get ( "disableautofetch" ) === "true" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "disablefontface" ) ) {
AppOptions . set ( "disableFontFace" , params . get ( "disablefontface" ) === "true" ) ;
}
if ( params . has ( "disablehistory" ) ) {
AppOptions . set ( "disableHistory" , params . get ( "disablehistory" ) === "true" ) ;
}
if ( params . has ( "verbosity" ) ) {
AppOptions . set ( "verbosity" , params . get ( "verbosity" ) | 0 ) ;
}
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 ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "pdfbug" ) ) {
AppOptions . setAll ( {
pdfBug : true ,
fontExtraProperties : true
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
const enabled = params . get ( "pdfbug" ) . split ( "," ) ;
try {
await loadPDFBug ( ) ;
this . _PDFBug . init ( mainContainer , enabled ) ;
} catch ( ex ) {
console . error ( ` _parseHashParams: " ${ ex . message } ". ` ) ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( params . has ( "locale" ) ) {
2024-08-07 13:16:38 +00:00
AppOptions . set ( "localeProperties" , {
lang : params . get ( "locale" )
} ) ;
2024-06-09 09:59:38 +00:00
}
} ,
async _initializeViewerComponents ( ) {
const {
appConfig ,
externalServices ,
l10n
} = this ;
2024-07-13 08:49:47 +00:00
let eventBus ;
eventBus = new EventBus ( ) ;
2024-06-09 09:59:38 +00:00
this . eventBus = eventBus ;
this . overlayManager = new OverlayManager ( ) ;
const pdfRenderingQueue = new PDFRenderingQueue ( ) ;
pdfRenderingQueue . onIdle = this . _cleanup . bind ( this ) ;
this . pdfRenderingQueue = pdfRenderingQueue ;
const pdfLinkService = new PDFLinkService ( {
2022-09-05 17:42:02 +00:00
eventBus ,
2024-06-09 09:59:38 +00:00
externalLinkTarget : AppOptions . get ( "externalLinkTarget" ) ,
externalLinkRel : AppOptions . get ( "externalLinkRel" ) ,
ignoreDestinationZoom : AppOptions . get ( "ignoreDestinationZoom" )
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . pdfLinkService = pdfLinkService ;
const downloadManager = this . downloadManager = new DownloadManager ( ) ;
const findController = new PDFFindController ( {
linkService : pdfLinkService ,
2022-09-05 17:42:02 +00:00
eventBus ,
2024-06-09 09:59:38 +00:00
updateMatchesCountOnProgress : true
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . findController = findController ;
const pdfScriptingManager = new PDFScriptingManager ( {
eventBus ,
externalServices ,
docProperties : this . _scriptingDocProperties . bind ( this )
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ;
const altTextManager = appConfig . altTextDialog ? new AltTextManager ( appConfig . altTextDialog , container , this . overlayManager , eventBus ) : null ;
2024-07-13 08:49:47 +00:00
const enableHWA = AppOptions . get ( "enableHWA" ) ;
2024-06-09 09:59:38 +00:00
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" ) ,
2024-08-07 13:16:38 +00:00
enableUpdatedAddImage : AppOptions . get ( "enableUpdatedAddImage" ) ,
2024-06-09 09:59:38 +00:00
imageResourcesPath : AppOptions . get ( "imageResourcesPath" ) ,
enablePrintAutoRotate : AppOptions . get ( "enablePrintAutoRotate" ) ,
maxCanvasPixels : AppOptions . get ( "maxCanvasPixels" ) ,
enablePermissions : AppOptions . get ( "enablePermissions" ) ,
pageColors ,
2024-07-13 08:49:47 +00:00
mlManager : this . mlManager ,
abortSignal : this . _globalAbortController . signal ,
enableHWA
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ,
2024-07-13 08:49:47 +00:00
pageColors ,
abortSignal : this . _globalAbortController . signal ,
enableHWA
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ( annotationEditorMode !== AnnotationEditorType . DISABLE ) {
const editorHighlightButton = appConfig . toolbar ? . editorHighlightButton ;
if ( editorHighlightButton && AppOptions . get ( "enableHighlightEditor" ) ) {
editorHighlightButton . hidden = false ;
}
this . annotationEditorParams = new AnnotationEditorParams ( appConfig . annotationEditorParams , eventBus ) ;
} else {
for ( const id of [ "editorModeButtons" , "editorModeSeparator" ] ) {
document . getElementById ( id ) ? . classList . add ( "hidden" ) ;
}
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( appConfig . documentProperties ) {
this . pdfDocumentProperties = new PDFDocumentProperties ( appConfig . documentProperties , this . overlayManager , eventBus , l10n , ( ) => this . _docFilename ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . secondaryToolbar ? . cursorHandToolButton ) {
this . pdfCursorTools = new PDFCursorTools ( {
container ,
eventBus ,
cursorToolOnLoad : AppOptions . get ( "cursorToolOnLoad" )
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . toolbar ) {
2024-08-07 13:16:38 +00:00
this . toolbar = new Toolbar ( appConfig . toolbar , eventBus , AppOptions . get ( "toolbarDensity" ) ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . secondaryToolbar ) {
this . secondaryToolbar = new SecondaryToolbar ( appConfig . secondaryToolbar , eventBus ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . supportsFullscreen && appConfig . secondaryToolbar ? . presentationModeButton ) {
this . pdfPresentationMode = new PDFPresentationMode ( {
container ,
pdfViewer ,
eventBus
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . passwordOverlay ) {
this . passwordPrompt = new PasswordPrompt ( appConfig . passwordOverlay , this . overlayManager , this . isViewerEmbedded ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . sidebar ? . outlineView ) {
this . pdfOutlineViewer = new PDFOutlineViewer ( {
container : appConfig . sidebar . outlineView ,
eventBus ,
l10n ,
linkService : pdfLinkService ,
downloadManager
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( appConfig . sidebar ? . attachmentsView ) {
this . pdfAttachmentViewer = new PDFAttachmentViewer ( {
container : appConfig . sidebar . attachmentsView ,
eventBus ,
l10n ,
downloadManager
} ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2024-07-13 08:49:47 +00:00
/ * c o n s t f i l e I n p u t = t h i s . _ o p e n F i l e I n p u t = d o c u m e n t . c r e a t e E l e m e n t ( " i n p u t " ) ;
2024-06-09 09:59:38 +00:00
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
} ) ;
2024-07-13 08:49:47 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
appConfig . mainContainer . addEventListener ( "dragover" , function ( evt ) {
2024-07-13 08:49:47 +00:00
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 ;
}
}
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
appConfig . mainContainer . addEventListener ( "drop" , function ( evt ) {
2024-07-13 08:49:47 +00:00
if ( evt . dataTransfer . files ? . [ 0 ] . type !== "application/pdf" ) {
2024-06-09 09:59:38 +00:00
return ;
}
2024-07-13 08:49:47 +00:00
evt . preventDefault ( ) ;
evt . stopPropagation ( ) ;
eventBus . dispatch ( "fileinputchange" , {
2024-06-09 09:59:38 +00:00
source : this ,
fileInput : evt . dataTransfer
2024-07-13 08:49:47 +00:00
} ) ;
} ) ; * /
2024-06-09 09:59:38 +00:00
if ( ! AppOptions . get ( "supportsDocumentFonts" ) ) {
AppOptions . set ( "disableFontFace" , true ) ;
this . l10n . get ( "pdfjs-web-fonts-disabled" ) . then ( msg => {
console . warn ( msg ) ;
} ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . supportsPrinting ) {
appConfig . toolbar ? . print ? . classList . add ( "hidden" ) ;
appConfig . secondaryToolbar ? . printButton . classList . add ( "hidden" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . supportsFullscreen ) {
appConfig . secondaryToolbar ? . presentationModeButton . classList . add ( "hidden" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . supportsIntegratedFind ) {
appConfig . toolbar ? . viewFind ? . classList . add ( "hidden" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( file ) {
this . open ( {
url : file
} ) ;
} else {
this . _hideViewBookmark ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
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
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
} ,
zoomIn ( ) {
this . updateZoom ( 1 ) ;
} ,
zoomOut ( ) {
this . updateZoom ( - 1 ) ;
} ,
zoomReset ( ) {
if ( this . pdfViewer . isInPresentationMode ) {
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 {
2024-08-07 13:16:38 +00:00
title = decodeURIComponent ( getFilenameFromUrl ( url ) ) ;
} catch { }
2021-03-25 17:57:25 +00:00
}
2024-08-07 13:16:38 +00:00
this . setTitle ( title || url ) ;
2024-06-09 09:59:38 +00:00
} ,
setTitle ( title = this . _title ) {
this . _title = title ;
if ( this . isViewerEmbedded ) {
2022-09-05 17:42:02 +00:00
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
async close ( ) {
this . _unblockDocumentLoadEvent ( ) ;
this . _hideViewBookmark ( ) ;
if ( ! this . pdfLoadingTask ) {
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . pdfDocument ? . annotationStorage . size > 0 && this . _annotationStorageModified ) {
try {
await this . save ( ) ;
} catch { }
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
const workerParams = AppOptions . getAll ( OptionKind . WORKER ) ;
Object . assign ( GlobalWorkerOptions , workerParams ) ;
if ( args . url ) {
this . setTitleUsingUrl ( args . originalUrl || args . url , args . url ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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 ( options = { } ) {
2024-07-13 08:49:47 +00:00
let data ;
2024-06-09 09:59:38 +00:00
try {
2024-08-07 13:16:38 +00:00
data = await this . pdfDocument . getData ( ) ;
2024-07-13 08:49:47 +00:00
} catch { }
this . downloadManager . download ( data , this . _downloadUrl , this . _docFilename , options ) ;
2024-06-09 09:59:38 +00:00
} ,
async save ( options = { } ) {
if ( this . _saveInProgress ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . _saveInProgress = true ;
await this . pdfScriptingManager . dispatchWillSave ( ) ;
try {
const data = await this . pdfDocument . saveDocument ( ) ;
2024-07-13 08:49:47 +00:00
this . downloadManager . download ( data , this . _downloadUrl , this . _docFilename , options ) ;
2024-06-09 09:59:38 +00:00
} catch ( reason ) {
console . error ( ` Error when saving the document: ${ reason . message } ` ) ;
await this . download ( options ) ;
} finally {
await this . pdfScriptingManager . dispatchDidSave ( ) ;
this . _saveInProgress = false ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . _hasAnnotationEditors ) {
this . externalServices . reportTelemetry ( {
type : "editing" ,
data : {
type : "save" ,
stats : this . pdfDocument ? . annotationStorage . editorStats
}
} ) ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
2024-07-13 08:49:47 +00:00
async downloadOrSave ( options = { } ) {
const {
classList
} = this . appConfig . appContainer ;
classList . add ( "wait" ) ;
await ( this . pdfDocument ? . annotationStorage . size > 0 ? this . save ( options ) : this . download ( options ) ) ;
classList . remove ( "wait" ) ;
2022-09-05 17:42:02 +00:00
} ,
2024-06-09 09:59:38 +00:00
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
} ) ;
2022-09-05 17:42:02 +00:00
} ,
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
} ,
2024-06-09 09:59:38 +00:00
progress ( level ) {
const percent = Math . round ( level * 100 ) ;
2024-08-07 13:16:38 +00:00
if ( ! this . loadingBar || percent <= this . loadingBar . percent ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
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
} ) ;
} ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
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 ) {
2022-09-05 17:42:02 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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
} ) ;
2022-09-05 17:42:02 +00:00
} ) ;
}
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . _initializePageLabels ( pdfDocument ) ;
this . _initializeMetadata ( pdfDocument ) ;
} ,
async _scriptingDocProperties ( pdfDocument ) {
if ( ! this . documentInfo ) {
await new Promise ( resolve => {
this . eventBus . _on ( "metadataloaded" , resolve , {
once : true
} ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( pdfDocument !== this . pdfDocument ) {
return null ;
}
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . _contentLength ) {
await new Promise ( resolve => {
this . eventBus . _on ( "documentloaded" , resolve , {
once : true
} ) ;
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( pdfDocument !== this . pdfDocument ) {
return null ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) ) ;
2022-09-05 17:42:02 +00:00
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( triggerAutoPrint ) {
this . triggerPrinting ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
async _initializeMetadata ( pdfDocument ) {
const {
info ,
metadata ,
contentDispositionFilename ,
contentLength
} = await pdfDocument . getMetadata ( ) ;
if ( pdfDocument !== this . pdfDocument ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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" ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} else if ( ( info . IsAcroFormPresent || info . IsXFAPresent ) && ! this . pdfViewer . renderForms ) {
console . warn ( "Warning: Interactive form support is not enabled" ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( info . IsSignaturesPresent ) {
console . warn ( "Warning: Digital signatures validation is not supported" ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . eventBus . dispatch ( "metadataloaded" , {
source : this
} ) ;
} ,
async _initializePageLabels ( pdfDocument ) {
const labels = await pdfDocument . getPageLabels ( ) ;
if ( pdfDocument !== this . pdfDocument ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! labels || AppOptions . get ( "disablePageLabels" ) ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( standardLabels >= numLabels || emptyLabels >= numLabels ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
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
2022-09-05 17:42:02 +00:00
} ) {
2024-06-09 09:59:38 +00:00
if ( ! this . pdfHistory ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . pdfHistory . initialize ( {
fingerprint ,
resetHistory : viewOnLoad === ViewOnLoad . INITIAL ,
updateUrl : AppOptions . get ( "historyUpdateUrl" )
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
if ( this . pdfHistory . initialBookmark ) {
this . initialBookmark = this . pdfHistory . initialBookmark ;
this . initialRotation = this . pdfHistory . initialRotation ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( initialDest && ! this . initialBookmark && viewOnLoad === ViewOnLoad . UNKNOWN ) {
this . initialBookmark = JSON . stringify ( initialDest ) ;
this . pdfHistory . push ( {
explicitDest : initialDest ,
pageNumber : null
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
}
} ,
_initializeAnnotationStorageCallbacks ( pdfDocument ) {
if ( pdfDocument !== this . pdfDocument ) {
2021-03-25 17:57:25 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
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 ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
} ;
const setViewerModes = ( scroll , spread ) => {
if ( isValidScrollMode ( scroll ) ) {
this . pdfViewer . scrollMode = scroll ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( isValidSpreadMode ( spread ) ) {
this . pdfViewer . spreadMode = spread ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} ;
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 ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
_cleanup ( ) {
if ( ! this . pdfDocument ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . supportsPrinting ) {
this . _otherError ( "pdfjs-printing-not-supported" ) ;
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! this . pdfViewer . pageViewsReady ) {
this . l10n . get ( "pdfjs-printing-not-ready" ) . then ( msg => {
window . alert ( msg ) ;
} ) ;
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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
}
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} ,
afterPrint ( ) {
if ( this . _printAnnotationStoragePromise ) {
this . _printAnnotationStoragePromise . then ( ( ) => {
this . pdfScriptingManager . dispatchDidPrint ( ) ;
} ) ;
this . _printAnnotationStoragePromise = null ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . printService ) {
this . printService . destroy ( ) ;
this . printService = null ;
this . pdfDocument ? . annotationStorage . resetModified ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this . forceRendering ( ) ;
this . setTitle ( ) ;
} ,
rotatePages ( delta ) {
this . pdfViewer . pagesRotation += delta ;
} ,
requestPresentationMode ( ) {
this . pdfPresentationMode ? . request ( ) ;
} ,
triggerPrinting ( ) {
if ( ! this . supportsPrinting ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
window . print ( ) ;
} ,
bindEvents ( ) {
if ( this . _eventBusAbortController ) {
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
this . _eventBusAbortController = new AbortController ( ) ;
2021-03-25 17:57:25 +00:00
const {
2024-06-09 09:59:38 +00:00
eventBus ,
_eventBusAbortController : {
signal
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
} = this ;
eventBus . _on ( "resize" , webViewerResize , {
signal
} ) ;
eventBus . _on ( "hashchange" , webViewerHashchange , {
signal
} ) ;
eventBus . _on ( "beforeprint" , this . beforePrint . bind ( this ) , {
signal
} ) ;
eventBus . _on ( "afterprint" , this . afterPrint . bind ( this ) , {
signal
} ) ;
eventBus . _on ( "pagerender" , webViewerPageRender , {
signal
} ) ;
eventBus . _on ( "pagerendered" , webViewerPageRendered , {
signal
} ) ;
eventBus . _on ( "updateviewarea" , webViewerUpdateViewarea , {
signal
} ) ;
eventBus . _on ( "pagechanging" , webViewerPageChanging , {
signal
} ) ;
eventBus . _on ( "scalechanging" , webViewerScaleChanging , {
signal
} ) ;
eventBus . _on ( "rotationchanging" , webViewerRotationChanging , {
signal
} ) ;
eventBus . _on ( "sidebarviewchanged" , webViewerSidebarViewChanged , {
signal
} ) ;
eventBus . _on ( "pagemode" , webViewerPageMode , {
signal
} ) ;
eventBus . _on ( "namedaction" , webViewerNamedAction , {
signal
} ) ;
eventBus . _on ( "presentationmodechanged" , webViewerPresentationModeChanged , {
signal
} ) ;
eventBus . _on ( "presentationmode" , webViewerPresentationMode , {
signal
} ) ;
eventBus . _on ( "switchannotationeditormode" , webViewerSwitchAnnotationEditorMode , {
signal
} ) ;
eventBus . _on ( "switchannotationeditorparams" , webViewerSwitchAnnotationEditorParams , {
signal
} ) ;
eventBus . _on ( "print" , webViewerPrint , {
signal
} ) ;
eventBus . _on ( "download" , webViewerDownload , {
signal
} ) ;
eventBus . _on ( "firstpage" , webViewerFirstPage , {
signal
} ) ;
eventBus . _on ( "lastpage" , webViewerLastPage , {
signal
} ) ;
eventBus . _on ( "nextpage" , webViewerNextPage , {
signal
} ) ;
eventBus . _on ( "previouspage" , webViewerPreviousPage , {
signal
} ) ;
eventBus . _on ( "zoomin" , webViewerZoomIn , {
signal
} ) ;
eventBus . _on ( "zoomout" , webViewerZoomOut , {
signal
} ) ;
eventBus . _on ( "zoomreset" , webViewerZoomReset , {
signal
} ) ;
eventBus . _on ( "pagenumberchanged" , webViewerPageNumberChanged , {
signal
} ) ;
eventBus . _on ( "scalechanged" , webViewerScaleChanged , {
signal
} ) ;
eventBus . _on ( "rotatecw" , webViewerRotateCw , {
signal
} ) ;
eventBus . _on ( "rotateccw" , webViewerRotateCcw , {
signal
} ) ;
eventBus . _on ( "optionalcontentconfig" , webViewerOptionalContentConfig , {
signal
} ) ;
eventBus . _on ( "switchscrollmode" , webViewerSwitchScrollMode , {
signal
} ) ;
eventBus . _on ( "scrollmodechanged" , webViewerScrollModeChanged , {
signal
} ) ;
eventBus . _on ( "switchspreadmode" , webViewerSwitchSpreadMode , {
signal
} ) ;
eventBus . _on ( "spreadmodechanged" , webViewerSpreadModeChanged , {
signal
} ) ;
eventBus . _on ( "documentproperties" , webViewerDocumentProperties , {
signal
} ) ;
eventBus . _on ( "findfromurlhash" , webViewerFindFromUrlHash , {
signal
} ) ;
eventBus . _on ( "updatefindmatchescount" , webViewerUpdateFindMatchesCount , {
signal
} ) ;
eventBus . _on ( "updatefindcontrolstate" , webViewerUpdateFindControlState , {
signal
} ) ;
/ * e v e n t B u s . _ o n ( " f i l e i n p u t c h a n g e " , w e b V i e w e r F i l e I n p u t C h a n g e , {
signal
} ) ;
eventBus . _on ( "openfile" , webViewerOpenFile , {
signal
} ) ; * /
} ,
bindWindowEvents ( ) {
if ( this . _windowAbortController ) {
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
this . _windowAbortController = new AbortController ( ) ;
const {
eventBus ,
appConfig : {
mainContainer
} ,
_windowAbortController : {
signal
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} = this ;
function addWindowResolutionChange ( evt = null ) {
if ( evt ) {
webViewerResolutionChange ( evt ) ;
}
const mediaQueryList = window . matchMedia ( ` (resolution: ${ window . devicePixelRatio || 1 } dppx) ` ) ;
mediaQueryList . addEventListener ( "change" , addWindowResolutionChange , {
once : true ,
signal
2022-09-05 17:42:02 +00:00
} ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
addWindowResolutionChange ( ) ;
window . addEventListener ( "wheel" , webViewerWheel , {
passive : false ,
signal
} ) ;
window . addEventListener ( "touchstart" , webViewerTouchStart , {
passive : false ,
signal
} ) ;
window . addEventListener ( "touchmove" , webViewerTouchMove , {
passive : false ,
signal
} ) ;
window . addEventListener ( "touchend" , webViewerTouchEnd , {
passive : false ,
signal
} ) ;
window . addEventListener ( "click" , webViewerClick , {
signal
} ) ;
window . addEventListener ( "keydown" , webViewerKeyDown , {
signal
} ) ;
window . addEventListener ( "keyup" , webViewerKeyUp , {
signal
} ) ;
window . addEventListener ( "resize" , ( ) => {
eventBus . dispatch ( "resize" , {
source : window
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
} , {
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" , event => {
eventBus . dispatch ( "updatefromsandbox" , {
source : window ,
detail : event . 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 ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
if ( this . _lastScrollTop === mainContainer . scrollTop && this . _lastScrollLeft === mainContainer . scrollLeft ) {
2021-03-25 17:57:25 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
mainContainer . removeEventListener ( "scroll" , scroll , {
passive : true
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
this . _isScrolling = true ;
mainContainer . addEventListener ( "scrollend" , scrollend , {
signal
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
mainContainer . addEventListener ( "blur" , scrollend , {
signal
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
} ;
mainContainer . addEventListener ( "scroll" , scroll , {
passive : true ,
signal
} ) ;
} ,
unbindEvents ( ) {
this . _eventBusAbortController ? . abort ( ) ;
this . _eventBusAbortController = null ;
} ,
unbindWindowEvents ( ) {
this . _windowAbortController ? . abort ( ) ;
this . _windowAbortController = null ;
} ,
2024-07-13 08:49:47 +00:00
async testingClose ( ) {
this . unbindEvents ( ) ;
this . unbindWindowEvents ( ) ;
this . _globalAbortController ? . abort ( ) ;
this . _globalAbortController = null ;
this . findBar ? . close ( ) ;
await Promise . all ( [ this . l10n ? . destroy ( ) , this . close ( ) ] ) ;
} ,
2024-06-09 09:59:38 +00:00
_accumulateTicks ( ticks , prop ) {
if ( this [ prop ] > 0 && ticks < 0 || this [ prop ] < 0 && ticks > 0 ) {
this [ prop ] = 0 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
this [ prop ] += ticks ;
const wholeTicks = Math . trunc ( this [ prop ] ) ;
this [ prop ] -= wholeTicks ;
return wholeTicks ;
} ,
_accumulateFactor ( previousScale , factor , prop ) {
if ( factor === 1 ) {
return 1 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} ;
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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
const fileOrigin = new URL ( file , window . location . href ) . origin ;
if ( fileOrigin !== viewerOrigin ) {
throw new Error ( "file origin does not match viewer's" ) ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
} catch ( ex ) {
PDFViewerApplication . _documentError ( "pdfjs-loading-error" , {
message : ex . message
2021-03-25 17:57:25 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
throw ex ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
} ;
}
function webViewerPageRender ( {
pageNumber
} ) {
if ( pageNumber === PDFViewerApplication . page ) {
PDFViewerApplication . toolbar ? . updateLoadingIndicatorState ( true ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerPageRendered ( {
pageNumber ,
error
} ) {
if ( pageNumber === PDFViewerApplication . page ) {
PDFViewerApplication . toolbar ? . updateLoadingIndicatorState ( false ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( PDFViewerApplication . pdfSidebar ? . visibleView === SidebarView . THUMBS ) {
const pageView = PDFViewerApplication . pdfViewer . getPageView ( pageNumber - 1 ) ;
const thumbnailView = PDFViewerApplication . pdfThumbnailViewer ? . getThumbnail ( pageNumber - 1 ) ;
if ( pageView ) {
thumbnailView ? . setImage ( pageView ) ;
2019-04-13 13:02:01 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
if ( error ) {
PDFViewerApplication . _otherError ( "pdfjs-rendering-error" , error ) ;
2022-09-05 17:42:02 +00:00
}
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
function webViewerPageMode ( {
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 ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
PDFViewerApplication . pdfSidebar ? . switchView ( view , true ) ;
}
function webViewerNamedAction ( evt ) {
switch ( evt . action ) {
case "GoToPage" :
PDFViewerApplication . appConfig . toolbar ? . pageNumber . select ( ) ;
break ;
case "Find" :
if ( ! PDFViewerApplication . supportsIntegratedFind ) {
PDFViewerApplication . findBar ? . toggle ( ) ;
}
break ;
case "Print" :
PDFViewerApplication . triggerPrinting ( ) ;
break ;
case "SaveAs" :
PDFViewerApplication . downloadOrSave ( ) ;
break ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerPresentationModeChanged ( evt ) {
PDFViewerApplication . pdfViewer . presentationModeState = evt . state ;
}
function webViewerSidebarViewChanged ( {
view
} ) {
PDFViewerApplication . pdfRenderingQueue . isThumbnailViewEnabled = view === SidebarView . THUMBS ;
if ( PDFViewerApplication . isInitialViewSet ) {
PDFViewerApplication . store ? . set ( "sidebarView" , view ) . catch ( ( ) => { } ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerUpdateViewarea ( {
location
} ) {
if ( PDFViewerApplication . isInitialViewSet ) {
PDFViewerApplication . store ? . setMultiple ( {
page : location . pageNumber ,
zoom : location . scale ,
scrollLeft : location . left ,
scrollTop : location . top ,
rotation : location . rotation
} ) . catch ( ( ) => { } ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( PDFViewerApplication . appConfig . secondaryToolbar ) {
const href = PDFViewerApplication . pdfLinkService . getAnchorUrl ( location . pdfOpenParams ) ;
PDFViewerApplication . appConfig . secondaryToolbar . viewBookmarkButton . href = href ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerScrollModeChanged ( evt ) {
if ( PDFViewerApplication . isInitialViewSet && ! PDFViewerApplication . pdfViewer . isInPresentationMode ) {
PDFViewerApplication . store ? . set ( "scrollMode" , evt . mode ) . catch ( ( ) => { } ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerSpreadModeChanged ( evt ) {
if ( PDFViewerApplication . isInitialViewSet && ! PDFViewerApplication . pdfViewer . isInPresentationMode ) {
PDFViewerApplication . store ? . set ( "spreadMode" , evt . mode ) . catch ( ( ) => { } ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
function webViewerResize ( ) {
const {
pdfDocument ,
pdfViewer ,
pdfRenderingQueue
} = PDFViewerApplication ;
if ( pdfRenderingQueue . printing && window . matchMedia ( "print" ) . matches ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! pdfDocument ) {
return ;
}
const currentScaleValue = pdfViewer . currentScaleValue ;
if ( currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width" ) {
pdfViewer . currentScaleValue = currentScaleValue ;
}
pdfViewer . update ( ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
function webViewerHashchange ( evt ) {
const hash = evt . hash ;
if ( ! hash ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( ! PDFViewerApplication . isInitialViewSet ) {
PDFViewerApplication . initialBookmark = hash ;
} else if ( ! PDFViewerApplication . pdfHistory ? . popStateInProgress ) {
PDFViewerApplication . pdfLinkService . setHash ( hash ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
}
{
2024-08-07 13:16:38 +00:00
var webViewerFileInputChange = function ( evt ) {
2024-06-09 09:59:38 +00:00
if ( PDFViewerApplication . pdfViewer ? . isInPresentationMode ) {
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
const file = evt . fileInput . files [ 0 ] ;
PDFViewerApplication . open ( {
url : URL . createObjectURL ( file ) ,
originalUrl : file . name
} ) ;
} ;
2024-07-13 08:49:47 +00:00
var webViewerOpenFile = function ( evt ) {
2024-06-09 09:59:38 +00:00
PDFViewerApplication . _openFileInput ? . click ( ) ;
2024-08-07 13:16:38 +00:00
} ;
2024-06-09 09:59:38 +00:00
}
function webViewerPresentationMode ( ) {
PDFViewerApplication . requestPresentationMode ( ) ;
}
function webViewerSwitchAnnotationEditorMode ( evt ) {
PDFViewerApplication . pdfViewer . annotationEditorMode = evt ;
}
function webViewerSwitchAnnotationEditorParams ( evt ) {
PDFViewerApplication . pdfViewer . annotationEditorParams = evt ;
}
function webViewerPrint ( ) {
PDFViewerApplication . triggerPrinting ( ) ;
}
function webViewerDownload ( ) {
PDFViewerApplication . downloadOrSave ( ) ;
}
function webViewerFirstPage ( ) {
PDFViewerApplication . page = 1 ;
}
function webViewerLastPage ( ) {
PDFViewerApplication . page = PDFViewerApplication . pagesCount ;
}
function webViewerNextPage ( ) {
PDFViewerApplication . pdfViewer . nextPage ( ) ;
}
function webViewerPreviousPage ( ) {
PDFViewerApplication . pdfViewer . previousPage ( ) ;
}
function webViewerZoomIn ( ) {
PDFViewerApplication . zoomIn ( ) ;
}
function webViewerZoomOut ( ) {
PDFViewerApplication . zoomOut ( ) ;
}
function webViewerZoomReset ( ) {
PDFViewerApplication . zoomReset ( ) ;
}
function webViewerPageNumberChanged ( evt ) {
const pdfViewer = PDFViewerApplication . pdfViewer ;
if ( evt . value !== "" ) {
PDFViewerApplication . pdfLinkService . goToPage ( evt . value ) ;
}
if ( evt . value !== pdfViewer . currentPageNumber . toString ( ) && evt . value !== pdfViewer . currentPageLabel ) {
PDFViewerApplication . toolbar ? . setPageNumber ( pdfViewer . currentPageNumber , pdfViewer . currentPageLabel ) ;
}
}
function webViewerScaleChanged ( evt ) {
PDFViewerApplication . pdfViewer . currentScaleValue = evt . value ;
}
function webViewerRotateCw ( ) {
PDFViewerApplication . rotatePages ( 90 ) ;
}
function webViewerRotateCcw ( ) {
PDFViewerApplication . rotatePages ( - 90 ) ;
}
function webViewerOptionalContentConfig ( evt ) {
PDFViewerApplication . pdfViewer . optionalContentConfigPromise = evt . promise ;
}
function webViewerSwitchScrollMode ( evt ) {
PDFViewerApplication . pdfViewer . scrollMode = evt . mode ;
}
function webViewerSwitchSpreadMode ( evt ) {
PDFViewerApplication . pdfViewer . spreadMode = evt . mode ;
}
function webViewerDocumentProperties ( ) {
PDFViewerApplication . pdfDocumentProperties ? . open ( ) ;
}
function webViewerFindFromUrlHash ( evt ) {
PDFViewerApplication . eventBus . dispatch ( "find" , {
source : evt . source ,
type : "" ,
query : evt . query ,
caseSensitive : false ,
entireWord : false ,
highlightAll : true ,
findPrevious : false ,
matchDiacritics : true
} ) ;
}
function webViewerUpdateFindMatchesCount ( {
matchesCount
} ) {
if ( PDFViewerApplication . supportsIntegratedFind ) {
PDFViewerApplication . externalServices . updateFindMatchesCount ( matchesCount ) ;
} else {
PDFViewerApplication . findBar ? . updateResultsCount ( matchesCount ) ;
}
}
function webViewerUpdateFindControlState ( {
state ,
previous ,
2024-07-13 08:49:47 +00:00
entireWord ,
2024-06-09 09:59:38 +00:00
matchesCount ,
rawQuery
} ) {
if ( PDFViewerApplication . supportsIntegratedFind ) {
PDFViewerApplication . externalServices . updateFindControlState ( {
result : state ,
findPrevious : previous ,
2024-07-13 08:49:47 +00:00
entireWord ,
2024-06-09 09:59:38 +00:00
matchesCount ,
rawQuery
} ) ;
} else {
PDFViewerApplication . findBar ? . updateUIState ( state , previous , matchesCount ) ;
}
}
function webViewerScaleChanging ( evt ) {
PDFViewerApplication . toolbar ? . setPageScale ( evt . presetValue , evt . scale ) ;
PDFViewerApplication . pdfViewer . update ( ) ;
}
function webViewerRotationChanging ( evt ) {
if ( PDFViewerApplication . pdfThumbnailViewer ) {
PDFViewerApplication . pdfThumbnailViewer . pagesRotation = evt . pagesRotation ;
}
PDFViewerApplication . forceRendering ( ) ;
PDFViewerApplication . pdfViewer . currentPageNumber = evt . pageNumber ;
}
function webViewerPageChanging ( {
pageNumber ,
pageLabel
} ) {
PDFViewerApplication . toolbar ? . setPageNumber ( pageNumber , pageLabel ) ;
PDFViewerApplication . secondaryToolbar ? . setPageNumber ( pageNumber ) ;
if ( PDFViewerApplication . pdfSidebar ? . visibleView === SidebarView . THUMBS ) {
PDFViewerApplication . pdfThumbnailViewer ? . scrollThumbnailIntoView ( pageNumber ) ;
}
const currentPage = PDFViewerApplication . pdfViewer . getPageView ( pageNumber - 1 ) ;
PDFViewerApplication . toolbar ? . updateLoadingIndicatorState ( currentPage ? . renderingState === RenderingStates . RUNNING ) ;
}
function webViewerResolutionChange ( evt ) {
PDFViewerApplication . pdfViewer . refresh ( ) ;
}
function webViewerWheel ( evt ) {
const {
pdfViewer ,
supportsMouseWheelZoomCtrlKey ,
supportsMouseWheelZoomMetaKey ,
supportsPinchToZoom
} = PDFViewerApplication ;
if ( pdfViewer . isInPresentationMode ) {
return ;
}
const deltaMode = evt . deltaMode ;
let scaleFactor = Math . exp ( - evt . deltaY / 100 ) ;
const isBuiltInMac = false ;
const isPinchToZoom = evt . ctrlKey && ! PDFViewerApplication . _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 ( ) ;
2024-08-07 13:16:38 +00:00
if ( PDFViewerApplication . _isScrolling || document . visibilityState === "hidden" || PDFViewerApplication . overlayManager . active ) {
2024-06-09 09:59:38 +00:00
return ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
if ( isPinchToZoom && supportsPinchToZoom ) {
scaleFactor = PDFViewerApplication . _accumulateFactor ( pdfViewer . currentScale , scaleFactor , "_wheelUnusedFactor" ) ;
PDFViewerApplication . updateZoom ( null , scaleFactor , origin ) ;
} else {
const delta = normalizeWheelEventDirection ( evt ) ;
let ticks = 0 ;
if ( deltaMode === WheelEvent . DOM _DELTA _LINE || deltaMode === WheelEvent . DOM _DELTA _PAGE ) {
if ( Math . abs ( delta ) >= 1 ) {
ticks = Math . sign ( delta ) ;
} else {
ticks = PDFViewerApplication . _accumulateTicks ( delta , "_wheelUnusedTicks" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
} else {
const PIXELS _PER _LINE _SCALE = 30 ;
ticks = PDFViewerApplication . _accumulateTicks ( delta / PIXELS _PER _LINE _SCALE , "_wheelUnusedTicks" ) ;
2022-09-05 17:42:02 +00:00
}
2024-06-09 09:59:38 +00:00
PDFViewerApplication . updateZoom ( ticks , null , origin ) ;
2022-09-05 17:42:02 +00:00
}
}
}
2024-06-09 09:59:38 +00:00
function webViewerTouchStart ( evt ) {
if ( PDFViewerApplication . pdfViewer . isInPresentationMode || evt . touches . length < 2 ) {
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
evt . preventDefault ( ) ;
if ( evt . touches . length !== 2 || PDFViewerApplication . overlayManager . active ) {
PDFViewerApplication . _touchInfo = null ;
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
let [ touch0 , touch1 ] = evt . touches ;
if ( touch0 . identifier > touch1 . identifier ) {
[ touch0 , touch1 ] = [ touch1 , touch0 ] ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
PDFViewerApplication . _touchInfo = {
touch0X : touch0 . pageX ,
touch0Y : touch0 . pageY ,
touch1X : touch1 . pageX ,
touch1Y : touch1 . pageY
} ;
}
function webViewerTouchMove ( evt ) {
if ( ! PDFViewerApplication . _touchInfo || evt . touches . length !== 2 ) {
return ;
}
const {
pdfViewer ,
_touchInfo ,
supportsPinchToZoom
} = PDFViewerApplication ;
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 ) ) {
2022-09-05 17:42:02 +00:00
return ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} 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 ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
} 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 ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
}
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 = PDFViewerApplication . _accumulateFactor ( pdfViewer . currentScale , distance / pDistance , "_touchUnusedFactor" ) ;
PDFViewerApplication . updateZoom ( null , newScaleFactor , origin ) ;
} else {
const PIXELS _PER _LINE _SCALE = 30 ;
const ticks = PDFViewerApplication . _accumulateTicks ( ( distance - pDistance ) / PIXELS _PER _LINE _SCALE , "_touchUnusedTicks" ) ;
PDFViewerApplication . updateZoom ( ticks , null , origin ) ;
}
}
function webViewerTouchEnd ( evt ) {
if ( ! PDFViewerApplication . _touchInfo ) {
return ;
}
evt . preventDefault ( ) ;
PDFViewerApplication . _touchInfo = null ;
PDFViewerApplication . _touchUnusedTicks = 0 ;
PDFViewerApplication . _touchUnusedFactor = 1 ;
}
function webViewerClick ( evt ) {
if ( ! PDFViewerApplication . secondaryToolbar ? . isOpen ) {
return ;
}
const appConfig = PDFViewerApplication . appConfig ;
if ( PDFViewerApplication . pdfViewer . containsElement ( evt . target ) || appConfig . toolbar ? . container . contains ( evt . target ) && evt . target !== appConfig . secondaryToolbar ? . toggleButton ) {
PDFViewerApplication . secondaryToolbar . close ( ) ;
}
}
function webViewerKeyUp ( evt ) {
if ( evt . key === "Control" ) {
PDFViewerApplication . _isCtrlKeyDown = false ;
}
}
function webViewerKeyDown ( evt ) {
PDFViewerApplication . _isCtrlKeyDown = evt . key === "Control" ;
if ( PDFViewerApplication . overlayManager . active ) {
return ;
}
const {
eventBus ,
pdfViewer
} = PDFViewerApplication ;
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 ( ! PDFViewerApplication . supportsIntegratedFind && ! evt . shiftKey ) {
PDFViewerApplication . findBar ? . open ( ) ;
handled = true ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
break ;
case 71 :
if ( ! PDFViewerApplication . supportsIntegratedFind ) {
const {
state
} = PDFViewerApplication . 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 :
PDFViewerApplication . zoomIn ( ) ;
handled = true ;
break ;
case 173 :
case 109 :
case 189 :
PDFViewerApplication . zoomOut ( ) ;
handled = true ;
break ;
case 48 :
case 96 :
if ( ! isViewerInPresentationMode ) {
setTimeout ( function ( ) {
PDFViewerApplication . zoomReset ( ) ;
} ) ;
handled = false ;
}
break ;
case 38 :
if ( isViewerInPresentationMode || PDFViewerApplication . page > 1 ) {
PDFViewerApplication . page = 1 ;
handled = true ;
ensureViewerFocused = true ;
}
break ;
case 40 :
if ( isViewerInPresentationMode || PDFViewerApplication . page < PDFViewerApplication . pagesCount ) {
PDFViewerApplication . page = PDFViewerApplication . pagesCount ;
handled = true ;
ensureViewerFocused = true ;
}
break ;
2021-03-25 17:57:25 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( cmd === 1 || cmd === 8 ) {
switch ( evt . keyCode ) {
case 83 :
eventBus . dispatch ( "download" , {
source : window
} ) ;
handled = true ;
break ;
2024-07-13 08:49:47 +00:00
case 79 :
2024-06-09 09:59:38 +00:00
{
eventBus . dispatch ( "openfile" , {
source : window
} ) ;
handled = true ;
2019-04-13 13:02:01 +00:00
}
2024-07-13 08:49:47 +00:00
break ;
2024-06-09 09:59:38 +00:00
}
}
if ( cmd === 3 || cmd === 10 ) {
switch ( evt . keyCode ) {
case 80 :
PDFViewerApplication . requestPresentationMode ( ) ;
handled = true ;
PDFViewerApplication . externalServices . reportTelemetry ( {
type : "buttons" ,
data : {
id : "presentationModeKeyboard"
}
2022-09-05 17:42:02 +00:00
} ) ;
2024-06-09 09:59:38 +00:00
break ;
case 71 :
if ( PDFViewerApplication . appConfig . toolbar ) {
PDFViewerApplication . appConfig . toolbar . pageNumber . select ( ) ;
handled = true ;
}
break ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
}
if ( handled ) {
if ( ensureViewerFocused && ! isViewerInPresentationMode ) {
pdfViewer . focus ( ) ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
evt . preventDefault ( ) ;
return ;
2021-03-25 17:57:25 +00:00
}
2024-06-09 09:59:38 +00:00
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 ) {
2021-03-25 17:57:25 +00:00
return ;
}
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( cmd === 0 ) {
let turnPage = 0 ,
turnOnlyIfPageFit = false ;
switch ( evt . keyCode ) {
case 38 :
if ( PDFViewerApplication . supportsCaretBrowsingMode ) {
PDFViewerApplication . moveCaret ( true , false ) ;
handled = true ;
break ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
case 33 :
if ( pdfViewer . isVerticalScrollbarEnabled ) {
turnOnlyIfPageFit = true ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
turnPage = - 1 ;
break ;
case 8 :
if ( ! isViewerInPresentationMode ) {
turnOnlyIfPageFit = true ;
}
turnPage = - 1 ;
break ;
case 37 :
if ( PDFViewerApplication . supportsCaretBrowsingMode ) {
return ;
}
if ( pdfViewer . isHorizontalScrollbarEnabled ) {
turnOnlyIfPageFit = true ;
}
case 75 :
case 80 :
turnPage = - 1 ;
break ;
case 27 :
if ( PDFViewerApplication . secondaryToolbar ? . isOpen ) {
PDFViewerApplication . secondaryToolbar . close ( ) ;
handled = true ;
}
if ( ! PDFViewerApplication . supportsIntegratedFind && PDFViewerApplication . findBar ? . opened ) {
PDFViewerApplication . findBar . close ( ) ;
handled = true ;
}
break ;
case 40 :
if ( PDFViewerApplication . supportsCaretBrowsingMode ) {
PDFViewerApplication . 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 ( PDFViewerApplication . supportsCaretBrowsingMode ) {
2019-04-13 13:02:01 +00:00
return ;
}
2024-06-09 09:59:38 +00:00
if ( pdfViewer . isHorizontalScrollbarEnabled ) {
turnOnlyIfPageFit = true ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
case 74 :
case 78 :
turnPage = 1 ;
break ;
case 36 :
if ( isViewerInPresentationMode || PDFViewerApplication . page > 1 ) {
PDFViewerApplication . page = 1 ;
handled = true ;
ensureViewerFocused = true ;
}
break ;
case 35 :
if ( isViewerInPresentationMode || PDFViewerApplication . page < PDFViewerApplication . pagesCount ) {
PDFViewerApplication . page = PDFViewerApplication . pagesCount ;
handled = true ;
ensureViewerFocused = true ;
}
break ;
case 83 :
PDFViewerApplication . pdfCursorTools ? . switchTool ( CursorTool . SELECT ) ;
break ;
case 72 :
PDFViewerApplication . pdfCursorTools ? . switchTool ( CursorTool . HAND ) ;
break ;
case 82 :
PDFViewerApplication . rotatePages ( 90 ) ;
break ;
case 115 :
PDFViewerApplication . pdfSidebar ? . toggle ( ) ;
break ;
2019-04-13 13:02:01 +00:00
}
2024-06-09 09:59:38 +00:00
if ( turnPage !== 0 && ( ! turnOnlyIfPageFit || pdfViewer . currentScaleValue === "page-fit" ) ) {
if ( turnPage > 0 ) {
pdfViewer . nextPage ( ) ;
} else {
pdfViewer . previousPage ( ) ;
2017-05-13 12:01:52 +00:00
}
2024-06-09 09:59:38 +00:00
handled = true ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( cmd === 4 ) {
switch ( evt . keyCode ) {
case 13 :
case 32 :
if ( ! isViewerInPresentationMode && pdfViewer . currentScaleValue !== "page-fit" ) {
break ;
}
pdfViewer . previousPage ( ) ;
handled = true ;
break ;
case 38 :
PDFViewerApplication . moveCaret ( true , true ) ;
handled = true ;
break ;
case 40 :
PDFViewerApplication . moveCaret ( false , true ) ;
handled = true ;
break ;
case 82 :
PDFViewerApplication . rotatePages ( - 90 ) ;
break ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( ! handled && ! isViewerInPresentationMode ) {
if ( evt . keyCode >= 33 && evt . keyCode <= 40 || evt . keyCode === 32 && curElementTagName !== "BUTTON" ) {
ensureViewerFocused = true ;
2019-04-13 13:02:01 +00:00
}
}
2024-06-09 09:59:38 +00:00
if ( ensureViewerFocused && ! pdfViewer . containsElement ( curElement ) ) {
pdfViewer . focus ( ) ;
}
if ( handled ) {
evt . preventDefault ( ) ;
2022-09-05 17:42:02 +00:00
}
}
2024-06-09 09:59:38 +00:00
function beforeUnload ( evt ) {
evt . preventDefault ( ) ;
evt . returnValue = "" ;
return false ;
}
function webViewerAnnotationEditorStatesChanged ( data ) {
PDFViewerApplication . externalServices . updateEditorStates ( data ) ;
}
function webViewerReportTelemetry ( {
details
} ) {
PDFViewerApplication . externalServices . reportTelemetry ( details ) ;
}
2024-08-07 13:16:38 +00:00
function webViewerSetPreference ( {
name ,
value
} ) {
PDFViewerApplication . preferences . set ( name , value ) ;
}
2022-09-05 17:42:02 +00:00
2024-06-09 09:59:38 +00:00
; // CONCATENATED MODULE: ./web/viewer.js
2022-09-05 17:42:02 +00:00
2024-08-07 13:16:38 +00:00
const pdfjsVersion = "4.5.136" ;
const pdfjsBuild = "3a21f03b0" ;
2022-09-05 17:42:02 +00:00
const AppConstants = {
2024-06-09 09:59:38 +00:00
LinkTarget : LinkTarget ,
RenderingStates : RenderingStates ,
ScrollMode : ScrollMode ,
SpreadMode : SpreadMode
2022-09-05 17:42:02 +00:00
} ;
2024-06-09 09:59:38 +00:00
window . PDFViewerApplication = PDFViewerApplication ;
2022-09-05 17:42:02 +00:00
window . PDFViewerApplicationConstants = AppConstants ;
2024-06-09 09:59:38 +00:00
window . PDFViewerApplicationOptions = AppOptions ;
2022-09-05 17:42:02 +00:00
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" ) ,
viewFind : document . getElementById ( "viewFind" ) ,
print : document . getElementById ( "print" ) ,
editorFreeTextButton : document . getElementById ( "editorFreeText" ) ,
editorFreeTextParamsToolbar : document . getElementById ( "editorFreeTextParamsToolbar" ) ,
2024-06-09 09:59:38 +00:00
editorHighlightButton : document . getElementById ( "editorHighlight" ) ,
editorHighlightParamsToolbar : document . getElementById ( "editorHighlightParamsToolbar" ) ,
editorHighlightColorPicker : document . getElementById ( "editorHighlightColorPicker" ) ,
2022-09-05 17:42:02 +00:00
editorInkButton : document . getElementById ( "editorInk" ) ,
editorInkParamsToolbar : document . getElementById ( "editorInkParamsToolbar" ) ,
2024-06-09 09:59:38 +00:00
editorStampButton : document . getElementById ( "editorStamp" ) ,
editorStampParamsToolbar : document . getElementById ( "editorStampParamsToolbar" ) ,
download : document . getElementById ( "download" )
2022-09-05 17:42:02 +00:00
} ,
secondaryToolbar : {
toolbar : document . getElementById ( "secondaryToolbar" ) ,
toggleButton : document . getElementById ( "secondaryToolbarToggle" ) ,
2024-06-09 09:59:38 +00:00
presentationModeButton : document . getElementById ( "presentationMode" ) ,
2022-09-05 17:42:02 +00:00
openFileButton : document . getElementById ( "secondaryOpenFile" ) ,
printButton : document . getElementById ( "secondaryPrint" ) ,
downloadButton : document . getElementById ( "secondaryDownload" ) ,
2024-06-09 09:59:38 +00:00
viewBookmarkButton : document . getElementById ( "viewBookmark" ) ,
2022-09-05 17:42:02 +00:00
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" ) ,
documentPropertiesButton : document . getElementById ( "documentProperties" )
} ,
sidebar : {
outerContainer : document . getElementById ( "outerContainer" ) ,
sidebarContainer : document . getElementById ( "sidebarContainer" ) ,
toggleButton : document . getElementById ( "sidebarToggle" ) ,
2024-06-09 09:59:38 +00:00
resizer : document . getElementById ( "sidebarResizer" ) ,
2022-09-05 17:42:02 +00:00
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" )
}
} ,
2024-06-09 09:59:38 +00:00
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" )
} ,
2022-09-05 17:42:02 +00:00
annotationEditorParams : {
editorFreeTextFontSize : document . getElementById ( "editorFreeTextFontSize" ) ,
editorFreeTextColor : document . getElementById ( "editorFreeTextColor" ) ,
editorInkColor : document . getElementById ( "editorInkColor" ) ,
editorInkThickness : document . getElementById ( "editorInkThickness" ) ,
2024-06-09 09:59:38 +00:00
editorInkOpacity : document . getElementById ( "editorInkOpacity" ) ,
editorStampAddImage : document . getElementById ( "editorStampAddImage" ) ,
editorFreeHighlightThickness : document . getElementById ( "editorFreeHighlightThickness" ) ,
editorHighlightShowAll : document . getElementById ( "editorHighlightShowAll" )
2022-09-05 17:42:02 +00:00
} ,
2024-06-09 09:59:38 +00:00
printContainer : document . getElementById ( "printContainer" )
2022-09-05 17:42:02 +00:00
} ;
}
function webViewerLoad ( ) {
const config = getViewerConfiguration ( ) ;
2024-06-09 09:59:38 +00:00
const event = new CustomEvent ( "webviewerloaded" , {
bubbles : true ,
cancelable : true ,
detail : {
source : window
}
2022-09-05 17:42:02 +00:00
} ) ;
try {
parent . document . dispatchEvent ( event ) ;
} catch ( ex ) {
console . error ( ` webviewerloaded: ${ ex } ` ) ;
document . dispatchEvent ( event ) ;
}
2024-06-09 09:59:38 +00:00
PDFViewerApplication . run ( config ) ;
2022-09-05 17:42:02 +00:00
}
document . blockUnblockOnload ? . ( true ) ;
if ( document . readyState === "interactive" || document . readyState === "complete" ) {
webViewerLoad ( ) ;
} else {
document . addEventListener ( "DOMContentLoaded" , webViewerLoad , true ) ;
}
2024-06-09 09:59:38 +00:00
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