viewer.mjs 517 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * JavaScript code in this page
  4. *
  5. * Copyright 2024 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * JavaScript code in this page
  21. */
  22. /******/ // The require scope
  23. /******/ var __webpack_require__ = {};
  24. /******/
  25. /************************************************************************/
  26. /******/ /* webpack/runtime/define property getters */
  27. /******/ (() => {
  28. /******/ // define getter functions for harmony exports
  29. /******/ __webpack_require__.d = (exports, definition) => {
  30. /******/ for(var key in definition) {
  31. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  32. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  33. /******/ }
  34. /******/ }
  35. /******/ };
  36. /******/ })();
  37. /******/
  38. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  39. /******/ (() => {
  40. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  41. /******/ })();
  42. /******/
  43. /************************************************************************/
  44. var __webpack_exports__ = {};
  45. // EXPORTS
  46. __webpack_require__.d(__webpack_exports__, {
  47. PDFViewerApplication: () => (/* reexport */ PDFViewerApplication),
  48. PDFViewerApplicationConstants: () => (/* binding */ AppConstants),
  49. PDFViewerApplicationOptions: () => (/* reexport */ AppOptions)
  50. });
  51. ;// ./web/pdfjs.js
  52. const {
  53. AbortException,
  54. AnnotationEditorLayer,
  55. AnnotationEditorParamsType,
  56. AnnotationEditorType,
  57. AnnotationEditorUIManager,
  58. AnnotationLayer,
  59. AnnotationMode,
  60. AnnotationType,
  61. build,
  62. ColorPicker,
  63. createValidAbsoluteUrl,
  64. DOMSVGFactory,
  65. DrawLayer,
  66. FeatureTest,
  67. fetchData,
  68. getDocument,
  69. getFilenameFromUrl,
  70. getPdfFilenameFromUrl: pdfjs_getPdfFilenameFromUrl,
  71. getUuid,
  72. getXfaPageViewport,
  73. GlobalWorkerOptions,
  74. ImageKind,
  75. InvalidPDFException,
  76. isDataScheme,
  77. isPdfFile,
  78. isValidExplicitDest,
  79. MathClamp,
  80. noContextMenu,
  81. normalizeUnicode,
  82. OPS,
  83. OutputScale,
  84. PasswordResponses,
  85. PDFDataRangeTransport,
  86. PDFDateString,
  87. PDFWorker,
  88. PermissionFlag,
  89. PixelsPerInch,
  90. RenderingCancelledException,
  91. ResponseException,
  92. setLayerDimensions,
  93. shadow,
  94. SignatureExtractor,
  95. stopEvent,
  96. SupportedImageMimeTypes,
  97. TextLayer,
  98. TouchManager,
  99. Util,
  100. VerbosityLevel,
  101. version,
  102. XfaLayer
  103. } = globalThis.pdfjsLib;
  104. ;// ./web/ui_utils.js
  105. const DEFAULT_SCALE_VALUE = "auto";
  106. const DEFAULT_SCALE = 1.0;
  107. const DEFAULT_SCALE_DELTA = 1.1;
  108. const MIN_SCALE = 0.1;
  109. const MAX_SCALE = 10.0;
  110. const UNKNOWN_SCALE = 0;
  111. const MAX_AUTO_SCALE = 1.25;
  112. const SCROLLBAR_PADDING = 40;
  113. const VERTICAL_PADDING = 5;
  114. const RenderingStates = {
  115. INITIAL: 0,
  116. RUNNING: 1,
  117. PAUSED: 2,
  118. FINISHED: 3
  119. };
  120. const PresentationModeState = {
  121. UNKNOWN: 0,
  122. NORMAL: 1,
  123. CHANGING: 2,
  124. FULLSCREEN: 3
  125. };
  126. const SidebarView = {
  127. UNKNOWN: -1,
  128. NONE: 0,
  129. THUMBS: 1,
  130. OUTLINE: 2,
  131. ATTACHMENTS: 3,
  132. LAYERS: 4
  133. };
  134. const TextLayerMode = {
  135. DISABLE: 0,
  136. ENABLE: 1,
  137. ENABLE_PERMISSIONS: 2
  138. };
  139. const ScrollMode = {
  140. UNKNOWN: -1,
  141. VERTICAL: 0,
  142. HORIZONTAL: 1,
  143. WRAPPED: 2,
  144. PAGE: 3
  145. };
  146. const SpreadMode = {
  147. UNKNOWN: -1,
  148. NONE: 0,
  149. ODD: 1,
  150. EVEN: 2
  151. };
  152. const CursorTool = {
  153. SELECT: 0,
  154. HAND: 1,
  155. ZOOM: 2
  156. };
  157. const AutoPrintRegExp = /\bprint\s*\(/;
  158. function scrollIntoView(element, spot, scrollMatches = false) {
  159. let parent = element.offsetParent;
  160. if (!parent) {
  161. console.error("offsetParent is not set -- cannot scroll");
  162. return;
  163. }
  164. let offsetY = element.offsetTop + element.clientTop;
  165. let offsetX = element.offsetLeft + element.clientLeft;
  166. while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || scrollMatches && (parent.classList.contains("markedContent") || getComputedStyle(parent).overflow === "hidden")) {
  167. offsetY += parent.offsetTop;
  168. offsetX += parent.offsetLeft;
  169. parent = parent.offsetParent;
  170. if (!parent) {
  171. return;
  172. }
  173. }
  174. if (spot) {
  175. if (spot.top !== undefined) {
  176. offsetY += spot.top;
  177. }
  178. if (spot.left !== undefined) {
  179. offsetX += spot.left;
  180. parent.scrollLeft = offsetX;
  181. }
  182. }
  183. parent.scrollTop = offsetY;
  184. }
  185. function watchScroll(viewAreaElement, callback, abortSignal = undefined) {
  186. const debounceScroll = function (evt) {
  187. if (rAF) {
  188. return;
  189. }
  190. rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
  191. rAF = null;
  192. const currentX = viewAreaElement.scrollLeft;
  193. const lastX = state.lastX;
  194. if (currentX !== lastX) {
  195. state.right = currentX > lastX;
  196. }
  197. state.lastX = currentX;
  198. const currentY = viewAreaElement.scrollTop;
  199. const lastY = state.lastY;
  200. if (currentY !== lastY) {
  201. state.down = currentY > lastY;
  202. }
  203. state.lastY = currentY;
  204. callback(state);
  205. });
  206. };
  207. const state = {
  208. right: true,
  209. down: true,
  210. lastX: viewAreaElement.scrollLeft,
  211. lastY: viewAreaElement.scrollTop,
  212. _eventHandler: debounceScroll
  213. };
  214. let rAF = null;
  215. viewAreaElement.addEventListener("scroll", debounceScroll, {
  216. useCapture: true,
  217. signal: abortSignal
  218. });
  219. abortSignal?.addEventListener("abort", () => window.cancelAnimationFrame(rAF), {
  220. once: true
  221. });
  222. return state;
  223. }
  224. function parseQueryString(query) {
  225. const params = new Map();
  226. for (const [key, value] of new URLSearchParams(query)) {
  227. params.set(key.toLowerCase(), value);
  228. }
  229. return params;
  230. }
  231. const InvisibleCharsRegExp = /[\x00-\x1F]/g;
  232. function removeNullCharacters(str, replaceInvisible = false) {
  233. if (!InvisibleCharsRegExp.test(str)) {
  234. return str;
  235. }
  236. if (replaceInvisible) {
  237. return str.replaceAll(InvisibleCharsRegExp, m => m === "\x00" ? "" : " ");
  238. }
  239. return str.replaceAll("\x00", "");
  240. }
  241. function binarySearchFirstItem(items, condition, start = 0) {
  242. let minIndex = start;
  243. let maxIndex = items.length - 1;
  244. if (maxIndex < 0 || !condition(items[maxIndex])) {
  245. return items.length;
  246. }
  247. if (condition(items[minIndex])) {
  248. return minIndex;
  249. }
  250. while (minIndex < maxIndex) {
  251. const currentIndex = minIndex + maxIndex >> 1;
  252. const currentItem = items[currentIndex];
  253. if (condition(currentItem)) {
  254. maxIndex = currentIndex;
  255. } else {
  256. minIndex = currentIndex + 1;
  257. }
  258. }
  259. return minIndex;
  260. }
  261. function approximateFraction(x) {
  262. if (Math.floor(x) === x) {
  263. return [x, 1];
  264. }
  265. const xinv = 1 / x;
  266. const limit = 8;
  267. if (xinv > limit) {
  268. return [1, limit];
  269. } else if (Math.floor(xinv) === xinv) {
  270. return [1, xinv];
  271. }
  272. const x_ = x > 1 ? xinv : x;
  273. let a = 0,
  274. b = 1,
  275. c = 1,
  276. d = 1;
  277. while (true) {
  278. const p = a + c,
  279. q = b + d;
  280. if (q > limit) {
  281. break;
  282. }
  283. if (x_ <= p / q) {
  284. c = p;
  285. d = q;
  286. } else {
  287. a = p;
  288. b = q;
  289. }
  290. }
  291. let result;
  292. if (x_ - a / b < c / d - x_) {
  293. result = x_ === x ? [a, b] : [b, a];
  294. } else {
  295. result = x_ === x ? [c, d] : [d, c];
  296. }
  297. return result;
  298. }
  299. function floorToDivide(x, div) {
  300. return x - x % div;
  301. }
  302. function getPageSizeInches({
  303. view,
  304. userUnit,
  305. rotate
  306. }) {
  307. const [x1, y1, x2, y2] = view;
  308. const changeOrientation = rotate % 180 !== 0;
  309. const width = (x2 - x1) / 72 * userUnit;
  310. const height = (y2 - y1) / 72 * userUnit;
  311. return {
  312. width: changeOrientation ? height : width,
  313. height: changeOrientation ? width : height
  314. };
  315. }
  316. function backtrackBeforeAllVisibleElements(index, views, top) {
  317. if (index < 2) {
  318. return index;
  319. }
  320. let elt = views[index].div;
  321. let pageTop = elt.offsetTop + elt.clientTop;
  322. if (pageTop >= top) {
  323. elt = views[index - 1].div;
  324. pageTop = elt.offsetTop + elt.clientTop;
  325. }
  326. for (let i = index - 2; i >= 0; --i) {
  327. elt = views[i].div;
  328. if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) {
  329. break;
  330. }
  331. index = i;
  332. }
  333. return index;
  334. }
  335. function getVisibleElements({
  336. scrollEl,
  337. views,
  338. sortByVisibility = false,
  339. horizontal = false,
  340. rtl = false
  341. }) {
  342. const top = scrollEl.scrollTop,
  343. bottom = top + scrollEl.clientHeight;
  344. const left = scrollEl.scrollLeft,
  345. right = left + scrollEl.clientWidth;
  346. function isElementBottomAfterViewTop(view) {
  347. const element = view.div;
  348. const elementBottom = element.offsetTop + element.clientTop + element.clientHeight;
  349. return elementBottom > top;
  350. }
  351. function isElementNextAfterViewHorizontally(view) {
  352. const element = view.div;
  353. const elementLeft = element.offsetLeft + element.clientLeft;
  354. const elementRight = elementLeft + element.clientWidth;
  355. return rtl ? elementLeft < right : elementRight > left;
  356. }
  357. const visible = [],
  358. ids = new Set(),
  359. numViews = views.length;
  360. let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop);
  361. if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) {
  362. firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top);
  363. }
  364. let lastEdge = horizontal ? right : -1;
  365. for (let i = firstVisibleElementInd; i < numViews; i++) {
  366. const view = views[i],
  367. element = view.div;
  368. const currentWidth = element.offsetLeft + element.clientLeft;
  369. const currentHeight = element.offsetTop + element.clientTop;
  370. const viewWidth = element.clientWidth,
  371. viewHeight = element.clientHeight;
  372. const viewRight = currentWidth + viewWidth;
  373. const viewBottom = currentHeight + viewHeight;
  374. if (lastEdge === -1) {
  375. if (viewBottom >= bottom) {
  376. lastEdge = viewBottom;
  377. }
  378. } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) {
  379. break;
  380. }
  381. if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) {
  382. continue;
  383. }
  384. const minY = Math.max(0, top - currentHeight);
  385. const minX = Math.max(0, left - currentWidth);
  386. const hiddenHeight = minY + Math.max(0, viewBottom - bottom);
  387. const hiddenWidth = minX + Math.max(0, viewRight - right);
  388. const fractionHeight = (viewHeight - hiddenHeight) / viewHeight,
  389. fractionWidth = (viewWidth - hiddenWidth) / viewWidth;
  390. const percent = fractionHeight * fractionWidth * 100 | 0;
  391. visible.push({
  392. id: view.id,
  393. x: currentWidth,
  394. y: currentHeight,
  395. visibleArea: percent === 100 ? null : {
  396. minX,
  397. minY,
  398. maxX: Math.min(viewRight, right) - currentWidth,
  399. maxY: Math.min(viewBottom, bottom) - currentHeight
  400. },
  401. view,
  402. percent,
  403. widthPercent: fractionWidth * 100 | 0
  404. });
  405. ids.add(view.id);
  406. }
  407. const first = visible[0],
  408. last = visible.at(-1);
  409. if (sortByVisibility) {
  410. visible.sort(function (a, b) {
  411. const pc = a.percent - b.percent;
  412. if (Math.abs(pc) > 0.001) {
  413. return -pc;
  414. }
  415. return a.id - b.id;
  416. });
  417. }
  418. return {
  419. first,
  420. last,
  421. views: visible,
  422. ids
  423. };
  424. }
  425. function normalizeWheelEventDirection(evt) {
  426. let delta = Math.hypot(evt.deltaX, evt.deltaY);
  427. const angle = Math.atan2(evt.deltaY, evt.deltaX);
  428. if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {
  429. delta = -delta;
  430. }
  431. return delta;
  432. }
  433. function normalizeWheelEventDelta(evt) {
  434. const deltaMode = evt.deltaMode;
  435. let delta = normalizeWheelEventDirection(evt);
  436. const MOUSE_PIXELS_PER_LINE = 30;
  437. const MOUSE_LINES_PER_PAGE = 30;
  438. if (deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
  439. delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;
  440. } else if (deltaMode === WheelEvent.DOM_DELTA_LINE) {
  441. delta /= MOUSE_LINES_PER_PAGE;
  442. }
  443. return delta;
  444. }
  445. function isValidRotation(angle) {
  446. return Number.isInteger(angle) && angle % 90 === 0;
  447. }
  448. function isValidScrollMode(mode) {
  449. return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN;
  450. }
  451. function isValidSpreadMode(mode) {
  452. return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN;
  453. }
  454. function isPortraitOrientation(size) {
  455. return size.width <= size.height;
  456. }
  457. const animationStarted = new Promise(function (resolve) {
  458. window.requestAnimationFrame(resolve);
  459. });
  460. const docStyle = document.documentElement.style;
  461. class ProgressBar {
  462. #classList = null;
  463. #disableAutoFetchTimeout = null;
  464. #percent = 0;
  465. #style = null;
  466. #visible = true;
  467. constructor(bar) {
  468. this.#classList = bar.classList;
  469. this.#style = bar.style;
  470. }
  471. get percent() {
  472. return this.#percent;
  473. }
  474. set percent(val) {
  475. this.#percent = MathClamp(val, 0, 100);
  476. if (isNaN(val)) {
  477. this.#classList.add("indeterminate");
  478. return;
  479. }
  480. this.#classList.remove("indeterminate");
  481. this.#style.setProperty("--progressBar-percent", `${this.#percent}%`);
  482. }
  483. setWidth(viewer) {
  484. if (!viewer) {
  485. return;
  486. }
  487. const container = viewer.parentNode;
  488. const scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
  489. if (scrollbarWidth > 0) {
  490. this.#style.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`);
  491. }
  492. }
  493. setDisableAutoFetch(delay = 5000) {
  494. if (this.#percent === 100 || isNaN(this.#percent)) {
  495. return;
  496. }
  497. if (this.#disableAutoFetchTimeout) {
  498. clearTimeout(this.#disableAutoFetchTimeout);
  499. }
  500. this.show();
  501. this.#disableAutoFetchTimeout = setTimeout(() => {
  502. this.#disableAutoFetchTimeout = null;
  503. this.hide();
  504. }, delay);
  505. }
  506. hide() {
  507. if (!this.#visible) {
  508. return;
  509. }
  510. this.#visible = false;
  511. this.#classList.add("hidden");
  512. }
  513. show() {
  514. if (this.#visible) {
  515. return;
  516. }
  517. this.#visible = true;
  518. this.#classList.remove("hidden");
  519. }
  520. }
  521. function getActiveOrFocusedElement() {
  522. let curRoot = document;
  523. let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
  524. while (curActiveOrFocused?.shadowRoot) {
  525. curRoot = curActiveOrFocused.shadowRoot;
  526. curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
  527. }
  528. return curActiveOrFocused;
  529. }
  530. function apiPageLayoutToViewerModes(layout) {
  531. let scrollMode = ScrollMode.VERTICAL,
  532. spreadMode = SpreadMode.NONE;
  533. switch (layout) {
  534. case "SinglePage":
  535. scrollMode = ScrollMode.PAGE;
  536. break;
  537. case "OneColumn":
  538. break;
  539. case "TwoPageLeft":
  540. scrollMode = ScrollMode.PAGE;
  541. case "TwoColumnLeft":
  542. spreadMode = SpreadMode.ODD;
  543. break;
  544. case "TwoPageRight":
  545. scrollMode = ScrollMode.PAGE;
  546. case "TwoColumnRight":
  547. spreadMode = SpreadMode.EVEN;
  548. break;
  549. }
  550. return {
  551. scrollMode,
  552. spreadMode
  553. };
  554. }
  555. function apiPageModeToSidebarView(mode) {
  556. switch (mode) {
  557. case "UseNone":
  558. return SidebarView.NONE;
  559. case "UseThumbs":
  560. return SidebarView.THUMBS;
  561. case "UseOutlines":
  562. return SidebarView.OUTLINE;
  563. case "UseAttachments":
  564. return SidebarView.ATTACHMENTS;
  565. case "UseOC":
  566. return SidebarView.LAYERS;
  567. }
  568. return SidebarView.NONE;
  569. }
  570. function toggleCheckedBtn(button, toggle, view = null) {
  571. button.classList.toggle("toggled", toggle);
  572. button.setAttribute("aria-checked", toggle);
  573. view?.classList.toggle("hidden", !toggle);
  574. }
  575. function toggleExpandedBtn(button, toggle, view = null) {
  576. button.classList.toggle("toggled", toggle);
  577. button.setAttribute("aria-expanded", toggle);
  578. view?.classList.toggle("hidden", !toggle);
  579. }
  580. const calcRound = function () {
  581. const e = document.createElement("div");
  582. e.style.width = "round(down, calc(1.6666666666666665 * 792px), 1px)";
  583. return e.style.width === "calc(1320px)" ? Math.fround : x => x;
  584. }();
  585. ;// ./web/app_options.js
  586. {
  587. var compatParams = new Map();
  588. const userAgent = navigator.userAgent || "";
  589. const platform = navigator.platform || "";
  590. const maxTouchPoints = navigator.maxTouchPoints || 1;
  591. const isAndroid = /Android/.test(userAgent);
  592. const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1;
  593. (function () {
  594. if (isIOS || isAndroid) {
  595. compatParams.set("maxCanvasPixels", 5242880);
  596. }
  597. })();
  598. (function () {
  599. if (isAndroid) {
  600. compatParams.set("useSystemFonts", false);
  601. }
  602. })();
  603. }
  604. const OptionKind = {
  605. BROWSER: 0x01,
  606. VIEWER: 0x02,
  607. API: 0x04,
  608. WORKER: 0x08,
  609. EVENT_DISPATCH: 0x10,
  610. PREFERENCE: 0x80
  611. };
  612. const Type = {
  613. BOOLEAN: 0x01,
  614. NUMBER: 0x02,
  615. OBJECT: 0x04,
  616. STRING: 0x08,
  617. UNDEFINED: 0x10
  618. };
  619. const defaultOptions = {
  620. allowedGlobalEvents: {
  621. value: null,
  622. kind: OptionKind.BROWSER
  623. },
  624. canvasMaxAreaInBytes: {
  625. value: -1,
  626. kind: OptionKind.BROWSER + OptionKind.API
  627. },
  628. isInAutomation: {
  629. value: false,
  630. kind: OptionKind.BROWSER
  631. },
  632. localeProperties: {
  633. value: {
  634. lang: navigator.language || "en-US"
  635. },
  636. kind: OptionKind.BROWSER
  637. },
  638. maxCanvasDim: {
  639. value: 32767,
  640. kind: OptionKind.BROWSER + OptionKind.VIEWER
  641. },
  642. nimbusDataStr: {
  643. value: "",
  644. kind: OptionKind.BROWSER
  645. },
  646. supportsCaretBrowsingMode: {
  647. value: false,
  648. kind: OptionKind.BROWSER
  649. },
  650. supportsDocumentFonts: {
  651. value: true,
  652. kind: OptionKind.BROWSER
  653. },
  654. supportsIntegratedFind: {
  655. value: false,
  656. kind: OptionKind.BROWSER
  657. },
  658. supportsMouseWheelZoomCtrlKey: {
  659. value: true,
  660. kind: OptionKind.BROWSER
  661. },
  662. supportsMouseWheelZoomMetaKey: {
  663. value: true,
  664. kind: OptionKind.BROWSER
  665. },
  666. supportsPinchToZoom: {
  667. value: true,
  668. kind: OptionKind.BROWSER
  669. },
  670. toolbarDensity: {
  671. value: 0,
  672. kind: OptionKind.BROWSER + OptionKind.EVENT_DISPATCH
  673. },
  674. altTextLearnMoreUrl: {
  675. value: "",
  676. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  677. },
  678. annotationEditorMode: {
  679. value: 0,
  680. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  681. },
  682. annotationMode: {
  683. value: 2,
  684. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  685. },
  686. cursorToolOnLoad: {
  687. value: 0,
  688. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  689. },
  690. debuggerSrc: {
  691. value: "./debugger.mjs",
  692. kind: OptionKind.VIEWER
  693. },
  694. defaultZoomDelay: {
  695. value: 400,
  696. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  697. },
  698. defaultZoomValue: {
  699. value: "",
  700. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  701. },
  702. disableHistory: {
  703. value: false,
  704. kind: OptionKind.VIEWER
  705. },
  706. disablePageLabels: {
  707. value: false,
  708. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  709. },
  710. enableAltText: {
  711. value: false,
  712. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  713. },
  714. enableAltTextModelDownload: {
  715. value: true,
  716. kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH
  717. },
  718. enableAutoLinking: {
  719. value: true,
  720. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  721. },
  722. enableDetailCanvas: {
  723. value: true,
  724. kind: OptionKind.VIEWER
  725. },
  726. enableGuessAltText: {
  727. value: true,
  728. kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH
  729. },
  730. enableHighlightFloatingButton: {
  731. value: false,
  732. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  733. },
  734. enableNewAltTextWhenAddingImage: {
  735. value: true,
  736. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  737. },
  738. enablePermissions: {
  739. value: false,
  740. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  741. },
  742. enablePrintAutoRotate: {
  743. value: true,
  744. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  745. },
  746. enableScripting: {
  747. value: true,
  748. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  749. },
  750. enableSignatureEditor: {
  751. value: false,
  752. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  753. },
  754. enableUpdatedAddImage: {
  755. value: false,
  756. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  757. },
  758. externalLinkRel: {
  759. value: "noopener noreferrer nofollow",
  760. kind: OptionKind.VIEWER
  761. },
  762. externalLinkTarget: {
  763. value: 0,
  764. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  765. },
  766. highlightEditorColors: {
  767. value: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F",
  768. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  769. },
  770. historyUpdateUrl: {
  771. value: false,
  772. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  773. },
  774. ignoreDestinationZoom: {
  775. value: false,
  776. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  777. },
  778. imageResourcesPath: {
  779. value: "./images/",
  780. kind: OptionKind.VIEWER
  781. },
  782. maxCanvasPixels: {
  783. value: 2 ** 25,
  784. kind: OptionKind.VIEWER
  785. },
  786. forcePageColors: {
  787. value: false,
  788. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  789. },
  790. pageColorsBackground: {
  791. value: "Canvas",
  792. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  793. },
  794. pageColorsForeground: {
  795. value: "CanvasText",
  796. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  797. },
  798. pdfBugEnabled: {
  799. value: false,
  800. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  801. },
  802. printResolution: {
  803. value: 150,
  804. kind: OptionKind.VIEWER
  805. },
  806. sidebarViewOnLoad: {
  807. value: -1,
  808. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  809. },
  810. scrollModeOnLoad: {
  811. value: -1,
  812. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  813. },
  814. spreadModeOnLoad: {
  815. value: -1,
  816. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  817. },
  818. textLayerMode: {
  819. value: 1,
  820. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  821. },
  822. viewerCssTheme: {
  823. value: 0,
  824. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  825. },
  826. viewOnLoad: {
  827. value: 0,
  828. kind: OptionKind.VIEWER + OptionKind.PREFERENCE
  829. },
  830. cMapPacked: {
  831. value: true,
  832. kind: OptionKind.API
  833. },
  834. cMapUrl: {
  835. value: "../web/cmaps/",
  836. kind: OptionKind.API
  837. },
  838. disableAutoFetch: {
  839. value: false,
  840. kind: OptionKind.API + OptionKind.PREFERENCE
  841. },
  842. disableFontFace: {
  843. value: false,
  844. kind: OptionKind.API + OptionKind.PREFERENCE
  845. },
  846. disableRange: {
  847. value: false,
  848. kind: OptionKind.API + OptionKind.PREFERENCE
  849. },
  850. disableStream: {
  851. value: false,
  852. kind: OptionKind.API + OptionKind.PREFERENCE
  853. },
  854. docBaseUrl: {
  855. value: "",
  856. kind: OptionKind.API
  857. },
  858. enableHWA: {
  859. value: true,
  860. kind: OptionKind.API + OptionKind.VIEWER + OptionKind.PREFERENCE
  861. },
  862. enableXfa: {
  863. value: true,
  864. kind: OptionKind.API + OptionKind.PREFERENCE
  865. },
  866. fontExtraProperties: {
  867. value: false,
  868. kind: OptionKind.API
  869. },
  870. iccUrl: {
  871. value: "../web/iccs/",
  872. kind: OptionKind.API
  873. },
  874. isEvalSupported: {
  875. value: true,
  876. kind: OptionKind.API
  877. },
  878. isOffscreenCanvasSupported: {
  879. value: true,
  880. kind: OptionKind.API
  881. },
  882. maxImageSize: {
  883. value: -1,
  884. kind: OptionKind.API
  885. },
  886. pdfBug: {
  887. value: false,
  888. kind: OptionKind.API
  889. },
  890. standardFontDataUrl: {
  891. value: "../web/standard_fonts/",
  892. kind: OptionKind.API
  893. },
  894. useSystemFonts: {
  895. value: undefined,
  896. kind: OptionKind.API,
  897. type: Type.BOOLEAN + Type.UNDEFINED
  898. },
  899. verbosity: {
  900. value: 1,
  901. kind: OptionKind.API
  902. },
  903. wasmUrl: {
  904. value: "../web/wasm/",
  905. kind: OptionKind.API
  906. },
  907. workerPort: {
  908. value: null,
  909. kind: OptionKind.WORKER
  910. },
  911. workerSrc: {
  912. value: "../build/pdf.worker.mjs",
  913. kind: OptionKind.WORKER
  914. }
  915. };
  916. {
  917. defaultOptions.defaultUrl = {
  918. value: "compressed.tracemonkey-pldi-09.pdf",
  919. kind: OptionKind.VIEWER
  920. };
  921. defaultOptions.sandboxBundleSrc = {
  922. value: "../build/pdf.sandbox.mjs",
  923. kind: OptionKind.VIEWER
  924. };
  925. defaultOptions.enableFakeMLManager = {
  926. value: true,
  927. kind: OptionKind.VIEWER
  928. };
  929. }
  930. {
  931. defaultOptions.disablePreferences = {
  932. value: false,
  933. kind: OptionKind.VIEWER
  934. };
  935. }
  936. class AppOptions {
  937. static eventBus;
  938. static #opts = new Map();
  939. static {
  940. for (const name in defaultOptions) {
  941. this.#opts.set(name, defaultOptions[name].value);
  942. }
  943. for (const [name, value] of compatParams) {
  944. this.#opts.set(name, value);
  945. }
  946. this._hasInvokedSet = false;
  947. this._checkDisablePreferences = () => {
  948. if (this.get("disablePreferences")) {
  949. return true;
  950. }
  951. if (this._hasInvokedSet) {
  952. console.warn("The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option to prevent that.');
  953. }
  954. return false;
  955. };
  956. }
  957. static get(name) {
  958. return this.#opts.get(name);
  959. }
  960. static getAll(kind = null, defaultOnly = false) {
  961. const options = Object.create(null);
  962. for (const name in defaultOptions) {
  963. const defaultOpt = defaultOptions[name];
  964. if (kind && !(kind & defaultOpt.kind)) {
  965. continue;
  966. }
  967. options[name] = !defaultOnly ? this.#opts.get(name) : defaultOpt.value;
  968. }
  969. return options;
  970. }
  971. static set(name, value) {
  972. this.setAll({
  973. [name]: value
  974. });
  975. }
  976. static setAll(options, prefs = false) {
  977. this._hasInvokedSet ||= true;
  978. let events;
  979. for (const name in options) {
  980. const defaultOpt = defaultOptions[name],
  981. userOpt = options[name];
  982. if (!defaultOpt || !(typeof userOpt === typeof defaultOpt.value || Type[(typeof userOpt).toUpperCase()] & defaultOpt.type)) {
  983. continue;
  984. }
  985. const {
  986. kind
  987. } = defaultOpt;
  988. if (prefs && !(kind & OptionKind.BROWSER || kind & OptionKind.PREFERENCE)) {
  989. continue;
  990. }
  991. if (this.eventBus && kind & OptionKind.EVENT_DISPATCH) {
  992. (events ||= new Map()).set(name, userOpt);
  993. }
  994. this.#opts.set(name, userOpt);
  995. }
  996. if (events) {
  997. for (const [name, value] of events) {
  998. this.eventBus.dispatch(name.toLowerCase(), {
  999. source: this,
  1000. value
  1001. });
  1002. }
  1003. }
  1004. }
  1005. }
  1006. ;// ./web/pdf_link_service.js
  1007. const DEFAULT_LINK_REL = "noopener noreferrer nofollow";
  1008. const LinkTarget = {
  1009. NONE: 0,
  1010. SELF: 1,
  1011. BLANK: 2,
  1012. PARENT: 3,
  1013. TOP: 4
  1014. };
  1015. class PDFLinkService {
  1016. externalLinkEnabled = true;
  1017. constructor({
  1018. eventBus,
  1019. externalLinkTarget = null,
  1020. externalLinkRel = null,
  1021. ignoreDestinationZoom = false
  1022. } = {}) {
  1023. this.eventBus = eventBus;
  1024. this.externalLinkTarget = externalLinkTarget;
  1025. this.externalLinkRel = externalLinkRel;
  1026. this._ignoreDestinationZoom = ignoreDestinationZoom;
  1027. this.baseUrl = null;
  1028. this.pdfDocument = null;
  1029. this.pdfViewer = null;
  1030. this.pdfHistory = null;
  1031. }
  1032. setDocument(pdfDocument, baseUrl = null) {
  1033. this.baseUrl = baseUrl;
  1034. this.pdfDocument = pdfDocument;
  1035. }
  1036. setViewer(pdfViewer) {
  1037. this.pdfViewer = pdfViewer;
  1038. }
  1039. setHistory(pdfHistory) {
  1040. this.pdfHistory = pdfHistory;
  1041. }
  1042. get pagesCount() {
  1043. return this.pdfDocument ? this.pdfDocument.numPages : 0;
  1044. }
  1045. get page() {
  1046. return this.pdfDocument ? this.pdfViewer.currentPageNumber : 1;
  1047. }
  1048. set page(value) {
  1049. if (this.pdfDocument) {
  1050. this.pdfViewer.currentPageNumber = value;
  1051. }
  1052. }
  1053. get rotation() {
  1054. return this.pdfDocument ? this.pdfViewer.pagesRotation : 0;
  1055. }
  1056. set rotation(value) {
  1057. if (this.pdfDocument) {
  1058. this.pdfViewer.pagesRotation = value;
  1059. }
  1060. }
  1061. get isInPresentationMode() {
  1062. return this.pdfDocument ? this.pdfViewer.isInPresentationMode : false;
  1063. }
  1064. async goToDestination(dest) {
  1065. if (!this.pdfDocument) {
  1066. return;
  1067. }
  1068. let namedDest, explicitDest, pageNumber;
  1069. if (typeof dest === "string") {
  1070. namedDest = dest;
  1071. explicitDest = await this.pdfDocument.getDestination(dest);
  1072. } else {
  1073. namedDest = null;
  1074. explicitDest = await dest;
  1075. }
  1076. if (!Array.isArray(explicitDest)) {
  1077. console.error(`goToDestination: "${explicitDest}" is not a valid destination array, for dest="${dest}".`);
  1078. return;
  1079. }
  1080. const [destRef] = explicitDest;
  1081. if (destRef && typeof destRef === "object") {
  1082. pageNumber = this.pdfDocument.cachedPageNumber(destRef);
  1083. if (!pageNumber) {
  1084. try {
  1085. pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
  1086. } catch {
  1087. console.error(`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`);
  1088. return;
  1089. }
  1090. }
  1091. } else if (Number.isInteger(destRef)) {
  1092. pageNumber = destRef + 1;
  1093. }
  1094. if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
  1095. console.error(`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`);
  1096. return;
  1097. }
  1098. if (this.pdfHistory) {
  1099. this.pdfHistory.pushCurrentPosition();
  1100. this.pdfHistory.push({
  1101. namedDest,
  1102. explicitDest,
  1103. pageNumber
  1104. });
  1105. }
  1106. this.pdfViewer.scrollPageIntoView({
  1107. pageNumber,
  1108. destArray: explicitDest,
  1109. ignoreDestinationZoom: this._ignoreDestinationZoom
  1110. });
  1111. }
  1112. goToPage(val) {
  1113. if (!this.pdfDocument) {
  1114. return;
  1115. }
  1116. const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0;
  1117. if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
  1118. console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`);
  1119. return;
  1120. }
  1121. if (this.pdfHistory) {
  1122. this.pdfHistory.pushCurrentPosition();
  1123. this.pdfHistory.pushPage(pageNumber);
  1124. }
  1125. this.pdfViewer.scrollPageIntoView({
  1126. pageNumber
  1127. });
  1128. }
  1129. addLinkAttributes(link, url, newWindow = false) {
  1130. if (!url || typeof url !== "string") {
  1131. throw new Error('A valid "url" parameter must provided.');
  1132. }
  1133. const target = newWindow ? LinkTarget.BLANK : this.externalLinkTarget,
  1134. rel = this.externalLinkRel;
  1135. if (this.externalLinkEnabled) {
  1136. link.href = link.title = url;
  1137. } else {
  1138. link.href = "";
  1139. link.title = `Disabled: ${url}`;
  1140. link.onclick = () => false;
  1141. }
  1142. let targetStr = "";
  1143. switch (target) {
  1144. case LinkTarget.NONE:
  1145. break;
  1146. case LinkTarget.SELF:
  1147. targetStr = "_self";
  1148. break;
  1149. case LinkTarget.BLANK:
  1150. targetStr = "_blank";
  1151. break;
  1152. case LinkTarget.PARENT:
  1153. targetStr = "_parent";
  1154. break;
  1155. case LinkTarget.TOP:
  1156. targetStr = "_top";
  1157. break;
  1158. }
  1159. link.target = targetStr;
  1160. link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
  1161. }
  1162. getDestinationHash(dest) {
  1163. if (typeof dest === "string") {
  1164. if (dest.length > 0) {
  1165. return this.getAnchorUrl("#" + escape(dest));
  1166. }
  1167. } else if (Array.isArray(dest)) {
  1168. const str = JSON.stringify(dest);
  1169. if (str.length > 0) {
  1170. return this.getAnchorUrl("#" + escape(str));
  1171. }
  1172. }
  1173. return this.getAnchorUrl("");
  1174. }
  1175. getAnchorUrl(anchor) {
  1176. return this.baseUrl ? this.baseUrl + anchor : anchor;
  1177. }
  1178. setHash(hash) {
  1179. if (!this.pdfDocument) {
  1180. return;
  1181. }
  1182. let pageNumber, dest;
  1183. if (hash.includes("=")) {
  1184. const params = parseQueryString(hash);
  1185. if (params.has("search")) {
  1186. const query = params.get("search").replaceAll('"', ""),
  1187. phrase = params.get("phrase") === "true";
  1188. this.eventBus.dispatch("findfromurlhash", {
  1189. source: this,
  1190. query: phrase ? query : query.match(/\S+/g)
  1191. });
  1192. }
  1193. if (params.has("page")) {
  1194. pageNumber = params.get("page") | 0 || 1;
  1195. }
  1196. if (params.has("zoom")) {
  1197. const zoomArgs = params.get("zoom").split(",");
  1198. const zoomArg = zoomArgs[0];
  1199. const zoomArgNumber = parseFloat(zoomArg);
  1200. if (!zoomArg.includes("Fit")) {
  1201. dest = [null, {
  1202. name: "XYZ"
  1203. }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg];
  1204. } else if (zoomArg === "Fit" || zoomArg === "FitB") {
  1205. dest = [null, {
  1206. name: zoomArg
  1207. }];
  1208. } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") {
  1209. dest = [null, {
  1210. name: zoomArg
  1211. }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null];
  1212. } else if (zoomArg === "FitR") {
  1213. if (zoomArgs.length !== 5) {
  1214. console.error('PDFLinkService.setHash: Not enough parameters for "FitR".');
  1215. } else {
  1216. dest = [null, {
  1217. name: zoomArg
  1218. }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0];
  1219. }
  1220. } else {
  1221. console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`);
  1222. }
  1223. }
  1224. if (dest) {
  1225. this.pdfViewer.scrollPageIntoView({
  1226. pageNumber: pageNumber || this.page,
  1227. destArray: dest,
  1228. allowNegativeOffset: true
  1229. });
  1230. } else if (pageNumber) {
  1231. this.page = pageNumber;
  1232. }
  1233. if (params.has("pagemode")) {
  1234. this.eventBus.dispatch("pagemode", {
  1235. source: this,
  1236. mode: params.get("pagemode")
  1237. });
  1238. }
  1239. if (params.has("nameddest")) {
  1240. this.goToDestination(params.get("nameddest"));
  1241. }
  1242. return;
  1243. }
  1244. dest = unescape(hash);
  1245. try {
  1246. dest = JSON.parse(dest);
  1247. if (!Array.isArray(dest)) {
  1248. dest = dest.toString();
  1249. }
  1250. } catch {}
  1251. if (typeof dest === "string" || isValidExplicitDest(dest)) {
  1252. this.goToDestination(dest);
  1253. return;
  1254. }
  1255. console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`);
  1256. }
  1257. executeNamedAction(action) {
  1258. if (!this.pdfDocument) {
  1259. return;
  1260. }
  1261. switch (action) {
  1262. case "GoBack":
  1263. this.pdfHistory?.back();
  1264. break;
  1265. case "GoForward":
  1266. this.pdfHistory?.forward();
  1267. break;
  1268. case "NextPage":
  1269. this.pdfViewer.nextPage();
  1270. break;
  1271. case "PrevPage":
  1272. this.pdfViewer.previousPage();
  1273. break;
  1274. case "LastPage":
  1275. this.page = this.pagesCount;
  1276. break;
  1277. case "FirstPage":
  1278. this.page = 1;
  1279. break;
  1280. default:
  1281. break;
  1282. }
  1283. this.eventBus.dispatch("namedaction", {
  1284. source: this,
  1285. action
  1286. });
  1287. }
  1288. async executeSetOCGState(action) {
  1289. if (!this.pdfDocument) {
  1290. return;
  1291. }
  1292. const pdfDocument = this.pdfDocument,
  1293. optionalContentConfig = await this.pdfViewer.optionalContentConfigPromise;
  1294. if (pdfDocument !== this.pdfDocument) {
  1295. return;
  1296. }
  1297. optionalContentConfig.setOCGState(action);
  1298. this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig);
  1299. }
  1300. }
  1301. class SimpleLinkService extends PDFLinkService {
  1302. setDocument(pdfDocument, baseUrl = null) {}
  1303. }
  1304. ;// ./web/event_utils.js
  1305. const WaitOnType = {
  1306. EVENT: "event",
  1307. TIMEOUT: "timeout"
  1308. };
  1309. async function waitOnEventOrTimeout({
  1310. target,
  1311. name,
  1312. delay = 0
  1313. }) {
  1314. if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) {
  1315. throw new Error("waitOnEventOrTimeout - invalid parameters.");
  1316. }
  1317. const {
  1318. promise,
  1319. resolve
  1320. } = Promise.withResolvers();
  1321. const ac = new AbortController();
  1322. function handler(type) {
  1323. ac.abort();
  1324. clearTimeout(timeout);
  1325. resolve(type);
  1326. }
  1327. const evtMethod = target instanceof EventBus ? "_on" : "addEventListener";
  1328. target[evtMethod](name, handler.bind(null, WaitOnType.EVENT), {
  1329. signal: ac.signal
  1330. });
  1331. const timeout = setTimeout(handler.bind(null, WaitOnType.TIMEOUT), delay);
  1332. return promise;
  1333. }
  1334. class EventBus {
  1335. #listeners = Object.create(null);
  1336. on(eventName, listener, options = null) {
  1337. this._on(eventName, listener, {
  1338. external: true,
  1339. once: options?.once,
  1340. signal: options?.signal
  1341. });
  1342. }
  1343. off(eventName, listener, options = null) {
  1344. this._off(eventName, listener);
  1345. }
  1346. dispatch(eventName, data) {
  1347. const eventListeners = this.#listeners[eventName];
  1348. if (!eventListeners || eventListeners.length === 0) {
  1349. return;
  1350. }
  1351. let externalListeners;
  1352. for (const {
  1353. listener,
  1354. external,
  1355. once
  1356. } of eventListeners.slice(0)) {
  1357. if (once) {
  1358. this._off(eventName, listener);
  1359. }
  1360. if (external) {
  1361. (externalListeners ||= []).push(listener);
  1362. continue;
  1363. }
  1364. listener(data);
  1365. }
  1366. if (externalListeners) {
  1367. for (const listener of externalListeners) {
  1368. listener(data);
  1369. }
  1370. externalListeners = null;
  1371. }
  1372. }
  1373. _on(eventName, listener, options = null) {
  1374. let rmAbort = null;
  1375. if (options?.signal instanceof AbortSignal) {
  1376. const {
  1377. signal
  1378. } = options;
  1379. if (signal.aborted) {
  1380. console.error("Cannot use an `aborted` signal.");
  1381. return;
  1382. }
  1383. const onAbort = () => this._off(eventName, listener);
  1384. rmAbort = () => signal.removeEventListener("abort", onAbort);
  1385. signal.addEventListener("abort", onAbort);
  1386. }
  1387. const eventListeners = this.#listeners[eventName] ||= [];
  1388. eventListeners.push({
  1389. listener,
  1390. external: options?.external === true,
  1391. once: options?.once === true,
  1392. rmAbort
  1393. });
  1394. }
  1395. _off(eventName, listener, options = null) {
  1396. const eventListeners = this.#listeners[eventName];
  1397. if (!eventListeners) {
  1398. return;
  1399. }
  1400. for (let i = 0, ii = eventListeners.length; i < ii; i++) {
  1401. const evt = eventListeners[i];
  1402. if (evt.listener === listener) {
  1403. evt.rmAbort?.();
  1404. eventListeners.splice(i, 1);
  1405. return;
  1406. }
  1407. }
  1408. }
  1409. }
  1410. class FirefoxEventBus extends EventBus {
  1411. #externalServices;
  1412. #globalEventNames;
  1413. #isInAutomation;
  1414. constructor(globalEventNames, externalServices, isInAutomation) {
  1415. super();
  1416. this.#globalEventNames = globalEventNames;
  1417. this.#externalServices = externalServices;
  1418. this.#isInAutomation = isInAutomation;
  1419. }
  1420. dispatch(eventName, data) {
  1421. throw new Error("Not implemented: FirefoxEventBus.dispatch");
  1422. }
  1423. }
  1424. ;// ./web/external_services.js
  1425. class BaseExternalServices {
  1426. updateFindControlState(data) {}
  1427. updateFindMatchesCount(data) {}
  1428. initPassiveLoading() {}
  1429. reportTelemetry(data) {}
  1430. async createL10n() {
  1431. throw new Error("Not implemented: createL10n");
  1432. }
  1433. createScripting() {
  1434. throw new Error("Not implemented: createScripting");
  1435. }
  1436. createSignatureStorage() {
  1437. throw new Error("Not implemented: createSignatureStorage");
  1438. }
  1439. updateEditorStates(data) {
  1440. throw new Error("Not implemented: updateEditorStates");
  1441. }
  1442. dispatchGlobalEvent(_event) {}
  1443. }
  1444. ;// ./web/preferences.js
  1445. class BasePreferences {
  1446. #defaults = Object.freeze({
  1447. altTextLearnMoreUrl: "",
  1448. annotationEditorMode: 0,
  1449. annotationMode: 2,
  1450. cursorToolOnLoad: 0,
  1451. defaultZoomDelay: 400,
  1452. defaultZoomValue: "",
  1453. disablePageLabels: false,
  1454. enableAltText: false,
  1455. enableAltTextModelDownload: true,
  1456. enableAutoLinking: true,
  1457. enableGuessAltText: true,
  1458. enableHighlightFloatingButton: false,
  1459. enableNewAltTextWhenAddingImage: true,
  1460. enablePermissions: false,
  1461. enablePrintAutoRotate: true,
  1462. enableScripting: true,
  1463. enableSignatureEditor: false,
  1464. enableUpdatedAddImage: false,
  1465. externalLinkTarget: 0,
  1466. highlightEditorColors: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F",
  1467. historyUpdateUrl: false,
  1468. ignoreDestinationZoom: false,
  1469. forcePageColors: false,
  1470. pageColorsBackground: "Canvas",
  1471. pageColorsForeground: "CanvasText",
  1472. pdfBugEnabled: false,
  1473. sidebarViewOnLoad: -1,
  1474. scrollModeOnLoad: -1,
  1475. spreadModeOnLoad: -1,
  1476. textLayerMode: 1,
  1477. viewerCssTheme: 0,
  1478. viewOnLoad: 0,
  1479. disableAutoFetch: false,
  1480. disableFontFace: false,
  1481. disableRange: false,
  1482. disableStream: false,
  1483. enableHWA: true,
  1484. enableXfa: true
  1485. });
  1486. #initializedPromise = null;
  1487. constructor() {
  1488. this.#initializedPromise = this._readFromStorage(this.#defaults).then(({
  1489. browserPrefs,
  1490. prefs
  1491. }) => {
  1492. if (AppOptions._checkDisablePreferences()) {
  1493. return;
  1494. }
  1495. AppOptions.setAll({
  1496. ...browserPrefs,
  1497. ...prefs
  1498. }, true);
  1499. });
  1500. }
  1501. async _writeToStorage(prefObj) {
  1502. throw new Error("Not implemented: _writeToStorage");
  1503. }
  1504. async _readFromStorage(prefObj) {
  1505. throw new Error("Not implemented: _readFromStorage");
  1506. }
  1507. async reset() {
  1508. await this.#initializedPromise;
  1509. AppOptions.setAll(this.#defaults, true);
  1510. await this._writeToStorage(this.#defaults);
  1511. }
  1512. async set(name, value) {
  1513. await this.#initializedPromise;
  1514. AppOptions.setAll({
  1515. [name]: value
  1516. }, true);
  1517. await this._writeToStorage(AppOptions.getAll(OptionKind.PREFERENCE));
  1518. }
  1519. async get(name) {
  1520. await this.#initializedPromise;
  1521. return AppOptions.get(name);
  1522. }
  1523. get initializedPromise() {
  1524. return this.#initializedPromise;
  1525. }
  1526. }
  1527. ;// ./node_modules/@fluent/bundle/esm/types.js
  1528. class FluentType {
  1529. constructor(value) {
  1530. this.value = value;
  1531. }
  1532. valueOf() {
  1533. return this.value;
  1534. }
  1535. }
  1536. class FluentNone extends FluentType {
  1537. constructor(value = "???") {
  1538. super(value);
  1539. }
  1540. toString(scope) {
  1541. return `{${this.value}}`;
  1542. }
  1543. }
  1544. class FluentNumber extends FluentType {
  1545. constructor(value, opts = {}) {
  1546. super(value);
  1547. this.opts = opts;
  1548. }
  1549. toString(scope) {
  1550. try {
  1551. const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);
  1552. return nf.format(this.value);
  1553. } catch (err) {
  1554. scope.reportError(err);
  1555. return this.value.toString(10);
  1556. }
  1557. }
  1558. }
  1559. class FluentDateTime extends FluentType {
  1560. constructor(value, opts = {}) {
  1561. super(value);
  1562. this.opts = opts;
  1563. }
  1564. toString(scope) {
  1565. try {
  1566. const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);
  1567. return dtf.format(this.value);
  1568. } catch (err) {
  1569. scope.reportError(err);
  1570. return new Date(this.value).toISOString();
  1571. }
  1572. }
  1573. }
  1574. ;// ./node_modules/@fluent/bundle/esm/resolver.js
  1575. const MAX_PLACEABLES = 100;
  1576. const FSI = "\u2068";
  1577. const PDI = "\u2069";
  1578. function match(scope, selector, key) {
  1579. if (key === selector) {
  1580. return true;
  1581. }
  1582. if (key instanceof FluentNumber && selector instanceof FluentNumber && key.value === selector.value) {
  1583. return true;
  1584. }
  1585. if (selector instanceof FluentNumber && typeof key === "string") {
  1586. let category = scope.memoizeIntlObject(Intl.PluralRules, selector.opts).select(selector.value);
  1587. if (key === category) {
  1588. return true;
  1589. }
  1590. }
  1591. return false;
  1592. }
  1593. function getDefault(scope, variants, star) {
  1594. if (variants[star]) {
  1595. return resolvePattern(scope, variants[star].value);
  1596. }
  1597. scope.reportError(new RangeError("No default"));
  1598. return new FluentNone();
  1599. }
  1600. function getArguments(scope, args) {
  1601. const positional = [];
  1602. const named = Object.create(null);
  1603. for (const arg of args) {
  1604. if (arg.type === "narg") {
  1605. named[arg.name] = resolveExpression(scope, arg.value);
  1606. } else {
  1607. positional.push(resolveExpression(scope, arg));
  1608. }
  1609. }
  1610. return {
  1611. positional,
  1612. named
  1613. };
  1614. }
  1615. function resolveExpression(scope, expr) {
  1616. switch (expr.type) {
  1617. case "str":
  1618. return expr.value;
  1619. case "num":
  1620. return new FluentNumber(expr.value, {
  1621. minimumFractionDigits: expr.precision
  1622. });
  1623. case "var":
  1624. return resolveVariableReference(scope, expr);
  1625. case "mesg":
  1626. return resolveMessageReference(scope, expr);
  1627. case "term":
  1628. return resolveTermReference(scope, expr);
  1629. case "func":
  1630. return resolveFunctionReference(scope, expr);
  1631. case "select":
  1632. return resolveSelectExpression(scope, expr);
  1633. default:
  1634. return new FluentNone();
  1635. }
  1636. }
  1637. function resolveVariableReference(scope, {
  1638. name
  1639. }) {
  1640. let arg;
  1641. if (scope.params) {
  1642. if (Object.prototype.hasOwnProperty.call(scope.params, name)) {
  1643. arg = scope.params[name];
  1644. } else {
  1645. return new FluentNone(`$${name}`);
  1646. }
  1647. } else if (scope.args && Object.prototype.hasOwnProperty.call(scope.args, name)) {
  1648. arg = scope.args[name];
  1649. } else {
  1650. scope.reportError(new ReferenceError(`Unknown variable: $${name}`));
  1651. return new FluentNone(`$${name}`);
  1652. }
  1653. if (arg instanceof FluentType) {
  1654. return arg;
  1655. }
  1656. switch (typeof arg) {
  1657. case "string":
  1658. return arg;
  1659. case "number":
  1660. return new FluentNumber(arg);
  1661. case "object":
  1662. if (arg instanceof Date) {
  1663. return new FluentDateTime(arg.getTime());
  1664. }
  1665. default:
  1666. scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`));
  1667. return new FluentNone(`$${name}`);
  1668. }
  1669. }
  1670. function resolveMessageReference(scope, {
  1671. name,
  1672. attr
  1673. }) {
  1674. const message = scope.bundle._messages.get(name);
  1675. if (!message) {
  1676. scope.reportError(new ReferenceError(`Unknown message: ${name}`));
  1677. return new FluentNone(name);
  1678. }
  1679. if (attr) {
  1680. const attribute = message.attributes[attr];
  1681. if (attribute) {
  1682. return resolvePattern(scope, attribute);
  1683. }
  1684. scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
  1685. return new FluentNone(`${name}.${attr}`);
  1686. }
  1687. if (message.value) {
  1688. return resolvePattern(scope, message.value);
  1689. }
  1690. scope.reportError(new ReferenceError(`No value: ${name}`));
  1691. return new FluentNone(name);
  1692. }
  1693. function resolveTermReference(scope, {
  1694. name,
  1695. attr,
  1696. args
  1697. }) {
  1698. const id = `-${name}`;
  1699. const term = scope.bundle._terms.get(id);
  1700. if (!term) {
  1701. scope.reportError(new ReferenceError(`Unknown term: ${id}`));
  1702. return new FluentNone(id);
  1703. }
  1704. if (attr) {
  1705. const attribute = term.attributes[attr];
  1706. if (attribute) {
  1707. scope.params = getArguments(scope, args).named;
  1708. const resolved = resolvePattern(scope, attribute);
  1709. scope.params = null;
  1710. return resolved;
  1711. }
  1712. scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
  1713. return new FluentNone(`${id}.${attr}`);
  1714. }
  1715. scope.params = getArguments(scope, args).named;
  1716. const resolved = resolvePattern(scope, term.value);
  1717. scope.params = null;
  1718. return resolved;
  1719. }
  1720. function resolveFunctionReference(scope, {
  1721. name,
  1722. args
  1723. }) {
  1724. let func = scope.bundle._functions[name];
  1725. if (!func) {
  1726. scope.reportError(new ReferenceError(`Unknown function: ${name}()`));
  1727. return new FluentNone(`${name}()`);
  1728. }
  1729. if (typeof func !== "function") {
  1730. scope.reportError(new TypeError(`Function ${name}() is not callable`));
  1731. return new FluentNone(`${name}()`);
  1732. }
  1733. try {
  1734. let resolved = getArguments(scope, args);
  1735. return func(resolved.positional, resolved.named);
  1736. } catch (err) {
  1737. scope.reportError(err);
  1738. return new FluentNone(`${name}()`);
  1739. }
  1740. }
  1741. function resolveSelectExpression(scope, {
  1742. selector,
  1743. variants,
  1744. star
  1745. }) {
  1746. let sel = resolveExpression(scope, selector);
  1747. if (sel instanceof FluentNone) {
  1748. return getDefault(scope, variants, star);
  1749. }
  1750. for (const variant of variants) {
  1751. const key = resolveExpression(scope, variant.key);
  1752. if (match(scope, sel, key)) {
  1753. return resolvePattern(scope, variant.value);
  1754. }
  1755. }
  1756. return getDefault(scope, variants, star);
  1757. }
  1758. function resolveComplexPattern(scope, ptn) {
  1759. if (scope.dirty.has(ptn)) {
  1760. scope.reportError(new RangeError("Cyclic reference"));
  1761. return new FluentNone();
  1762. }
  1763. scope.dirty.add(ptn);
  1764. const result = [];
  1765. const useIsolating = scope.bundle._useIsolating && ptn.length > 1;
  1766. for (const elem of ptn) {
  1767. if (typeof elem === "string") {
  1768. result.push(scope.bundle._transform(elem));
  1769. continue;
  1770. }
  1771. scope.placeables++;
  1772. if (scope.placeables > MAX_PLACEABLES) {
  1773. scope.dirty.delete(ptn);
  1774. throw new RangeError(`Too many placeables expanded: ${scope.placeables}, ` + `max allowed is ${MAX_PLACEABLES}`);
  1775. }
  1776. if (useIsolating) {
  1777. result.push(FSI);
  1778. }
  1779. result.push(resolveExpression(scope, elem).toString(scope));
  1780. if (useIsolating) {
  1781. result.push(PDI);
  1782. }
  1783. }
  1784. scope.dirty.delete(ptn);
  1785. return result.join("");
  1786. }
  1787. function resolvePattern(scope, value) {
  1788. if (typeof value === "string") {
  1789. return scope.bundle._transform(value);
  1790. }
  1791. return resolveComplexPattern(scope, value);
  1792. }
  1793. ;// ./node_modules/@fluent/bundle/esm/scope.js
  1794. class Scope {
  1795. constructor(bundle, errors, args) {
  1796. this.dirty = new WeakSet();
  1797. this.params = null;
  1798. this.placeables = 0;
  1799. this.bundle = bundle;
  1800. this.errors = errors;
  1801. this.args = args;
  1802. }
  1803. reportError(error) {
  1804. if (!this.errors || !(error instanceof Error)) {
  1805. throw error;
  1806. }
  1807. this.errors.push(error);
  1808. }
  1809. memoizeIntlObject(ctor, opts) {
  1810. let cache = this.bundle._intls.get(ctor);
  1811. if (!cache) {
  1812. cache = {};
  1813. this.bundle._intls.set(ctor, cache);
  1814. }
  1815. let id = JSON.stringify(opts);
  1816. if (!cache[id]) {
  1817. cache[id] = new ctor(this.bundle.locales, opts);
  1818. }
  1819. return cache[id];
  1820. }
  1821. }
  1822. ;// ./node_modules/@fluent/bundle/esm/builtins.js
  1823. function values(opts, allowed) {
  1824. const unwrapped = Object.create(null);
  1825. for (const [name, opt] of Object.entries(opts)) {
  1826. if (allowed.includes(name)) {
  1827. unwrapped[name] = opt.valueOf();
  1828. }
  1829. }
  1830. return unwrapped;
  1831. }
  1832. const NUMBER_ALLOWED = ["unitDisplay", "currencyDisplay", "useGrouping", "minimumIntegerDigits", "minimumFractionDigits", "maximumFractionDigits", "minimumSignificantDigits", "maximumSignificantDigits"];
  1833. function NUMBER(args, opts) {
  1834. let arg = args[0];
  1835. if (arg instanceof FluentNone) {
  1836. return new FluentNone(`NUMBER(${arg.valueOf()})`);
  1837. }
  1838. if (arg instanceof FluentNumber) {
  1839. return new FluentNumber(arg.valueOf(), {
  1840. ...arg.opts,
  1841. ...values(opts, NUMBER_ALLOWED)
  1842. });
  1843. }
  1844. if (arg instanceof FluentDateTime) {
  1845. return new FluentNumber(arg.valueOf(), {
  1846. ...values(opts, NUMBER_ALLOWED)
  1847. });
  1848. }
  1849. throw new TypeError("Invalid argument to NUMBER");
  1850. }
  1851. const DATETIME_ALLOWED = ["dateStyle", "timeStyle", "fractionalSecondDigits", "dayPeriod", "hour12", "weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
  1852. function DATETIME(args, opts) {
  1853. let arg = args[0];
  1854. if (arg instanceof FluentNone) {
  1855. return new FluentNone(`DATETIME(${arg.valueOf()})`);
  1856. }
  1857. if (arg instanceof FluentDateTime) {
  1858. return new FluentDateTime(arg.valueOf(), {
  1859. ...arg.opts,
  1860. ...values(opts, DATETIME_ALLOWED)
  1861. });
  1862. }
  1863. if (arg instanceof FluentNumber) {
  1864. return new FluentDateTime(arg.valueOf(), {
  1865. ...values(opts, DATETIME_ALLOWED)
  1866. });
  1867. }
  1868. throw new TypeError("Invalid argument to DATETIME");
  1869. }
  1870. ;// ./node_modules/@fluent/bundle/esm/memoizer.js
  1871. const cache = new Map();
  1872. function getMemoizerForLocale(locales) {
  1873. const stringLocale = Array.isArray(locales) ? locales.join(" ") : locales;
  1874. let memoizer = cache.get(stringLocale);
  1875. if (memoizer === undefined) {
  1876. memoizer = new Map();
  1877. cache.set(stringLocale, memoizer);
  1878. }
  1879. return memoizer;
  1880. }
  1881. ;// ./node_modules/@fluent/bundle/esm/bundle.js
  1882. class FluentBundle {
  1883. constructor(locales, {
  1884. functions,
  1885. useIsolating = true,
  1886. transform = v => v
  1887. } = {}) {
  1888. this._terms = new Map();
  1889. this._messages = new Map();
  1890. this.locales = Array.isArray(locales) ? locales : [locales];
  1891. this._functions = {
  1892. NUMBER: NUMBER,
  1893. DATETIME: DATETIME,
  1894. ...functions
  1895. };
  1896. this._useIsolating = useIsolating;
  1897. this._transform = transform;
  1898. this._intls = getMemoizerForLocale(locales);
  1899. }
  1900. hasMessage(id) {
  1901. return this._messages.has(id);
  1902. }
  1903. getMessage(id) {
  1904. return this._messages.get(id);
  1905. }
  1906. addResource(res, {
  1907. allowOverrides = false
  1908. } = {}) {
  1909. const errors = [];
  1910. for (let i = 0; i < res.body.length; i++) {
  1911. let entry = res.body[i];
  1912. if (entry.id.startsWith("-")) {
  1913. if (allowOverrides === false && this._terms.has(entry.id)) {
  1914. errors.push(new Error(`Attempt to override an existing term: "${entry.id}"`));
  1915. continue;
  1916. }
  1917. this._terms.set(entry.id, entry);
  1918. } else {
  1919. if (allowOverrides === false && this._messages.has(entry.id)) {
  1920. errors.push(new Error(`Attempt to override an existing message: "${entry.id}"`));
  1921. continue;
  1922. }
  1923. this._messages.set(entry.id, entry);
  1924. }
  1925. }
  1926. return errors;
  1927. }
  1928. formatPattern(pattern, args = null, errors = null) {
  1929. if (typeof pattern === "string") {
  1930. return this._transform(pattern);
  1931. }
  1932. let scope = new Scope(this, errors, args);
  1933. try {
  1934. let value = resolveComplexPattern(scope, pattern);
  1935. return value.toString(scope);
  1936. } catch (err) {
  1937. if (scope.errors && err instanceof Error) {
  1938. scope.errors.push(err);
  1939. return new FluentNone().toString(scope);
  1940. }
  1941. throw err;
  1942. }
  1943. }
  1944. }
  1945. ;// ./node_modules/@fluent/bundle/esm/resource.js
  1946. const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */gm;
  1947. const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y;
  1948. const RE_VARIANT_START = /\*?\[/y;
  1949. const RE_NUMBER_LITERAL = /(-?[0-9]+(?:\.([0-9]+))?)/y;
  1950. const RE_IDENTIFIER = /([a-zA-Z][\w-]*)/y;
  1951. const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y;
  1952. const RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/;
  1953. const RE_TEXT_RUN = /([^{}\n\r]+)/y;
  1954. const RE_STRING_RUN = /([^\\"\n\r]*)/y;
  1955. const RE_STRING_ESCAPE = /\\([\\"])/y;
  1956. const RE_UNICODE_ESCAPE = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{6})/y;
  1957. const RE_LEADING_NEWLINES = /^\n+/;
  1958. const RE_TRAILING_SPACES = / +$/;
  1959. const RE_BLANK_LINES = / *\r?\n/g;
  1960. const RE_INDENT = /( *)$/;
  1961. const TOKEN_BRACE_OPEN = /{\s*/y;
  1962. const TOKEN_BRACE_CLOSE = /\s*}/y;
  1963. const TOKEN_BRACKET_OPEN = /\[\s*/y;
  1964. const TOKEN_BRACKET_CLOSE = /\s*] */y;
  1965. const TOKEN_PAREN_OPEN = /\s*\(\s*/y;
  1966. const TOKEN_ARROW = /\s*->\s*/y;
  1967. const TOKEN_COLON = /\s*:\s*/y;
  1968. const TOKEN_COMMA = /\s*,?\s*/y;
  1969. const TOKEN_BLANK = /\s+/y;
  1970. class FluentResource {
  1971. constructor(source) {
  1972. this.body = [];
  1973. RE_MESSAGE_START.lastIndex = 0;
  1974. let cursor = 0;
  1975. while (true) {
  1976. let next = RE_MESSAGE_START.exec(source);
  1977. if (next === null) {
  1978. break;
  1979. }
  1980. cursor = RE_MESSAGE_START.lastIndex;
  1981. try {
  1982. this.body.push(parseMessage(next[1]));
  1983. } catch (err) {
  1984. if (err instanceof SyntaxError) {
  1985. continue;
  1986. }
  1987. throw err;
  1988. }
  1989. }
  1990. function test(re) {
  1991. re.lastIndex = cursor;
  1992. return re.test(source);
  1993. }
  1994. function consumeChar(char, errorClass) {
  1995. if (source[cursor] === char) {
  1996. cursor++;
  1997. return true;
  1998. }
  1999. if (errorClass) {
  2000. throw new errorClass(`Expected ${char}`);
  2001. }
  2002. return false;
  2003. }
  2004. function consumeToken(re, errorClass) {
  2005. if (test(re)) {
  2006. cursor = re.lastIndex;
  2007. return true;
  2008. }
  2009. if (errorClass) {
  2010. throw new errorClass(`Expected ${re.toString()}`);
  2011. }
  2012. return false;
  2013. }
  2014. function match(re) {
  2015. re.lastIndex = cursor;
  2016. let result = re.exec(source);
  2017. if (result === null) {
  2018. throw new SyntaxError(`Expected ${re.toString()}`);
  2019. }
  2020. cursor = re.lastIndex;
  2021. return result;
  2022. }
  2023. function match1(re) {
  2024. return match(re)[1];
  2025. }
  2026. function parseMessage(id) {
  2027. let value = parsePattern();
  2028. let attributes = parseAttributes();
  2029. if (value === null && Object.keys(attributes).length === 0) {
  2030. throw new SyntaxError("Expected message value or attributes");
  2031. }
  2032. return {
  2033. id,
  2034. value,
  2035. attributes
  2036. };
  2037. }
  2038. function parseAttributes() {
  2039. let attrs = Object.create(null);
  2040. while (test(RE_ATTRIBUTE_START)) {
  2041. let name = match1(RE_ATTRIBUTE_START);
  2042. let value = parsePattern();
  2043. if (value === null) {
  2044. throw new SyntaxError("Expected attribute value");
  2045. }
  2046. attrs[name] = value;
  2047. }
  2048. return attrs;
  2049. }
  2050. function parsePattern() {
  2051. let first;
  2052. if (test(RE_TEXT_RUN)) {
  2053. first = match1(RE_TEXT_RUN);
  2054. }
  2055. if (source[cursor] === "{" || source[cursor] === "}") {
  2056. return parsePatternElements(first ? [first] : [], Infinity);
  2057. }
  2058. let indent = parseIndent();
  2059. if (indent) {
  2060. if (first) {
  2061. return parsePatternElements([first, indent], indent.length);
  2062. }
  2063. indent.value = trim(indent.value, RE_LEADING_NEWLINES);
  2064. return parsePatternElements([indent], indent.length);
  2065. }
  2066. if (first) {
  2067. return trim(first, RE_TRAILING_SPACES);
  2068. }
  2069. return null;
  2070. }
  2071. function parsePatternElements(elements = [], commonIndent) {
  2072. while (true) {
  2073. if (test(RE_TEXT_RUN)) {
  2074. elements.push(match1(RE_TEXT_RUN));
  2075. continue;
  2076. }
  2077. if (source[cursor] === "{") {
  2078. elements.push(parsePlaceable());
  2079. continue;
  2080. }
  2081. if (source[cursor] === "}") {
  2082. throw new SyntaxError("Unbalanced closing brace");
  2083. }
  2084. let indent = parseIndent();
  2085. if (indent) {
  2086. elements.push(indent);
  2087. commonIndent = Math.min(commonIndent, indent.length);
  2088. continue;
  2089. }
  2090. break;
  2091. }
  2092. let lastIndex = elements.length - 1;
  2093. let lastElement = elements[lastIndex];
  2094. if (typeof lastElement === "string") {
  2095. elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES);
  2096. }
  2097. let baked = [];
  2098. for (let element of elements) {
  2099. if (element instanceof Indent) {
  2100. element = element.value.slice(0, element.value.length - commonIndent);
  2101. }
  2102. if (element) {
  2103. baked.push(element);
  2104. }
  2105. }
  2106. return baked;
  2107. }
  2108. function parsePlaceable() {
  2109. consumeToken(TOKEN_BRACE_OPEN, SyntaxError);
  2110. let selector = parseInlineExpression();
  2111. if (consumeToken(TOKEN_BRACE_CLOSE)) {
  2112. return selector;
  2113. }
  2114. if (consumeToken(TOKEN_ARROW)) {
  2115. let variants = parseVariants();
  2116. consumeToken(TOKEN_BRACE_CLOSE, SyntaxError);
  2117. return {
  2118. type: "select",
  2119. selector,
  2120. ...variants
  2121. };
  2122. }
  2123. throw new SyntaxError("Unclosed placeable");
  2124. }
  2125. function parseInlineExpression() {
  2126. if (source[cursor] === "{") {
  2127. return parsePlaceable();
  2128. }
  2129. if (test(RE_REFERENCE)) {
  2130. let [, sigil, name, attr = null] = match(RE_REFERENCE);
  2131. if (sigil === "$") {
  2132. return {
  2133. type: "var",
  2134. name
  2135. };
  2136. }
  2137. if (consumeToken(TOKEN_PAREN_OPEN)) {
  2138. let args = parseArguments();
  2139. if (sigil === "-") {
  2140. return {
  2141. type: "term",
  2142. name,
  2143. attr,
  2144. args
  2145. };
  2146. }
  2147. if (RE_FUNCTION_NAME.test(name)) {
  2148. return {
  2149. type: "func",
  2150. name,
  2151. args
  2152. };
  2153. }
  2154. throw new SyntaxError("Function names must be all upper-case");
  2155. }
  2156. if (sigil === "-") {
  2157. return {
  2158. type: "term",
  2159. name,
  2160. attr,
  2161. args: []
  2162. };
  2163. }
  2164. return {
  2165. type: "mesg",
  2166. name,
  2167. attr
  2168. };
  2169. }
  2170. return parseLiteral();
  2171. }
  2172. function parseArguments() {
  2173. let args = [];
  2174. while (true) {
  2175. switch (source[cursor]) {
  2176. case ")":
  2177. cursor++;
  2178. return args;
  2179. case undefined:
  2180. throw new SyntaxError("Unclosed argument list");
  2181. }
  2182. args.push(parseArgument());
  2183. consumeToken(TOKEN_COMMA);
  2184. }
  2185. }
  2186. function parseArgument() {
  2187. let expr = parseInlineExpression();
  2188. if (expr.type !== "mesg") {
  2189. return expr;
  2190. }
  2191. if (consumeToken(TOKEN_COLON)) {
  2192. return {
  2193. type: "narg",
  2194. name: expr.name,
  2195. value: parseLiteral()
  2196. };
  2197. }
  2198. return expr;
  2199. }
  2200. function parseVariants() {
  2201. let variants = [];
  2202. let count = 0;
  2203. let star;
  2204. while (test(RE_VARIANT_START)) {
  2205. if (consumeChar("*")) {
  2206. star = count;
  2207. }
  2208. let key = parseVariantKey();
  2209. let value = parsePattern();
  2210. if (value === null) {
  2211. throw new SyntaxError("Expected variant value");
  2212. }
  2213. variants[count++] = {
  2214. key,
  2215. value
  2216. };
  2217. }
  2218. if (count === 0) {
  2219. return null;
  2220. }
  2221. if (star === undefined) {
  2222. throw new SyntaxError("Expected default variant");
  2223. }
  2224. return {
  2225. variants,
  2226. star
  2227. };
  2228. }
  2229. function parseVariantKey() {
  2230. consumeToken(TOKEN_BRACKET_OPEN, SyntaxError);
  2231. let key;
  2232. if (test(RE_NUMBER_LITERAL)) {
  2233. key = parseNumberLiteral();
  2234. } else {
  2235. key = {
  2236. type: "str",
  2237. value: match1(RE_IDENTIFIER)
  2238. };
  2239. }
  2240. consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError);
  2241. return key;
  2242. }
  2243. function parseLiteral() {
  2244. if (test(RE_NUMBER_LITERAL)) {
  2245. return parseNumberLiteral();
  2246. }
  2247. if (source[cursor] === '"') {
  2248. return parseStringLiteral();
  2249. }
  2250. throw new SyntaxError("Invalid expression");
  2251. }
  2252. function parseNumberLiteral() {
  2253. let [, value, fraction = ""] = match(RE_NUMBER_LITERAL);
  2254. let precision = fraction.length;
  2255. return {
  2256. type: "num",
  2257. value: parseFloat(value),
  2258. precision
  2259. };
  2260. }
  2261. function parseStringLiteral() {
  2262. consumeChar('"', SyntaxError);
  2263. let value = "";
  2264. while (true) {
  2265. value += match1(RE_STRING_RUN);
  2266. if (source[cursor] === "\\") {
  2267. value += parseEscapeSequence();
  2268. continue;
  2269. }
  2270. if (consumeChar('"')) {
  2271. return {
  2272. type: "str",
  2273. value
  2274. };
  2275. }
  2276. throw new SyntaxError("Unclosed string literal");
  2277. }
  2278. }
  2279. function parseEscapeSequence() {
  2280. if (test(RE_STRING_ESCAPE)) {
  2281. return match1(RE_STRING_ESCAPE);
  2282. }
  2283. if (test(RE_UNICODE_ESCAPE)) {
  2284. let [, codepoint4, codepoint6] = match(RE_UNICODE_ESCAPE);
  2285. let codepoint = parseInt(codepoint4 || codepoint6, 16);
  2286. return codepoint <= 0xd7ff || 0xe000 <= codepoint ? String.fromCodePoint(codepoint) : "�";
  2287. }
  2288. throw new SyntaxError("Unknown escape sequence");
  2289. }
  2290. function parseIndent() {
  2291. let start = cursor;
  2292. consumeToken(TOKEN_BLANK);
  2293. switch (source[cursor]) {
  2294. case ".":
  2295. case "[":
  2296. case "*":
  2297. case "}":
  2298. case undefined:
  2299. return false;
  2300. case "{":
  2301. return makeIndent(source.slice(start, cursor));
  2302. }
  2303. if (source[cursor - 1] === " ") {
  2304. return makeIndent(source.slice(start, cursor));
  2305. }
  2306. return false;
  2307. }
  2308. function trim(text, re) {
  2309. return text.replace(re, "");
  2310. }
  2311. function makeIndent(blank) {
  2312. let value = blank.replace(RE_BLANK_LINES, "\n");
  2313. let length = RE_INDENT.exec(blank)[1].length;
  2314. return new Indent(value, length);
  2315. }
  2316. }
  2317. }
  2318. class Indent {
  2319. constructor(value, length) {
  2320. this.value = value;
  2321. this.length = length;
  2322. }
  2323. }
  2324. ;// ./node_modules/@fluent/bundle/esm/index.js
  2325. ;// ./node_modules/@fluent/dom/esm/overlay.js
  2326. const reOverlay = /<|&#?\w+;/;
  2327. const TEXT_LEVEL_ELEMENTS = {
  2328. "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"]
  2329. };
  2330. const LOCALIZABLE_ATTRIBUTES = {
  2331. "http://www.w3.org/1999/xhtml": {
  2332. global: ["title", "aria-description", "aria-label", "aria-valuetext"],
  2333. a: ["download"],
  2334. area: ["download", "alt"],
  2335. input: ["alt", "placeholder"],
  2336. menuitem: ["label"],
  2337. menu: ["label"],
  2338. optgroup: ["label"],
  2339. option: ["label"],
  2340. track: ["label"],
  2341. img: ["alt"],
  2342. textarea: ["placeholder"],
  2343. th: ["abbr"]
  2344. },
  2345. "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": {
  2346. global: ["accesskey", "aria-label", "aria-valuetext", "label", "title", "tooltiptext"],
  2347. description: ["value"],
  2348. key: ["key", "keycode"],
  2349. label: ["value"],
  2350. textbox: ["placeholder", "value"]
  2351. }
  2352. };
  2353. function translateElement(element, translation) {
  2354. const {
  2355. value
  2356. } = translation;
  2357. if (typeof value === "string") {
  2358. if (element.localName === "title" && element.namespaceURI === "http://www.w3.org/1999/xhtml") {
  2359. element.textContent = value;
  2360. } else if (!reOverlay.test(value)) {
  2361. element.textContent = value;
  2362. } else {
  2363. const templateElement = element.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml", "template");
  2364. templateElement.innerHTML = value;
  2365. overlayChildNodes(templateElement.content, element);
  2366. }
  2367. }
  2368. overlayAttributes(translation, element);
  2369. }
  2370. function overlayChildNodes(fromFragment, toElement) {
  2371. for (const childNode of fromFragment.childNodes) {
  2372. if (childNode.nodeType === childNode.TEXT_NODE) {
  2373. continue;
  2374. }
  2375. if (childNode.hasAttribute("data-l10n-name")) {
  2376. const sanitized = getNodeForNamedElement(toElement, childNode);
  2377. fromFragment.replaceChild(sanitized, childNode);
  2378. continue;
  2379. }
  2380. if (isElementAllowed(childNode)) {
  2381. const sanitized = createSanitizedElement(childNode);
  2382. fromFragment.replaceChild(sanitized, childNode);
  2383. continue;
  2384. }
  2385. 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.");
  2386. fromFragment.replaceChild(createTextNodeFromTextContent(childNode), childNode);
  2387. }
  2388. toElement.textContent = "";
  2389. toElement.appendChild(fromFragment);
  2390. }
  2391. function hasAttribute(attributes, name) {
  2392. if (!attributes) {
  2393. return false;
  2394. }
  2395. for (let attr of attributes) {
  2396. if (attr.name === name) {
  2397. return true;
  2398. }
  2399. }
  2400. return false;
  2401. }
  2402. function overlayAttributes(fromElement, toElement) {
  2403. const explicitlyAllowed = toElement.hasAttribute("data-l10n-attrs") ? toElement.getAttribute("data-l10n-attrs").split(",").map(i => i.trim()) : null;
  2404. for (const attr of Array.from(toElement.attributes)) {
  2405. if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && !hasAttribute(fromElement.attributes, attr.name)) {
  2406. toElement.removeAttribute(attr.name);
  2407. }
  2408. }
  2409. if (!fromElement.attributes) {
  2410. return;
  2411. }
  2412. for (const attr of Array.from(fromElement.attributes)) {
  2413. if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && toElement.getAttribute(attr.name) !== attr.value) {
  2414. toElement.setAttribute(attr.name, attr.value);
  2415. }
  2416. }
  2417. }
  2418. function getNodeForNamedElement(sourceElement, translatedChild) {
  2419. const childName = translatedChild.getAttribute("data-l10n-name");
  2420. const sourceChild = sourceElement.querySelector(`[data-l10n-name="${childName}"]`);
  2421. if (!sourceChild) {
  2422. console.warn(`An element named "${childName}" wasn't found in the source.`);
  2423. return createTextNodeFromTextContent(translatedChild);
  2424. }
  2425. if (sourceChild.localName !== translatedChild.localName) {
  2426. 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}).`);
  2427. return createTextNodeFromTextContent(translatedChild);
  2428. }
  2429. sourceElement.removeChild(sourceChild);
  2430. const clone = sourceChild.cloneNode(false);
  2431. return shallowPopulateUsing(translatedChild, clone);
  2432. }
  2433. function createSanitizedElement(element) {
  2434. const clone = element.ownerDocument.createElement(element.localName);
  2435. return shallowPopulateUsing(element, clone);
  2436. }
  2437. function createTextNodeFromTextContent(element) {
  2438. return element.ownerDocument.createTextNode(element.textContent);
  2439. }
  2440. function isElementAllowed(element) {
  2441. const allowed = TEXT_LEVEL_ELEMENTS[element.namespaceURI];
  2442. return allowed && allowed.includes(element.localName);
  2443. }
  2444. function isAttrNameLocalizable(name, element, explicitlyAllowed = null) {
  2445. if (explicitlyAllowed && explicitlyAllowed.includes(name)) {
  2446. return true;
  2447. }
  2448. const allowed = LOCALIZABLE_ATTRIBUTES[element.namespaceURI];
  2449. if (!allowed) {
  2450. return false;
  2451. }
  2452. const attrName = name.toLowerCase();
  2453. const elemName = element.localName;
  2454. if (allowed.global.includes(attrName)) {
  2455. return true;
  2456. }
  2457. if (!allowed[elemName]) {
  2458. return false;
  2459. }
  2460. if (allowed[elemName].includes(attrName)) {
  2461. return true;
  2462. }
  2463. if (element.namespaceURI === "http://www.w3.org/1999/xhtml" && elemName === "input" && attrName === "value") {
  2464. const type = element.type.toLowerCase();
  2465. if (type === "submit" || type === "button" || type === "reset") {
  2466. return true;
  2467. }
  2468. }
  2469. return false;
  2470. }
  2471. function shallowPopulateUsing(fromElement, toElement) {
  2472. toElement.textContent = fromElement.textContent;
  2473. overlayAttributes(fromElement, toElement);
  2474. return toElement;
  2475. }
  2476. ;// ./node_modules/cached-iterable/src/cached_iterable.mjs
  2477. class CachedIterable extends Array {
  2478. static from(iterable) {
  2479. if (iterable instanceof this) {
  2480. return iterable;
  2481. }
  2482. return new this(iterable);
  2483. }
  2484. }
  2485. ;// ./node_modules/cached-iterable/src/cached_sync_iterable.mjs
  2486. class CachedSyncIterable extends CachedIterable {
  2487. constructor(iterable) {
  2488. super();
  2489. if (Symbol.iterator in Object(iterable)) {
  2490. this.iterator = iterable[Symbol.iterator]();
  2491. } else {
  2492. throw new TypeError("Argument must implement the iteration protocol.");
  2493. }
  2494. }
  2495. [Symbol.iterator]() {
  2496. const cached = this;
  2497. let cur = 0;
  2498. return {
  2499. next() {
  2500. if (cached.length <= cur) {
  2501. cached.push(cached.iterator.next());
  2502. }
  2503. return cached[cur++];
  2504. }
  2505. };
  2506. }
  2507. touchNext(count = 1) {
  2508. let idx = 0;
  2509. while (idx++ < count) {
  2510. const last = this[this.length - 1];
  2511. if (last && last.done) {
  2512. break;
  2513. }
  2514. this.push(this.iterator.next());
  2515. }
  2516. return this[this.length - 1];
  2517. }
  2518. }
  2519. ;// ./node_modules/cached-iterable/src/cached_async_iterable.mjs
  2520. class CachedAsyncIterable extends CachedIterable {
  2521. constructor(iterable) {
  2522. super();
  2523. if (Symbol.asyncIterator in Object(iterable)) {
  2524. this.iterator = iterable[Symbol.asyncIterator]();
  2525. } else if (Symbol.iterator in Object(iterable)) {
  2526. this.iterator = iterable[Symbol.iterator]();
  2527. } else {
  2528. throw new TypeError("Argument must implement the iteration protocol.");
  2529. }
  2530. }
  2531. [Symbol.asyncIterator]() {
  2532. const cached = this;
  2533. let cur = 0;
  2534. return {
  2535. async next() {
  2536. if (cached.length <= cur) {
  2537. cached.push(cached.iterator.next());
  2538. }
  2539. return cached[cur++];
  2540. }
  2541. };
  2542. }
  2543. async touchNext(count = 1) {
  2544. let idx = 0;
  2545. while (idx++ < count) {
  2546. const last = this[this.length - 1];
  2547. if (last && (await last).done) {
  2548. break;
  2549. }
  2550. this.push(this.iterator.next());
  2551. }
  2552. return this[this.length - 1];
  2553. }
  2554. }
  2555. ;// ./node_modules/cached-iterable/src/index.mjs
  2556. ;// ./node_modules/@fluent/dom/esm/localization.js
  2557. class Localization {
  2558. constructor(resourceIds = [], generateBundles) {
  2559. this.resourceIds = resourceIds;
  2560. this.generateBundles = generateBundles;
  2561. this.onChange(true);
  2562. }
  2563. addResourceIds(resourceIds, eager = false) {
  2564. this.resourceIds.push(...resourceIds);
  2565. this.onChange(eager);
  2566. return this.resourceIds.length;
  2567. }
  2568. removeResourceIds(resourceIds) {
  2569. this.resourceIds = this.resourceIds.filter(r => !resourceIds.includes(r));
  2570. this.onChange();
  2571. return this.resourceIds.length;
  2572. }
  2573. async formatWithFallback(keys, method) {
  2574. const translations = [];
  2575. let hasAtLeastOneBundle = false;
  2576. for await (const bundle of this.bundles) {
  2577. hasAtLeastOneBundle = true;
  2578. const missingIds = keysFromBundle(method, bundle, keys, translations);
  2579. if (missingIds.size === 0) {
  2580. break;
  2581. }
  2582. if (typeof console !== "undefined") {
  2583. const locale = bundle.locales[0];
  2584. const ids = Array.from(missingIds).join(", ");
  2585. console.warn(`[fluent] Missing translations in ${locale}: ${ids}`);
  2586. }
  2587. }
  2588. if (!hasAtLeastOneBundle && typeof console !== "undefined") {
  2589. console.warn(`[fluent] Request for keys failed because no resource bundles got generated.
  2590. keys: ${JSON.stringify(keys)}.
  2591. resourceIds: ${JSON.stringify(this.resourceIds)}.`);
  2592. }
  2593. return translations;
  2594. }
  2595. formatMessages(keys) {
  2596. return this.formatWithFallback(keys, messageFromBundle);
  2597. }
  2598. formatValues(keys) {
  2599. return this.formatWithFallback(keys, valueFromBundle);
  2600. }
  2601. async formatValue(id, args) {
  2602. const [val] = await this.formatValues([{
  2603. id,
  2604. args
  2605. }]);
  2606. return val;
  2607. }
  2608. handleEvent() {
  2609. this.onChange();
  2610. }
  2611. onChange(eager = false) {
  2612. this.bundles = CachedAsyncIterable.from(this.generateBundles(this.resourceIds));
  2613. if (eager) {
  2614. this.bundles.touchNext(2);
  2615. }
  2616. }
  2617. }
  2618. function valueFromBundle(bundle, errors, message, args) {
  2619. if (message.value) {
  2620. return bundle.formatPattern(message.value, args, errors);
  2621. }
  2622. return null;
  2623. }
  2624. function messageFromBundle(bundle, errors, message, args) {
  2625. const formatted = {
  2626. value: null,
  2627. attributes: null
  2628. };
  2629. if (message.value) {
  2630. formatted.value = bundle.formatPattern(message.value, args, errors);
  2631. }
  2632. let attrNames = Object.keys(message.attributes);
  2633. if (attrNames.length > 0) {
  2634. formatted.attributes = new Array(attrNames.length);
  2635. for (let [i, name] of attrNames.entries()) {
  2636. let value = bundle.formatPattern(message.attributes[name], args, errors);
  2637. formatted.attributes[i] = {
  2638. name,
  2639. value
  2640. };
  2641. }
  2642. }
  2643. return formatted;
  2644. }
  2645. function keysFromBundle(method, bundle, keys, translations) {
  2646. const messageErrors = [];
  2647. const missingIds = new Set();
  2648. keys.forEach(({
  2649. id,
  2650. args
  2651. }, i) => {
  2652. if (translations[i] !== undefined) {
  2653. return;
  2654. }
  2655. let message = bundle.getMessage(id);
  2656. if (message) {
  2657. messageErrors.length = 0;
  2658. translations[i] = method(bundle, messageErrors, message, args);
  2659. if (messageErrors.length > 0 && typeof console !== "undefined") {
  2660. const locale = bundle.locales[0];
  2661. const errors = messageErrors.join(", ");
  2662. console.warn(`[fluent][resolver] errors in ${locale}/${id}: ${errors}.`);
  2663. }
  2664. } else {
  2665. missingIds.add(id);
  2666. }
  2667. });
  2668. return missingIds;
  2669. }
  2670. ;// ./node_modules/@fluent/dom/esm/dom_localization.js
  2671. const L10NID_ATTR_NAME = "data-l10n-id";
  2672. const L10NARGS_ATTR_NAME = "data-l10n-args";
  2673. const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
  2674. class DOMLocalization extends Localization {
  2675. constructor(resourceIds, generateBundles) {
  2676. super(resourceIds, generateBundles);
  2677. this.roots = new Set();
  2678. this.pendingrAF = null;
  2679. this.pendingElements = new Set();
  2680. this.windowElement = null;
  2681. this.mutationObserver = null;
  2682. this.observerConfig = {
  2683. attributes: true,
  2684. characterData: false,
  2685. childList: true,
  2686. subtree: true,
  2687. attributeFilter: [L10NID_ATTR_NAME, L10NARGS_ATTR_NAME]
  2688. };
  2689. }
  2690. onChange(eager = false) {
  2691. super.onChange(eager);
  2692. if (this.roots) {
  2693. this.translateRoots();
  2694. }
  2695. }
  2696. setAttributes(element, id, args) {
  2697. element.setAttribute(L10NID_ATTR_NAME, id);
  2698. if (args) {
  2699. element.setAttribute(L10NARGS_ATTR_NAME, JSON.stringify(args));
  2700. } else {
  2701. element.removeAttribute(L10NARGS_ATTR_NAME);
  2702. }
  2703. return element;
  2704. }
  2705. getAttributes(element) {
  2706. return {
  2707. id: element.getAttribute(L10NID_ATTR_NAME),
  2708. args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null)
  2709. };
  2710. }
  2711. connectRoot(newRoot) {
  2712. for (const root of this.roots) {
  2713. if (root === newRoot || root.contains(newRoot) || newRoot.contains(root)) {
  2714. throw new Error("Cannot add a root that overlaps with existing root.");
  2715. }
  2716. }
  2717. if (this.windowElement) {
  2718. if (this.windowElement !== newRoot.ownerDocument.defaultView) {
  2719. throw new Error(`Cannot connect a root:
  2720. DOMLocalization already has a root from a different window.`);
  2721. }
  2722. } else {
  2723. this.windowElement = newRoot.ownerDocument.defaultView;
  2724. this.mutationObserver = new this.windowElement.MutationObserver(mutations => this.translateMutations(mutations));
  2725. }
  2726. this.roots.add(newRoot);
  2727. this.mutationObserver.observe(newRoot, this.observerConfig);
  2728. }
  2729. disconnectRoot(root) {
  2730. this.roots.delete(root);
  2731. this.pauseObserving();
  2732. if (this.roots.size === 0) {
  2733. this.mutationObserver = null;
  2734. if (this.windowElement && this.pendingrAF) {
  2735. this.windowElement.cancelAnimationFrame(this.pendingrAF);
  2736. }
  2737. this.windowElement = null;
  2738. this.pendingrAF = null;
  2739. this.pendingElements.clear();
  2740. return true;
  2741. }
  2742. this.resumeObserving();
  2743. return false;
  2744. }
  2745. translateRoots() {
  2746. const roots = Array.from(this.roots);
  2747. return Promise.all(roots.map(root => this.translateFragment(root)));
  2748. }
  2749. pauseObserving() {
  2750. if (!this.mutationObserver) {
  2751. return;
  2752. }
  2753. this.translateMutations(this.mutationObserver.takeRecords());
  2754. this.mutationObserver.disconnect();
  2755. }
  2756. resumeObserving() {
  2757. if (!this.mutationObserver) {
  2758. return;
  2759. }
  2760. for (const root of this.roots) {
  2761. this.mutationObserver.observe(root, this.observerConfig);
  2762. }
  2763. }
  2764. translateMutations(mutations) {
  2765. for (const mutation of mutations) {
  2766. switch (mutation.type) {
  2767. case "attributes":
  2768. if (mutation.target.hasAttribute("data-l10n-id")) {
  2769. this.pendingElements.add(mutation.target);
  2770. }
  2771. break;
  2772. case "childList":
  2773. for (const addedNode of mutation.addedNodes) {
  2774. if (addedNode.nodeType === addedNode.ELEMENT_NODE) {
  2775. if (addedNode.childElementCount) {
  2776. for (const element of this.getTranslatables(addedNode)) {
  2777. this.pendingElements.add(element);
  2778. }
  2779. } else if (addedNode.hasAttribute(L10NID_ATTR_NAME)) {
  2780. this.pendingElements.add(addedNode);
  2781. }
  2782. }
  2783. }
  2784. break;
  2785. }
  2786. }
  2787. if (this.pendingElements.size > 0) {
  2788. if (this.pendingrAF === null) {
  2789. this.pendingrAF = this.windowElement.requestAnimationFrame(() => {
  2790. this.translateElements(Array.from(this.pendingElements));
  2791. this.pendingElements.clear();
  2792. this.pendingrAF = null;
  2793. });
  2794. }
  2795. }
  2796. }
  2797. translateFragment(frag) {
  2798. return this.translateElements(this.getTranslatables(frag));
  2799. }
  2800. async translateElements(elements) {
  2801. if (!elements.length) {
  2802. return undefined;
  2803. }
  2804. const keys = elements.map(this.getKeysForElement);
  2805. const translations = await this.formatMessages(keys);
  2806. return this.applyTranslations(elements, translations);
  2807. }
  2808. applyTranslations(elements, translations) {
  2809. this.pauseObserving();
  2810. for (let i = 0; i < elements.length; i++) {
  2811. if (translations[i] !== undefined) {
  2812. translateElement(elements[i], translations[i]);
  2813. }
  2814. }
  2815. this.resumeObserving();
  2816. }
  2817. getTranslatables(element) {
  2818. const nodes = Array.from(element.querySelectorAll(L10N_ELEMENT_QUERY));
  2819. if (typeof element.hasAttribute === "function" && element.hasAttribute(L10NID_ATTR_NAME)) {
  2820. nodes.push(element);
  2821. }
  2822. return nodes;
  2823. }
  2824. getKeysForElement(element) {
  2825. return {
  2826. id: element.getAttribute(L10NID_ATTR_NAME),
  2827. args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null)
  2828. };
  2829. }
  2830. }
  2831. ;// ./node_modules/@fluent/dom/esm/index.js
  2832. ;// ./web/l10n.js
  2833. class L10n {
  2834. #dir;
  2835. #elements;
  2836. #lang;
  2837. #l10n;
  2838. constructor({
  2839. lang,
  2840. isRTL
  2841. }, l10n = null) {
  2842. this.#lang = L10n.#fixupLangCode(lang);
  2843. this.#l10n = l10n;
  2844. this.#dir = isRTL ?? L10n.#isRTL(this.#lang) ? "rtl" : "ltr";
  2845. }
  2846. _setL10n(l10n) {
  2847. this.#l10n = l10n;
  2848. }
  2849. getLanguage() {
  2850. return this.#lang;
  2851. }
  2852. getDirection() {
  2853. return this.#dir;
  2854. }
  2855. async get(ids, args = null, fallback) {
  2856. if (Array.isArray(ids)) {
  2857. ids = ids.map(id => ({
  2858. id
  2859. }));
  2860. const messages = await this.#l10n.formatMessages(ids);
  2861. return messages.map(message => message.value);
  2862. }
  2863. const messages = await this.#l10n.formatMessages([{
  2864. id: ids,
  2865. args
  2866. }]);
  2867. return messages[0]?.value || fallback;
  2868. }
  2869. async translate(element) {
  2870. (this.#elements ||= new Set()).add(element);
  2871. try {
  2872. this.#l10n.connectRoot(element);
  2873. await this.#l10n.translateRoots();
  2874. } catch {}
  2875. }
  2876. async translateOnce(element) {
  2877. try {
  2878. await this.#l10n.translateElements([element]);
  2879. } catch (ex) {
  2880. console.error("translateOnce:", ex);
  2881. }
  2882. }
  2883. async destroy() {
  2884. if (this.#elements) {
  2885. for (const element of this.#elements) {
  2886. this.#l10n.disconnectRoot(element);
  2887. }
  2888. this.#elements.clear();
  2889. this.#elements = null;
  2890. }
  2891. this.#l10n.pauseObserving();
  2892. }
  2893. pause() {
  2894. this.#l10n.pauseObserving();
  2895. }
  2896. resume() {
  2897. this.#l10n.resumeObserving();
  2898. }
  2899. static #fixupLangCode(langCode) {
  2900. langCode = langCode?.toLowerCase() || "en-us";
  2901. const PARTIAL_LANG_CODES = {
  2902. en: "en-us",
  2903. es: "es-es",
  2904. fy: "fy-nl",
  2905. ga: "ga-ie",
  2906. gu: "gu-in",
  2907. hi: "hi-in",
  2908. hy: "hy-am",
  2909. nb: "nb-no",
  2910. ne: "ne-np",
  2911. nn: "nn-no",
  2912. pa: "pa-in",
  2913. pt: "pt-pt",
  2914. sv: "sv-se",
  2915. zh: "zh-cn"
  2916. };
  2917. return PARTIAL_LANG_CODES[langCode] || langCode;
  2918. }
  2919. static #isRTL(lang) {
  2920. const shortCode = lang.split("-", 1)[0];
  2921. return ["ar", "he", "fa", "ps", "ur"].includes(shortCode);
  2922. }
  2923. }
  2924. const GenericL10n = null;
  2925. ;// ./web/genericl10n.js
  2926. function PLATFORM() {
  2927. const {
  2928. isAndroid,
  2929. isLinux,
  2930. isMac,
  2931. isWindows
  2932. } = FeatureTest.platform;
  2933. if (isLinux) {
  2934. return "linux";
  2935. }
  2936. if (isWindows) {
  2937. return "windows";
  2938. }
  2939. if (isMac) {
  2940. return "macos";
  2941. }
  2942. if (isAndroid) {
  2943. return "android";
  2944. }
  2945. return "other";
  2946. }
  2947. function createBundle(lang, text) {
  2948. const resource = new FluentResource(text);
  2949. const bundle = new FluentBundle(lang, {
  2950. functions: {
  2951. PLATFORM
  2952. }
  2953. });
  2954. const errors = bundle.addResource(resource);
  2955. if (errors.length) {
  2956. console.error("L10n errors", errors);
  2957. }
  2958. return bundle;
  2959. }
  2960. class genericl10n_GenericL10n extends L10n {
  2961. constructor(lang) {
  2962. super({
  2963. lang
  2964. });
  2965. const generateBundles = !lang ? genericl10n_GenericL10n.#generateBundlesFallback.bind(genericl10n_GenericL10n, this.getLanguage()) : genericl10n_GenericL10n.#generateBundles.bind(genericl10n_GenericL10n, "en-us", this.getLanguage());
  2966. this._setL10n(new DOMLocalization([], generateBundles));
  2967. }
  2968. static async *#generateBundles(defaultLang, baseLang) {
  2969. const {
  2970. baseURL,
  2971. paths
  2972. } = await this.#getPaths();
  2973. const langs = [baseLang];
  2974. if (defaultLang !== baseLang) {
  2975. const shortLang = baseLang.split("-", 1)[0];
  2976. if (shortLang !== baseLang) {
  2977. langs.push(shortLang);
  2978. }
  2979. langs.push(defaultLang);
  2980. }
  2981. const bundles = langs.map(lang => [lang, this.#createBundle(lang, baseURL, paths)]);
  2982. for (const [lang, bundlePromise] of bundles) {
  2983. const bundle = await bundlePromise;
  2984. if (bundle) {
  2985. yield bundle;
  2986. } else if (lang === "en-us") {
  2987. yield this.#createBundleFallback(lang);
  2988. }
  2989. }
  2990. }
  2991. static async #createBundle(lang, baseURL, paths) {
  2992. const path = paths[lang];
  2993. if (!path) {
  2994. return null;
  2995. }
  2996. const url = new URL(path, baseURL);
  2997. const text = await fetchData(url, "text");
  2998. return createBundle(lang, text);
  2999. }
  3000. static async #getPaths() {
  3001. try {
  3002. const {
  3003. href
  3004. } = document.querySelector(`link[type="application/l10n"]`);
  3005. const paths = await fetchData(href, "json");
  3006. return {
  3007. baseURL: href.substring(0, href.lastIndexOf("/") + 1) || "./",
  3008. paths
  3009. };
  3010. } catch {}
  3011. return {
  3012. baseURL: "./",
  3013. paths: Object.create(null)
  3014. };
  3015. }
  3016. static async *#generateBundlesFallback(lang) {
  3017. yield this.#createBundleFallback(lang);
  3018. }
  3019. static async #createBundleFallback(lang) {
  3020. const text = "pdfjs-previous-button =\n .title = Previous Page\npdfjs-previous-button-label = Previous\npdfjs-next-button =\n .title = Next Page\npdfjs-next-button-label = Next\npdfjs-page-input =\n .title = Page\npdfjs-of-pages = of { $pagesCount }\npdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })\npdfjs-zoom-out-button =\n .title = Zoom Out\npdfjs-zoom-out-button-label = Zoom Out\npdfjs-zoom-in-button =\n .title = Zoom In\npdfjs-zoom-in-button-label = Zoom In\npdfjs-zoom-select =\n .title = Zoom\npdfjs-presentation-mode-button =\n .title = Switch to Presentation Mode\npdfjs-presentation-mode-button-label = Presentation Mode\npdfjs-open-file-button =\n .title = Open File\npdfjs-open-file-button-label = Open\npdfjs-print-button =\n .title = Print\npdfjs-print-button-label = Print\npdfjs-save-button =\n .title = Save\npdfjs-save-button-label = Save\npdfjs-download-button =\n .title = Download\npdfjs-download-button-label = Download\npdfjs-bookmark-button =\n .title = Current Page (View URL from Current Page)\npdfjs-bookmark-button-label = Current Page\npdfjs-tools-button =\n .title = Tools\npdfjs-tools-button-label = Tools\npdfjs-first-page-button =\n .title = Go to First Page\npdfjs-first-page-button-label = Go to First Page\npdfjs-last-page-button =\n .title = Go to Last Page\npdfjs-last-page-button-label = Go to Last Page\npdfjs-page-rotate-cw-button =\n .title = Rotate Clockwise\npdfjs-page-rotate-cw-button-label = Rotate Clockwise\npdfjs-page-rotate-ccw-button =\n .title = Rotate Counterclockwise\npdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise\npdfjs-cursor-text-select-tool-button =\n .title = Enable Text Selection Tool\npdfjs-cursor-text-select-tool-button-label = Text Selection Tool\npdfjs-cursor-hand-tool-button =\n .title = Enable Hand Tool\npdfjs-cursor-hand-tool-button-label = Hand Tool\npdfjs-scroll-page-button =\n .title = Use Page Scrolling\npdfjs-scroll-page-button-label = Page Scrolling\npdfjs-scroll-vertical-button =\n .title = Use Vertical Scrolling\npdfjs-scroll-vertical-button-label = Vertical Scrolling\npdfjs-scroll-horizontal-button =\n .title = Use Horizontal Scrolling\npdfjs-scroll-horizontal-button-label = Horizontal Scrolling\npdfjs-scroll-wrapped-button =\n .title = Use Wrapped Scrolling\npdfjs-scroll-wrapped-button-label = Wrapped Scrolling\npdfjs-spread-none-button =\n .title = Do not join page spreads\npdfjs-spread-none-button-label = No Spreads\npdfjs-spread-odd-button =\n .title = Join page spreads starting with odd-numbered pages\npdfjs-spread-odd-button-label = Odd Spreads\npdfjs-spread-even-button =\n .title = Join page spreads starting with even-numbered pages\npdfjs-spread-even-button-label = Even Spreads\npdfjs-document-properties-button =\n .title = Document Properties\u2026\npdfjs-document-properties-button-label = Document Properties\u2026\npdfjs-document-properties-file-name = File name:\npdfjs-document-properties-file-size = File size:\npdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)\npdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)\npdfjs-document-properties-title = Title:\npdfjs-document-properties-author = Author:\npdfjs-document-properties-subject = Subject:\npdfjs-document-properties-keywords = Keywords:\npdfjs-document-properties-creation-date = Creation Date:\npdfjs-document-properties-modification-date = Modification Date:\npdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-document-properties-creator = Creator:\npdfjs-document-properties-producer = PDF Producer:\npdfjs-document-properties-version = PDF Version:\npdfjs-document-properties-page-count = Page Count:\npdfjs-document-properties-page-size = Page Size:\npdfjs-document-properties-page-size-unit-inches = in\npdfjs-document-properties-page-size-unit-millimeters = mm\npdfjs-document-properties-page-size-orientation-portrait = portrait\npdfjs-document-properties-page-size-orientation-landscape = landscape\npdfjs-document-properties-page-size-name-a-three = A3\npdfjs-document-properties-page-size-name-a-four = A4\npdfjs-document-properties-page-size-name-letter = Letter\npdfjs-document-properties-page-size-name-legal = Legal\npdfjs-document-properties-page-size-dimension-string = { $width } \xD7 { $height } { $unit } ({ $orientation })\npdfjs-document-properties-page-size-dimension-name-string = { $width } \xD7 { $height } { $unit } ({ $name }, { $orientation })\npdfjs-document-properties-linearized = Fast Web View:\npdfjs-document-properties-linearized-yes = Yes\npdfjs-document-properties-linearized-no = No\npdfjs-document-properties-close-button = Close\npdfjs-print-progress-message = Preparing document for printing\u2026\npdfjs-print-progress-percent = { $progress }%\npdfjs-print-progress-close-button = Cancel\npdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.\npdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.\npdfjs-toggle-sidebar-button =\n .title = Toggle Sidebar\npdfjs-toggle-sidebar-notification-button =\n .title = Toggle Sidebar (document contains outline/attachments/layers)\npdfjs-toggle-sidebar-button-label = Toggle Sidebar\npdfjs-document-outline-button =\n .title = Show Document Outline (double-click to expand/collapse all items)\npdfjs-document-outline-button-label = Document Outline\npdfjs-attachments-button =\n .title = Show Attachments\npdfjs-attachments-button-label = Attachments\npdfjs-layers-button =\n .title = Show Layers (double-click to reset all layers to the default state)\npdfjs-layers-button-label = Layers\npdfjs-thumbs-button =\n .title = Show Thumbnails\npdfjs-thumbs-button-label = Thumbnails\npdfjs-current-outline-item-button =\n .title = Find Current Outline Item\npdfjs-current-outline-item-button-label = Current Outline Item\npdfjs-findbar-button =\n .title = Find in Document\npdfjs-findbar-button-label = Find\npdfjs-additional-layers = Additional Layers\npdfjs-thumb-page-title =\n .title = Page { $page }\npdfjs-thumb-page-canvas =\n .aria-label = Thumbnail of Page { $page }\npdfjs-find-input =\n .title = Find\n .placeholder = Find in document\u2026\npdfjs-find-previous-button =\n .title = Find the previous occurrence of the phrase\npdfjs-find-previous-button-label = Previous\npdfjs-find-next-button =\n .title = Find the next occurrence of the phrase\npdfjs-find-next-button-label = Next\npdfjs-find-highlight-checkbox = Highlight All\npdfjs-find-match-case-checkbox-label = Match Case\npdfjs-find-match-diacritics-checkbox-label = Match Diacritics\npdfjs-find-entire-word-checkbox-label = Whole Words\npdfjs-find-reached-top = Reached top of document, continued from bottom\npdfjs-find-reached-bottom = Reached end of document, continued from top\npdfjs-find-match-count =\n { $total ->\n [one] { $current } of { $total } match\n *[other] { $current } of { $total } matches\n }\npdfjs-find-match-count-limit =\n { $limit ->\n [one] More than { $limit } match\n *[other] More than { $limit } matches\n }\npdfjs-find-not-found = Phrase not found\npdfjs-page-scale-width = Page Width\npdfjs-page-scale-fit = Page Fit\npdfjs-page-scale-auto = Automatic Zoom\npdfjs-page-scale-actual = Actual Size\npdfjs-page-scale-percent = { $scale }%\npdfjs-page-landmark =\n .aria-label = Page { $page }\npdfjs-loading-error = An error occurred while loading the PDF.\npdfjs-invalid-file-error = Invalid or corrupted PDF file.\npdfjs-missing-file-error = Missing PDF file.\npdfjs-unexpected-response-error = Unexpected server response.\npdfjs-rendering-error = An error occurred while rendering the page.\npdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-text-annotation-type =\n .alt = [{ $type } Annotation]\npdfjs-password-label = Enter the password to open this PDF file.\npdfjs-password-invalid = Invalid password. Please try again.\npdfjs-password-ok-button = OK\npdfjs-password-cancel-button = Cancel\npdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.\npdfjs-editor-free-text-button =\n .title = Text\npdfjs-editor-free-text-button-label = Text\npdfjs-editor-ink-button =\n .title = Draw\npdfjs-editor-ink-button-label = Draw\npdfjs-editor-stamp-button =\n .title = Add or edit images\npdfjs-editor-stamp-button-label = Add or edit images\npdfjs-editor-highlight-button =\n .title = Highlight\npdfjs-editor-highlight-button-label = Highlight\npdfjs-highlight-floating-button1 =\n .title = Highlight\n .aria-label = Highlight\npdfjs-highlight-floating-button-label = Highlight\npdfjs-editor-signature-button =\n .title = Add signature\npdfjs-editor-signature-button-label = Add signature\npdfjs-editor-highlight-editor =\n .aria-label = Highlight editor\npdfjs-editor-ink-editor =\n .aria-label = Drawing editor\npdfjs-editor-signature-editor1 =\n .aria-description = Signature editor: { $description }\npdfjs-editor-stamp-editor =\n .aria-label = Image editor\npdfjs-editor-remove-ink-button =\n .title = Remove drawing\npdfjs-editor-remove-freetext-button =\n .title = Remove text\npdfjs-editor-remove-stamp-button =\n .title = Remove image\npdfjs-editor-remove-highlight-button =\n .title = Remove highlight\npdfjs-editor-remove-signature-button =\n .title = Remove signature\npdfjs-editor-free-text-color-input = Color\npdfjs-editor-free-text-size-input = Size\npdfjs-editor-ink-color-input = Color\npdfjs-editor-ink-thickness-input = Thickness\npdfjs-editor-ink-opacity-input = Opacity\npdfjs-editor-stamp-add-image-button =\n .title = Add image\npdfjs-editor-stamp-add-image-button-label = Add image\npdfjs-editor-free-highlight-thickness-input = Thickness\npdfjs-editor-free-highlight-thickness-title =\n .title = Change thickness when highlighting items other than text\npdfjs-editor-add-signature-container =\n .aria-label = Signature controls and saved signatures\npdfjs-editor-signature-add-signature-button =\n .title = Add new signature\npdfjs-editor-signature-add-signature-button-label = Add new signature\npdfjs-editor-add-saved-signature-button =\n .title = Saved signature: { $description }\npdfjs-free-text2 =\n .aria-label = Text Editor\n .default-content = Start typing\u2026\npdfjs-editor-alt-text-button =\n .aria-label = Alt text\npdfjs-editor-alt-text-button-label = Alt text\npdfjs-editor-alt-text-edit-button =\n .aria-label = Edit alt text\npdfjs-editor-alt-text-dialog-label = Choose an option\npdfjs-editor-alt-text-dialog-description = Alt text (alternative text) helps when people can\u2019t see the image or when it doesn\u2019t load.\npdfjs-editor-alt-text-add-description-label = Add a description\npdfjs-editor-alt-text-add-description-description = Aim for 1-2 sentences that describe the subject, setting, or actions.\npdfjs-editor-alt-text-mark-decorative-label = Mark as decorative\npdfjs-editor-alt-text-mark-decorative-description = This is used for ornamental images, like borders or watermarks.\npdfjs-editor-alt-text-cancel-button = Cancel\npdfjs-editor-alt-text-save-button = Save\npdfjs-editor-alt-text-decorative-tooltip = Marked as decorative\npdfjs-editor-alt-text-textarea =\n .placeholder = For example, \u201CA young man sits down at a table to eat a meal\u201D\npdfjs-editor-resizer-top-left =\n .aria-label = Top left corner \u2014 resize\npdfjs-editor-resizer-top-middle =\n .aria-label = Top middle \u2014 resize\npdfjs-editor-resizer-top-right =\n .aria-label = Top right corner \u2014 resize\npdfjs-editor-resizer-middle-right =\n .aria-label = Middle right \u2014 resize\npdfjs-editor-resizer-bottom-right =\n .aria-label = Bottom right corner \u2014 resize\npdfjs-editor-resizer-bottom-middle =\n .aria-label = Bottom middle \u2014 resize\npdfjs-editor-resizer-bottom-left =\n .aria-label = Bottom left corner \u2014 resize\npdfjs-editor-resizer-middle-left =\n .aria-label = Middle left \u2014 resize\npdfjs-editor-highlight-colorpicker-label = Highlight color\npdfjs-editor-colorpicker-button =\n .title = Change color\npdfjs-editor-colorpicker-dropdown =\n .aria-label = Color choices\npdfjs-editor-colorpicker-yellow =\n .title = Yellow\npdfjs-editor-colorpicker-green =\n .title = Green\npdfjs-editor-colorpicker-blue =\n .title = Blue\npdfjs-editor-colorpicker-pink =\n .title = Pink\npdfjs-editor-colorpicker-red =\n .title = Red\npdfjs-editor-highlight-show-all-button-label = Show all\npdfjs-editor-highlight-show-all-button =\n .title = Show all\npdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)\npdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)\npdfjs-editor-new-alt-text-textarea =\n .placeholder = Write your description here\u2026\npdfjs-editor-new-alt-text-description = Short description for people who can\u2019t see the image or when the image doesn\u2019t load.\npdfjs-editor-new-alt-text-disclaimer1 = This alt text was created automatically and may be inaccurate.\npdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more\npdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically\npdfjs-editor-new-alt-text-not-now-button = Not now\npdfjs-editor-new-alt-text-error-title = Couldn\u2019t create alt text automatically\npdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.\npdfjs-editor-new-alt-text-error-close-button = Close\npdfjs-editor-new-alt-text-ai-model-downloading-progress = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)\n .aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)\npdfjs-editor-new-alt-text-added-button =\n .aria-label = Alt text added\npdfjs-editor-new-alt-text-added-button-label = Alt text added\npdfjs-editor-new-alt-text-missing-button =\n .aria-label = Missing alt text\npdfjs-editor-new-alt-text-missing-button-label = Missing alt text\npdfjs-editor-new-alt-text-to-review-button =\n .aria-label = Review alt text\npdfjs-editor-new-alt-text-to-review-button-label = Review alt text\npdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }\npdfjs-image-alt-text-settings-button =\n .title = Image alt text settings\npdfjs-image-alt-text-settings-button-label = Image alt text settings\npdfjs-editor-alt-text-settings-dialog-label = Image alt text settings\npdfjs-editor-alt-text-settings-automatic-title = Automatic alt text\npdfjs-editor-alt-text-settings-create-model-button-label = Create alt text automatically\npdfjs-editor-alt-text-settings-create-model-description = Suggests descriptions to help people who can\u2019t see the image or when the image doesn\u2019t load.\npdfjs-editor-alt-text-settings-download-model-label = Alt text AI model ({ $totalSize } MB)\npdfjs-editor-alt-text-settings-ai-model-description = Runs locally on your device so your data stays private. Required for automatic alt text.\npdfjs-editor-alt-text-settings-delete-model-button = Delete\npdfjs-editor-alt-text-settings-download-model-button = Download\npdfjs-editor-alt-text-settings-downloading-model-button = Downloading\u2026\npdfjs-editor-alt-text-settings-editor-title = Alt text editor\npdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image\npdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.\npdfjs-editor-alt-text-settings-close-button = Close\npdfjs-editor-undo-bar-message-highlight = Highlight removed\npdfjs-editor-undo-bar-message-freetext = Text removed\npdfjs-editor-undo-bar-message-ink = Drawing removed\npdfjs-editor-undo-bar-message-stamp = Image removed\npdfjs-editor-undo-bar-message-signature = Signature removed\npdfjs-editor-undo-bar-message-multiple =\n { $count ->\n [one] { $count } annotation removed\n *[other] { $count } annotations removed\n }\npdfjs-editor-undo-bar-undo-button =\n .title = Undo\npdfjs-editor-undo-bar-undo-button-label = Undo\npdfjs-editor-undo-bar-close-button =\n .title = Close\npdfjs-editor-undo-bar-close-button-label = Close\npdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.\npdfjs-editor-add-signature-dialog-title = Add a signature\npdfjs-editor-add-signature-type-button = Type\n .title = Type\npdfjs-editor-add-signature-draw-button = Draw\n .title = Draw\npdfjs-editor-add-signature-image-button = Image\n .title = Image\npdfjs-editor-add-signature-type-input =\n .aria-label = Type your signature\n .placeholder = Type your signature\npdfjs-editor-add-signature-draw-placeholder = Draw your signature\npdfjs-editor-add-signature-draw-thickness-range-label = Thickness\npdfjs-editor-add-signature-draw-thickness-range =\n .title = Drawing thickness: { $thickness }\npdfjs-editor-add-signature-image-placeholder = Drag a file here to upload\npdfjs-editor-add-signature-image-browse-link =\n { PLATFORM() ->\n [macos] Or choose image files\n *[other] Or browse image files\n }\npdfjs-editor-add-signature-description-label = Description (alt text)\npdfjs-editor-add-signature-description-input =\n .title = Description (alt text)\npdfjs-editor-add-signature-description-default-when-drawing = Signature\npdfjs-editor-add-signature-clear-button-label = Clear signature\npdfjs-editor-add-signature-clear-button =\n .title = Clear signature\npdfjs-editor-add-signature-save-checkbox = Save signature\npdfjs-editor-add-signature-save-warning-message = You\u2019ve reached the limit of 5 saved signatures. Remove one to save more.\npdfjs-editor-add-signature-image-upload-error-title = Couldn\u2019t upload image\npdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.\npdfjs-editor-add-signature-error-close-button = Close\npdfjs-editor-add-signature-cancel-button = Cancel\npdfjs-editor-add-signature-add-button = Add\npdfjs-editor-delete-signature-button1 =\n .title = Remove saved signature\npdfjs-editor-delete-signature-button-label1 = Remove saved signature\npdfjs-editor-add-signature-edit-button-label = Edit description\npdfjs-editor-edit-signature-dialog-title = Edit description\npdfjs-editor-edit-signature-update-button = Update";
  3021. return createBundle(lang, text);
  3022. }
  3023. }
  3024. ;// ./web/generic_scripting.js
  3025. async function docProperties(pdfDocument) {
  3026. const url = "",
  3027. baseUrl = url.split("#", 1)[0];
  3028. const {
  3029. info,
  3030. metadata,
  3031. contentDispositionFilename,
  3032. contentLength
  3033. } = await pdfDocument.getMetadata();
  3034. return {
  3035. ...info,
  3036. baseURL: baseUrl,
  3037. filesize: contentLength || (await pdfDocument.getDownloadInfo()).length,
  3038. filename: contentDispositionFilename || getPdfFilenameFromUrl(url),
  3039. metadata: metadata?.getRaw(),
  3040. authors: metadata?.get("dc:creator"),
  3041. numPages: pdfDocument.numPages,
  3042. URL: url
  3043. };
  3044. }
  3045. class GenericScripting {
  3046. constructor(sandboxBundleSrc) {
  3047. this._ready = new Promise((resolve, reject) => {
  3048. const sandbox = import(
  3049. /*webpackIgnore: true*/
  3050. /*@vite-ignore*/
  3051. sandboxBundleSrc);
  3052. sandbox.then(pdfjsSandbox => {
  3053. resolve(pdfjsSandbox.QuickJSSandbox());
  3054. }).catch(reject);
  3055. });
  3056. }
  3057. async createSandbox(data) {
  3058. const sandbox = await this._ready;
  3059. sandbox.create(data);
  3060. }
  3061. async dispatchEventInSandbox(event) {
  3062. const sandbox = await this._ready;
  3063. setTimeout(() => sandbox.dispatchEvent(event), 0);
  3064. }
  3065. async destroySandbox() {
  3066. const sandbox = await this._ready;
  3067. sandbox.nukeSandbox();
  3068. }
  3069. }
  3070. ;// ./web/generic_signature_storage.js
  3071. const KEY_STORAGE = "pdfjs.signature";
  3072. class SignatureStorage {
  3073. #eventBus;
  3074. #signatures = null;
  3075. #signal = null;
  3076. constructor(eventBus, signal) {
  3077. this.#eventBus = eventBus;
  3078. this.#signal = signal;
  3079. }
  3080. #save() {
  3081. localStorage.setItem(KEY_STORAGE, JSON.stringify(Object.fromEntries(this.#signatures.entries())));
  3082. }
  3083. async getAll() {
  3084. if (this.#signal) {
  3085. window.addEventListener("storage", ({
  3086. key
  3087. }) => {
  3088. if (key === KEY_STORAGE) {
  3089. this.#signatures = null;
  3090. this.#eventBus?.dispatch("storedsignatureschanged", {
  3091. source: this
  3092. });
  3093. }
  3094. }, {
  3095. signal: this.#signal
  3096. });
  3097. this.#signal = null;
  3098. }
  3099. if (!this.#signatures) {
  3100. this.#signatures = new Map();
  3101. const data = localStorage.getItem(KEY_STORAGE);
  3102. if (data) {
  3103. for (const [key, value] of Object.entries(JSON.parse(data))) {
  3104. this.#signatures.set(key, value);
  3105. }
  3106. }
  3107. }
  3108. return this.#signatures;
  3109. }
  3110. async isFull() {
  3111. return (await this.size()) === 5;
  3112. }
  3113. async size() {
  3114. return (await this.getAll()).size;
  3115. }
  3116. async create(data) {
  3117. if (await this.isFull()) {
  3118. return null;
  3119. }
  3120. const uuid = getUuid();
  3121. this.#signatures.set(uuid, data);
  3122. this.#save();
  3123. return uuid;
  3124. }
  3125. async delete(uuid) {
  3126. const signatures = await this.getAll();
  3127. if (!signatures.has(uuid)) {
  3128. return false;
  3129. }
  3130. signatures.delete(uuid);
  3131. this.#save();
  3132. return true;
  3133. }
  3134. }
  3135. ;// ./web/genericcom.js
  3136. function initCom(app) {}
  3137. class Preferences extends BasePreferences {
  3138. async _writeToStorage(prefObj) {
  3139. localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj));
  3140. }
  3141. async _readFromStorage(prefObj) {
  3142. return {
  3143. prefs: JSON.parse(localStorage.getItem("pdfjs.preferences"))
  3144. };
  3145. }
  3146. }
  3147. class ExternalServices extends BaseExternalServices {
  3148. async createL10n() {
  3149. return new genericl10n_GenericL10n(AppOptions.get("localeProperties")?.lang);
  3150. }
  3151. createScripting() {
  3152. return new GenericScripting(AppOptions.get("sandboxBundleSrc"));
  3153. }
  3154. createSignatureStorage(eventBus, signal) {
  3155. return new SignatureStorage(eventBus, signal);
  3156. }
  3157. }
  3158. class MLManager {
  3159. async isEnabledFor(_name) {
  3160. return false;
  3161. }
  3162. async deleteModel(_service) {
  3163. return null;
  3164. }
  3165. isReady(_name) {
  3166. return false;
  3167. }
  3168. guess(_data) {}
  3169. toggleService(_name, _enabled) {}
  3170. }
  3171. ;// ./web/new_alt_text_manager.js
  3172. class NewAltTextManager {
  3173. #boundCancel = this.#cancel.bind(this);
  3174. #createAutomaticallyButton;
  3175. #currentEditor = null;
  3176. #cancelButton;
  3177. #descriptionContainer;
  3178. #dialog;
  3179. #disclaimer;
  3180. #downloadModel;
  3181. #downloadModelDescription;
  3182. #eventBus;
  3183. #firstTime = false;
  3184. #guessedAltText;
  3185. #hasAI = null;
  3186. #isEditing = null;
  3187. #imagePreview;
  3188. #imageData;
  3189. #isAILoading = false;
  3190. #wasAILoading = false;
  3191. #learnMore;
  3192. #notNowButton;
  3193. #overlayManager;
  3194. #textarea;
  3195. #title;
  3196. #uiManager;
  3197. #previousAltText = null;
  3198. constructor({
  3199. descriptionContainer,
  3200. dialog,
  3201. imagePreview,
  3202. cancelButton,
  3203. disclaimer,
  3204. notNowButton,
  3205. saveButton,
  3206. textarea,
  3207. learnMore,
  3208. errorCloseButton,
  3209. createAutomaticallyButton,
  3210. downloadModel,
  3211. downloadModelDescription,
  3212. title
  3213. }, overlayManager, eventBus) {
  3214. this.#cancelButton = cancelButton;
  3215. this.#createAutomaticallyButton = createAutomaticallyButton;
  3216. this.#descriptionContainer = descriptionContainer;
  3217. this.#dialog = dialog;
  3218. this.#disclaimer = disclaimer;
  3219. this.#notNowButton = notNowButton;
  3220. this.#imagePreview = imagePreview;
  3221. this.#textarea = textarea;
  3222. this.#learnMore = learnMore;
  3223. this.#title = title;
  3224. this.#downloadModel = downloadModel;
  3225. this.#downloadModelDescription = downloadModelDescription;
  3226. this.#overlayManager = overlayManager;
  3227. this.#eventBus = eventBus;
  3228. dialog.addEventListener("close", this.#close.bind(this));
  3229. dialog.addEventListener("contextmenu", event => {
  3230. if (event.target !== this.#textarea) {
  3231. event.preventDefault();
  3232. }
  3233. });
  3234. cancelButton.addEventListener("click", this.#boundCancel);
  3235. notNowButton.addEventListener("click", this.#boundCancel);
  3236. saveButton.addEventListener("click", this.#save.bind(this));
  3237. errorCloseButton.addEventListener("click", () => {
  3238. this.#toggleError(false);
  3239. });
  3240. createAutomaticallyButton.addEventListener("click", async () => {
  3241. const checked = createAutomaticallyButton.getAttribute("aria-pressed") !== "true";
  3242. this.#currentEditor._reportTelemetry({
  3243. action: "pdfjs.image.alt_text.ai_generation_check",
  3244. data: {
  3245. status: checked
  3246. }
  3247. });
  3248. if (this.#uiManager) {
  3249. this.#uiManager.setPreference("enableGuessAltText", checked);
  3250. await this.#uiManager.mlManager.toggleService("altText", checked);
  3251. }
  3252. this.#toggleGuessAltText(checked, false);
  3253. });
  3254. textarea.addEventListener("focus", () => {
  3255. this.#wasAILoading = this.#isAILoading;
  3256. this.#toggleLoading(false);
  3257. this.#toggleTitleAndDisclaimer();
  3258. });
  3259. textarea.addEventListener("blur", () => {
  3260. if (!textarea.value) {
  3261. this.#toggleLoading(this.#wasAILoading);
  3262. }
  3263. this.#toggleTitleAndDisclaimer();
  3264. });
  3265. textarea.addEventListener("input", () => {
  3266. this.#toggleTitleAndDisclaimer();
  3267. });
  3268. eventBus._on("enableguessalttext", ({
  3269. value
  3270. }) => {
  3271. this.#toggleGuessAltText(value, false);
  3272. });
  3273. this.#overlayManager.register(dialog);
  3274. this.#learnMore.addEventListener("click", () => {
  3275. this.#currentEditor._reportTelemetry({
  3276. action: "pdfjs.image.alt_text.info",
  3277. data: {
  3278. topic: "alt_text"
  3279. }
  3280. });
  3281. });
  3282. }
  3283. #toggleLoading(value) {
  3284. if (!this.#uiManager || this.#isAILoading === value) {
  3285. return;
  3286. }
  3287. this.#isAILoading = value;
  3288. this.#descriptionContainer.classList.toggle("loading", value);
  3289. }
  3290. #toggleError(value) {
  3291. if (!this.#uiManager) {
  3292. return;
  3293. }
  3294. this.#dialog.classList.toggle("error", value);
  3295. }
  3296. async #toggleGuessAltText(value, isInitial = false) {
  3297. if (!this.#uiManager) {
  3298. return;
  3299. }
  3300. this.#dialog.classList.toggle("aiDisabled", !value);
  3301. this.#createAutomaticallyButton.setAttribute("aria-pressed", value);
  3302. if (value) {
  3303. const {
  3304. altTextLearnMoreUrl
  3305. } = this.#uiManager.mlManager;
  3306. if (altTextLearnMoreUrl) {
  3307. this.#learnMore.href = altTextLearnMoreUrl;
  3308. }
  3309. this.#mlGuessAltText(isInitial);
  3310. } else {
  3311. this.#toggleLoading(false);
  3312. this.#isAILoading = false;
  3313. this.#toggleTitleAndDisclaimer();
  3314. }
  3315. }
  3316. #toggleNotNow() {
  3317. this.#notNowButton.classList.toggle("hidden", !this.#firstTime);
  3318. this.#cancelButton.classList.toggle("hidden", this.#firstTime);
  3319. }
  3320. #toggleAI(value) {
  3321. if (!this.#uiManager || this.#hasAI === value) {
  3322. return;
  3323. }
  3324. this.#hasAI = value;
  3325. this.#dialog.classList.toggle("noAi", !value);
  3326. this.#toggleTitleAndDisclaimer();
  3327. }
  3328. #toggleTitleAndDisclaimer() {
  3329. const visible = this.#isAILoading || this.#guessedAltText && this.#guessedAltText === this.#textarea.value;
  3330. this.#disclaimer.hidden = !visible;
  3331. const isEditing = this.#isAILoading || !!this.#textarea.value;
  3332. if (this.#isEditing === isEditing) {
  3333. return;
  3334. }
  3335. this.#isEditing = isEditing;
  3336. this.#title.setAttribute("data-l10n-id", isEditing ? "pdfjs-editor-new-alt-text-dialog-edit-label" : "pdfjs-editor-new-alt-text-dialog-add-label");
  3337. }
  3338. async #mlGuessAltText(isInitial) {
  3339. if (this.#isAILoading) {
  3340. return;
  3341. }
  3342. if (this.#textarea.value) {
  3343. return;
  3344. }
  3345. if (isInitial && this.#previousAltText !== null) {
  3346. return;
  3347. }
  3348. this.#guessedAltText = this.#currentEditor.guessedAltText;
  3349. if (this.#previousAltText === null && this.#guessedAltText) {
  3350. this.#addAltText(this.#guessedAltText);
  3351. return;
  3352. }
  3353. this.#toggleLoading(true);
  3354. this.#toggleTitleAndDisclaimer();
  3355. let hasError = false;
  3356. try {
  3357. const altText = await this.#currentEditor.mlGuessAltText(this.#imageData, false);
  3358. if (altText) {
  3359. this.#guessedAltText = altText;
  3360. this.#wasAILoading = this.#isAILoading;
  3361. if (this.#isAILoading) {
  3362. this.#addAltText(altText);
  3363. }
  3364. }
  3365. } catch (e) {
  3366. console.error(e);
  3367. hasError = true;
  3368. }
  3369. this.#toggleLoading(false);
  3370. this.#toggleTitleAndDisclaimer();
  3371. if (hasError && this.#uiManager) {
  3372. this.#toggleError(true);
  3373. }
  3374. }
  3375. #addAltText(altText) {
  3376. if (!this.#uiManager || this.#textarea.value) {
  3377. return;
  3378. }
  3379. this.#textarea.value = altText;
  3380. this.#toggleTitleAndDisclaimer();
  3381. }
  3382. #setProgress() {
  3383. this.#downloadModel.classList.toggle("hidden", false);
  3384. const callback = async ({
  3385. detail: {
  3386. finished,
  3387. total,
  3388. totalLoaded
  3389. }
  3390. }) => {
  3391. const ONE_MEGA_BYTES = 1e6;
  3392. totalLoaded = Math.min(0.99 * total, totalLoaded);
  3393. const totalSize = this.#downloadModelDescription.ariaValueMax = Math.round(total / ONE_MEGA_BYTES);
  3394. const downloadedSize = this.#downloadModelDescription.ariaValueNow = Math.round(totalLoaded / ONE_MEGA_BYTES);
  3395. this.#downloadModelDescription.setAttribute("data-l10n-args", JSON.stringify({
  3396. totalSize,
  3397. downloadedSize
  3398. }));
  3399. if (!finished) {
  3400. return;
  3401. }
  3402. this.#eventBus._off("loadaiengineprogress", callback);
  3403. this.#downloadModel.classList.toggle("hidden", true);
  3404. this.#toggleAI(true);
  3405. if (!this.#uiManager) {
  3406. return;
  3407. }
  3408. const {
  3409. mlManager
  3410. } = this.#uiManager;
  3411. mlManager.toggleService("altText", true);
  3412. this.#toggleGuessAltText(await mlManager.isEnabledFor("altText"), true);
  3413. };
  3414. this.#eventBus._on("loadaiengineprogress", callback);
  3415. }
  3416. async editAltText(uiManager, editor, firstTime) {
  3417. if (this.#currentEditor || !editor) {
  3418. return;
  3419. }
  3420. if (firstTime && editor.hasAltTextData()) {
  3421. editor.altTextFinish();
  3422. return;
  3423. }
  3424. this.#firstTime = firstTime;
  3425. let {
  3426. mlManager
  3427. } = uiManager;
  3428. let hasAI = !!mlManager;
  3429. this.#toggleTitleAndDisclaimer();
  3430. if (mlManager && !mlManager.isReady("altText")) {
  3431. hasAI = false;
  3432. if (mlManager.hasProgress) {
  3433. this.#setProgress();
  3434. } else {
  3435. mlManager = null;
  3436. }
  3437. } else {
  3438. this.#downloadModel.classList.toggle("hidden", true);
  3439. }
  3440. const isAltTextEnabledPromise = mlManager?.isEnabledFor("altText");
  3441. this.#currentEditor = editor;
  3442. this.#uiManager = uiManager;
  3443. this.#uiManager.removeEditListeners();
  3444. ({
  3445. altText: this.#previousAltText
  3446. } = editor.altTextData);
  3447. this.#textarea.value = this.#previousAltText ?? "";
  3448. const AI_MAX_IMAGE_DIMENSION = 224;
  3449. const MAX_PREVIEW_DIMENSION = 180;
  3450. let canvas, width, height;
  3451. if (mlManager) {
  3452. ({
  3453. canvas,
  3454. width,
  3455. height,
  3456. imageData: this.#imageData
  3457. } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, MAX_PREVIEW_DIMENSION, true));
  3458. if (hasAI) {
  3459. this.#toggleGuessAltText(await isAltTextEnabledPromise, true);
  3460. }
  3461. } else {
  3462. ({
  3463. canvas,
  3464. width,
  3465. height
  3466. } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, MAX_PREVIEW_DIMENSION, false));
  3467. }
  3468. canvas.setAttribute("role", "presentation");
  3469. const {
  3470. style
  3471. } = canvas;
  3472. style.width = `${width}px`;
  3473. style.height = `${height}px`;
  3474. this.#imagePreview.append(canvas);
  3475. this.#toggleNotNow();
  3476. this.#toggleAI(hasAI);
  3477. this.#toggleError(false);
  3478. try {
  3479. await this.#overlayManager.open(this.#dialog);
  3480. } catch (ex) {
  3481. this.#close();
  3482. throw ex;
  3483. }
  3484. }
  3485. #cancel() {
  3486. this.#currentEditor.altTextData = {
  3487. cancel: true
  3488. };
  3489. const altText = this.#textarea.value.trim();
  3490. this.#currentEditor._reportTelemetry({
  3491. action: "pdfjs.image.alt_text.dismiss",
  3492. data: {
  3493. alt_text_type: altText ? "present" : "empty",
  3494. flow: this.#firstTime ? "image_add" : "alt_text_edit"
  3495. }
  3496. });
  3497. this.#currentEditor._reportTelemetry({
  3498. action: "pdfjs.image.image_added",
  3499. data: {
  3500. alt_text_modal: true,
  3501. alt_text_type: "skipped"
  3502. }
  3503. });
  3504. this.#finish();
  3505. }
  3506. #finish() {
  3507. this.#overlayManager.closeIfActive(this.#dialog);
  3508. }
  3509. #close() {
  3510. const canvas = this.#imagePreview.firstChild;
  3511. canvas.remove();
  3512. canvas.width = canvas.height = 0;
  3513. this.#imageData = null;
  3514. this.#toggleLoading(false);
  3515. this.#uiManager?.addEditListeners();
  3516. this.#currentEditor.altTextFinish();
  3517. this.#uiManager?.setSelected(this.#currentEditor);
  3518. this.#currentEditor = null;
  3519. this.#uiManager = null;
  3520. }
  3521. #extractWords(text) {
  3522. return new Set(text.toLowerCase().split(/[^\p{L}\p{N}]+/gu).filter(x => !!x));
  3523. }
  3524. #save() {
  3525. const altText = this.#textarea.value.trim();
  3526. this.#currentEditor.altTextData = {
  3527. altText,
  3528. decorative: false
  3529. };
  3530. this.#currentEditor.altTextData.guessedAltText = this.#guessedAltText;
  3531. if (this.#guessedAltText && this.#guessedAltText !== altText) {
  3532. const guessedWords = this.#extractWords(this.#guessedAltText);
  3533. const words = this.#extractWords(altText);
  3534. this.#currentEditor._reportTelemetry({
  3535. action: "pdfjs.image.alt_text.user_edit",
  3536. data: {
  3537. total_words: guessedWords.size,
  3538. words_removed: guessedWords.difference(words).size,
  3539. words_added: words.difference(guessedWords).size
  3540. }
  3541. });
  3542. }
  3543. this.#currentEditor._reportTelemetry({
  3544. action: "pdfjs.image.image_added",
  3545. data: {
  3546. alt_text_modal: true,
  3547. alt_text_type: altText ? "present" : "empty"
  3548. }
  3549. });
  3550. this.#currentEditor._reportTelemetry({
  3551. action: "pdfjs.image.alt_text.save",
  3552. data: {
  3553. alt_text_type: altText ? "present" : "empty",
  3554. flow: this.#firstTime ? "image_add" : "alt_text_edit"
  3555. }
  3556. });
  3557. this.#finish();
  3558. }
  3559. destroy() {
  3560. this.#uiManager = null;
  3561. this.#finish();
  3562. }
  3563. }
  3564. class ImageAltTextSettings {
  3565. #aiModelSettings;
  3566. #createModelButton;
  3567. #downloadModelButton;
  3568. #dialog;
  3569. #eventBus;
  3570. #mlManager;
  3571. #overlayManager;
  3572. #showAltTextDialogButton;
  3573. constructor({
  3574. dialog,
  3575. createModelButton,
  3576. aiModelSettings,
  3577. learnMore,
  3578. closeButton,
  3579. deleteModelButton,
  3580. downloadModelButton,
  3581. showAltTextDialogButton
  3582. }, overlayManager, eventBus, mlManager) {
  3583. this.#dialog = dialog;
  3584. this.#aiModelSettings = aiModelSettings;
  3585. this.#createModelButton = createModelButton;
  3586. this.#downloadModelButton = downloadModelButton;
  3587. this.#showAltTextDialogButton = showAltTextDialogButton;
  3588. this.#overlayManager = overlayManager;
  3589. this.#eventBus = eventBus;
  3590. this.#mlManager = mlManager;
  3591. const {
  3592. altTextLearnMoreUrl
  3593. } = mlManager;
  3594. if (altTextLearnMoreUrl) {
  3595. learnMore.href = altTextLearnMoreUrl;
  3596. }
  3597. dialog.addEventListener("contextmenu", noContextMenu);
  3598. createModelButton.addEventListener("click", async e => {
  3599. const checked = this.#togglePref("enableGuessAltText", e);
  3600. await mlManager.toggleService("altText", checked);
  3601. this.#reportTelemetry({
  3602. type: "stamp",
  3603. action: "pdfjs.image.alt_text.settings_ai_generation_check",
  3604. data: {
  3605. status: checked
  3606. }
  3607. });
  3608. });
  3609. showAltTextDialogButton.addEventListener("click", e => {
  3610. const checked = this.#togglePref("enableNewAltTextWhenAddingImage", e);
  3611. this.#reportTelemetry({
  3612. type: "stamp",
  3613. action: "pdfjs.image.alt_text.settings_edit_alt_text_check",
  3614. data: {
  3615. status: checked
  3616. }
  3617. });
  3618. });
  3619. deleteModelButton.addEventListener("click", this.#delete.bind(this, true));
  3620. downloadModelButton.addEventListener("click", this.#download.bind(this, true));
  3621. closeButton.addEventListener("click", this.#finish.bind(this));
  3622. learnMore.addEventListener("click", () => {
  3623. this.#reportTelemetry({
  3624. type: "stamp",
  3625. action: "pdfjs.image.alt_text.info",
  3626. data: {
  3627. topic: "ai_generation"
  3628. }
  3629. });
  3630. });
  3631. eventBus._on("enablealttextmodeldownload", ({
  3632. value
  3633. }) => {
  3634. if (value) {
  3635. this.#download(false);
  3636. } else {
  3637. this.#delete(false);
  3638. }
  3639. });
  3640. this.#overlayManager.register(dialog);
  3641. }
  3642. #reportTelemetry(data) {
  3643. this.#eventBus.dispatch("reporttelemetry", {
  3644. source: this,
  3645. details: {
  3646. type: "editing",
  3647. data
  3648. }
  3649. });
  3650. }
  3651. async #download(isFromUI = false) {
  3652. if (isFromUI) {
  3653. this.#downloadModelButton.disabled = true;
  3654. const span = this.#downloadModelButton.firstChild;
  3655. span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-downloading-model-button");
  3656. await this.#mlManager.downloadModel("altText");
  3657. span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-download-model-button");
  3658. this.#createModelButton.disabled = false;
  3659. this.#setPref("enableGuessAltText", true);
  3660. this.#mlManager.toggleService("altText", true);
  3661. this.#setPref("enableAltTextModelDownload", true);
  3662. this.#downloadModelButton.disabled = false;
  3663. }
  3664. this.#aiModelSettings.classList.toggle("download", false);
  3665. this.#createModelButton.setAttribute("aria-pressed", true);
  3666. }
  3667. async #delete(isFromUI = false) {
  3668. if (isFromUI) {
  3669. await this.#mlManager.deleteModel("altText");
  3670. this.#setPref("enableGuessAltText", false);
  3671. this.#setPref("enableAltTextModelDownload", false);
  3672. }
  3673. this.#aiModelSettings.classList.toggle("download", true);
  3674. this.#createModelButton.disabled = true;
  3675. this.#createModelButton.setAttribute("aria-pressed", false);
  3676. }
  3677. async open({
  3678. enableGuessAltText,
  3679. enableNewAltTextWhenAddingImage
  3680. }) {
  3681. const {
  3682. enableAltTextModelDownload
  3683. } = this.#mlManager;
  3684. this.#createModelButton.disabled = !enableAltTextModelDownload;
  3685. this.#createModelButton.setAttribute("aria-pressed", enableAltTextModelDownload && enableGuessAltText);
  3686. this.#showAltTextDialogButton.setAttribute("aria-pressed", enableNewAltTextWhenAddingImage);
  3687. this.#aiModelSettings.classList.toggle("download", !enableAltTextModelDownload);
  3688. await this.#overlayManager.open(this.#dialog);
  3689. this.#reportTelemetry({
  3690. type: "stamp",
  3691. action: "pdfjs.image.alt_text.settings_displayed"
  3692. });
  3693. }
  3694. #togglePref(name, {
  3695. target
  3696. }) {
  3697. const checked = target.getAttribute("aria-pressed") !== "true";
  3698. this.#setPref(name, checked);
  3699. target.setAttribute("aria-pressed", checked);
  3700. return checked;
  3701. }
  3702. #setPref(name, value) {
  3703. this.#eventBus.dispatch("setpreference", {
  3704. source: this,
  3705. name,
  3706. value
  3707. });
  3708. }
  3709. #finish() {
  3710. this.#overlayManager.closeIfActive(this.#dialog);
  3711. }
  3712. }
  3713. ;// ./web/alt_text_manager.js
  3714. class AltTextManager {
  3715. #clickAC = null;
  3716. #currentEditor = null;
  3717. #cancelButton;
  3718. #dialog;
  3719. #eventBus;
  3720. #hasUsedPointer = false;
  3721. #optionDescription;
  3722. #optionDecorative;
  3723. #overlayManager;
  3724. #saveButton;
  3725. #textarea;
  3726. #uiManager;
  3727. #previousAltText = null;
  3728. #resizeAC = null;
  3729. #svgElement = null;
  3730. #rectElement = null;
  3731. #container;
  3732. #telemetryData = null;
  3733. constructor({
  3734. dialog,
  3735. optionDescription,
  3736. optionDecorative,
  3737. textarea,
  3738. cancelButton,
  3739. saveButton
  3740. }, container, overlayManager, eventBus) {
  3741. this.#dialog = dialog;
  3742. this.#optionDescription = optionDescription;
  3743. this.#optionDecorative = optionDecorative;
  3744. this.#textarea = textarea;
  3745. this.#cancelButton = cancelButton;
  3746. this.#saveButton = saveButton;
  3747. this.#overlayManager = overlayManager;
  3748. this.#eventBus = eventBus;
  3749. this.#container = container;
  3750. const onUpdateUIState = this.#updateUIState.bind(this);
  3751. dialog.addEventListener("close", this.#close.bind(this));
  3752. dialog.addEventListener("contextmenu", event => {
  3753. if (event.target !== this.#textarea) {
  3754. event.preventDefault();
  3755. }
  3756. });
  3757. cancelButton.addEventListener("click", this.#finish.bind(this));
  3758. saveButton.addEventListener("click", this.#save.bind(this));
  3759. optionDescription.addEventListener("change", onUpdateUIState);
  3760. optionDecorative.addEventListener("change", onUpdateUIState);
  3761. this.#overlayManager.register(dialog);
  3762. }
  3763. #createSVGElement() {
  3764. if (this.#svgElement) {
  3765. return;
  3766. }
  3767. const svgFactory = new DOMSVGFactory();
  3768. const svg = this.#svgElement = svgFactory.createElement("svg");
  3769. svg.setAttribute("width", "0");
  3770. svg.setAttribute("height", "0");
  3771. const defs = svgFactory.createElement("defs");
  3772. svg.append(defs);
  3773. const mask = svgFactory.createElement("mask");
  3774. defs.append(mask);
  3775. mask.setAttribute("id", "alttext-manager-mask");
  3776. mask.setAttribute("maskContentUnits", "objectBoundingBox");
  3777. let rect = svgFactory.createElement("rect");
  3778. mask.append(rect);
  3779. rect.setAttribute("fill", "white");
  3780. rect.setAttribute("width", "1");
  3781. rect.setAttribute("height", "1");
  3782. rect.setAttribute("x", "0");
  3783. rect.setAttribute("y", "0");
  3784. rect = this.#rectElement = svgFactory.createElement("rect");
  3785. mask.append(rect);
  3786. rect.setAttribute("fill", "black");
  3787. this.#dialog.append(svg);
  3788. }
  3789. async editAltText(uiManager, editor) {
  3790. if (this.#currentEditor || !editor) {
  3791. return;
  3792. }
  3793. this.#createSVGElement();
  3794. this.#hasUsedPointer = false;
  3795. this.#clickAC = new AbortController();
  3796. const clickOpts = {
  3797. signal: this.#clickAC.signal
  3798. },
  3799. onClick = this.#onClick.bind(this);
  3800. for (const element of [this.#optionDescription, this.#optionDecorative, this.#textarea, this.#saveButton, this.#cancelButton]) {
  3801. element.addEventListener("click", onClick, clickOpts);
  3802. }
  3803. const {
  3804. altText,
  3805. decorative
  3806. } = editor.altTextData;
  3807. if (decorative === true) {
  3808. this.#optionDecorative.checked = true;
  3809. this.#optionDescription.checked = false;
  3810. } else {
  3811. this.#optionDecorative.checked = false;
  3812. this.#optionDescription.checked = true;
  3813. }
  3814. this.#previousAltText = this.#textarea.value = altText?.trim() || "";
  3815. this.#updateUIState();
  3816. this.#currentEditor = editor;
  3817. this.#uiManager = uiManager;
  3818. this.#uiManager.removeEditListeners();
  3819. this.#resizeAC = new AbortController();
  3820. this.#eventBus._on("resize", this.#setPosition.bind(this), {
  3821. signal: this.#resizeAC.signal
  3822. });
  3823. try {
  3824. await this.#overlayManager.open(this.#dialog);
  3825. this.#setPosition();
  3826. } catch (ex) {
  3827. this.#close();
  3828. throw ex;
  3829. }
  3830. }
  3831. #setPosition() {
  3832. if (!this.#currentEditor) {
  3833. return;
  3834. }
  3835. const dialog = this.#dialog;
  3836. const {
  3837. style
  3838. } = dialog;
  3839. const {
  3840. x: containerX,
  3841. y: containerY,
  3842. width: containerW,
  3843. height: containerH
  3844. } = this.#container.getBoundingClientRect();
  3845. const {
  3846. innerWidth: windowW,
  3847. innerHeight: windowH
  3848. } = window;
  3849. const {
  3850. width: dialogW,
  3851. height: dialogH
  3852. } = dialog.getBoundingClientRect();
  3853. const {
  3854. x,
  3855. y,
  3856. width,
  3857. height
  3858. } = this.#currentEditor.getClientDimensions();
  3859. const MARGIN = 10;
  3860. const isLTR = this.#uiManager.direction === "ltr";
  3861. const xs = Math.max(x, containerX);
  3862. const xe = Math.min(x + width, containerX + containerW);
  3863. const ys = Math.max(y, containerY);
  3864. const ye = Math.min(y + height, containerY + containerH);
  3865. this.#rectElement.setAttribute("width", `${(xe - xs) / windowW}`);
  3866. this.#rectElement.setAttribute("height", `${(ye - ys) / windowH}`);
  3867. this.#rectElement.setAttribute("x", `${xs / windowW}`);
  3868. this.#rectElement.setAttribute("y", `${ys / windowH}`);
  3869. let left = null;
  3870. let top = Math.max(y, 0);
  3871. top += Math.min(windowH - (top + dialogH), 0);
  3872. if (isLTR) {
  3873. if (x + width + MARGIN + dialogW < windowW) {
  3874. left = x + width + MARGIN;
  3875. } else if (x > dialogW + MARGIN) {
  3876. left = x - dialogW - MARGIN;
  3877. }
  3878. } else if (x > dialogW + MARGIN) {
  3879. left = x - dialogW - MARGIN;
  3880. } else if (x + width + MARGIN + dialogW < windowW) {
  3881. left = x + width + MARGIN;
  3882. }
  3883. if (left === null) {
  3884. top = null;
  3885. left = Math.max(x, 0);
  3886. left += Math.min(windowW - (left + dialogW), 0);
  3887. if (y > dialogH + MARGIN) {
  3888. top = y - dialogH - MARGIN;
  3889. } else if (y + height + MARGIN + dialogH < windowH) {
  3890. top = y + height + MARGIN;
  3891. }
  3892. }
  3893. if (top !== null) {
  3894. dialog.classList.add("positioned");
  3895. if (isLTR) {
  3896. style.left = `${left}px`;
  3897. } else {
  3898. style.right = `${windowW - left - dialogW}px`;
  3899. }
  3900. style.top = `${top}px`;
  3901. } else {
  3902. dialog.classList.remove("positioned");
  3903. style.left = "";
  3904. style.top = "";
  3905. }
  3906. }
  3907. #finish() {
  3908. this.#overlayManager.closeIfActive(this.#dialog);
  3909. }
  3910. #close() {
  3911. this.#currentEditor._reportTelemetry(this.#telemetryData || {
  3912. action: "alt_text_cancel",
  3913. alt_text_keyboard: !this.#hasUsedPointer
  3914. });
  3915. this.#telemetryData = null;
  3916. this.#removeOnClickListeners();
  3917. this.#uiManager?.addEditListeners();
  3918. this.#resizeAC?.abort();
  3919. this.#resizeAC = null;
  3920. this.#currentEditor.altTextFinish();
  3921. this.#currentEditor = null;
  3922. this.#uiManager = null;
  3923. }
  3924. #updateUIState() {
  3925. this.#textarea.disabled = this.#optionDecorative.checked;
  3926. }
  3927. #save() {
  3928. const altText = this.#textarea.value.trim();
  3929. const decorative = this.#optionDecorative.checked;
  3930. this.#currentEditor.altTextData = {
  3931. altText,
  3932. decorative
  3933. };
  3934. this.#telemetryData = {
  3935. action: "alt_text_save",
  3936. alt_text_description: !!altText,
  3937. alt_text_edit: !!this.#previousAltText && this.#previousAltText !== altText,
  3938. alt_text_decorative: decorative,
  3939. alt_text_keyboard: !this.#hasUsedPointer
  3940. };
  3941. this.#finish();
  3942. }
  3943. #onClick(evt) {
  3944. if (evt.detail === 0) {
  3945. return;
  3946. }
  3947. this.#hasUsedPointer = true;
  3948. this.#removeOnClickListeners();
  3949. }
  3950. #removeOnClickListeners() {
  3951. this.#clickAC?.abort();
  3952. this.#clickAC = null;
  3953. }
  3954. destroy() {
  3955. this.#uiManager = null;
  3956. this.#finish();
  3957. this.#svgElement?.remove();
  3958. this.#svgElement = this.#rectElement = null;
  3959. }
  3960. }
  3961. ;// ./web/annotation_editor_params.js
  3962. class AnnotationEditorParams {
  3963. constructor(options, eventBus) {
  3964. this.eventBus = eventBus;
  3965. this.#bindListeners(options);
  3966. }
  3967. #bindListeners({
  3968. editorFreeTextFontSize,
  3969. editorFreeTextColor,
  3970. editorInkColor,
  3971. editorInkThickness,
  3972. editorInkOpacity,
  3973. editorStampAddImage,
  3974. editorFreeHighlightThickness,
  3975. editorHighlightShowAll,
  3976. editorSignatureAddSignature
  3977. }) {
  3978. const {
  3979. eventBus
  3980. } = this;
  3981. const dispatchEvent = (typeStr, value) => {
  3982. eventBus.dispatch("switchannotationeditorparams", {
  3983. source: this,
  3984. type: AnnotationEditorParamsType[typeStr],
  3985. value
  3986. });
  3987. };
  3988. editorFreeTextFontSize.addEventListener("input", function () {
  3989. dispatchEvent("FREETEXT_SIZE", this.valueAsNumber);
  3990. });
  3991. editorFreeTextColor.addEventListener("input", function () {
  3992. dispatchEvent("FREETEXT_COLOR", this.value);
  3993. });
  3994. editorInkColor.addEventListener("input", function () {
  3995. dispatchEvent("INK_COLOR", this.value);
  3996. });
  3997. editorInkThickness.addEventListener("input", function () {
  3998. dispatchEvent("INK_THICKNESS", this.valueAsNumber);
  3999. });
  4000. editorInkOpacity.addEventListener("input", function () {
  4001. dispatchEvent("INK_OPACITY", this.valueAsNumber);
  4002. });
  4003. editorStampAddImage.addEventListener("click", () => {
  4004. eventBus.dispatch("reporttelemetry", {
  4005. source: this,
  4006. details: {
  4007. type: "editing",
  4008. data: {
  4009. action: "pdfjs.image.add_image_click"
  4010. }
  4011. }
  4012. });
  4013. dispatchEvent("CREATE");
  4014. });
  4015. editorFreeHighlightThickness.addEventListener("input", function () {
  4016. dispatchEvent("HIGHLIGHT_THICKNESS", this.valueAsNumber);
  4017. });
  4018. editorHighlightShowAll.addEventListener("click", function () {
  4019. const checked = this.getAttribute("aria-pressed") === "true";
  4020. this.setAttribute("aria-pressed", !checked);
  4021. dispatchEvent("HIGHLIGHT_SHOW_ALL", !checked);
  4022. });
  4023. editorSignatureAddSignature.addEventListener("click", () => {
  4024. dispatchEvent("CREATE");
  4025. });
  4026. eventBus._on("annotationeditorparamschanged", evt => {
  4027. for (const [type, value] of evt.details) {
  4028. switch (type) {
  4029. case AnnotationEditorParamsType.FREETEXT_SIZE:
  4030. editorFreeTextFontSize.value = value;
  4031. break;
  4032. case AnnotationEditorParamsType.FREETEXT_COLOR:
  4033. editorFreeTextColor.value = value;
  4034. break;
  4035. case AnnotationEditorParamsType.INK_COLOR:
  4036. editorInkColor.value = value;
  4037. break;
  4038. case AnnotationEditorParamsType.INK_THICKNESS:
  4039. editorInkThickness.value = value;
  4040. break;
  4041. case AnnotationEditorParamsType.INK_OPACITY:
  4042. editorInkOpacity.value = value;
  4043. break;
  4044. case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
  4045. eventBus.dispatch("mainhighlightcolorpickerupdatecolor", {
  4046. source: this,
  4047. value
  4048. });
  4049. break;
  4050. case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
  4051. editorFreeHighlightThickness.value = value;
  4052. break;
  4053. case AnnotationEditorParamsType.HIGHLIGHT_FREE:
  4054. editorFreeHighlightThickness.disabled = !value;
  4055. break;
  4056. case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
  4057. editorHighlightShowAll.setAttribute("aria-pressed", value);
  4058. break;
  4059. }
  4060. }
  4061. });
  4062. }
  4063. }
  4064. ;// ./web/caret_browsing.js
  4065. const PRECISION = 1e-1;
  4066. class CaretBrowsingMode {
  4067. #mainContainer;
  4068. #toolBarHeight = 0;
  4069. #viewerContainer;
  4070. constructor(abortSignal, mainContainer, viewerContainer, toolbarContainer) {
  4071. this.#mainContainer = mainContainer;
  4072. this.#viewerContainer = viewerContainer;
  4073. if (!toolbarContainer) {
  4074. return;
  4075. }
  4076. this.#toolBarHeight = toolbarContainer.getBoundingClientRect().height;
  4077. const toolbarObserver = new ResizeObserver(entries => {
  4078. for (const entry of entries) {
  4079. if (entry.target === toolbarContainer) {
  4080. this.#toolBarHeight = Math.floor(entry.borderBoxSize[0].blockSize);
  4081. break;
  4082. }
  4083. }
  4084. });
  4085. toolbarObserver.observe(toolbarContainer);
  4086. abortSignal.addEventListener("abort", () => toolbarObserver.disconnect(), {
  4087. once: true
  4088. });
  4089. }
  4090. #isOnSameLine(rect1, rect2) {
  4091. const top1 = rect1.y;
  4092. const bot1 = rect1.bottom;
  4093. const mid1 = rect1.y + rect1.height / 2;
  4094. const top2 = rect2.y;
  4095. const bot2 = rect2.bottom;
  4096. const mid2 = rect2.y + rect2.height / 2;
  4097. return top1 <= mid2 && mid2 <= bot1 || top2 <= mid1 && mid1 <= bot2;
  4098. }
  4099. #isUnderOver(rect, x, y, isUp) {
  4100. const midY = rect.y + rect.height / 2;
  4101. return (isUp ? y >= midY : y <= midY) && rect.x - PRECISION <= x && x <= rect.right + PRECISION;
  4102. }
  4103. #isVisible(rect) {
  4104. return rect.top >= this.#toolBarHeight && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
  4105. }
  4106. #getCaretPosition(selection, isUp) {
  4107. const {
  4108. focusNode,
  4109. focusOffset
  4110. } = selection;
  4111. const range = document.createRange();
  4112. range.setStart(focusNode, focusOffset);
  4113. range.setEnd(focusNode, focusOffset);
  4114. const rect = range.getBoundingClientRect();
  4115. return [rect.x, isUp ? rect.top : rect.bottom];
  4116. }
  4117. static #caretPositionFromPoint(x, y) {
  4118. if (!document.caretPositionFromPoint) {
  4119. const {
  4120. startContainer: offsetNode,
  4121. startOffset: offset
  4122. } = document.caretRangeFromPoint(x, y);
  4123. return {
  4124. offsetNode,
  4125. offset
  4126. };
  4127. }
  4128. return document.caretPositionFromPoint(x, y);
  4129. }
  4130. #setCaretPositionHelper(selection, caretX, select, element, rect) {
  4131. rect ||= element.getBoundingClientRect();
  4132. if (caretX <= rect.x + PRECISION) {
  4133. if (select) {
  4134. selection.extend(element.firstChild, 0);
  4135. } else {
  4136. selection.setPosition(element.firstChild, 0);
  4137. }
  4138. return;
  4139. }
  4140. if (rect.right - PRECISION <= caretX) {
  4141. const {
  4142. lastChild
  4143. } = element;
  4144. if (select) {
  4145. selection.extend(lastChild, lastChild.length);
  4146. } else {
  4147. selection.setPosition(lastChild, lastChild.length);
  4148. }
  4149. return;
  4150. }
  4151. const midY = rect.y + rect.height / 2;
  4152. let caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
  4153. let parentElement = caretPosition.offsetNode?.parentElement;
  4154. if (parentElement && parentElement !== element) {
  4155. const elementsAtPoint = document.elementsFromPoint(caretX, midY);
  4156. const savedVisibilities = [];
  4157. for (const el of elementsAtPoint) {
  4158. if (el === element) {
  4159. break;
  4160. }
  4161. const {
  4162. style
  4163. } = el;
  4164. savedVisibilities.push([el, style.visibility]);
  4165. style.visibility = "hidden";
  4166. }
  4167. caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
  4168. parentElement = caretPosition.offsetNode?.parentElement;
  4169. for (const [el, visibility] of savedVisibilities) {
  4170. el.style.visibility = visibility;
  4171. }
  4172. }
  4173. if (parentElement !== element) {
  4174. if (select) {
  4175. selection.extend(element.firstChild, 0);
  4176. } else {
  4177. selection.setPosition(element.firstChild, 0);
  4178. }
  4179. return;
  4180. }
  4181. if (select) {
  4182. selection.extend(caretPosition.offsetNode, caretPosition.offset);
  4183. } else {
  4184. selection.setPosition(caretPosition.offsetNode, caretPosition.offset);
  4185. }
  4186. }
  4187. #setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX) {
  4188. if (this.#isVisible(newLineElementRect)) {
  4189. this.#setCaretPositionHelper(selection, caretX, select, newLineElement, newLineElementRect);
  4190. return;
  4191. }
  4192. this.#mainContainer.addEventListener("scrollend", this.#setCaretPositionHelper.bind(this, selection, caretX, select, newLineElement, null), {
  4193. once: true
  4194. });
  4195. newLineElement.scrollIntoView();
  4196. }
  4197. #getNodeOnNextPage(textLayer, isUp) {
  4198. while (true) {
  4199. const page = textLayer.closest(".page");
  4200. const pageNumber = parseInt(page.getAttribute("data-page-number"));
  4201. const nextPage = isUp ? pageNumber - 1 : pageNumber + 1;
  4202. textLayer = this.#viewerContainer.querySelector(`.page[data-page-number="${nextPage}"] .textLayer`);
  4203. if (!textLayer) {
  4204. return null;
  4205. }
  4206. const walker = document.createTreeWalker(textLayer, NodeFilter.SHOW_TEXT);
  4207. const node = isUp ? walker.lastChild() : walker.firstChild();
  4208. if (node) {
  4209. return node;
  4210. }
  4211. }
  4212. }
  4213. moveCaret(isUp, select) {
  4214. const selection = document.getSelection();
  4215. if (selection.rangeCount === 0) {
  4216. return;
  4217. }
  4218. const {
  4219. focusNode
  4220. } = selection;
  4221. const focusElement = focusNode.nodeType !== Node.ELEMENT_NODE ? focusNode.parentElement : focusNode;
  4222. const root = focusElement.closest(".textLayer");
  4223. if (!root) {
  4224. return;
  4225. }
  4226. const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
  4227. walker.currentNode = focusNode;
  4228. const focusRect = focusElement.getBoundingClientRect();
  4229. let newLineElement = null;
  4230. const nodeIterator = (isUp ? walker.previousSibling : walker.nextSibling).bind(walker);
  4231. while (nodeIterator()) {
  4232. const element = walker.currentNode.parentElement;
  4233. if (!this.#isOnSameLine(focusRect, element.getBoundingClientRect())) {
  4234. newLineElement = element;
  4235. break;
  4236. }
  4237. }
  4238. if (!newLineElement) {
  4239. const node = this.#getNodeOnNextPage(root, isUp);
  4240. if (!node) {
  4241. return;
  4242. }
  4243. if (select) {
  4244. const lastNode = (isUp ? walker.firstChild() : walker.lastChild()) || focusNode;
  4245. selection.extend(lastNode, isUp ? 0 : lastNode.length);
  4246. const range = document.createRange();
  4247. range.setStart(node, isUp ? node.length : 0);
  4248. range.setEnd(node, isUp ? node.length : 0);
  4249. selection.addRange(range);
  4250. return;
  4251. }
  4252. const [caretX] = this.#getCaretPosition(selection, isUp);
  4253. const {
  4254. parentElement
  4255. } = node;
  4256. this.#setCaretPosition(select, selection, parentElement, parentElement.getBoundingClientRect(), caretX);
  4257. return;
  4258. }
  4259. const [caretX, caretY] = this.#getCaretPosition(selection, isUp);
  4260. const newLineElementRect = newLineElement.getBoundingClientRect();
  4261. if (this.#isUnderOver(newLineElementRect, caretX, caretY, isUp)) {
  4262. this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
  4263. return;
  4264. }
  4265. while (nodeIterator()) {
  4266. const element = walker.currentNode.parentElement;
  4267. const elementRect = element.getBoundingClientRect();
  4268. if (!this.#isOnSameLine(newLineElementRect, elementRect)) {
  4269. break;
  4270. }
  4271. if (this.#isUnderOver(elementRect, caretX, caretY, isUp)) {
  4272. this.#setCaretPosition(select, selection, element, elementRect, caretX);
  4273. return;
  4274. }
  4275. }
  4276. this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
  4277. }
  4278. }
  4279. ;// ./web/download_manager.js
  4280. function download(blobUrl, filename) {
  4281. const a = document.createElement("a");
  4282. if (!a.click) {
  4283. throw new Error('DownloadManager: "a.click()" is not supported.');
  4284. }
  4285. a.href = blobUrl;
  4286. a.target = "_parent";
  4287. if ("download" in a) {
  4288. a.download = filename;
  4289. }
  4290. (document.body || document.documentElement).append(a);
  4291. a.click();
  4292. a.remove();
  4293. }
  4294. class DownloadManager {
  4295. #openBlobUrls = new WeakMap();
  4296. downloadData(data, filename, contentType) {
  4297. const blobUrl = URL.createObjectURL(new Blob([data], {
  4298. type: contentType
  4299. }));
  4300. download(blobUrl, filename);
  4301. }
  4302. openOrDownloadData(data, filename, dest = null) {
  4303. const isPdfData = isPdfFile(filename);
  4304. const contentType = isPdfData ? "application/pdf" : "";
  4305. if (isPdfData) {
  4306. let blobUrl = this.#openBlobUrls.get(data);
  4307. if (!blobUrl) {
  4308. blobUrl = URL.createObjectURL(new Blob([data], {
  4309. type: contentType
  4310. }));
  4311. this.#openBlobUrls.set(data, blobUrl);
  4312. }
  4313. let viewerUrl;
  4314. viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename);
  4315. if (dest) {
  4316. viewerUrl += `#${escape(dest)}`;
  4317. }
  4318. try {
  4319. window.open(viewerUrl);
  4320. return true;
  4321. } catch (ex) {
  4322. console.error("openOrDownloadData:", ex);
  4323. URL.revokeObjectURL(blobUrl);
  4324. this.#openBlobUrls.delete(data);
  4325. }
  4326. }
  4327. this.downloadData(data, filename, contentType);
  4328. return false;
  4329. }
  4330. download(data, url, filename) {
  4331. let blobUrl;
  4332. if (data) {
  4333. blobUrl = URL.createObjectURL(new Blob([data], {
  4334. type: "application/pdf"
  4335. }));
  4336. } else {
  4337. if (!createValidAbsoluteUrl(url, "http://example.com")) {
  4338. console.error(`download - not a valid URL: ${url}`);
  4339. return;
  4340. }
  4341. blobUrl = url + "#pdfjs.action=download";
  4342. }
  4343. download(blobUrl, filename);
  4344. }
  4345. }
  4346. ;// ./web/editor_undo_bar.js
  4347. class EditorUndoBar {
  4348. #closeButton = null;
  4349. #container;
  4350. #eventBus = null;
  4351. #focusTimeout = null;
  4352. #initController = null;
  4353. isOpen = false;
  4354. #message;
  4355. #showController = null;
  4356. #undoButton;
  4357. static #l10nMessages = Object.freeze({
  4358. highlight: "pdfjs-editor-undo-bar-message-highlight",
  4359. freetext: "pdfjs-editor-undo-bar-message-freetext",
  4360. stamp: "pdfjs-editor-undo-bar-message-stamp",
  4361. ink: "pdfjs-editor-undo-bar-message-ink",
  4362. signature: "pdfjs-editor-undo-bar-message-signature",
  4363. _multiple: "pdfjs-editor-undo-bar-message-multiple"
  4364. });
  4365. constructor({
  4366. container,
  4367. message,
  4368. undoButton,
  4369. closeButton
  4370. }, eventBus) {
  4371. this.#container = container;
  4372. this.#message = message;
  4373. this.#undoButton = undoButton;
  4374. this.#closeButton = closeButton;
  4375. this.#eventBus = eventBus;
  4376. }
  4377. destroy() {
  4378. this.#initController?.abort();
  4379. this.#initController = null;
  4380. this.hide();
  4381. }
  4382. show(undoAction, messageData) {
  4383. if (!this.#initController) {
  4384. this.#initController = new AbortController();
  4385. const opts = {
  4386. signal: this.#initController.signal
  4387. };
  4388. const boundHide = this.hide.bind(this);
  4389. this.#container.addEventListener("contextmenu", noContextMenu, opts);
  4390. this.#closeButton.addEventListener("click", boundHide, opts);
  4391. this.#eventBus._on("beforeprint", boundHide, opts);
  4392. this.#eventBus._on("download", boundHide, opts);
  4393. }
  4394. this.hide();
  4395. if (typeof messageData === "string") {
  4396. this.#message.setAttribute("data-l10n-id", EditorUndoBar.#l10nMessages[messageData]);
  4397. } else {
  4398. this.#message.setAttribute("data-l10n-id", EditorUndoBar.#l10nMessages._multiple);
  4399. this.#message.setAttribute("data-l10n-args", JSON.stringify({
  4400. count: messageData
  4401. }));
  4402. }
  4403. this.isOpen = true;
  4404. this.#container.hidden = false;
  4405. this.#showController = new AbortController();
  4406. this.#undoButton.addEventListener("click", () => {
  4407. undoAction();
  4408. this.hide();
  4409. }, {
  4410. signal: this.#showController.signal
  4411. });
  4412. this.#focusTimeout = setTimeout(() => {
  4413. this.#container.focus();
  4414. this.#focusTimeout = null;
  4415. }, 100);
  4416. }
  4417. hide() {
  4418. if (!this.isOpen) {
  4419. return;
  4420. }
  4421. this.isOpen = false;
  4422. this.#container.hidden = true;
  4423. this.#showController?.abort();
  4424. this.#showController = null;
  4425. if (this.#focusTimeout) {
  4426. clearTimeout(this.#focusTimeout);
  4427. this.#focusTimeout = null;
  4428. }
  4429. }
  4430. }
  4431. ;// ./web/overlay_manager.js
  4432. class OverlayManager {
  4433. #overlays = new WeakMap();
  4434. #active = null;
  4435. get active() {
  4436. return this.#active;
  4437. }
  4438. async register(dialog, canForceClose = false) {
  4439. if (typeof dialog !== "object") {
  4440. throw new Error("Not enough parameters.");
  4441. } else if (this.#overlays.has(dialog)) {
  4442. throw new Error("The overlay is already registered.");
  4443. }
  4444. this.#overlays.set(dialog, {
  4445. canForceClose
  4446. });
  4447. dialog.addEventListener("cancel", ({
  4448. target
  4449. }) => {
  4450. if (this.#active === target) {
  4451. this.#active = null;
  4452. }
  4453. });
  4454. }
  4455. async open(dialog) {
  4456. if (!this.#overlays.has(dialog)) {
  4457. throw new Error("The overlay does not exist.");
  4458. } else if (this.#active) {
  4459. if (this.#active === dialog) {
  4460. throw new Error("The overlay is already active.");
  4461. } else if (this.#overlays.get(dialog).canForceClose) {
  4462. await this.close();
  4463. } else {
  4464. throw new Error("Another overlay is currently active.");
  4465. }
  4466. }
  4467. this.#active = dialog;
  4468. dialog.showModal();
  4469. }
  4470. async close(dialog = this.#active) {
  4471. if (!this.#overlays.has(dialog)) {
  4472. throw new Error("The overlay does not exist.");
  4473. } else if (!this.#active) {
  4474. throw new Error("The overlay is currently not active.");
  4475. } else if (this.#active !== dialog) {
  4476. throw new Error("Another overlay is currently active.");
  4477. }
  4478. dialog.close();
  4479. this.#active = null;
  4480. }
  4481. async closeIfActive(dialog) {
  4482. if (this.#active === dialog) {
  4483. await this.close(dialog);
  4484. }
  4485. }
  4486. }
  4487. ;// ./web/password_prompt.js
  4488. class PasswordPrompt {
  4489. #activeCapability = null;
  4490. #updateCallback = null;
  4491. #reason = null;
  4492. constructor(options, overlayManager, isViewerEmbedded = false) {
  4493. this.dialog = options.dialog;
  4494. this.label = options.label;
  4495. this.input = options.input;
  4496. this.submitButton = options.submitButton;
  4497. this.cancelButton = options.cancelButton;
  4498. this.overlayManager = overlayManager;
  4499. this._isViewerEmbedded = isViewerEmbedded;
  4500. this.submitButton.addEventListener("click", this.#verify.bind(this));
  4501. this.cancelButton.addEventListener("click", this.close.bind(this));
  4502. this.input.addEventListener("keydown", e => {
  4503. if (e.keyCode === 13) {
  4504. this.#verify();
  4505. }
  4506. });
  4507. this.overlayManager.register(this.dialog, true);
  4508. this.dialog.addEventListener("close", this.#cancel.bind(this));
  4509. }
  4510. async open() {
  4511. await this.#activeCapability?.promise;
  4512. this.#activeCapability = Promise.withResolvers();
  4513. try {
  4514. await this.overlayManager.open(this.dialog);
  4515. } catch (ex) {
  4516. this.#activeCapability.resolve();
  4517. throw ex;
  4518. }
  4519. const passwordIncorrect = this.#reason === PasswordResponses.INCORRECT_PASSWORD;
  4520. if (!this._isViewerEmbedded || passwordIncorrect) {
  4521. this.input.focus();
  4522. }
  4523. this.label.setAttribute("data-l10n-id", passwordIncorrect ? "pdfjs-password-invalid" : "pdfjs-password-label");
  4524. }
  4525. async close() {
  4526. this.overlayManager.closeIfActive(this.dialog);
  4527. }
  4528. #verify() {
  4529. const password = this.input.value;
  4530. if (password?.length > 0) {
  4531. this.#invokeCallback(password);
  4532. }
  4533. }
  4534. #cancel() {
  4535. this.#invokeCallback(new Error("PasswordPrompt cancelled."));
  4536. this.#activeCapability.resolve();
  4537. }
  4538. #invokeCallback(password) {
  4539. if (!this.#updateCallback) {
  4540. return;
  4541. }
  4542. this.close();
  4543. this.input.value = "";
  4544. this.#updateCallback(password);
  4545. this.#updateCallback = null;
  4546. }
  4547. async setUpdateCallback(updateCallback, reason) {
  4548. if (this.#activeCapability) {
  4549. await this.#activeCapability.promise;
  4550. }
  4551. this.#updateCallback = updateCallback;
  4552. this.#reason = reason;
  4553. }
  4554. }
  4555. ;// ./web/base_tree_viewer.js
  4556. const TREEITEM_OFFSET_TOP = -100;
  4557. const TREEITEM_SELECTED_CLASS = "selected";
  4558. class BaseTreeViewer {
  4559. constructor(options) {
  4560. this.container = options.container;
  4561. this.eventBus = options.eventBus;
  4562. this._l10n = options.l10n;
  4563. this.reset();
  4564. }
  4565. reset() {
  4566. this._pdfDocument = null;
  4567. this._lastToggleIsShow = true;
  4568. this._currentTreeItem = null;
  4569. this.container.textContent = "";
  4570. this.container.classList.remove("treeWithDeepNesting");
  4571. }
  4572. _dispatchEvent(count) {
  4573. throw new Error("Not implemented: _dispatchEvent");
  4574. }
  4575. _bindLink(element, params) {
  4576. throw new Error("Not implemented: _bindLink");
  4577. }
  4578. _normalizeTextContent(str) {
  4579. return removeNullCharacters(str, true) || "\u2013";
  4580. }
  4581. _addToggleButton(div, hidden = false) {
  4582. const toggler = document.createElement("div");
  4583. toggler.className = "treeItemToggler";
  4584. if (hidden) {
  4585. toggler.classList.add("treeItemsHidden");
  4586. }
  4587. toggler.onclick = evt => {
  4588. evt.stopPropagation();
  4589. toggler.classList.toggle("treeItemsHidden");
  4590. if (evt.shiftKey) {
  4591. const shouldShowAll = !toggler.classList.contains("treeItemsHidden");
  4592. this._toggleTreeItem(div, shouldShowAll);
  4593. }
  4594. };
  4595. div.prepend(toggler);
  4596. }
  4597. _toggleTreeItem(root, show = false) {
  4598. this._l10n.pause();
  4599. this._lastToggleIsShow = show;
  4600. for (const toggler of root.querySelectorAll(".treeItemToggler")) {
  4601. toggler.classList.toggle("treeItemsHidden", !show);
  4602. }
  4603. this._l10n.resume();
  4604. }
  4605. _toggleAllTreeItems() {
  4606. this._toggleTreeItem(this.container, !this._lastToggleIsShow);
  4607. }
  4608. _finishRendering(fragment, count, hasAnyNesting = false) {
  4609. if (hasAnyNesting) {
  4610. this.container.classList.add("treeWithDeepNesting");
  4611. this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden");
  4612. }
  4613. this._l10n.pause();
  4614. this.container.append(fragment);
  4615. this._l10n.resume();
  4616. this._dispatchEvent(count);
  4617. }
  4618. render(params) {
  4619. throw new Error("Not implemented: render");
  4620. }
  4621. _updateCurrentTreeItem(treeItem = null) {
  4622. if (this._currentTreeItem) {
  4623. this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS);
  4624. this._currentTreeItem = null;
  4625. }
  4626. if (treeItem) {
  4627. treeItem.classList.add(TREEITEM_SELECTED_CLASS);
  4628. this._currentTreeItem = treeItem;
  4629. }
  4630. }
  4631. _scrollToCurrentTreeItem(treeItem) {
  4632. if (!treeItem) {
  4633. return;
  4634. }
  4635. this._l10n.pause();
  4636. let currentNode = treeItem.parentNode;
  4637. while (currentNode && currentNode !== this.container) {
  4638. if (currentNode.classList.contains("treeItem")) {
  4639. const toggler = currentNode.firstElementChild;
  4640. toggler?.classList.remove("treeItemsHidden");
  4641. }
  4642. currentNode = currentNode.parentNode;
  4643. }
  4644. this._l10n.resume();
  4645. this._updateCurrentTreeItem(treeItem);
  4646. this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP);
  4647. }
  4648. }
  4649. ;// ./web/pdf_attachment_viewer.js
  4650. class PDFAttachmentViewer extends BaseTreeViewer {
  4651. constructor(options) {
  4652. super(options);
  4653. this.downloadManager = options.downloadManager;
  4654. this.eventBus._on("fileattachmentannotation", this.#appendAttachment.bind(this));
  4655. }
  4656. reset(keepRenderedCapability = false) {
  4657. super.reset();
  4658. this._attachments = null;
  4659. if (!keepRenderedCapability) {
  4660. this._renderedCapability = Promise.withResolvers();
  4661. }
  4662. this._pendingDispatchEvent = false;
  4663. }
  4664. async _dispatchEvent(attachmentsCount) {
  4665. this._renderedCapability.resolve();
  4666. if (attachmentsCount === 0 && !this._pendingDispatchEvent) {
  4667. this._pendingDispatchEvent = true;
  4668. await waitOnEventOrTimeout({
  4669. target: this.eventBus,
  4670. name: "annotationlayerrendered",
  4671. delay: 1000
  4672. });
  4673. if (!this._pendingDispatchEvent) {
  4674. return;
  4675. }
  4676. }
  4677. this._pendingDispatchEvent = false;
  4678. this.eventBus.dispatch("attachmentsloaded", {
  4679. source: this,
  4680. attachmentsCount
  4681. });
  4682. }
  4683. _bindLink(element, {
  4684. content,
  4685. description,
  4686. filename
  4687. }) {
  4688. if (description) {
  4689. element.title = description;
  4690. }
  4691. element.onclick = () => {
  4692. this.downloadManager.openOrDownloadData(content, filename);
  4693. return false;
  4694. };
  4695. }
  4696. render({
  4697. attachments,
  4698. keepRenderedCapability = false
  4699. }) {
  4700. if (this._attachments) {
  4701. this.reset(keepRenderedCapability);
  4702. }
  4703. this._attachments = attachments || null;
  4704. if (!attachments) {
  4705. this._dispatchEvent(0);
  4706. return;
  4707. }
  4708. const fragment = document.createDocumentFragment();
  4709. let attachmentsCount = 0;
  4710. for (const name in attachments) {
  4711. const item = attachments[name];
  4712. const div = document.createElement("div");
  4713. div.className = "treeItem";
  4714. const element = document.createElement("a");
  4715. this._bindLink(element, item);
  4716. element.textContent = this._normalizeTextContent(item.filename);
  4717. div.append(element);
  4718. fragment.append(div);
  4719. attachmentsCount++;
  4720. }
  4721. this._finishRendering(fragment, attachmentsCount);
  4722. }
  4723. #appendAttachment(item) {
  4724. const renderedPromise = this._renderedCapability.promise;
  4725. renderedPromise.then(() => {
  4726. if (renderedPromise !== this._renderedCapability.promise) {
  4727. return;
  4728. }
  4729. const attachments = this._attachments || Object.create(null);
  4730. for (const name in attachments) {
  4731. if (item.filename === name) {
  4732. return;
  4733. }
  4734. }
  4735. attachments[item.filename] = item;
  4736. this.render({
  4737. attachments,
  4738. keepRenderedCapability: true
  4739. });
  4740. });
  4741. }
  4742. }
  4743. ;// ./web/grab_to_pan.js
  4744. const CSS_CLASS_GRAB = "grab-to-pan-grab";
  4745. class GrabToPan {
  4746. #activateAC = null;
  4747. #mouseDownAC = null;
  4748. #scrollAC = null;
  4749. constructor({
  4750. element
  4751. }) {
  4752. this.element = element;
  4753. this.document = element.ownerDocument;
  4754. const overlay = this.overlay = document.createElement("div");
  4755. overlay.className = "grab-to-pan-grabbing";
  4756. }
  4757. activate() {
  4758. if (!this.#activateAC) {
  4759. this.#activateAC = new AbortController();
  4760. this.element.addEventListener("mousedown", this.#onMouseDown.bind(this), {
  4761. capture: true,
  4762. signal: this.#activateAC.signal
  4763. });
  4764. this.element.classList.add(CSS_CLASS_GRAB);
  4765. }
  4766. }
  4767. deactivate() {
  4768. if (this.#activateAC) {
  4769. this.#activateAC.abort();
  4770. this.#activateAC = null;
  4771. this.#endPan();
  4772. this.element.classList.remove(CSS_CLASS_GRAB);
  4773. }
  4774. }
  4775. toggle() {
  4776. if (this.#activateAC) {
  4777. this.deactivate();
  4778. } else {
  4779. this.activate();
  4780. }
  4781. }
  4782. ignoreTarget(node) {
  4783. return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option");
  4784. }
  4785. #onMouseDown(event) {
  4786. if (event.button !== 0 || this.ignoreTarget(event.target)) {
  4787. return;
  4788. }
  4789. if (event.originalTarget) {
  4790. try {
  4791. event.originalTarget.tagName;
  4792. } catch {
  4793. return;
  4794. }
  4795. }
  4796. this.scrollLeftStart = this.element.scrollLeft;
  4797. this.scrollTopStart = this.element.scrollTop;
  4798. this.clientXStart = event.clientX;
  4799. this.clientYStart = event.clientY;
  4800. this.#mouseDownAC = new AbortController();
  4801. const boundEndPan = this.#endPan.bind(this),
  4802. mouseOpts = {
  4803. capture: true,
  4804. signal: this.#mouseDownAC.signal
  4805. };
  4806. this.document.addEventListener("mousemove", this.#onMouseMove.bind(this), mouseOpts);
  4807. this.document.addEventListener("mouseup", boundEndPan, mouseOpts);
  4808. this.#scrollAC = new AbortController();
  4809. this.element.addEventListener("scroll", boundEndPan, {
  4810. capture: true,
  4811. signal: this.#scrollAC.signal
  4812. });
  4813. stopEvent(event);
  4814. const focusedElement = document.activeElement;
  4815. if (focusedElement && !focusedElement.contains(event.target)) {
  4816. focusedElement.blur();
  4817. }
  4818. }
  4819. #onMouseMove(event) {
  4820. this.#scrollAC?.abort();
  4821. this.#scrollAC = null;
  4822. if (!(event.buttons & 1)) {
  4823. this.#endPan();
  4824. return;
  4825. }
  4826. const xDiff = event.clientX - this.clientXStart;
  4827. const yDiff = event.clientY - this.clientYStart;
  4828. this.element.scrollTo({
  4829. top: this.scrollTopStart - yDiff,
  4830. left: this.scrollLeftStart - xDiff,
  4831. behavior: "instant"
  4832. });
  4833. if (!this.overlay.parentNode) {
  4834. document.body.append(this.overlay);
  4835. }
  4836. }
  4837. #endPan() {
  4838. this.#mouseDownAC?.abort();
  4839. this.#mouseDownAC = null;
  4840. this.#scrollAC?.abort();
  4841. this.#scrollAC = null;
  4842. this.overlay.remove();
  4843. }
  4844. }
  4845. ;// ./web/pdf_cursor_tools.js
  4846. class PDFCursorTools {
  4847. #active = CursorTool.SELECT;
  4848. #prevActive = null;
  4849. constructor({
  4850. container,
  4851. eventBus,
  4852. cursorToolOnLoad = CursorTool.SELECT
  4853. }) {
  4854. this.container = container;
  4855. this.eventBus = eventBus;
  4856. this.#addEventListeners();
  4857. Promise.resolve().then(() => {
  4858. this.switchTool(cursorToolOnLoad);
  4859. });
  4860. }
  4861. get activeTool() {
  4862. return this.#active;
  4863. }
  4864. switchTool(tool) {
  4865. if (this.#prevActive !== null) {
  4866. return;
  4867. }
  4868. this.#switchTool(tool);
  4869. }
  4870. #switchTool(tool, disabled = false) {
  4871. if (tool === this.#active) {
  4872. if (this.#prevActive !== null) {
  4873. this.eventBus.dispatch("cursortoolchanged", {
  4874. source: this,
  4875. tool,
  4876. disabled
  4877. });
  4878. }
  4879. return;
  4880. }
  4881. const disableActiveTool = () => {
  4882. switch (this.#active) {
  4883. case CursorTool.SELECT:
  4884. break;
  4885. case CursorTool.HAND:
  4886. this._handTool.deactivate();
  4887. break;
  4888. case CursorTool.ZOOM:
  4889. }
  4890. };
  4891. switch (tool) {
  4892. case CursorTool.SELECT:
  4893. disableActiveTool();
  4894. break;
  4895. case CursorTool.HAND:
  4896. disableActiveTool();
  4897. this._handTool.activate();
  4898. break;
  4899. case CursorTool.ZOOM:
  4900. default:
  4901. console.error(`switchTool: "${tool}" is an unsupported value.`);
  4902. return;
  4903. }
  4904. this.#active = tool;
  4905. this.eventBus.dispatch("cursortoolchanged", {
  4906. source: this,
  4907. tool,
  4908. disabled
  4909. });
  4910. }
  4911. #addEventListeners() {
  4912. this.eventBus._on("switchcursortool", evt => {
  4913. if (!evt.reset) {
  4914. this.switchTool(evt.tool);
  4915. } else if (this.#prevActive !== null) {
  4916. annotationEditorMode = AnnotationEditorType.NONE;
  4917. presentationModeState = PresentationModeState.NORMAL;
  4918. enableActive();
  4919. }
  4920. });
  4921. let annotationEditorMode = AnnotationEditorType.NONE,
  4922. presentationModeState = PresentationModeState.NORMAL;
  4923. const disableActive = () => {
  4924. this.#prevActive ??= this.#active;
  4925. this.#switchTool(CursorTool.SELECT, true);
  4926. };
  4927. const enableActive = () => {
  4928. if (this.#prevActive !== null && annotationEditorMode === AnnotationEditorType.NONE && presentationModeState === PresentationModeState.NORMAL) {
  4929. this.#switchTool(this.#prevActive);
  4930. this.#prevActive = null;
  4931. }
  4932. };
  4933. this.eventBus._on("annotationeditormodechanged", ({
  4934. mode
  4935. }) => {
  4936. annotationEditorMode = mode;
  4937. if (mode === AnnotationEditorType.NONE) {
  4938. enableActive();
  4939. } else {
  4940. disableActive();
  4941. }
  4942. });
  4943. this.eventBus._on("presentationmodechanged", ({
  4944. state
  4945. }) => {
  4946. presentationModeState = state;
  4947. if (state === PresentationModeState.NORMAL) {
  4948. enableActive();
  4949. } else if (state === PresentationModeState.FULLSCREEN) {
  4950. disableActive();
  4951. }
  4952. });
  4953. }
  4954. get _handTool() {
  4955. return shadow(this, "_handTool", new GrabToPan({
  4956. element: this.container
  4957. }));
  4958. }
  4959. }
  4960. ;// ./web/pdf_document_properties.js
  4961. const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"];
  4962. const US_PAGE_NAMES = {
  4963. "8.5x11": "pdfjs-document-properties-page-size-name-letter",
  4964. "8.5x14": "pdfjs-document-properties-page-size-name-legal"
  4965. };
  4966. const METRIC_PAGE_NAMES = {
  4967. "297x420": "pdfjs-document-properties-page-size-name-a-three",
  4968. "210x297": "pdfjs-document-properties-page-size-name-a-four"
  4969. };
  4970. function getPageName(size, isPortrait, pageNames) {
  4971. const width = isPortrait ? size.width : size.height;
  4972. const height = isPortrait ? size.height : size.width;
  4973. return pageNames[`${width}x${height}`];
  4974. }
  4975. class PDFDocumentProperties {
  4976. #fieldData = null;
  4977. constructor({
  4978. dialog,
  4979. fields,
  4980. closeButton
  4981. }, overlayManager, eventBus, l10n, fileNameLookup) {
  4982. this.dialog = dialog;
  4983. this.fields = fields;
  4984. this.overlayManager = overlayManager;
  4985. this.l10n = l10n;
  4986. this._fileNameLookup = fileNameLookup;
  4987. this.#reset();
  4988. closeButton.addEventListener("click", this.close.bind(this));
  4989. this.overlayManager.register(this.dialog);
  4990. eventBus._on("pagechanging", evt => {
  4991. this._currentPageNumber = evt.pageNumber;
  4992. });
  4993. eventBus._on("rotationchanging", evt => {
  4994. this._pagesRotation = evt.pagesRotation;
  4995. });
  4996. }
  4997. async open() {
  4998. await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]);
  4999. const currentPageNumber = this._currentPageNumber;
  5000. const pagesRotation = this._pagesRotation;
  5001. if (this.#fieldData && currentPageNumber === this.#fieldData._currentPageNumber && pagesRotation === this.#fieldData._pagesRotation) {
  5002. this.#updateUI();
  5003. return;
  5004. }
  5005. const [{
  5006. info,
  5007. contentLength
  5008. }, pdfPage] = await Promise.all([this.pdfDocument.getMetadata(), this.pdfDocument.getPage(currentPageNumber)]);
  5009. const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), this.#parseFileSize(contentLength), this.#parseDate(info.CreationDate), this.#parseDate(info.ModDate), this.#parsePageSize(getPageSizeInches(pdfPage), pagesRotation), this.#parseLinearization(info.IsLinearized)]);
  5010. this.#fieldData = Object.freeze({
  5011. fileName,
  5012. fileSize,
  5013. title: info.Title,
  5014. author: info.Author,
  5015. subject: info.Subject,
  5016. keywords: info.Keywords,
  5017. creationDate,
  5018. modificationDate,
  5019. creator: info.Creator,
  5020. producer: info.Producer,
  5021. version: info.PDFFormatVersion,
  5022. pageCount: this.pdfDocument.numPages,
  5023. pageSize,
  5024. linearized: isLinearized,
  5025. _currentPageNumber: currentPageNumber,
  5026. _pagesRotation: pagesRotation
  5027. });
  5028. this.#updateUI();
  5029. const {
  5030. length
  5031. } = await this.pdfDocument.getDownloadInfo();
  5032. if (contentLength === length) {
  5033. return;
  5034. }
  5035. const data = Object.assign(Object.create(null), this.#fieldData);
  5036. data.fileSize = await this.#parseFileSize(length);
  5037. this.#fieldData = Object.freeze(data);
  5038. this.#updateUI();
  5039. }
  5040. async close() {
  5041. this.overlayManager.close(this.dialog);
  5042. }
  5043. setDocument(pdfDocument) {
  5044. if (this.pdfDocument) {
  5045. this.#reset();
  5046. this.#updateUI();
  5047. }
  5048. if (!pdfDocument) {
  5049. return;
  5050. }
  5051. this.pdfDocument = pdfDocument;
  5052. this._dataAvailableCapability.resolve();
  5053. }
  5054. #reset() {
  5055. this.pdfDocument = null;
  5056. this.#fieldData = null;
  5057. this._dataAvailableCapability = Promise.withResolvers();
  5058. this._currentPageNumber = 1;
  5059. this._pagesRotation = 0;
  5060. }
  5061. #updateUI() {
  5062. if (this.#fieldData && this.overlayManager.active !== this.dialog) {
  5063. return;
  5064. }
  5065. for (const id in this.fields) {
  5066. const content = this.#fieldData?.[id];
  5067. this.fields[id].textContent = content || content === 0 ? content : "-";
  5068. }
  5069. }
  5070. async #parseFileSize(b = 0) {
  5071. const kb = b / 1024,
  5072. mb = kb / 1024;
  5073. return kb ? this.l10n.get(mb >= 1 ? "pdfjs-document-properties-size-mb" : "pdfjs-document-properties-size-kb", {
  5074. mb,
  5075. kb,
  5076. b
  5077. }) : undefined;
  5078. }
  5079. async #parsePageSize(pageSizeInches, pagesRotation) {
  5080. if (!pageSizeInches) {
  5081. return undefined;
  5082. }
  5083. if (pagesRotation % 180 !== 0) {
  5084. pageSizeInches = {
  5085. width: pageSizeInches.height,
  5086. height: pageSizeInches.width
  5087. };
  5088. }
  5089. const isPortrait = isPortraitOrientation(pageSizeInches),
  5090. nonMetric = NON_METRIC_LOCALES.includes(this.l10n.getLanguage());
  5091. let sizeInches = {
  5092. width: Math.round(pageSizeInches.width * 100) / 100,
  5093. height: Math.round(pageSizeInches.height * 100) / 100
  5094. };
  5095. let sizeMillimeters = {
  5096. width: Math.round(pageSizeInches.width * 25.4 * 10) / 10,
  5097. height: Math.round(pageSizeInches.height * 25.4 * 10) / 10
  5098. };
  5099. let nameId = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES);
  5100. if (!nameId && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) {
  5101. const exactMillimeters = {
  5102. width: pageSizeInches.width * 25.4,
  5103. height: pageSizeInches.height * 25.4
  5104. };
  5105. const intMillimeters = {
  5106. width: Math.round(sizeMillimeters.width),
  5107. height: Math.round(sizeMillimeters.height)
  5108. };
  5109. if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) {
  5110. nameId = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES);
  5111. if (nameId) {
  5112. sizeInches = {
  5113. width: Math.round(intMillimeters.width / 25.4 * 100) / 100,
  5114. height: Math.round(intMillimeters.height / 25.4 * 100) / 100
  5115. };
  5116. sizeMillimeters = intMillimeters;
  5117. }
  5118. }
  5119. }
  5120. const [{
  5121. width,
  5122. height
  5123. }, unit, name, orientation] = await Promise.all([nonMetric ? sizeInches : sizeMillimeters, this.l10n.get(nonMetric ? "pdfjs-document-properties-page-size-unit-inches" : "pdfjs-document-properties-page-size-unit-millimeters"), nameId && this.l10n.get(nameId), this.l10n.get(isPortrait ? "pdfjs-document-properties-page-size-orientation-portrait" : "pdfjs-document-properties-page-size-orientation-landscape")]);
  5124. return this.l10n.get(name ? "pdfjs-document-properties-page-size-dimension-name-string" : "pdfjs-document-properties-page-size-dimension-string", {
  5125. width,
  5126. height,
  5127. unit,
  5128. name,
  5129. orientation
  5130. });
  5131. }
  5132. async #parseDate(inputDate) {
  5133. const dateObj = PDFDateString.toDateObject(inputDate);
  5134. return dateObj ? this.l10n.get("pdfjs-document-properties-date-time-string", {
  5135. dateObj: dateObj.valueOf()
  5136. }) : undefined;
  5137. }
  5138. #parseLinearization(isLinearized) {
  5139. return this.l10n.get(isLinearized ? "pdfjs-document-properties-linearized-yes" : "pdfjs-document-properties-linearized-no");
  5140. }
  5141. }
  5142. ;// ./web/pdf_find_utils.js
  5143. const CharacterType = {
  5144. SPACE: 0,
  5145. ALPHA_LETTER: 1,
  5146. PUNCT: 2,
  5147. HAN_LETTER: 3,
  5148. KATAKANA_LETTER: 4,
  5149. HIRAGANA_LETTER: 5,
  5150. HALFWIDTH_KATAKANA_LETTER: 6,
  5151. THAI_LETTER: 7
  5152. };
  5153. function isAlphabeticalScript(charCode) {
  5154. return charCode < 0x2e80;
  5155. }
  5156. function isAscii(charCode) {
  5157. return (charCode & 0xff80) === 0;
  5158. }
  5159. function isAsciiAlpha(charCode) {
  5160. return charCode >= 0x61 && charCode <= 0x7a || charCode >= 0x41 && charCode <= 0x5a;
  5161. }
  5162. function isAsciiDigit(charCode) {
  5163. return charCode >= 0x30 && charCode <= 0x39;
  5164. }
  5165. function isAsciiSpace(charCode) {
  5166. return charCode === 0x20 || charCode === 0x09 || charCode === 0x0d || charCode === 0x0a;
  5167. }
  5168. function isHan(charCode) {
  5169. return charCode >= 0x3400 && charCode <= 0x9fff || charCode >= 0xf900 && charCode <= 0xfaff;
  5170. }
  5171. function isKatakana(charCode) {
  5172. return charCode >= 0x30a0 && charCode <= 0x30ff;
  5173. }
  5174. function isHiragana(charCode) {
  5175. return charCode >= 0x3040 && charCode <= 0x309f;
  5176. }
  5177. function isHalfwidthKatakana(charCode) {
  5178. return charCode >= 0xff60 && charCode <= 0xff9f;
  5179. }
  5180. function isThai(charCode) {
  5181. return (charCode & 0xff80) === 0x0e00;
  5182. }
  5183. function getCharacterType(charCode) {
  5184. if (isAlphabeticalScript(charCode)) {
  5185. if (isAscii(charCode)) {
  5186. if (isAsciiSpace(charCode)) {
  5187. return CharacterType.SPACE;
  5188. } else if (isAsciiAlpha(charCode) || isAsciiDigit(charCode) || charCode === 0x5f) {
  5189. return CharacterType.ALPHA_LETTER;
  5190. }
  5191. return CharacterType.PUNCT;
  5192. } else if (isThai(charCode)) {
  5193. return CharacterType.THAI_LETTER;
  5194. } else if (charCode === 0xa0) {
  5195. return CharacterType.SPACE;
  5196. }
  5197. return CharacterType.ALPHA_LETTER;
  5198. }
  5199. if (isHan(charCode)) {
  5200. return CharacterType.HAN_LETTER;
  5201. } else if (isKatakana(charCode)) {
  5202. return CharacterType.KATAKANA_LETTER;
  5203. } else if (isHiragana(charCode)) {
  5204. return CharacterType.HIRAGANA_LETTER;
  5205. } else if (isHalfwidthKatakana(charCode)) {
  5206. return CharacterType.HALFWIDTH_KATAKANA_LETTER;
  5207. }
  5208. return CharacterType.ALPHA_LETTER;
  5209. }
  5210. let NormalizeWithNFKC;
  5211. function getNormalizeWithNFKC() {
  5212. NormalizeWithNFKC ||= ` ¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰꟲ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`;
  5213. return NormalizeWithNFKC;
  5214. }
  5215. ;// ./web/pdf_find_controller.js
  5216. const FindState = {
  5217. FOUND: 0,
  5218. NOT_FOUND: 1,
  5219. WRAPPED: 2,
  5220. PENDING: 3
  5221. };
  5222. const FIND_TIMEOUT = 250;
  5223. const MATCH_SCROLL_OFFSET_TOP = -50;
  5224. const MATCH_SCROLL_OFFSET_LEFT = -400;
  5225. const CHARACTERS_TO_NORMALIZE = {
  5226. "\u2010": "-",
  5227. "\u2018": "'",
  5228. "\u2019": "'",
  5229. "\u201A": "'",
  5230. "\u201B": "'",
  5231. "\u201C": '"',
  5232. "\u201D": '"',
  5233. "\u201E": '"',
  5234. "\u201F": '"',
  5235. "\u00BC": "1/4",
  5236. "\u00BD": "1/2",
  5237. "\u00BE": "3/4"
  5238. };
  5239. 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]);
  5240. let DIACRITICS_EXCEPTION_STR;
  5241. const DIACRITICS_REG_EXP = /\p{M}+/gu;
  5242. const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu;
  5243. const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u;
  5244. const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u;
  5245. const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g;
  5246. const SYLLABLES_LENGTHS = new Map();
  5247. const FIRST_CHAR_SYLLABLES_REG_EXP = "[\\u1100-\\u1112\\ud7a4-\\ud7af\\ud84a\\ud84c\\ud850\\ud854\\ud857\\ud85f]";
  5248. const NFKC_CHARS_TO_NORMALIZE = new Map();
  5249. let noSyllablesRegExp = null;
  5250. let withSyllablesRegExp = null;
  5251. function normalize(text) {
  5252. const syllablePositions = [];
  5253. let m;
  5254. while ((m = SYLLABLES_REG_EXP.exec(text)) !== null) {
  5255. let {
  5256. index
  5257. } = m;
  5258. for (const char of m[0]) {
  5259. let len = SYLLABLES_LENGTHS.get(char);
  5260. if (!len) {
  5261. len = char.normalize("NFD").length;
  5262. SYLLABLES_LENGTHS.set(char, len);
  5263. }
  5264. syllablePositions.push([len, index++]);
  5265. }
  5266. }
  5267. const hasSyllables = syllablePositions.length > 0;
  5268. let normalizationRegex;
  5269. if (!hasSyllables && noSyllablesRegExp) {
  5270. normalizationRegex = noSyllablesRegExp;
  5271. } else if (hasSyllables && withSyllablesRegExp) {
  5272. normalizationRegex = withSyllablesRegExp;
  5273. } else {
  5274. const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join("");
  5275. const toNormalizeWithNFKC = getNormalizeWithNFKC();
  5276. const CJK = "(?:\\p{Ideographic}|[\u3040-\u30FF])";
  5277. const HKDiacritics = "(?:\u3099|\u309A)";
  5278. const BrokenWord = `\\p{Ll}-\\n(?=\\p{Ll})|\\p{Lu}-\\n(?=\\p{L})`;
  5279. const regexps = [`[${replace}]`, `[${toNormalizeWithNFKC}]`, `${HKDiacritics}\\n`, "\\p{M}+(?:-\\n)?", `${BrokenWord}`, "\\S-\\n", `${CJK}\\n`, "\\n", hasSyllables ? FIRST_CHAR_SYLLABLES_REG_EXP : "\\u0000"];
  5280. normalizationRegex = new RegExp(regexps.map(r => `(${r})`).join("|"), "gum");
  5281. if (hasSyllables) {
  5282. withSyllablesRegExp = normalizationRegex;
  5283. } else {
  5284. noSyllablesRegExp = normalizationRegex;
  5285. }
  5286. }
  5287. const rawDiacriticsPositions = [];
  5288. while ((m = DIACRITICS_REG_EXP.exec(text)) !== null) {
  5289. rawDiacriticsPositions.push([m[0].length, m.index]);
  5290. }
  5291. let normalized = text.normalize("NFD");
  5292. const positions = [0, 0];
  5293. let rawDiacriticsIndex = 0;
  5294. let syllableIndex = 0;
  5295. let shift = 0;
  5296. let shiftOrigin = 0;
  5297. let eol = 0;
  5298. let hasDiacritics = false;
  5299. normalized = normalized.replace(normalizationRegex, (match, p1, p2, p3, p4, p5, p6, p7, p8, p9, i) => {
  5300. i -= shiftOrigin;
  5301. if (p1) {
  5302. const replacement = CHARACTERS_TO_NORMALIZE[p1];
  5303. const jj = replacement.length;
  5304. for (let j = 1; j < jj; j++) {
  5305. positions.push(i - shift + j, shift - j);
  5306. }
  5307. shift -= jj - 1;
  5308. return replacement;
  5309. }
  5310. if (p2) {
  5311. let replacement = NFKC_CHARS_TO_NORMALIZE.get(p2);
  5312. if (!replacement) {
  5313. replacement = p2.normalize("NFKC");
  5314. NFKC_CHARS_TO_NORMALIZE.set(p2, replacement);
  5315. }
  5316. const jj = replacement.length;
  5317. for (let j = 1; j < jj; j++) {
  5318. positions.push(i - shift + j, shift - j);
  5319. }
  5320. shift -= jj - 1;
  5321. return replacement;
  5322. }
  5323. if (p3) {
  5324. hasDiacritics = true;
  5325. if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) {
  5326. ++rawDiacriticsIndex;
  5327. } else {
  5328. positions.push(i - 1 - shift + 1, shift - 1);
  5329. shift -= 1;
  5330. shiftOrigin += 1;
  5331. }
  5332. positions.push(i - shift + 1, shift);
  5333. shiftOrigin += 1;
  5334. eol += 1;
  5335. return p3.charAt(0);
  5336. }
  5337. if (p4) {
  5338. const hasTrailingDashEOL = p4.endsWith("\n");
  5339. const len = hasTrailingDashEOL ? p4.length - 2 : p4.length;
  5340. hasDiacritics = true;
  5341. let jj = len;
  5342. if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) {
  5343. jj -= rawDiacriticsPositions[rawDiacriticsIndex][0];
  5344. ++rawDiacriticsIndex;
  5345. }
  5346. for (let j = 1; j <= jj; j++) {
  5347. positions.push(i - 1 - shift + j, shift - j);
  5348. }
  5349. shift -= jj;
  5350. shiftOrigin += jj;
  5351. if (hasTrailingDashEOL) {
  5352. i += len - 1;
  5353. positions.push(i - shift + 1, 1 + shift);
  5354. shift += 1;
  5355. shiftOrigin += 1;
  5356. eol += 1;
  5357. return p4.slice(0, len);
  5358. }
  5359. return p4;
  5360. }
  5361. if (p5) {
  5362. const len = p5.length - 2;
  5363. positions.push(i - shift + len, 1 + shift);
  5364. shift += 1;
  5365. shiftOrigin += 1;
  5366. eol += 1;
  5367. return p5.slice(0, -2);
  5368. }
  5369. if (p6) {
  5370. shiftOrigin += 1;
  5371. eol += 1;
  5372. return p6.slice(0, -1);
  5373. }
  5374. if (p7) {
  5375. const len = p7.length - 1;
  5376. positions.push(i - shift + len, shift);
  5377. shiftOrigin += 1;
  5378. eol += 1;
  5379. return p7.slice(0, -1);
  5380. }
  5381. if (p8) {
  5382. positions.push(i - shift + 1, shift - 1);
  5383. shift -= 1;
  5384. shiftOrigin += 1;
  5385. eol += 1;
  5386. return " ";
  5387. }
  5388. if (i + eol === syllablePositions[syllableIndex]?.[1]) {
  5389. const newCharLen = syllablePositions[syllableIndex][0] - 1;
  5390. ++syllableIndex;
  5391. for (let j = 1; j <= newCharLen; j++) {
  5392. positions.push(i - (shift - j), shift - j);
  5393. }
  5394. shift -= newCharLen;
  5395. shiftOrigin += newCharLen;
  5396. }
  5397. return p9;
  5398. });
  5399. positions.push(normalized.length, shift);
  5400. const starts = new Uint32Array(positions.length >> 1);
  5401. const shifts = new Int32Array(positions.length >> 1);
  5402. for (let i = 0, ii = positions.length; i < ii; i += 2) {
  5403. starts[i >> 1] = positions[i];
  5404. shifts[i >> 1] = positions[i + 1];
  5405. }
  5406. return [normalized, [starts, shifts], hasDiacritics];
  5407. }
  5408. function getOriginalIndex(diffs, pos, len) {
  5409. if (!diffs) {
  5410. return [pos, len];
  5411. }
  5412. const [starts, shifts] = diffs;
  5413. const start = pos;
  5414. const end = pos + len - 1;
  5415. let i = binarySearchFirstItem(starts, x => x >= start);
  5416. if (starts[i] > start) {
  5417. --i;
  5418. }
  5419. let j = binarySearchFirstItem(starts, x => x >= end, i);
  5420. if (starts[j] > end) {
  5421. --j;
  5422. }
  5423. const oldStart = start + shifts[i];
  5424. const oldEnd = end + shifts[j];
  5425. const oldLen = oldEnd + 1 - oldStart;
  5426. return [oldStart, oldLen];
  5427. }
  5428. class PDFFindController {
  5429. #state = null;
  5430. #updateMatchesCountOnProgress = true;
  5431. #visitedPagesCount = 0;
  5432. constructor({
  5433. linkService,
  5434. eventBus,
  5435. updateMatchesCountOnProgress = true
  5436. }) {
  5437. this._linkService = linkService;
  5438. this._eventBus = eventBus;
  5439. this.#updateMatchesCountOnProgress = updateMatchesCountOnProgress;
  5440. this.onIsPageVisible = null;
  5441. this.#reset();
  5442. eventBus._on("find", this.#onFind.bind(this));
  5443. eventBus._on("findbarclose", this.#onFindBarClose.bind(this));
  5444. }
  5445. get highlightMatches() {
  5446. return this._highlightMatches;
  5447. }
  5448. get pageMatches() {
  5449. return this._pageMatches;
  5450. }
  5451. get pageMatchesLength() {
  5452. return this._pageMatchesLength;
  5453. }
  5454. get selected() {
  5455. return this._selected;
  5456. }
  5457. get state() {
  5458. return this.#state;
  5459. }
  5460. setDocument(pdfDocument) {
  5461. if (this._pdfDocument) {
  5462. this.#reset();
  5463. }
  5464. if (!pdfDocument) {
  5465. return;
  5466. }
  5467. this._pdfDocument = pdfDocument;
  5468. this._firstPageCapability.resolve();
  5469. }
  5470. #onFind(state) {
  5471. if (!state) {
  5472. return;
  5473. }
  5474. const pdfDocument = this._pdfDocument;
  5475. const {
  5476. type
  5477. } = state;
  5478. if (this.#state === null || this.#shouldDirtyMatch(state)) {
  5479. this._dirtyMatch = true;
  5480. }
  5481. this.#state = state;
  5482. if (type !== "highlightallchange") {
  5483. this.#updateUIState(FindState.PENDING);
  5484. }
  5485. this._firstPageCapability.promise.then(() => {
  5486. if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
  5487. return;
  5488. }
  5489. this.#extractText();
  5490. const findbarClosed = !this._highlightMatches;
  5491. const pendingTimeout = !!this._findTimeout;
  5492. if (this._findTimeout) {
  5493. clearTimeout(this._findTimeout);
  5494. this._findTimeout = null;
  5495. }
  5496. if (!type) {
  5497. this._findTimeout = setTimeout(() => {
  5498. this.#nextMatch();
  5499. this._findTimeout = null;
  5500. }, FIND_TIMEOUT);
  5501. } else if (this._dirtyMatch) {
  5502. this.#nextMatch();
  5503. } else if (type === "again") {
  5504. this.#nextMatch();
  5505. if (findbarClosed && this.#state.highlightAll) {
  5506. this.#updateAllPages();
  5507. }
  5508. } else if (type === "highlightallchange") {
  5509. if (pendingTimeout) {
  5510. this.#nextMatch();
  5511. } else {
  5512. this._highlightMatches = true;
  5513. }
  5514. this.#updateAllPages();
  5515. } else {
  5516. this.#nextMatch();
  5517. }
  5518. });
  5519. }
  5520. scrollMatchIntoView({
  5521. element = null,
  5522. selectedLeft = 0,
  5523. pageIndex = -1,
  5524. matchIndex = -1
  5525. }) {
  5526. if (!this._scrollMatches || !element) {
  5527. return;
  5528. } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) {
  5529. return;
  5530. } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) {
  5531. return;
  5532. }
  5533. this._scrollMatches = false;
  5534. const spot = {
  5535. top: MATCH_SCROLL_OFFSET_TOP,
  5536. left: selectedLeft + MATCH_SCROLL_OFFSET_LEFT
  5537. };
  5538. scrollIntoView(element, spot, true);
  5539. }
  5540. #reset() {
  5541. this._highlightMatches = false;
  5542. this._scrollMatches = false;
  5543. this._pdfDocument = null;
  5544. this._pageMatches = [];
  5545. this._pageMatchesLength = [];
  5546. this.#visitedPagesCount = 0;
  5547. this.#state = null;
  5548. this._selected = {
  5549. pageIdx: -1,
  5550. matchIdx: -1
  5551. };
  5552. this._offset = {
  5553. pageIdx: null,
  5554. matchIdx: null,
  5555. wrapped: false
  5556. };
  5557. this._extractTextPromises = [];
  5558. this._pageContents = [];
  5559. this._pageDiffs = [];
  5560. this._hasDiacritics = [];
  5561. this._matchesCountTotal = 0;
  5562. this._pagesToSearch = null;
  5563. this._pendingFindMatches = new Set();
  5564. this._resumePageIdx = null;
  5565. this._dirtyMatch = false;
  5566. clearTimeout(this._findTimeout);
  5567. this._findTimeout = null;
  5568. this._firstPageCapability = Promise.withResolvers();
  5569. }
  5570. get #query() {
  5571. const {
  5572. query
  5573. } = this.#state;
  5574. if (typeof query === "string") {
  5575. if (query !== this._rawQuery) {
  5576. this._rawQuery = query;
  5577. [this._normalizedQuery] = normalize(query);
  5578. }
  5579. return this._normalizedQuery;
  5580. }
  5581. return (query || []).filter(q => !!q).map(q => normalize(q)[0]);
  5582. }
  5583. #shouldDirtyMatch(state) {
  5584. const newQuery = state.query,
  5585. prevQuery = this.#state.query;
  5586. const newType = typeof newQuery,
  5587. prevType = typeof prevQuery;
  5588. if (newType !== prevType) {
  5589. return true;
  5590. }
  5591. if (newType === "string") {
  5592. if (newQuery !== prevQuery) {
  5593. return true;
  5594. }
  5595. } else if (JSON.stringify(newQuery) !== JSON.stringify(prevQuery)) {
  5596. return true;
  5597. }
  5598. switch (state.type) {
  5599. case "again":
  5600. const pageNumber = this._selected.pageIdx + 1;
  5601. const linkService = this._linkService;
  5602. return pageNumber >= 1 && pageNumber <= linkService.pagesCount && pageNumber !== linkService.page && !(this.onIsPageVisible?.(pageNumber) ?? true);
  5603. case "highlightallchange":
  5604. return false;
  5605. }
  5606. return true;
  5607. }
  5608. #isEntireWord(content, startIdx, length) {
  5609. let match = content.slice(0, startIdx).match(NOT_DIACRITIC_FROM_END_REG_EXP);
  5610. if (match) {
  5611. const first = content.charCodeAt(startIdx);
  5612. const limit = match[1].charCodeAt(0);
  5613. if (getCharacterType(first) === getCharacterType(limit)) {
  5614. return false;
  5615. }
  5616. }
  5617. match = content.slice(startIdx + length).match(NOT_DIACRITIC_FROM_START_REG_EXP);
  5618. if (match) {
  5619. const last = content.charCodeAt(startIdx + length - 1);
  5620. const limit = match[1].charCodeAt(0);
  5621. if (getCharacterType(last) === getCharacterType(limit)) {
  5622. return false;
  5623. }
  5624. }
  5625. return true;
  5626. }
  5627. #convertToRegExpString(query, hasDiacritics) {
  5628. const {
  5629. matchDiacritics
  5630. } = this.#state;
  5631. let isUnicode = false;
  5632. query = query.replaceAll(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => {
  5633. if (p1) {
  5634. return `[ ]*\\${p1}[ ]*`;
  5635. }
  5636. if (p2) {
  5637. return `[ ]*${p2}[ ]*`;
  5638. }
  5639. if (p3) {
  5640. return "[ ]+";
  5641. }
  5642. if (matchDiacritics) {
  5643. return p4 || p5;
  5644. }
  5645. if (p4) {
  5646. return DIACRITICS_EXCEPTION.has(p4.charCodeAt(0)) ? p4 : "";
  5647. }
  5648. if (hasDiacritics) {
  5649. isUnicode = true;
  5650. return `${p5}\\p{M}*`;
  5651. }
  5652. return p5;
  5653. });
  5654. const trailingSpaces = "[ ]*";
  5655. if (query.endsWith(trailingSpaces)) {
  5656. query = query.slice(0, query.length - trailingSpaces.length);
  5657. }
  5658. if (matchDiacritics) {
  5659. if (hasDiacritics) {
  5660. DIACRITICS_EXCEPTION_STR ||= String.fromCharCode(...DIACRITICS_EXCEPTION);
  5661. isUnicode = true;
  5662. query = `${query}(?=[${DIACRITICS_EXCEPTION_STR}]|[^\\p{M}]|$)`;
  5663. }
  5664. }
  5665. return [isUnicode, query];
  5666. }
  5667. #calculateMatch(pageIndex) {
  5668. const query = this.#query;
  5669. if (query.length === 0) {
  5670. return;
  5671. }
  5672. const pageContent = this._pageContents[pageIndex];
  5673. const matcherResult = this.match(query, pageContent, pageIndex);
  5674. const matches = this._pageMatches[pageIndex] = [];
  5675. const matchesLength = this._pageMatchesLength[pageIndex] = [];
  5676. const diffs = this._pageDiffs[pageIndex];
  5677. matcherResult?.forEach(({
  5678. index,
  5679. length
  5680. }) => {
  5681. const [matchPos, matchLen] = getOriginalIndex(diffs, index, length);
  5682. if (matchLen) {
  5683. matches.push(matchPos);
  5684. matchesLength.push(matchLen);
  5685. }
  5686. });
  5687. if (this.#state.highlightAll) {
  5688. this.#updatePage(pageIndex);
  5689. }
  5690. if (this._resumePageIdx === pageIndex) {
  5691. this._resumePageIdx = null;
  5692. this.#nextPageMatch();
  5693. }
  5694. const pageMatchesCount = matches.length;
  5695. this._matchesCountTotal += pageMatchesCount;
  5696. if (this.#updateMatchesCountOnProgress) {
  5697. if (pageMatchesCount > 0) {
  5698. this.#updateUIResultsCount();
  5699. }
  5700. } else if (++this.#visitedPagesCount === this._linkService.pagesCount) {
  5701. this.#updateUIResultsCount();
  5702. }
  5703. }
  5704. match(query, pageContent, pageIndex) {
  5705. const hasDiacritics = this._hasDiacritics[pageIndex];
  5706. let isUnicode = false;
  5707. if (typeof query === "string") {
  5708. [isUnicode, query] = this.#convertToRegExpString(query, hasDiacritics);
  5709. } else {
  5710. query = query.sort().reverse().map(q => {
  5711. const [isUnicodePart, queryPart] = this.#convertToRegExpString(q, hasDiacritics);
  5712. isUnicode ||= isUnicodePart;
  5713. return `(${queryPart})`;
  5714. }).join("|");
  5715. }
  5716. if (!query) {
  5717. return undefined;
  5718. }
  5719. const {
  5720. caseSensitive,
  5721. entireWord
  5722. } = this.#state;
  5723. const flags = `g${isUnicode ? "u" : ""}${caseSensitive ? "" : "i"}`;
  5724. query = new RegExp(query, flags);
  5725. const matches = [];
  5726. let match;
  5727. while ((match = query.exec(pageContent)) !== null) {
  5728. if (entireWord && !this.#isEntireWord(pageContent, match.index, match[0].length)) {
  5729. continue;
  5730. }
  5731. matches.push({
  5732. index: match.index,
  5733. length: match[0].length
  5734. });
  5735. }
  5736. return matches;
  5737. }
  5738. #extractText() {
  5739. if (this._extractTextPromises.length > 0) {
  5740. return;
  5741. }
  5742. let deferred = Promise.resolve();
  5743. const textOptions = {
  5744. disableNormalization: true
  5745. };
  5746. for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) {
  5747. const {
  5748. promise,
  5749. resolve
  5750. } = Promise.withResolvers();
  5751. this._extractTextPromises[i] = promise;
  5752. deferred = deferred.then(() => this._pdfDocument.getPage(i + 1).then(pdfPage => pdfPage.getTextContent(textOptions)).then(textContent => {
  5753. const strBuf = [];
  5754. for (const textItem of textContent.items) {
  5755. strBuf.push(textItem.str);
  5756. if (textItem.hasEOL) {
  5757. strBuf.push("\n");
  5758. }
  5759. }
  5760. [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = normalize(strBuf.join(""));
  5761. resolve();
  5762. }, reason => {
  5763. console.error(`Unable to get text content for page ${i + 1}`, reason);
  5764. this._pageContents[i] = "";
  5765. this._pageDiffs[i] = null;
  5766. this._hasDiacritics[i] = false;
  5767. resolve();
  5768. }));
  5769. }
  5770. }
  5771. #updatePage(index) {
  5772. if (this._scrollMatches && this._selected.pageIdx === index) {
  5773. this._linkService.page = index + 1;
  5774. }
  5775. this._eventBus.dispatch("updatetextlayermatches", {
  5776. source: this,
  5777. pageIndex: index
  5778. });
  5779. }
  5780. #updateAllPages() {
  5781. this._eventBus.dispatch("updatetextlayermatches", {
  5782. source: this,
  5783. pageIndex: -1
  5784. });
  5785. }
  5786. #nextMatch() {
  5787. const previous = this.#state.findPrevious;
  5788. const currentPageIndex = this._linkService.page - 1;
  5789. const numPages = this._linkService.pagesCount;
  5790. this._highlightMatches = true;
  5791. if (this._dirtyMatch) {
  5792. this._dirtyMatch = false;
  5793. this._selected.pageIdx = this._selected.matchIdx = -1;
  5794. this._offset.pageIdx = currentPageIndex;
  5795. this._offset.matchIdx = null;
  5796. this._offset.wrapped = false;
  5797. this._resumePageIdx = null;
  5798. this._pageMatches.length = 0;
  5799. this._pageMatchesLength.length = 0;
  5800. this.#visitedPagesCount = 0;
  5801. this._matchesCountTotal = 0;
  5802. this.#updateAllPages();
  5803. for (let i = 0; i < numPages; i++) {
  5804. if (this._pendingFindMatches.has(i)) {
  5805. continue;
  5806. }
  5807. this._pendingFindMatches.add(i);
  5808. this._extractTextPromises[i].then(() => {
  5809. this._pendingFindMatches.delete(i);
  5810. this.#calculateMatch(i);
  5811. });
  5812. }
  5813. }
  5814. const query = this.#query;
  5815. if (query.length === 0) {
  5816. this.#updateUIState(FindState.FOUND);
  5817. return;
  5818. }
  5819. if (this._resumePageIdx) {
  5820. return;
  5821. }
  5822. const offset = this._offset;
  5823. this._pagesToSearch = numPages;
  5824. if (offset.matchIdx !== null) {
  5825. const numPageMatches = this._pageMatches[offset.pageIdx].length;
  5826. if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) {
  5827. offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
  5828. this.#updateMatch(true);
  5829. return;
  5830. }
  5831. this.#advanceOffsetPage(previous);
  5832. }
  5833. this.#nextPageMatch();
  5834. }
  5835. #matchesReady(matches) {
  5836. const offset = this._offset;
  5837. const numMatches = matches.length;
  5838. const previous = this.#state.findPrevious;
  5839. if (numMatches) {
  5840. offset.matchIdx = previous ? numMatches - 1 : 0;
  5841. this.#updateMatch(true);
  5842. return true;
  5843. }
  5844. this.#advanceOffsetPage(previous);
  5845. if (offset.wrapped) {
  5846. offset.matchIdx = null;
  5847. if (this._pagesToSearch < 0) {
  5848. this.#updateMatch(false);
  5849. return true;
  5850. }
  5851. }
  5852. return false;
  5853. }
  5854. #nextPageMatch() {
  5855. if (this._resumePageIdx !== null) {
  5856. console.error("There can only be one pending page.");
  5857. }
  5858. let matches = null;
  5859. do {
  5860. const pageIdx = this._offset.pageIdx;
  5861. matches = this._pageMatches[pageIdx];
  5862. if (!matches) {
  5863. this._resumePageIdx = pageIdx;
  5864. break;
  5865. }
  5866. } while (!this.#matchesReady(matches));
  5867. }
  5868. #advanceOffsetPage(previous) {
  5869. const offset = this._offset;
  5870. const numPages = this._linkService.pagesCount;
  5871. offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
  5872. offset.matchIdx = null;
  5873. this._pagesToSearch--;
  5874. if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
  5875. offset.pageIdx = previous ? numPages - 1 : 0;
  5876. offset.wrapped = true;
  5877. }
  5878. }
  5879. #updateMatch(found = false) {
  5880. let state = FindState.NOT_FOUND;
  5881. const wrapped = this._offset.wrapped;
  5882. this._offset.wrapped = false;
  5883. if (found) {
  5884. const previousPage = this._selected.pageIdx;
  5885. this._selected.pageIdx = this._offset.pageIdx;
  5886. this._selected.matchIdx = this._offset.matchIdx;
  5887. state = wrapped ? FindState.WRAPPED : FindState.FOUND;
  5888. if (previousPage !== -1 && previousPage !== this._selected.pageIdx) {
  5889. this.#updatePage(previousPage);
  5890. }
  5891. }
  5892. this.#updateUIState(state, this.#state.findPrevious);
  5893. if (this._selected.pageIdx !== -1) {
  5894. this._scrollMatches = true;
  5895. this.#updatePage(this._selected.pageIdx);
  5896. }
  5897. }
  5898. #onFindBarClose(evt) {
  5899. const pdfDocument = this._pdfDocument;
  5900. this._firstPageCapability.promise.then(() => {
  5901. if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
  5902. return;
  5903. }
  5904. if (this._findTimeout) {
  5905. clearTimeout(this._findTimeout);
  5906. this._findTimeout = null;
  5907. }
  5908. if (this._resumePageIdx) {
  5909. this._resumePageIdx = null;
  5910. this._dirtyMatch = true;
  5911. }
  5912. this.#updateUIState(FindState.FOUND);
  5913. this._highlightMatches = false;
  5914. this.#updateAllPages();
  5915. });
  5916. }
  5917. #requestMatchesCount() {
  5918. const {
  5919. pageIdx,
  5920. matchIdx
  5921. } = this._selected;
  5922. let current = 0,
  5923. total = this._matchesCountTotal;
  5924. if (matchIdx !== -1) {
  5925. for (let i = 0; i < pageIdx; i++) {
  5926. current += this._pageMatches[i]?.length || 0;
  5927. }
  5928. current += matchIdx + 1;
  5929. }
  5930. if (current < 1 || current > total) {
  5931. current = total = 0;
  5932. }
  5933. return {
  5934. current,
  5935. total
  5936. };
  5937. }
  5938. #updateUIResultsCount() {
  5939. this._eventBus.dispatch("updatefindmatchescount", {
  5940. source: this,
  5941. matchesCount: this.#requestMatchesCount()
  5942. });
  5943. }
  5944. #updateUIState(state, previous = false) {
  5945. if (!this.#updateMatchesCountOnProgress && (this.#visitedPagesCount !== this._linkService.pagesCount || state === FindState.PENDING)) {
  5946. return;
  5947. }
  5948. this._eventBus.dispatch("updatefindcontrolstate", {
  5949. source: this,
  5950. state,
  5951. previous,
  5952. entireWord: this.#state?.entireWord ?? null,
  5953. matchesCount: this.#requestMatchesCount(),
  5954. rawQuery: this.#state?.query ?? null
  5955. });
  5956. }
  5957. }
  5958. ;// ./web/pdf_find_bar.js
  5959. const MATCHES_COUNT_LIMIT = 1000;
  5960. class PDFFindBar {
  5961. #mainContainer;
  5962. #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this));
  5963. constructor(options, mainContainer, eventBus) {
  5964. this.opened = false;
  5965. this.bar = options.bar;
  5966. this.toggleButton = options.toggleButton;
  5967. this.findField = options.findField;
  5968. this.highlightAll = options.highlightAllCheckbox;
  5969. this.caseSensitive = options.caseSensitiveCheckbox;
  5970. this.matchDiacritics = options.matchDiacriticsCheckbox;
  5971. this.entireWord = options.entireWordCheckbox;
  5972. this.findMsg = options.findMsg;
  5973. this.findResultsCount = options.findResultsCount;
  5974. this.findPreviousButton = options.findPreviousButton;
  5975. this.findNextButton = options.findNextButton;
  5976. this.eventBus = eventBus;
  5977. this.#mainContainer = mainContainer;
  5978. const checkedInputs = new Map([[this.highlightAll, "highlightallchange"], [this.caseSensitive, "casesensitivitychange"], [this.entireWord, "entirewordchange"], [this.matchDiacritics, "diacriticmatchingchange"]]);
  5979. this.toggleButton.addEventListener("click", () => {
  5980. this.toggle();
  5981. });
  5982. this.findField.addEventListener("input", () => {
  5983. this.dispatchEvent("");
  5984. });
  5985. this.bar.addEventListener("keydown", ({
  5986. keyCode,
  5987. shiftKey,
  5988. target
  5989. }) => {
  5990. switch (keyCode) {
  5991. case 13:
  5992. if (target === this.findField) {
  5993. this.dispatchEvent("again", shiftKey);
  5994. } else if (checkedInputs.has(target)) {
  5995. target.checked = !target.checked;
  5996. this.dispatchEvent(checkedInputs.get(target));
  5997. }
  5998. break;
  5999. case 27:
  6000. this.close();
  6001. break;
  6002. }
  6003. });
  6004. this.findPreviousButton.addEventListener("click", () => {
  6005. this.dispatchEvent("again", true);
  6006. });
  6007. this.findNextButton.addEventListener("click", () => {
  6008. this.dispatchEvent("again", false);
  6009. });
  6010. for (const [elem, evtName] of checkedInputs) {
  6011. elem.addEventListener("click", () => {
  6012. this.dispatchEvent(evtName);
  6013. });
  6014. }
  6015. }
  6016. reset() {
  6017. this.updateUIState();
  6018. }
  6019. dispatchEvent(type, findPrev = false) {
  6020. this.eventBus.dispatch("find", {
  6021. source: this,
  6022. type,
  6023. query: this.findField.value,
  6024. caseSensitive: this.caseSensitive.checked,
  6025. entireWord: this.entireWord.checked,
  6026. highlightAll: this.highlightAll.checked,
  6027. findPrevious: findPrev,
  6028. matchDiacritics: this.matchDiacritics.checked
  6029. });
  6030. }
  6031. updateUIState(state, previous, matchesCount) {
  6032. const {
  6033. findField,
  6034. findMsg
  6035. } = this;
  6036. let findMsgId = "",
  6037. status = "";
  6038. switch (state) {
  6039. case FindState.FOUND:
  6040. break;
  6041. case FindState.PENDING:
  6042. status = "pending";
  6043. break;
  6044. case FindState.NOT_FOUND:
  6045. findMsgId = "pdfjs-find-not-found";
  6046. status = "notFound";
  6047. break;
  6048. case FindState.WRAPPED:
  6049. findMsgId = previous ? "pdfjs-find-reached-top" : "pdfjs-find-reached-bottom";
  6050. break;
  6051. }
  6052. findField.setAttribute("data-status", status);
  6053. findField.setAttribute("aria-invalid", state === FindState.NOT_FOUND);
  6054. findMsg.setAttribute("data-status", status);
  6055. if (findMsgId) {
  6056. findMsg.setAttribute("data-l10n-id", findMsgId);
  6057. } else {
  6058. findMsg.removeAttribute("data-l10n-id");
  6059. findMsg.textContent = "";
  6060. }
  6061. this.updateResultsCount(matchesCount);
  6062. }
  6063. updateResultsCount({
  6064. current = 0,
  6065. total = 0
  6066. } = {}) {
  6067. const {
  6068. findResultsCount
  6069. } = this;
  6070. if (total > 0) {
  6071. const limit = MATCHES_COUNT_LIMIT;
  6072. findResultsCount.setAttribute("data-l10n-id", total > limit ? "pdfjs-find-match-count-limit" : "pdfjs-find-match-count");
  6073. findResultsCount.setAttribute("data-l10n-args", JSON.stringify({
  6074. limit,
  6075. current,
  6076. total
  6077. }));
  6078. } else {
  6079. findResultsCount.removeAttribute("data-l10n-id");
  6080. findResultsCount.textContent = "";
  6081. }
  6082. }
  6083. open() {
  6084. if (!this.opened) {
  6085. this.#resizeObserver.observe(this.#mainContainer);
  6086. this.#resizeObserver.observe(this.bar);
  6087. this.opened = true;
  6088. toggleExpandedBtn(this.toggleButton, true, this.bar);
  6089. }
  6090. this.findField.select();
  6091. this.findField.focus();
  6092. }
  6093. close() {
  6094. if (!this.opened) {
  6095. return;
  6096. }
  6097. this.#resizeObserver.disconnect();
  6098. this.opened = false;
  6099. toggleExpandedBtn(this.toggleButton, false, this.bar);
  6100. this.eventBus.dispatch("findbarclose", {
  6101. source: this
  6102. });
  6103. }
  6104. toggle() {
  6105. if (this.opened) {
  6106. this.close();
  6107. } else {
  6108. this.open();
  6109. }
  6110. }
  6111. #resizeObserverCallback() {
  6112. const {
  6113. bar
  6114. } = this;
  6115. bar.classList.remove("wrapContainers");
  6116. const findbarHeight = bar.clientHeight;
  6117. const inputContainerHeight = bar.firstElementChild.clientHeight;
  6118. if (findbarHeight > inputContainerHeight) {
  6119. bar.classList.add("wrapContainers");
  6120. }
  6121. }
  6122. }
  6123. ;// ./web/pdf_history.js
  6124. const HASH_CHANGE_TIMEOUT = 1000;
  6125. const POSITION_UPDATED_THRESHOLD = 50;
  6126. const UPDATE_VIEWAREA_TIMEOUT = 1000;
  6127. function getCurrentHash() {
  6128. return document.location.hash;
  6129. }
  6130. class PDFHistory {
  6131. #eventAbortController = null;
  6132. constructor({
  6133. linkService,
  6134. eventBus
  6135. }) {
  6136. this.linkService = linkService;
  6137. this.eventBus = eventBus;
  6138. this._initialized = false;
  6139. this._fingerprint = "";
  6140. this.reset();
  6141. this.eventBus._on("pagesinit", () => {
  6142. this._isPagesLoaded = false;
  6143. this.eventBus._on("pagesloaded", evt => {
  6144. this._isPagesLoaded = !!evt.pagesCount;
  6145. }, {
  6146. once: true
  6147. });
  6148. });
  6149. }
  6150. initialize({
  6151. fingerprint,
  6152. resetHistory = false,
  6153. updateUrl = false
  6154. }) {
  6155. if (!fingerprint || typeof fingerprint !== "string") {
  6156. console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.');
  6157. return;
  6158. }
  6159. if (this._initialized) {
  6160. this.reset();
  6161. }
  6162. const reInitialized = this._fingerprint !== "" && this._fingerprint !== fingerprint;
  6163. this._fingerprint = fingerprint;
  6164. this._updateUrl = updateUrl === true;
  6165. this._initialized = true;
  6166. this.#bindEvents();
  6167. const state = window.history.state;
  6168. this._popStateInProgress = false;
  6169. this._blockHashChange = 0;
  6170. this._currentHash = getCurrentHash();
  6171. this._numPositionUpdates = 0;
  6172. this._uid = this._maxUid = 0;
  6173. this._destination = null;
  6174. this._position = null;
  6175. if (!this.#isValidState(state, true) || resetHistory) {
  6176. const {
  6177. hash,
  6178. page,
  6179. rotation
  6180. } = this.#parseCurrentHash(true);
  6181. if (!hash || reInitialized || resetHistory) {
  6182. this.#pushOrReplaceState(null, true);
  6183. return;
  6184. }
  6185. this.#pushOrReplaceState({
  6186. hash,
  6187. page,
  6188. rotation
  6189. }, true);
  6190. return;
  6191. }
  6192. const destination = state.destination;
  6193. this.#updateInternalState(destination, state.uid, true);
  6194. if (destination.rotation !== undefined) {
  6195. this._initialRotation = destination.rotation;
  6196. }
  6197. if (destination.dest) {
  6198. this._initialBookmark = JSON.stringify(destination.dest);
  6199. this._destination.page = null;
  6200. } else if (destination.hash) {
  6201. this._initialBookmark = destination.hash;
  6202. } else if (destination.page) {
  6203. this._initialBookmark = `page=${destination.page}`;
  6204. }
  6205. }
  6206. reset() {
  6207. if (this._initialized) {
  6208. this.#pageHide();
  6209. this._initialized = false;
  6210. this.#unbindEvents();
  6211. }
  6212. if (this._updateViewareaTimeout) {
  6213. clearTimeout(this._updateViewareaTimeout);
  6214. this._updateViewareaTimeout = null;
  6215. }
  6216. this._initialBookmark = null;
  6217. this._initialRotation = null;
  6218. }
  6219. push({
  6220. namedDest = null,
  6221. explicitDest,
  6222. pageNumber
  6223. }) {
  6224. if (!this._initialized) {
  6225. return;
  6226. }
  6227. if (namedDest && typeof namedDest !== "string") {
  6228. console.error("PDFHistory.push: " + `"${namedDest}" is not a valid namedDest parameter.`);
  6229. return;
  6230. } else if (!Array.isArray(explicitDest)) {
  6231. console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`);
  6232. return;
  6233. } else if (!this.#isValidPage(pageNumber)) {
  6234. if (pageNumber !== null || this._destination) {
  6235. console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`);
  6236. return;
  6237. }
  6238. }
  6239. const hash = namedDest || JSON.stringify(explicitDest);
  6240. if (!hash) {
  6241. return;
  6242. }
  6243. let forceReplace = false;
  6244. if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) {
  6245. if (this._destination.page) {
  6246. return;
  6247. }
  6248. forceReplace = true;
  6249. }
  6250. if (this._popStateInProgress && !forceReplace) {
  6251. return;
  6252. }
  6253. this.#pushOrReplaceState({
  6254. dest: explicitDest,
  6255. hash,
  6256. page: pageNumber,
  6257. rotation: this.linkService.rotation
  6258. }, forceReplace);
  6259. if (!this._popStateInProgress) {
  6260. this._popStateInProgress = true;
  6261. Promise.resolve().then(() => {
  6262. this._popStateInProgress = false;
  6263. });
  6264. }
  6265. }
  6266. pushPage(pageNumber) {
  6267. if (!this._initialized) {
  6268. return;
  6269. }
  6270. if (!this.#isValidPage(pageNumber)) {
  6271. console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`);
  6272. return;
  6273. }
  6274. if (this._destination?.page === pageNumber) {
  6275. return;
  6276. }
  6277. if (this._popStateInProgress) {
  6278. return;
  6279. }
  6280. this.#pushOrReplaceState({
  6281. dest: null,
  6282. hash: `page=${pageNumber}`,
  6283. page: pageNumber,
  6284. rotation: this.linkService.rotation
  6285. });
  6286. if (!this._popStateInProgress) {
  6287. this._popStateInProgress = true;
  6288. Promise.resolve().then(() => {
  6289. this._popStateInProgress = false;
  6290. });
  6291. }
  6292. }
  6293. pushCurrentPosition() {
  6294. if (!this._initialized || this._popStateInProgress) {
  6295. return;
  6296. }
  6297. this.#tryPushCurrentPosition();
  6298. }
  6299. back() {
  6300. if (!this._initialized || this._popStateInProgress) {
  6301. return;
  6302. }
  6303. const state = window.history.state;
  6304. if (this.#isValidState(state) && state.uid > 0) {
  6305. window.history.back();
  6306. }
  6307. }
  6308. forward() {
  6309. if (!this._initialized || this._popStateInProgress) {
  6310. return;
  6311. }
  6312. const state = window.history.state;
  6313. if (this.#isValidState(state) && state.uid < this._maxUid) {
  6314. window.history.forward();
  6315. }
  6316. }
  6317. get popStateInProgress() {
  6318. return this._initialized && (this._popStateInProgress || this._blockHashChange > 0);
  6319. }
  6320. get initialBookmark() {
  6321. return this._initialized ? this._initialBookmark : null;
  6322. }
  6323. get initialRotation() {
  6324. return this._initialized ? this._initialRotation : null;
  6325. }
  6326. #pushOrReplaceState(destination, forceReplace = false) {
  6327. const shouldReplace = forceReplace || !this._destination;
  6328. const newState = {
  6329. fingerprint: this._fingerprint,
  6330. uid: shouldReplace ? this._uid : this._uid + 1,
  6331. destination
  6332. };
  6333. this.#updateInternalState(destination, newState.uid);
  6334. let newUrl;
  6335. if (this._updateUrl && destination?.hash) {
  6336. const baseUrl = document.location.href.split("#", 1)[0];
  6337. if (!baseUrl.startsWith("file://")) {
  6338. newUrl = `${baseUrl}#${destination.hash}`;
  6339. }
  6340. }
  6341. if (shouldReplace) {
  6342. window.history.replaceState(newState, "", newUrl);
  6343. } else {
  6344. window.history.pushState(newState, "", newUrl);
  6345. }
  6346. }
  6347. #tryPushCurrentPosition(temporary = false) {
  6348. if (!this._position) {
  6349. return;
  6350. }
  6351. let position = this._position;
  6352. if (temporary) {
  6353. position = Object.assign(Object.create(null), this._position);
  6354. position.temporary = true;
  6355. }
  6356. if (!this._destination) {
  6357. this.#pushOrReplaceState(position);
  6358. return;
  6359. }
  6360. if (this._destination.temporary) {
  6361. this.#pushOrReplaceState(position, true);
  6362. return;
  6363. }
  6364. if (this._destination.hash === position.hash) {
  6365. return;
  6366. }
  6367. if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) {
  6368. return;
  6369. }
  6370. let forceReplace = false;
  6371. if (this._destination.page >= position.first && this._destination.page <= position.page) {
  6372. if (this._destination.dest !== undefined || !this._destination.first) {
  6373. return;
  6374. }
  6375. forceReplace = true;
  6376. }
  6377. this.#pushOrReplaceState(position, forceReplace);
  6378. }
  6379. #isValidPage(val) {
  6380. return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount;
  6381. }
  6382. #isValidState(state, checkReload = false) {
  6383. if (!state) {
  6384. return false;
  6385. }
  6386. if (state.fingerprint !== this._fingerprint) {
  6387. if (checkReload) {
  6388. if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) {
  6389. return false;
  6390. }
  6391. const [perfEntry] = performance.getEntriesByType("navigation");
  6392. if (perfEntry?.type !== "reload") {
  6393. return false;
  6394. }
  6395. } else {
  6396. return false;
  6397. }
  6398. }
  6399. if (!Number.isInteger(state.uid) || state.uid < 0) {
  6400. return false;
  6401. }
  6402. if (state.destination === null || typeof state.destination !== "object") {
  6403. return false;
  6404. }
  6405. return true;
  6406. }
  6407. #updateInternalState(destination, uid, removeTemporary = false) {
  6408. if (this._updateViewareaTimeout) {
  6409. clearTimeout(this._updateViewareaTimeout);
  6410. this._updateViewareaTimeout = null;
  6411. }
  6412. if (removeTemporary && destination?.temporary) {
  6413. delete destination.temporary;
  6414. }
  6415. this._destination = destination;
  6416. this._uid = uid;
  6417. this._maxUid = Math.max(this._maxUid, uid);
  6418. this._numPositionUpdates = 0;
  6419. }
  6420. #parseCurrentHash(checkNameddest = false) {
  6421. const hash = unescape(getCurrentHash()).substring(1);
  6422. const params = parseQueryString(hash);
  6423. const nameddest = params.get("nameddest") || "";
  6424. let page = params.get("page") | 0;
  6425. if (!this.#isValidPage(page) || checkNameddest && nameddest.length > 0) {
  6426. page = null;
  6427. }
  6428. return {
  6429. hash,
  6430. page,
  6431. rotation: this.linkService.rotation
  6432. };
  6433. }
  6434. #updateViewarea({
  6435. location
  6436. }) {
  6437. if (this._updateViewareaTimeout) {
  6438. clearTimeout(this._updateViewareaTimeout);
  6439. this._updateViewareaTimeout = null;
  6440. }
  6441. this._position = {
  6442. hash: location.pdfOpenParams.substring(1),
  6443. page: this.linkService.page,
  6444. first: location.pageNumber,
  6445. rotation: location.rotation
  6446. };
  6447. if (this._popStateInProgress) {
  6448. return;
  6449. }
  6450. if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) {
  6451. this._numPositionUpdates++;
  6452. }
  6453. if (UPDATE_VIEWAREA_TIMEOUT > 0) {
  6454. this._updateViewareaTimeout = setTimeout(() => {
  6455. if (!this._popStateInProgress) {
  6456. this.#tryPushCurrentPosition(true);
  6457. }
  6458. this._updateViewareaTimeout = null;
  6459. }, UPDATE_VIEWAREA_TIMEOUT);
  6460. }
  6461. }
  6462. #popState({
  6463. state
  6464. }) {
  6465. const newHash = getCurrentHash(),
  6466. hashChanged = this._currentHash !== newHash;
  6467. this._currentHash = newHash;
  6468. if (!state) {
  6469. this._uid++;
  6470. const {
  6471. hash,
  6472. page,
  6473. rotation
  6474. } = this.#parseCurrentHash();
  6475. this.#pushOrReplaceState({
  6476. hash,
  6477. page,
  6478. rotation
  6479. }, true);
  6480. return;
  6481. }
  6482. if (!this.#isValidState(state)) {
  6483. return;
  6484. }
  6485. this._popStateInProgress = true;
  6486. if (hashChanged) {
  6487. this._blockHashChange++;
  6488. waitOnEventOrTimeout({
  6489. target: window,
  6490. name: "hashchange",
  6491. delay: HASH_CHANGE_TIMEOUT
  6492. }).then(() => {
  6493. this._blockHashChange--;
  6494. });
  6495. }
  6496. const destination = state.destination;
  6497. this.#updateInternalState(destination, state.uid, true);
  6498. if (isValidRotation(destination.rotation)) {
  6499. this.linkService.rotation = destination.rotation;
  6500. }
  6501. if (destination.dest) {
  6502. this.linkService.goToDestination(destination.dest);
  6503. } else if (destination.hash) {
  6504. this.linkService.setHash(destination.hash);
  6505. } else if (destination.page) {
  6506. this.linkService.page = destination.page;
  6507. }
  6508. Promise.resolve().then(() => {
  6509. this._popStateInProgress = false;
  6510. });
  6511. }
  6512. #pageHide() {
  6513. if (!this._destination || this._destination.temporary) {
  6514. this.#tryPushCurrentPosition();
  6515. }
  6516. }
  6517. #bindEvents() {
  6518. if (this.#eventAbortController) {
  6519. return;
  6520. }
  6521. this.#eventAbortController = new AbortController();
  6522. const {
  6523. signal
  6524. } = this.#eventAbortController;
  6525. this.eventBus._on("updateviewarea", this.#updateViewarea.bind(this), {
  6526. signal
  6527. });
  6528. window.addEventListener("popstate", this.#popState.bind(this), {
  6529. signal
  6530. });
  6531. window.addEventListener("pagehide", this.#pageHide.bind(this), {
  6532. signal
  6533. });
  6534. }
  6535. #unbindEvents() {
  6536. this.#eventAbortController?.abort();
  6537. this.#eventAbortController = null;
  6538. }
  6539. }
  6540. function isDestHashesEqual(destHash, pushHash) {
  6541. if (typeof destHash !== "string" || typeof pushHash !== "string") {
  6542. return false;
  6543. }
  6544. if (destHash === pushHash) {
  6545. return true;
  6546. }
  6547. const nameddest = parseQueryString(destHash).get("nameddest");
  6548. if (nameddest === pushHash) {
  6549. return true;
  6550. }
  6551. return false;
  6552. }
  6553. function isDestArraysEqual(firstDest, secondDest) {
  6554. function isEntryEqual(first, second) {
  6555. if (typeof first !== typeof second) {
  6556. return false;
  6557. }
  6558. if (Array.isArray(first) || Array.isArray(second)) {
  6559. return false;
  6560. }
  6561. if (first !== null && typeof first === "object" && second !== null) {
  6562. if (Object.keys(first).length !== Object.keys(second).length) {
  6563. return false;
  6564. }
  6565. for (const key in first) {
  6566. if (!isEntryEqual(first[key], second[key])) {
  6567. return false;
  6568. }
  6569. }
  6570. return true;
  6571. }
  6572. return first === second || Number.isNaN(first) && Number.isNaN(second);
  6573. }
  6574. if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) {
  6575. return false;
  6576. }
  6577. if (firstDest.length !== secondDest.length) {
  6578. return false;
  6579. }
  6580. for (let i = 0, ii = firstDest.length; i < ii; i++) {
  6581. if (!isEntryEqual(firstDest[i], secondDest[i])) {
  6582. return false;
  6583. }
  6584. }
  6585. return true;
  6586. }
  6587. ;// ./web/pdf_layer_viewer.js
  6588. class PDFLayerViewer extends BaseTreeViewer {
  6589. constructor(options) {
  6590. super(options);
  6591. this.eventBus._on("optionalcontentconfigchanged", evt => {
  6592. this.#updateLayers(evt.promise);
  6593. });
  6594. this.eventBus._on("resetlayers", () => {
  6595. this.#updateLayers();
  6596. });
  6597. this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this));
  6598. }
  6599. reset() {
  6600. super.reset();
  6601. this._optionalContentConfig = null;
  6602. this._optionalContentVisibility?.clear();
  6603. this._optionalContentVisibility = null;
  6604. }
  6605. _dispatchEvent(layersCount) {
  6606. this.eventBus.dispatch("layersloaded", {
  6607. source: this,
  6608. layersCount
  6609. });
  6610. }
  6611. _bindLink(element, {
  6612. groupId,
  6613. input
  6614. }) {
  6615. const setVisibility = () => {
  6616. const visible = input.checked;
  6617. this._optionalContentConfig.setVisibility(groupId, visible);
  6618. const cached = this._optionalContentVisibility.get(groupId);
  6619. if (cached) {
  6620. cached.visible = visible;
  6621. }
  6622. this.eventBus.dispatch("optionalcontentconfig", {
  6623. source: this,
  6624. promise: Promise.resolve(this._optionalContentConfig)
  6625. });
  6626. };
  6627. element.onclick = evt => {
  6628. if (evt.target === input) {
  6629. setVisibility();
  6630. return true;
  6631. } else if (evt.target !== element) {
  6632. return true;
  6633. }
  6634. input.checked = !input.checked;
  6635. setVisibility();
  6636. return false;
  6637. };
  6638. }
  6639. _setNestedName(element, {
  6640. name = null
  6641. }) {
  6642. if (typeof name === "string") {
  6643. element.textContent = this._normalizeTextContent(name);
  6644. return;
  6645. }
  6646. element.setAttribute("data-l10n-id", "pdfjs-additional-layers");
  6647. element.style.fontStyle = "italic";
  6648. this._l10n.translateOnce(element);
  6649. }
  6650. _addToggleButton(div, {
  6651. name = null
  6652. }) {
  6653. super._addToggleButton(div, name === null);
  6654. }
  6655. _toggleAllTreeItems() {
  6656. if (!this._optionalContentConfig) {
  6657. return;
  6658. }
  6659. super._toggleAllTreeItems();
  6660. }
  6661. render({
  6662. optionalContentConfig,
  6663. pdfDocument
  6664. }) {
  6665. if (this._optionalContentConfig) {
  6666. this.reset();
  6667. }
  6668. this._optionalContentConfig = optionalContentConfig || null;
  6669. this._pdfDocument = pdfDocument || null;
  6670. const groups = optionalContentConfig?.getOrder();
  6671. if (!groups) {
  6672. this._dispatchEvent(0);
  6673. return;
  6674. }
  6675. this._optionalContentVisibility = new Map();
  6676. const fragment = document.createDocumentFragment(),
  6677. queue = [{
  6678. parent: fragment,
  6679. groups
  6680. }];
  6681. let layersCount = 0,
  6682. hasAnyNesting = false;
  6683. while (queue.length > 0) {
  6684. const levelData = queue.shift();
  6685. for (const groupId of levelData.groups) {
  6686. const div = document.createElement("div");
  6687. div.className = "treeItem";
  6688. const element = document.createElement("a");
  6689. div.append(element);
  6690. if (typeof groupId === "object") {
  6691. hasAnyNesting = true;
  6692. this._addToggleButton(div, groupId);
  6693. this._setNestedName(element, groupId);
  6694. const itemsDiv = document.createElement("div");
  6695. itemsDiv.className = "treeItems";
  6696. div.append(itemsDiv);
  6697. queue.push({
  6698. parent: itemsDiv,
  6699. groups: groupId.order
  6700. });
  6701. } else {
  6702. const group = optionalContentConfig.getGroup(groupId);
  6703. const input = document.createElement("input");
  6704. this._bindLink(element, {
  6705. groupId,
  6706. input
  6707. });
  6708. input.type = "checkbox";
  6709. input.checked = group.visible;
  6710. this._optionalContentVisibility.set(groupId, {
  6711. input,
  6712. visible: input.checked
  6713. });
  6714. const label = document.createElement("label");
  6715. label.textContent = this._normalizeTextContent(group.name);
  6716. label.append(input);
  6717. element.append(label);
  6718. layersCount++;
  6719. }
  6720. levelData.parent.append(div);
  6721. }
  6722. }
  6723. this._finishRendering(fragment, layersCount, hasAnyNesting);
  6724. }
  6725. async #updateLayers(promise = null) {
  6726. if (!this._optionalContentConfig) {
  6727. return;
  6728. }
  6729. const pdfDocument = this._pdfDocument;
  6730. const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig({
  6731. intent: "display"
  6732. }));
  6733. if (pdfDocument !== this._pdfDocument) {
  6734. return;
  6735. }
  6736. if (promise) {
  6737. for (const [groupId, cached] of this._optionalContentVisibility) {
  6738. const group = optionalContentConfig.getGroup(groupId);
  6739. if (group && cached.visible !== group.visible) {
  6740. cached.input.checked = cached.visible = !cached.visible;
  6741. }
  6742. }
  6743. return;
  6744. }
  6745. this.eventBus.dispatch("optionalcontentconfig", {
  6746. source: this,
  6747. promise: Promise.resolve(optionalContentConfig)
  6748. });
  6749. this.render({
  6750. optionalContentConfig,
  6751. pdfDocument: this._pdfDocument
  6752. });
  6753. }
  6754. }
  6755. ;// ./web/pdf_outline_viewer.js
  6756. class PDFOutlineViewer extends BaseTreeViewer {
  6757. constructor(options) {
  6758. super(options);
  6759. this.linkService = options.linkService;
  6760. this.downloadManager = options.downloadManager;
  6761. this.eventBus._on("toggleoutlinetree", this._toggleAllTreeItems.bind(this));
  6762. this.eventBus._on("currentoutlineitem", this._currentOutlineItem.bind(this));
  6763. this.eventBus._on("pagechanging", evt => {
  6764. this._currentPageNumber = evt.pageNumber;
  6765. });
  6766. this.eventBus._on("pagesloaded", evt => {
  6767. this._isPagesLoaded = !!evt.pagesCount;
  6768. this._currentOutlineItemCapability?.resolve(this._isPagesLoaded);
  6769. });
  6770. this.eventBus._on("sidebarviewchanged", evt => {
  6771. this._sidebarView = evt.view;
  6772. });
  6773. }
  6774. reset() {
  6775. super.reset();
  6776. this._outline = null;
  6777. this._pageNumberToDestHashCapability = null;
  6778. this._currentPageNumber = 1;
  6779. this._isPagesLoaded = null;
  6780. this._currentOutlineItemCapability?.resolve(false);
  6781. this._currentOutlineItemCapability = null;
  6782. }
  6783. _dispatchEvent(outlineCount) {
  6784. this._currentOutlineItemCapability = Promise.withResolvers();
  6785. if (outlineCount === 0 || this._pdfDocument?.loadingParams.disableAutoFetch) {
  6786. this._currentOutlineItemCapability.resolve(false);
  6787. } else if (this._isPagesLoaded !== null) {
  6788. this._currentOutlineItemCapability.resolve(this._isPagesLoaded);
  6789. }
  6790. this.eventBus.dispatch("outlineloaded", {
  6791. source: this,
  6792. outlineCount,
  6793. currentOutlineItemPromise: this._currentOutlineItemCapability.promise
  6794. });
  6795. }
  6796. _bindLink(element, {
  6797. url,
  6798. newWindow,
  6799. action,
  6800. attachment,
  6801. dest,
  6802. setOCGState
  6803. }) {
  6804. const {
  6805. linkService
  6806. } = this;
  6807. if (url) {
  6808. linkService.addLinkAttributes(element, url, newWindow);
  6809. return;
  6810. }
  6811. if (action) {
  6812. element.href = linkService.getAnchorUrl("");
  6813. element.onclick = () => {
  6814. linkService.executeNamedAction(action);
  6815. return false;
  6816. };
  6817. return;
  6818. }
  6819. if (attachment) {
  6820. element.href = linkService.getAnchorUrl("");
  6821. element.onclick = () => {
  6822. this.downloadManager.openOrDownloadData(attachment.content, attachment.filename);
  6823. return false;
  6824. };
  6825. return;
  6826. }
  6827. if (setOCGState) {
  6828. element.href = linkService.getAnchorUrl("");
  6829. element.onclick = () => {
  6830. linkService.executeSetOCGState(setOCGState);
  6831. return false;
  6832. };
  6833. return;
  6834. }
  6835. element.href = linkService.getDestinationHash(dest);
  6836. element.onclick = evt => {
  6837. this._updateCurrentTreeItem(evt.target.parentNode);
  6838. if (dest) {
  6839. linkService.goToDestination(dest);
  6840. }
  6841. return false;
  6842. };
  6843. }
  6844. _setStyles(element, {
  6845. bold,
  6846. italic
  6847. }) {
  6848. if (bold) {
  6849. element.style.fontWeight = "bold";
  6850. }
  6851. if (italic) {
  6852. element.style.fontStyle = "italic";
  6853. }
  6854. }
  6855. _addToggleButton(div, {
  6856. count,
  6857. items
  6858. }) {
  6859. let hidden = false;
  6860. if (count < 0) {
  6861. let totalCount = items.length;
  6862. if (totalCount > 0) {
  6863. const queue = [...items];
  6864. while (queue.length > 0) {
  6865. const {
  6866. count: nestedCount,
  6867. items: nestedItems
  6868. } = queue.shift();
  6869. if (nestedCount > 0 && nestedItems.length > 0) {
  6870. totalCount += nestedItems.length;
  6871. queue.push(...nestedItems);
  6872. }
  6873. }
  6874. }
  6875. if (Math.abs(count) === totalCount) {
  6876. hidden = true;
  6877. }
  6878. }
  6879. super._addToggleButton(div, hidden);
  6880. }
  6881. _toggleAllTreeItems() {
  6882. if (!this._outline) {
  6883. return;
  6884. }
  6885. super._toggleAllTreeItems();
  6886. }
  6887. render({
  6888. outline,
  6889. pdfDocument
  6890. }) {
  6891. if (this._outline) {
  6892. this.reset();
  6893. }
  6894. this._outline = outline || null;
  6895. this._pdfDocument = pdfDocument || null;
  6896. if (!outline) {
  6897. this._dispatchEvent(0);
  6898. return;
  6899. }
  6900. const fragment = document.createDocumentFragment();
  6901. const queue = [{
  6902. parent: fragment,
  6903. items: outline
  6904. }];
  6905. let outlineCount = 0,
  6906. hasAnyNesting = false;
  6907. while (queue.length > 0) {
  6908. const levelData = queue.shift();
  6909. for (const item of levelData.items) {
  6910. const div = document.createElement("div");
  6911. div.className = "treeItem";
  6912. const element = document.createElement("a");
  6913. this._bindLink(element, item);
  6914. this._setStyles(element, item);
  6915. element.textContent = this._normalizeTextContent(item.title);
  6916. div.append(element);
  6917. if (item.items.length > 0) {
  6918. hasAnyNesting = true;
  6919. this._addToggleButton(div, item);
  6920. const itemsDiv = document.createElement("div");
  6921. itemsDiv.className = "treeItems";
  6922. div.append(itemsDiv);
  6923. queue.push({
  6924. parent: itemsDiv,
  6925. items: item.items
  6926. });
  6927. }
  6928. levelData.parent.append(div);
  6929. outlineCount++;
  6930. }
  6931. }
  6932. this._finishRendering(fragment, outlineCount, hasAnyNesting);
  6933. }
  6934. async _currentOutlineItem() {
  6935. if (!this._isPagesLoaded) {
  6936. throw new Error("_currentOutlineItem: All pages have not been loaded.");
  6937. }
  6938. if (!this._outline || !this._pdfDocument) {
  6939. return;
  6940. }
  6941. const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument);
  6942. if (!pageNumberToDestHash) {
  6943. return;
  6944. }
  6945. this._updateCurrentTreeItem(null);
  6946. if (this._sidebarView !== SidebarView.OUTLINE) {
  6947. return;
  6948. }
  6949. for (let i = this._currentPageNumber; i > 0; i--) {
  6950. const destHash = pageNumberToDestHash.get(i);
  6951. if (!destHash) {
  6952. continue;
  6953. }
  6954. const linkElement = this.container.querySelector(`a[href="${destHash}"]`);
  6955. if (!linkElement) {
  6956. continue;
  6957. }
  6958. this._scrollToCurrentTreeItem(linkElement.parentNode);
  6959. break;
  6960. }
  6961. }
  6962. async _getPageNumberToDestHash(pdfDocument) {
  6963. if (this._pageNumberToDestHashCapability) {
  6964. return this._pageNumberToDestHashCapability.promise;
  6965. }
  6966. this._pageNumberToDestHashCapability = Promise.withResolvers();
  6967. const pageNumberToDestHash = new Map(),
  6968. pageNumberNesting = new Map();
  6969. const queue = [{
  6970. nesting: 0,
  6971. items: this._outline
  6972. }];
  6973. while (queue.length > 0) {
  6974. const levelData = queue.shift(),
  6975. currentNesting = levelData.nesting;
  6976. for (const {
  6977. dest,
  6978. items
  6979. } of levelData.items) {
  6980. let explicitDest, pageNumber;
  6981. if (typeof dest === "string") {
  6982. explicitDest = await pdfDocument.getDestination(dest);
  6983. if (pdfDocument !== this._pdfDocument) {
  6984. return null;
  6985. }
  6986. } else {
  6987. explicitDest = dest;
  6988. }
  6989. if (Array.isArray(explicitDest)) {
  6990. const [destRef] = explicitDest;
  6991. if (destRef && typeof destRef === "object") {
  6992. pageNumber = pdfDocument.cachedPageNumber(destRef);
  6993. } else if (Number.isInteger(destRef)) {
  6994. pageNumber = destRef + 1;
  6995. }
  6996. if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) {
  6997. const destHash = this.linkService.getDestinationHash(dest);
  6998. pageNumberToDestHash.set(pageNumber, destHash);
  6999. pageNumberNesting.set(pageNumber, currentNesting);
  7000. }
  7001. }
  7002. if (items.length > 0) {
  7003. queue.push({
  7004. nesting: currentNesting + 1,
  7005. items
  7006. });
  7007. }
  7008. }
  7009. }
  7010. this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null);
  7011. return this._pageNumberToDestHashCapability.promise;
  7012. }
  7013. }
  7014. ;// ./web/pdf_presentation_mode.js
  7015. const DELAY_BEFORE_HIDING_CONTROLS = 3000;
  7016. const ACTIVE_SELECTOR = "pdfPresentationMode";
  7017. const CONTROLS_SELECTOR = "pdfPresentationModeControls";
  7018. const MOUSE_SCROLL_COOLDOWN_TIME = 50;
  7019. const PAGE_SWITCH_THRESHOLD = 0.1;
  7020. const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
  7021. const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
  7022. class PDFPresentationMode {
  7023. #state = PresentationModeState.UNKNOWN;
  7024. #args = null;
  7025. #fullscreenChangeAbortController = null;
  7026. #windowAbortController = null;
  7027. constructor({
  7028. container,
  7029. pdfViewer,
  7030. eventBus
  7031. }) {
  7032. this.container = container;
  7033. this.pdfViewer = pdfViewer;
  7034. this.eventBus = eventBus;
  7035. this.contextMenuOpen = false;
  7036. this.mouseScrollTimeStamp = 0;
  7037. this.mouseScrollDelta = 0;
  7038. this.touchSwipeState = null;
  7039. }
  7040. async request() {
  7041. const {
  7042. container,
  7043. pdfViewer
  7044. } = this;
  7045. if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) {
  7046. return false;
  7047. }
  7048. this.#addFullscreenChangeListeners();
  7049. this.#notifyStateChange(PresentationModeState.CHANGING);
  7050. const promise = container.requestFullscreen();
  7051. this.#args = {
  7052. pageNumber: pdfViewer.currentPageNumber,
  7053. scaleValue: pdfViewer.currentScaleValue,
  7054. scrollMode: pdfViewer.scrollMode,
  7055. spreadMode: null,
  7056. annotationEditorMode: null
  7057. };
  7058. if (pdfViewer.spreadMode !== SpreadMode.NONE && !(pdfViewer.pageViewsReady && pdfViewer.hasEqualPageSizes)) {
  7059. console.warn("Ignoring Spread modes when entering PresentationMode, " + "since the document may contain varying page sizes.");
  7060. this.#args.spreadMode = pdfViewer.spreadMode;
  7061. }
  7062. if (pdfViewer.annotationEditorMode !== AnnotationEditorType.DISABLE) {
  7063. this.#args.annotationEditorMode = pdfViewer.annotationEditorMode;
  7064. }
  7065. try {
  7066. await promise;
  7067. pdfViewer.focus();
  7068. return true;
  7069. } catch {
  7070. this.#removeFullscreenChangeListeners();
  7071. this.#notifyStateChange(PresentationModeState.NORMAL);
  7072. }
  7073. return false;
  7074. }
  7075. get active() {
  7076. return this.#state === PresentationModeState.CHANGING || this.#state === PresentationModeState.FULLSCREEN;
  7077. }
  7078. #mouseWheel(evt) {
  7079. if (!this.active) {
  7080. return;
  7081. }
  7082. evt.preventDefault();
  7083. const delta = normalizeWheelEventDelta(evt);
  7084. const currentTime = Date.now();
  7085. const storedTime = this.mouseScrollTimeStamp;
  7086. if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
  7087. return;
  7088. }
  7089. if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
  7090. this.#resetMouseScrollState();
  7091. }
  7092. this.mouseScrollDelta += delta;
  7093. if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
  7094. const totalDelta = this.mouseScrollDelta;
  7095. this.#resetMouseScrollState();
  7096. const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage();
  7097. if (success) {
  7098. this.mouseScrollTimeStamp = currentTime;
  7099. }
  7100. }
  7101. }
  7102. #notifyStateChange(state) {
  7103. this.#state = state;
  7104. this.eventBus.dispatch("presentationmodechanged", {
  7105. source: this,
  7106. state
  7107. });
  7108. }
  7109. #enter() {
  7110. this.#notifyStateChange(PresentationModeState.FULLSCREEN);
  7111. this.container.classList.add(ACTIVE_SELECTOR);
  7112. setTimeout(() => {
  7113. this.pdfViewer.scrollMode = ScrollMode.PAGE;
  7114. if (this.#args.spreadMode !== null) {
  7115. this.pdfViewer.spreadMode = SpreadMode.NONE;
  7116. }
  7117. this.pdfViewer.currentPageNumber = this.#args.pageNumber;
  7118. this.pdfViewer.currentScaleValue = "page-fit";
  7119. if (this.#args.annotationEditorMode !== null) {
  7120. this.pdfViewer.annotationEditorMode = {
  7121. mode: AnnotationEditorType.NONE
  7122. };
  7123. }
  7124. }, 0);
  7125. this.#addWindowListeners();
  7126. this.#showControls();
  7127. this.contextMenuOpen = false;
  7128. document.getSelection().empty();
  7129. }
  7130. #exit() {
  7131. const pageNumber = this.pdfViewer.currentPageNumber;
  7132. this.container.classList.remove(ACTIVE_SELECTOR);
  7133. setTimeout(() => {
  7134. this.#removeFullscreenChangeListeners();
  7135. this.#notifyStateChange(PresentationModeState.NORMAL);
  7136. this.pdfViewer.scrollMode = this.#args.scrollMode;
  7137. if (this.#args.spreadMode !== null) {
  7138. this.pdfViewer.spreadMode = this.#args.spreadMode;
  7139. }
  7140. this.pdfViewer.currentScaleValue = this.#args.scaleValue;
  7141. this.pdfViewer.currentPageNumber = pageNumber;
  7142. if (this.#args.annotationEditorMode !== null) {
  7143. this.pdfViewer.annotationEditorMode = {
  7144. mode: this.#args.annotationEditorMode
  7145. };
  7146. }
  7147. this.#args = null;
  7148. }, 0);
  7149. this.#removeWindowListeners();
  7150. this.#hideControls();
  7151. this.#resetMouseScrollState();
  7152. this.contextMenuOpen = false;
  7153. }
  7154. #mouseDown(evt) {
  7155. if (this.contextMenuOpen) {
  7156. this.contextMenuOpen = false;
  7157. evt.preventDefault();
  7158. return;
  7159. }
  7160. if (evt.button !== 0) {
  7161. return;
  7162. }
  7163. if (evt.target.href && evt.target.parentNode?.hasAttribute("data-internal-link")) {
  7164. return;
  7165. }
  7166. evt.preventDefault();
  7167. if (evt.shiftKey) {
  7168. this.pdfViewer.previousPage();
  7169. } else {
  7170. this.pdfViewer.nextPage();
  7171. }
  7172. }
  7173. #contextMenu() {
  7174. this.contextMenuOpen = true;
  7175. }
  7176. #showControls() {
  7177. if (this.controlsTimeout) {
  7178. clearTimeout(this.controlsTimeout);
  7179. } else {
  7180. this.container.classList.add(CONTROLS_SELECTOR);
  7181. }
  7182. this.controlsTimeout = setTimeout(() => {
  7183. this.container.classList.remove(CONTROLS_SELECTOR);
  7184. delete this.controlsTimeout;
  7185. }, DELAY_BEFORE_HIDING_CONTROLS);
  7186. }
  7187. #hideControls() {
  7188. if (!this.controlsTimeout) {
  7189. return;
  7190. }
  7191. clearTimeout(this.controlsTimeout);
  7192. this.container.classList.remove(CONTROLS_SELECTOR);
  7193. delete this.controlsTimeout;
  7194. }
  7195. #resetMouseScrollState() {
  7196. this.mouseScrollTimeStamp = 0;
  7197. this.mouseScrollDelta = 0;
  7198. }
  7199. #touchSwipe(evt) {
  7200. if (!this.active) {
  7201. return;
  7202. }
  7203. if (evt.touches.length > 1) {
  7204. this.touchSwipeState = null;
  7205. return;
  7206. }
  7207. switch (evt.type) {
  7208. case "touchstart":
  7209. this.touchSwipeState = {
  7210. startX: evt.touches[0].pageX,
  7211. startY: evt.touches[0].pageY,
  7212. endX: evt.touches[0].pageX,
  7213. endY: evt.touches[0].pageY
  7214. };
  7215. break;
  7216. case "touchmove":
  7217. if (this.touchSwipeState === null) {
  7218. return;
  7219. }
  7220. this.touchSwipeState.endX = evt.touches[0].pageX;
  7221. this.touchSwipeState.endY = evt.touches[0].pageY;
  7222. evt.preventDefault();
  7223. break;
  7224. case "touchend":
  7225. if (this.touchSwipeState === null) {
  7226. return;
  7227. }
  7228. let delta = 0;
  7229. const dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
  7230. const dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
  7231. const absAngle = Math.abs(Math.atan2(dy, dx));
  7232. if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
  7233. delta = dx;
  7234. } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
  7235. delta = dy;
  7236. }
  7237. if (delta > 0) {
  7238. this.pdfViewer.previousPage();
  7239. } else if (delta < 0) {
  7240. this.pdfViewer.nextPage();
  7241. }
  7242. break;
  7243. }
  7244. }
  7245. #addWindowListeners() {
  7246. if (this.#windowAbortController) {
  7247. return;
  7248. }
  7249. this.#windowAbortController = new AbortController();
  7250. const {
  7251. signal
  7252. } = this.#windowAbortController;
  7253. const touchSwipeBind = this.#touchSwipe.bind(this);
  7254. window.addEventListener("mousemove", this.#showControls.bind(this), {
  7255. signal
  7256. });
  7257. window.addEventListener("mousedown", this.#mouseDown.bind(this), {
  7258. signal
  7259. });
  7260. window.addEventListener("wheel", this.#mouseWheel.bind(this), {
  7261. passive: false,
  7262. signal
  7263. });
  7264. window.addEventListener("keydown", this.#resetMouseScrollState.bind(this), {
  7265. signal
  7266. });
  7267. window.addEventListener("contextmenu", this.#contextMenu.bind(this), {
  7268. signal
  7269. });
  7270. window.addEventListener("touchstart", touchSwipeBind, {
  7271. signal
  7272. });
  7273. window.addEventListener("touchmove", touchSwipeBind, {
  7274. signal
  7275. });
  7276. window.addEventListener("touchend", touchSwipeBind, {
  7277. signal
  7278. });
  7279. }
  7280. #removeWindowListeners() {
  7281. this.#windowAbortController?.abort();
  7282. this.#windowAbortController = null;
  7283. }
  7284. #addFullscreenChangeListeners() {
  7285. if (this.#fullscreenChangeAbortController) {
  7286. return;
  7287. }
  7288. this.#fullscreenChangeAbortController = new AbortController();
  7289. window.addEventListener("fullscreenchange", () => {
  7290. if (document.fullscreenElement) {
  7291. this.#enter();
  7292. } else {
  7293. this.#exit();
  7294. }
  7295. }, {
  7296. signal: this.#fullscreenChangeAbortController.signal
  7297. });
  7298. }
  7299. #removeFullscreenChangeListeners() {
  7300. this.#fullscreenChangeAbortController?.abort();
  7301. this.#fullscreenChangeAbortController = null;
  7302. }
  7303. }
  7304. ;// ./web/xfa_layer_builder.js
  7305. class XfaLayerBuilder {
  7306. constructor({
  7307. pdfPage,
  7308. annotationStorage = null,
  7309. linkService,
  7310. xfaHtml = null
  7311. }) {
  7312. this.pdfPage = pdfPage;
  7313. this.annotationStorage = annotationStorage;
  7314. this.linkService = linkService;
  7315. this.xfaHtml = xfaHtml;
  7316. this.div = null;
  7317. this._cancelled = false;
  7318. }
  7319. async render({
  7320. viewport,
  7321. intent = "display"
  7322. }) {
  7323. if (intent === "print") {
  7324. const parameters = {
  7325. viewport: viewport.clone({
  7326. dontFlip: true
  7327. }),
  7328. div: this.div,
  7329. xfaHtml: this.xfaHtml,
  7330. annotationStorage: this.annotationStorage,
  7331. linkService: this.linkService,
  7332. intent
  7333. };
  7334. this.div = document.createElement("div");
  7335. parameters.div = this.div;
  7336. return XfaLayer.render(parameters);
  7337. }
  7338. const xfaHtml = await this.pdfPage.getXfa();
  7339. if (this._cancelled || !xfaHtml) {
  7340. return {
  7341. textDivs: []
  7342. };
  7343. }
  7344. const parameters = {
  7345. viewport: viewport.clone({
  7346. dontFlip: true
  7347. }),
  7348. div: this.div,
  7349. xfaHtml,
  7350. annotationStorage: this.annotationStorage,
  7351. linkService: this.linkService,
  7352. intent
  7353. };
  7354. if (this.div) {
  7355. return XfaLayer.update(parameters);
  7356. }
  7357. this.div = document.createElement("div");
  7358. parameters.div = this.div;
  7359. return XfaLayer.render(parameters);
  7360. }
  7361. cancel() {
  7362. this._cancelled = true;
  7363. }
  7364. hide() {
  7365. if (!this.div) {
  7366. return;
  7367. }
  7368. this.div.hidden = true;
  7369. }
  7370. }
  7371. ;// ./web/print_utils.js
  7372. function getXfaHtmlForPrinting(printContainer, pdfDocument) {
  7373. const xfaHtml = pdfDocument.allXfaHtml;
  7374. const linkService = new SimpleLinkService();
  7375. const scale = Math.round(PixelsPerInch.PDF_TO_CSS_UNITS * 100) / 100;
  7376. for (const xfaPage of xfaHtml.children) {
  7377. const page = document.createElement("div");
  7378. page.className = "xfaPrintedPage";
  7379. printContainer.append(page);
  7380. const builder = new XfaLayerBuilder({
  7381. pdfPage: null,
  7382. annotationStorage: pdfDocument.annotationStorage,
  7383. linkService,
  7384. xfaHtml: xfaPage
  7385. });
  7386. const viewport = getXfaPageViewport(xfaPage, {
  7387. scale
  7388. });
  7389. builder.render(viewport, "print");
  7390. page.append(builder.div);
  7391. }
  7392. }
  7393. ;// ./web/pdf_print_service.js
  7394. let activeService = null;
  7395. let dialog = null;
  7396. let overlayManager = null;
  7397. let viewerApp = {
  7398. initialized: false
  7399. };
  7400. function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) {
  7401. const scratchCanvas = activeService.scratchCanvas;
  7402. const PRINT_UNITS = printResolution / PixelsPerInch.PDF;
  7403. scratchCanvas.width = Math.floor(size.width * PRINT_UNITS);
  7404. scratchCanvas.height = Math.floor(size.height * PRINT_UNITS);
  7405. const ctx = scratchCanvas.getContext("2d");
  7406. ctx.save();
  7407. ctx.fillStyle = "rgb(255, 255, 255)";
  7408. ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height);
  7409. ctx.restore();
  7410. return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function ([pdfPage, printAnnotationStorage]) {
  7411. const renderContext = {
  7412. canvasContext: ctx,
  7413. transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
  7414. viewport: pdfPage.getViewport({
  7415. scale: 1,
  7416. rotation: size.rotation
  7417. }),
  7418. intent: "print",
  7419. annotationMode: AnnotationMode.ENABLE_STORAGE,
  7420. optionalContentConfigPromise,
  7421. printAnnotationStorage
  7422. };
  7423. const renderTask = pdfPage.render(renderContext);
  7424. return renderTask.promise.catch(reason => {
  7425. if (!(reason instanceof RenderingCancelledException)) {
  7426. console.error(reason);
  7427. }
  7428. throw reason;
  7429. });
  7430. });
  7431. }
  7432. class PDFPrintService {
  7433. constructor({
  7434. pdfDocument,
  7435. pagesOverview,
  7436. printContainer,
  7437. printResolution,
  7438. printAnnotationStoragePromise = null
  7439. }) {
  7440. this.pdfDocument = pdfDocument;
  7441. this.pagesOverview = pagesOverview;
  7442. this.printContainer = printContainer;
  7443. this._printResolution = printResolution || 150;
  7444. this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
  7445. intent: "print"
  7446. });
  7447. this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve();
  7448. this.currentPage = -1;
  7449. this.scratchCanvas = document.createElement("canvas");
  7450. }
  7451. layout() {
  7452. this.throwIfInactive();
  7453. const body = document.querySelector("body");
  7454. body.setAttribute("data-pdfjsprinting", true);
  7455. const {
  7456. width,
  7457. height
  7458. } = this.pagesOverview[0];
  7459. const hasEqualPageSizes = this.pagesOverview.every(size => size.width === width && size.height === height);
  7460. if (!hasEqualPageSizes) {
  7461. console.warn("Not all pages have the same size. The printed result may be incorrect!");
  7462. }
  7463. this.pageStyleSheet = document.createElement("style");
  7464. this.pageStyleSheet.textContent = `@page { size: ${width}pt ${height}pt;}`;
  7465. body.append(this.pageStyleSheet);
  7466. }
  7467. destroy() {
  7468. if (activeService !== this) {
  7469. return;
  7470. }
  7471. this.printContainer.textContent = "";
  7472. const body = document.querySelector("body");
  7473. body.removeAttribute("data-pdfjsprinting");
  7474. if (this.pageStyleSheet) {
  7475. this.pageStyleSheet.remove();
  7476. this.pageStyleSheet = null;
  7477. }
  7478. this.scratchCanvas.width = this.scratchCanvas.height = 0;
  7479. this.scratchCanvas = null;
  7480. activeService = null;
  7481. ensureOverlay().then(function () {
  7482. overlayManager.closeIfActive(dialog);
  7483. });
  7484. }
  7485. renderPages() {
  7486. if (this.pdfDocument.isPureXfa) {
  7487. getXfaHtmlForPrinting(this.printContainer, this.pdfDocument);
  7488. return Promise.resolve();
  7489. }
  7490. const pageCount = this.pagesOverview.length;
  7491. const renderNextPage = (resolve, reject) => {
  7492. this.throwIfInactive();
  7493. if (++this.currentPage >= pageCount) {
  7494. renderProgress(pageCount, pageCount);
  7495. resolve();
  7496. return;
  7497. }
  7498. const index = this.currentPage;
  7499. renderProgress(index, pageCount);
  7500. renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () {
  7501. renderNextPage(resolve, reject);
  7502. }, reject);
  7503. };
  7504. return new Promise(renderNextPage);
  7505. }
  7506. useRenderedPage() {
  7507. this.throwIfInactive();
  7508. const img = document.createElement("img");
  7509. this.scratchCanvas.toBlob(blob => {
  7510. img.src = URL.createObjectURL(blob);
  7511. });
  7512. const wrapper = document.createElement("div");
  7513. wrapper.className = "printedPage";
  7514. wrapper.append(img);
  7515. this.printContainer.append(wrapper);
  7516. const {
  7517. promise,
  7518. resolve,
  7519. reject
  7520. } = Promise.withResolvers();
  7521. img.onload = resolve;
  7522. img.onerror = reject;
  7523. promise.catch(() => {}).then(() => {
  7524. URL.revokeObjectURL(img.src);
  7525. });
  7526. return promise;
  7527. }
  7528. performPrint() {
  7529. this.throwIfInactive();
  7530. return new Promise(resolve => {
  7531. setTimeout(() => {
  7532. if (!this.active) {
  7533. resolve();
  7534. return;
  7535. }
  7536. print.call(window);
  7537. setTimeout(resolve, 20);
  7538. }, 0);
  7539. });
  7540. }
  7541. get active() {
  7542. return this === activeService;
  7543. }
  7544. throwIfInactive() {
  7545. if (!this.active) {
  7546. throw new Error("This print request was cancelled or completed.");
  7547. }
  7548. }
  7549. }
  7550. const print = window.print;
  7551. window.print = function () {
  7552. if (activeService) {
  7553. console.warn("Ignored window.print() because of a pending print job.");
  7554. return;
  7555. }
  7556. ensureOverlay().then(function () {
  7557. if (activeService) {
  7558. overlayManager.open(dialog);
  7559. }
  7560. });
  7561. try {
  7562. dispatchEvent("beforeprint");
  7563. } finally {
  7564. if (!activeService) {
  7565. console.error("Expected print service to be initialized.");
  7566. ensureOverlay().then(function () {
  7567. overlayManager.closeIfActive(dialog);
  7568. });
  7569. } else {
  7570. const activeServiceOnEntry = activeService;
  7571. activeService.renderPages().then(() => activeServiceOnEntry.performPrint()).catch(() => {}).then(() => {
  7572. if (activeServiceOnEntry.active) {
  7573. abort();
  7574. }
  7575. });
  7576. }
  7577. }
  7578. };
  7579. function dispatchEvent(eventType) {
  7580. const event = new CustomEvent(eventType, {
  7581. bubbles: false,
  7582. cancelable: false,
  7583. detail: "custom"
  7584. });
  7585. window.dispatchEvent(event);
  7586. }
  7587. function abort() {
  7588. if (activeService) {
  7589. activeService.destroy();
  7590. dispatchEvent("afterprint");
  7591. }
  7592. }
  7593. function renderProgress(index, total) {
  7594. dialog ||= document.getElementById("printServiceDialog");
  7595. const progress = Math.round(100 * index / total);
  7596. const progressBar = dialog.querySelector("progress");
  7597. const progressPerc = dialog.querySelector(".relative-progress");
  7598. progressBar.value = progress;
  7599. progressPerc.setAttribute("data-l10n-args", JSON.stringify({
  7600. progress
  7601. }));
  7602. }
  7603. window.addEventListener("keydown", function (event) {
  7604. if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
  7605. window.print();
  7606. event.preventDefault();
  7607. event.stopImmediatePropagation();
  7608. }
  7609. }, true);
  7610. if ("onbeforeprint" in window) {
  7611. const stopPropagationIfNeeded = function (event) {
  7612. if (event.detail !== "custom") {
  7613. event.stopImmediatePropagation();
  7614. }
  7615. };
  7616. window.addEventListener("beforeprint", stopPropagationIfNeeded);
  7617. window.addEventListener("afterprint", stopPropagationIfNeeded);
  7618. }
  7619. let overlayPromise;
  7620. function ensureOverlay() {
  7621. if (!overlayPromise) {
  7622. overlayManager = viewerApp.overlayManager;
  7623. if (!overlayManager) {
  7624. throw new Error("The overlay manager has not yet been initialized.");
  7625. }
  7626. dialog ||= document.getElementById("printServiceDialog");
  7627. overlayPromise = overlayManager.register(dialog, true);
  7628. document.getElementById("printCancel").onclick = abort;
  7629. dialog.addEventListener("close", abort);
  7630. }
  7631. return overlayPromise;
  7632. }
  7633. class PDFPrintServiceFactory {
  7634. static initGlobals(app) {
  7635. viewerApp = app;
  7636. }
  7637. static get supportsPrinting() {
  7638. return shadow(this, "supportsPrinting", true);
  7639. }
  7640. static createPrintService(params) {
  7641. if (activeService) {
  7642. throw new Error("The print service is created and active.");
  7643. }
  7644. return activeService = new PDFPrintService(params);
  7645. }
  7646. }
  7647. ;// ./web/pdf_rendering_queue.js
  7648. const CLEANUP_TIMEOUT = 30000;
  7649. class PDFRenderingQueue {
  7650. constructor() {
  7651. this.pdfViewer = null;
  7652. this.pdfThumbnailViewer = null;
  7653. this.onIdle = null;
  7654. this.highestPriorityPage = null;
  7655. this.idleTimeout = null;
  7656. this.printing = false;
  7657. this.isThumbnailViewEnabled = false;
  7658. Object.defineProperty(this, "hasViewer", {
  7659. value: () => !!this.pdfViewer
  7660. });
  7661. }
  7662. setViewer(pdfViewer) {
  7663. this.pdfViewer = pdfViewer;
  7664. }
  7665. setThumbnailViewer(pdfThumbnailViewer) {
  7666. this.pdfThumbnailViewer = pdfThumbnailViewer;
  7667. }
  7668. isHighestPriority(view) {
  7669. return this.highestPriorityPage === view.renderingId;
  7670. }
  7671. renderHighestPriority(currentlyVisiblePages) {
  7672. if (this.idleTimeout) {
  7673. clearTimeout(this.idleTimeout);
  7674. this.idleTimeout = null;
  7675. }
  7676. if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
  7677. return;
  7678. }
  7679. if (this.isThumbnailViewEnabled && this.pdfThumbnailViewer?.forceRendering()) {
  7680. return;
  7681. }
  7682. if (this.printing) {
  7683. return;
  7684. }
  7685. if (this.onIdle) {
  7686. this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
  7687. }
  7688. }
  7689. getHighestPriority(visible, views, scrolledDown, preRenderExtra = false, ignoreDetailViews = false) {
  7690. const visibleViews = visible.views,
  7691. numVisible = visibleViews.length;
  7692. if (numVisible === 0) {
  7693. return null;
  7694. }
  7695. for (let i = 0; i < numVisible; i++) {
  7696. const view = visibleViews[i].view;
  7697. if (!this.isViewFinished(view)) {
  7698. return view;
  7699. }
  7700. }
  7701. if (!ignoreDetailViews) {
  7702. for (let i = 0; i < numVisible; i++) {
  7703. const {
  7704. detailView
  7705. } = visibleViews[i].view;
  7706. if (detailView && !this.isViewFinished(detailView)) {
  7707. return detailView;
  7708. }
  7709. }
  7710. }
  7711. const firstId = visible.first.id,
  7712. lastId = visible.last.id;
  7713. if (lastId - firstId + 1 > numVisible) {
  7714. const visibleIds = visible.ids;
  7715. for (let i = 1, ii = lastId - firstId; i < ii; i++) {
  7716. const holeId = scrolledDown ? firstId + i : lastId - i;
  7717. if (visibleIds.has(holeId)) {
  7718. continue;
  7719. }
  7720. const holeView = views[holeId - 1];
  7721. if (!this.isViewFinished(holeView)) {
  7722. return holeView;
  7723. }
  7724. }
  7725. }
  7726. let preRenderIndex = scrolledDown ? lastId : firstId - 2;
  7727. let preRenderView = views[preRenderIndex];
  7728. if (preRenderView && !this.isViewFinished(preRenderView)) {
  7729. return preRenderView;
  7730. }
  7731. if (preRenderExtra) {
  7732. preRenderIndex += scrolledDown ? 1 : -1;
  7733. preRenderView = views[preRenderIndex];
  7734. if (preRenderView && !this.isViewFinished(preRenderView)) {
  7735. return preRenderView;
  7736. }
  7737. }
  7738. return null;
  7739. }
  7740. isViewFinished(view) {
  7741. return view.renderingState === RenderingStates.FINISHED;
  7742. }
  7743. renderView(view) {
  7744. switch (view.renderingState) {
  7745. case RenderingStates.FINISHED:
  7746. return false;
  7747. case RenderingStates.PAUSED:
  7748. this.highestPriorityPage = view.renderingId;
  7749. view.resume();
  7750. break;
  7751. case RenderingStates.RUNNING:
  7752. this.highestPriorityPage = view.renderingId;
  7753. break;
  7754. case RenderingStates.INITIAL:
  7755. this.highestPriorityPage = view.renderingId;
  7756. view.draw().finally(() => {
  7757. this.renderHighestPriority();
  7758. }).catch(reason => {
  7759. if (reason instanceof RenderingCancelledException) {
  7760. return;
  7761. }
  7762. console.error("renderView:", reason);
  7763. });
  7764. break;
  7765. }
  7766. return true;
  7767. }
  7768. }
  7769. ;// ./web/pdf_scripting_manager.js
  7770. class PDFScriptingManager {
  7771. #closeCapability = null;
  7772. #destroyCapability = null;
  7773. #docProperties = null;
  7774. #eventAbortController = null;
  7775. #eventBus = null;
  7776. #externalServices = null;
  7777. #pdfDocument = null;
  7778. #pdfViewer = null;
  7779. #ready = false;
  7780. #scripting = null;
  7781. #willPrintCapability = null;
  7782. constructor({
  7783. eventBus,
  7784. externalServices = null,
  7785. docProperties = null
  7786. }) {
  7787. this.#eventBus = eventBus;
  7788. this.#externalServices = externalServices;
  7789. this.#docProperties = docProperties;
  7790. }
  7791. setViewer(pdfViewer) {
  7792. this.#pdfViewer = pdfViewer;
  7793. }
  7794. async setDocument(pdfDocument) {
  7795. if (this.#pdfDocument) {
  7796. await this.#destroyScripting();
  7797. }
  7798. this.#pdfDocument = pdfDocument;
  7799. if (!pdfDocument) {
  7800. return;
  7801. }
  7802. const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]);
  7803. if (!objects && !docActions) {
  7804. await this.#destroyScripting();
  7805. return;
  7806. }
  7807. if (pdfDocument !== this.#pdfDocument) {
  7808. return;
  7809. }
  7810. try {
  7811. this.#scripting = this.#initScripting();
  7812. } catch (error) {
  7813. console.error("setDocument:", error);
  7814. await this.#destroyScripting();
  7815. return;
  7816. }
  7817. const eventBus = this.#eventBus;
  7818. this.#eventAbortController = new AbortController();
  7819. const {
  7820. signal
  7821. } = this.#eventAbortController;
  7822. eventBus._on("updatefromsandbox", event => {
  7823. if (event?.source === window) {
  7824. this.#updateFromSandbox(event.detail);
  7825. }
  7826. }, {
  7827. signal
  7828. });
  7829. eventBus._on("dispatcheventinsandbox", event => {
  7830. this.#scripting?.dispatchEventInSandbox(event.detail);
  7831. }, {
  7832. signal
  7833. });
  7834. eventBus._on("pagechanging", ({
  7835. pageNumber,
  7836. previous
  7837. }) => {
  7838. if (pageNumber === previous) {
  7839. return;
  7840. }
  7841. this.#dispatchPageClose(previous);
  7842. this.#dispatchPageOpen(pageNumber);
  7843. }, {
  7844. signal
  7845. });
  7846. eventBus._on("pagerendered", ({
  7847. pageNumber
  7848. }) => {
  7849. if (!this._pageOpenPending.has(pageNumber)) {
  7850. return;
  7851. }
  7852. if (pageNumber !== this.#pdfViewer.currentPageNumber) {
  7853. return;
  7854. }
  7855. this.#dispatchPageOpen(pageNumber);
  7856. }, {
  7857. signal
  7858. });
  7859. eventBus._on("pagesdestroy", async () => {
  7860. await this.#dispatchPageClose(this.#pdfViewer.currentPageNumber);
  7861. await this.#scripting?.dispatchEventInSandbox({
  7862. id: "doc",
  7863. name: "WillClose"
  7864. });
  7865. this.#closeCapability?.resolve();
  7866. }, {
  7867. signal
  7868. });
  7869. try {
  7870. const docProperties = await this.#docProperties(pdfDocument);
  7871. if (pdfDocument !== this.#pdfDocument) {
  7872. return;
  7873. }
  7874. await this.#scripting.createSandbox({
  7875. objects,
  7876. calculationOrder,
  7877. appInfo: {
  7878. platform: navigator.platform,
  7879. language: navigator.language
  7880. },
  7881. docInfo: {
  7882. ...docProperties,
  7883. actions: docActions
  7884. }
  7885. });
  7886. eventBus.dispatch("sandboxcreated", {
  7887. source: this
  7888. });
  7889. } catch (error) {
  7890. console.error("setDocument:", error);
  7891. await this.#destroyScripting();
  7892. return;
  7893. }
  7894. await this.#scripting?.dispatchEventInSandbox({
  7895. id: "doc",
  7896. name: "Open"
  7897. });
  7898. await this.#dispatchPageOpen(this.#pdfViewer.currentPageNumber, true);
  7899. Promise.resolve().then(() => {
  7900. if (pdfDocument === this.#pdfDocument) {
  7901. this.#ready = true;
  7902. }
  7903. });
  7904. }
  7905. async dispatchWillSave() {
  7906. return this.#scripting?.dispatchEventInSandbox({
  7907. id: "doc",
  7908. name: "WillSave"
  7909. });
  7910. }
  7911. async dispatchDidSave() {
  7912. return this.#scripting?.dispatchEventInSandbox({
  7913. id: "doc",
  7914. name: "DidSave"
  7915. });
  7916. }
  7917. async dispatchWillPrint() {
  7918. if (!this.#scripting) {
  7919. return;
  7920. }
  7921. await this.#willPrintCapability?.promise;
  7922. this.#willPrintCapability = Promise.withResolvers();
  7923. try {
  7924. await this.#scripting.dispatchEventInSandbox({
  7925. id: "doc",
  7926. name: "WillPrint"
  7927. });
  7928. } catch (ex) {
  7929. this.#willPrintCapability.resolve();
  7930. this.#willPrintCapability = null;
  7931. throw ex;
  7932. }
  7933. await this.#willPrintCapability.promise;
  7934. }
  7935. async dispatchDidPrint() {
  7936. return this.#scripting?.dispatchEventInSandbox({
  7937. id: "doc",
  7938. name: "DidPrint"
  7939. });
  7940. }
  7941. get destroyPromise() {
  7942. return this.#destroyCapability?.promise || null;
  7943. }
  7944. get ready() {
  7945. return this.#ready;
  7946. }
  7947. get _pageOpenPending() {
  7948. return shadow(this, "_pageOpenPending", new Set());
  7949. }
  7950. get _visitedPages() {
  7951. return shadow(this, "_visitedPages", new Map());
  7952. }
  7953. async #updateFromSandbox(detail) {
  7954. const pdfViewer = this.#pdfViewer;
  7955. const isInPresentationMode = pdfViewer.isInPresentationMode || pdfViewer.isChangingPresentationMode;
  7956. const {
  7957. id,
  7958. siblings,
  7959. command,
  7960. value
  7961. } = detail;
  7962. if (!id) {
  7963. switch (command) {
  7964. case "clear":
  7965. console.clear();
  7966. break;
  7967. case "error":
  7968. console.error(value);
  7969. break;
  7970. case "layout":
  7971. if (!isInPresentationMode) {
  7972. const modes = apiPageLayoutToViewerModes(value);
  7973. pdfViewer.spreadMode = modes.spreadMode;
  7974. }
  7975. break;
  7976. case "page-num":
  7977. pdfViewer.currentPageNumber = value + 1;
  7978. break;
  7979. case "print":
  7980. await pdfViewer.pagesPromise;
  7981. this.#eventBus.dispatch("print", {
  7982. source: this
  7983. });
  7984. break;
  7985. case "println":
  7986. console.log(value);
  7987. break;
  7988. case "zoom":
  7989. if (!isInPresentationMode) {
  7990. pdfViewer.currentScaleValue = value;
  7991. }
  7992. break;
  7993. case "SaveAs":
  7994. this.#eventBus.dispatch("download", {
  7995. source: this
  7996. });
  7997. break;
  7998. case "FirstPage":
  7999. pdfViewer.currentPageNumber = 1;
  8000. break;
  8001. case "LastPage":
  8002. pdfViewer.currentPageNumber = pdfViewer.pagesCount;
  8003. break;
  8004. case "NextPage":
  8005. pdfViewer.nextPage();
  8006. break;
  8007. case "PrevPage":
  8008. pdfViewer.previousPage();
  8009. break;
  8010. case "ZoomViewIn":
  8011. if (!isInPresentationMode) {
  8012. pdfViewer.increaseScale();
  8013. }
  8014. break;
  8015. case "ZoomViewOut":
  8016. if (!isInPresentationMode) {
  8017. pdfViewer.decreaseScale();
  8018. }
  8019. break;
  8020. case "WillPrintFinished":
  8021. this.#willPrintCapability?.resolve();
  8022. this.#willPrintCapability = null;
  8023. break;
  8024. }
  8025. return;
  8026. }
  8027. if (isInPresentationMode && detail.focus) {
  8028. return;
  8029. }
  8030. delete detail.id;
  8031. delete detail.siblings;
  8032. const ids = siblings ? [id, ...siblings] : [id];
  8033. for (const elementId of ids) {
  8034. const element = document.querySelector(`[data-element-id="${elementId}"]`);
  8035. if (element) {
  8036. element.dispatchEvent(new CustomEvent("updatefromsandbox", {
  8037. detail
  8038. }));
  8039. } else {
  8040. this.#pdfDocument?.annotationStorage.setValue(elementId, detail);
  8041. }
  8042. }
  8043. }
  8044. async #dispatchPageOpen(pageNumber, initialize = false) {
  8045. const pdfDocument = this.#pdfDocument,
  8046. visitedPages = this._visitedPages;
  8047. if (initialize) {
  8048. this.#closeCapability = Promise.withResolvers();
  8049. }
  8050. if (!this.#closeCapability) {
  8051. return;
  8052. }
  8053. const pageView = this.#pdfViewer.getPageView(pageNumber - 1);
  8054. if (pageView?.renderingState !== RenderingStates.FINISHED) {
  8055. this._pageOpenPending.add(pageNumber);
  8056. return;
  8057. }
  8058. this._pageOpenPending.delete(pageNumber);
  8059. const actionsPromise = (async () => {
  8060. const actions = await (!visitedPages.has(pageNumber) ? pageView.pdfPage?.getJSActions() : null);
  8061. if (pdfDocument !== this.#pdfDocument) {
  8062. return;
  8063. }
  8064. await this.#scripting?.dispatchEventInSandbox({
  8065. id: "page",
  8066. name: "PageOpen",
  8067. pageNumber,
  8068. actions
  8069. });
  8070. })();
  8071. visitedPages.set(pageNumber, actionsPromise);
  8072. }
  8073. async #dispatchPageClose(pageNumber) {
  8074. const pdfDocument = this.#pdfDocument,
  8075. visitedPages = this._visitedPages;
  8076. if (!this.#closeCapability) {
  8077. return;
  8078. }
  8079. if (this._pageOpenPending.has(pageNumber)) {
  8080. return;
  8081. }
  8082. const actionsPromise = visitedPages.get(pageNumber);
  8083. if (!actionsPromise) {
  8084. return;
  8085. }
  8086. visitedPages.set(pageNumber, null);
  8087. await actionsPromise;
  8088. if (pdfDocument !== this.#pdfDocument) {
  8089. return;
  8090. }
  8091. await this.#scripting?.dispatchEventInSandbox({
  8092. id: "page",
  8093. name: "PageClose",
  8094. pageNumber
  8095. });
  8096. }
  8097. #initScripting() {
  8098. this.#destroyCapability = Promise.withResolvers();
  8099. if (this.#scripting) {
  8100. throw new Error("#initScripting: Scripting already exists.");
  8101. }
  8102. return this.#externalServices.createScripting();
  8103. }
  8104. async #destroyScripting() {
  8105. if (!this.#scripting) {
  8106. this.#pdfDocument = null;
  8107. this.#destroyCapability?.resolve();
  8108. return;
  8109. }
  8110. if (this.#closeCapability) {
  8111. await Promise.race([this.#closeCapability.promise, new Promise(resolve => {
  8112. setTimeout(resolve, 1000);
  8113. })]).catch(() => {});
  8114. this.#closeCapability = null;
  8115. }
  8116. this.#pdfDocument = null;
  8117. try {
  8118. await this.#scripting.destroySandbox();
  8119. } catch {}
  8120. this.#willPrintCapability?.reject(new Error("Scripting destroyed."));
  8121. this.#willPrintCapability = null;
  8122. this.#eventAbortController?.abort();
  8123. this.#eventAbortController = null;
  8124. this._pageOpenPending.clear();
  8125. this._visitedPages.clear();
  8126. this.#scripting = null;
  8127. this.#ready = false;
  8128. this.#destroyCapability?.resolve();
  8129. }
  8130. }
  8131. ;// ./web/pdf_sidebar.js
  8132. const SIDEBAR_WIDTH_VAR = "--sidebar-width";
  8133. const SIDEBAR_MIN_WIDTH = 200;
  8134. const SIDEBAR_RESIZING_CLASS = "sidebarResizing";
  8135. const UI_NOTIFICATION_CLASS = "pdfSidebarNotification";
  8136. class PDFSidebar {
  8137. #isRTL = false;
  8138. #mouseAC = null;
  8139. #outerContainerWidth = null;
  8140. #width = null;
  8141. constructor({
  8142. elements,
  8143. eventBus,
  8144. l10n
  8145. }) {
  8146. this.isOpen = false;
  8147. this.active = SidebarView.THUMBS;
  8148. this.isInitialViewSet = false;
  8149. this.isInitialEventDispatched = false;
  8150. this.onToggled = null;
  8151. this.onUpdateThumbnails = null;
  8152. this.outerContainer = elements.outerContainer;
  8153. this.sidebarContainer = elements.sidebarContainer;
  8154. this.toggleButton = elements.toggleButton;
  8155. this.resizer = elements.resizer;
  8156. this.thumbnailButton = elements.thumbnailButton;
  8157. this.outlineButton = elements.outlineButton;
  8158. this.attachmentsButton = elements.attachmentsButton;
  8159. this.layersButton = elements.layersButton;
  8160. this.thumbnailView = elements.thumbnailView;
  8161. this.outlineView = elements.outlineView;
  8162. this.attachmentsView = elements.attachmentsView;
  8163. this.layersView = elements.layersView;
  8164. this._currentOutlineItemButton = elements.currentOutlineItemButton;
  8165. this.eventBus = eventBus;
  8166. this.#isRTL = l10n.getDirection() === "rtl";
  8167. this.#addEventListeners();
  8168. }
  8169. reset() {
  8170. this.isInitialViewSet = false;
  8171. this.isInitialEventDispatched = false;
  8172. this.#hideUINotification(true);
  8173. this.switchView(SidebarView.THUMBS);
  8174. this.outlineButton.disabled = false;
  8175. this.attachmentsButton.disabled = false;
  8176. this.layersButton.disabled = false;
  8177. this._currentOutlineItemButton.disabled = true;
  8178. }
  8179. get visibleView() {
  8180. return this.isOpen ? this.active : SidebarView.NONE;
  8181. }
  8182. setInitialView(view = SidebarView.NONE) {
  8183. if (this.isInitialViewSet) {
  8184. return;
  8185. }
  8186. this.isInitialViewSet = true;
  8187. if (view === SidebarView.NONE || view === SidebarView.UNKNOWN) {
  8188. this.#dispatchEvent();
  8189. return;
  8190. }
  8191. this.switchView(view, true);
  8192. if (!this.isInitialEventDispatched) {
  8193. this.#dispatchEvent();
  8194. }
  8195. }
  8196. switchView(view, forceOpen = false) {
  8197. const isViewChanged = view !== this.active;
  8198. let forceRendering = false;
  8199. switch (view) {
  8200. case SidebarView.NONE:
  8201. if (this.isOpen) {
  8202. this.close();
  8203. }
  8204. return;
  8205. case SidebarView.THUMBS:
  8206. if (this.isOpen && isViewChanged) {
  8207. forceRendering = true;
  8208. }
  8209. break;
  8210. case SidebarView.OUTLINE:
  8211. if (this.outlineButton.disabled) {
  8212. return;
  8213. }
  8214. break;
  8215. case SidebarView.ATTACHMENTS:
  8216. if (this.attachmentsButton.disabled) {
  8217. return;
  8218. }
  8219. break;
  8220. case SidebarView.LAYERS:
  8221. if (this.layersButton.disabled) {
  8222. return;
  8223. }
  8224. break;
  8225. default:
  8226. console.error(`PDFSidebar.switchView: "${view}" is not a valid view.`);
  8227. return;
  8228. }
  8229. this.active = view;
  8230. toggleCheckedBtn(this.thumbnailButton, view === SidebarView.THUMBS, this.thumbnailView);
  8231. toggleCheckedBtn(this.outlineButton, view === SidebarView.OUTLINE, this.outlineView);
  8232. toggleCheckedBtn(this.attachmentsButton, view === SidebarView.ATTACHMENTS, this.attachmentsView);
  8233. toggleCheckedBtn(this.layersButton, view === SidebarView.LAYERS, this.layersView);
  8234. if (forceOpen && !this.isOpen) {
  8235. this.open();
  8236. return;
  8237. }
  8238. if (forceRendering) {
  8239. this.onUpdateThumbnails();
  8240. this.onToggled();
  8241. }
  8242. if (isViewChanged) {
  8243. this.#dispatchEvent();
  8244. }
  8245. }
  8246. open() {
  8247. if (this.isOpen) {
  8248. return;
  8249. }
  8250. this.isOpen = true;
  8251. toggleExpandedBtn(this.toggleButton, true);
  8252. this.outerContainer.classList.add("sidebarMoving", "sidebarOpen");
  8253. if (this.active === SidebarView.THUMBS) {
  8254. this.onUpdateThumbnails();
  8255. }
  8256. this.onToggled();
  8257. this.#dispatchEvent();
  8258. this.#hideUINotification();
  8259. }
  8260. close(evt = null) {
  8261. if (!this.isOpen) {
  8262. return;
  8263. }
  8264. this.isOpen = false;
  8265. toggleExpandedBtn(this.toggleButton, false);
  8266. this.outerContainer.classList.add("sidebarMoving");
  8267. this.outerContainer.classList.remove("sidebarOpen");
  8268. this.onToggled();
  8269. this.#dispatchEvent();
  8270. if (evt?.detail > 0) {
  8271. this.toggleButton.blur();
  8272. }
  8273. }
  8274. toggle(evt = null) {
  8275. if (this.isOpen) {
  8276. this.close(evt);
  8277. } else {
  8278. this.open();
  8279. }
  8280. }
  8281. #dispatchEvent() {
  8282. if (this.isInitialViewSet) {
  8283. this.isInitialEventDispatched ||= true;
  8284. }
  8285. this.eventBus.dispatch("sidebarviewchanged", {
  8286. source: this,
  8287. view: this.visibleView
  8288. });
  8289. }
  8290. #showUINotification() {
  8291. this.toggleButton.setAttribute("data-l10n-id", "pdfjs-toggle-sidebar-notification-button");
  8292. if (!this.isOpen) {
  8293. this.toggleButton.classList.add(UI_NOTIFICATION_CLASS);
  8294. }
  8295. }
  8296. #hideUINotification(reset = false) {
  8297. if (this.isOpen || reset) {
  8298. this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS);
  8299. }
  8300. if (reset) {
  8301. this.toggleButton.setAttribute("data-l10n-id", "pdfjs-toggle-sidebar-button");
  8302. }
  8303. }
  8304. #addEventListeners() {
  8305. const {
  8306. eventBus,
  8307. outerContainer
  8308. } = this;
  8309. this.sidebarContainer.addEventListener("transitionend", evt => {
  8310. if (evt.target === this.sidebarContainer) {
  8311. outerContainer.classList.remove("sidebarMoving");
  8312. eventBus.dispatch("resize", {
  8313. source: this
  8314. });
  8315. }
  8316. });
  8317. this.toggleButton.addEventListener("click", evt => {
  8318. this.toggle(evt);
  8319. });
  8320. this.thumbnailButton.addEventListener("click", () => {
  8321. this.switchView(SidebarView.THUMBS);
  8322. });
  8323. this.outlineButton.addEventListener("click", () => {
  8324. this.switchView(SidebarView.OUTLINE);
  8325. });
  8326. this.outlineButton.addEventListener("dblclick", () => {
  8327. eventBus.dispatch("toggleoutlinetree", {
  8328. source: this
  8329. });
  8330. });
  8331. this.attachmentsButton.addEventListener("click", () => {
  8332. this.switchView(SidebarView.ATTACHMENTS);
  8333. });
  8334. this.layersButton.addEventListener("click", () => {
  8335. this.switchView(SidebarView.LAYERS);
  8336. });
  8337. this.layersButton.addEventListener("dblclick", () => {
  8338. eventBus.dispatch("resetlayers", {
  8339. source: this
  8340. });
  8341. });
  8342. this._currentOutlineItemButton.addEventListener("click", () => {
  8343. eventBus.dispatch("currentoutlineitem", {
  8344. source: this
  8345. });
  8346. });
  8347. const onTreeLoaded = (count, button, view) => {
  8348. button.disabled = !count;
  8349. if (count) {
  8350. this.#showUINotification();
  8351. } else if (this.active === view) {
  8352. this.switchView(SidebarView.THUMBS);
  8353. }
  8354. };
  8355. eventBus._on("outlineloaded", evt => {
  8356. onTreeLoaded(evt.outlineCount, this.outlineButton, SidebarView.OUTLINE);
  8357. evt.currentOutlineItemPromise.then(enabled => {
  8358. if (!this.isInitialViewSet) {
  8359. return;
  8360. }
  8361. this._currentOutlineItemButton.disabled = !enabled;
  8362. });
  8363. });
  8364. eventBus._on("attachmentsloaded", evt => {
  8365. onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, SidebarView.ATTACHMENTS);
  8366. });
  8367. eventBus._on("layersloaded", evt => {
  8368. onTreeLoaded(evt.layersCount, this.layersButton, SidebarView.LAYERS);
  8369. });
  8370. eventBus._on("presentationmodechanged", evt => {
  8371. if (evt.state === PresentationModeState.NORMAL && this.visibleView === SidebarView.THUMBS) {
  8372. this.onUpdateThumbnails();
  8373. }
  8374. });
  8375. this.resizer.addEventListener("mousedown", evt => {
  8376. if (evt.button !== 0) {
  8377. return;
  8378. }
  8379. outerContainer.classList.add(SIDEBAR_RESIZING_CLASS);
  8380. this.#mouseAC = new AbortController();
  8381. const opts = {
  8382. signal: this.#mouseAC.signal
  8383. };
  8384. window.addEventListener("mousemove", this.#mouseMove.bind(this), opts);
  8385. window.addEventListener("mouseup", this.#mouseUp.bind(this), opts);
  8386. window.addEventListener("blur", this.#mouseUp.bind(this), opts);
  8387. });
  8388. eventBus._on("resize", evt => {
  8389. if (evt.source !== window) {
  8390. return;
  8391. }
  8392. this.#outerContainerWidth = null;
  8393. if (!this.#width) {
  8394. return;
  8395. }
  8396. if (!this.isOpen) {
  8397. this.#updateWidth(this.#width);
  8398. return;
  8399. }
  8400. outerContainer.classList.add(SIDEBAR_RESIZING_CLASS);
  8401. const updated = this.#updateWidth(this.#width);
  8402. Promise.resolve().then(() => {
  8403. outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS);
  8404. if (updated) {
  8405. eventBus.dispatch("resize", {
  8406. source: this
  8407. });
  8408. }
  8409. });
  8410. });
  8411. }
  8412. get outerContainerWidth() {
  8413. return this.#outerContainerWidth ||= this.outerContainer.clientWidth;
  8414. }
  8415. #updateWidth(width = 0) {
  8416. const maxWidth = Math.floor(this.outerContainerWidth / 2);
  8417. if (width > maxWidth) {
  8418. width = maxWidth;
  8419. }
  8420. if (width < SIDEBAR_MIN_WIDTH) {
  8421. width = SIDEBAR_MIN_WIDTH;
  8422. }
  8423. if (width === this.#width) {
  8424. return false;
  8425. }
  8426. this.#width = width;
  8427. docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`);
  8428. return true;
  8429. }
  8430. #mouseMove(evt) {
  8431. let width = evt.clientX;
  8432. if (this.#isRTL) {
  8433. width = this.outerContainerWidth - width;
  8434. }
  8435. this.#updateWidth(width);
  8436. }
  8437. #mouseUp(evt) {
  8438. this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS);
  8439. this.eventBus.dispatch("resize", {
  8440. source: this
  8441. });
  8442. this.#mouseAC?.abort();
  8443. this.#mouseAC = null;
  8444. }
  8445. }
  8446. ;// ./web/pdf_thumbnail_view.js
  8447. const DRAW_UPSCALE_FACTOR = 2;
  8448. const MAX_NUM_SCALING_STEPS = 3;
  8449. const THUMBNAIL_WIDTH = 98;
  8450. function zeroCanvas(c) {
  8451. c.width = 0;
  8452. c.height = 0;
  8453. }
  8454. class TempImageFactory {
  8455. static #tempCanvas = null;
  8456. static getCanvas(width, height) {
  8457. const tempCanvas = this.#tempCanvas ||= document.createElement("canvas");
  8458. tempCanvas.width = width;
  8459. tempCanvas.height = height;
  8460. const ctx = tempCanvas.getContext("2d", {
  8461. alpha: false
  8462. });
  8463. ctx.save();
  8464. ctx.fillStyle = "rgb(255, 255, 255)";
  8465. ctx.fillRect(0, 0, width, height);
  8466. ctx.restore();
  8467. return [tempCanvas, tempCanvas.getContext("2d")];
  8468. }
  8469. static destroyCanvas() {
  8470. if (this.#tempCanvas) {
  8471. zeroCanvas(this.#tempCanvas);
  8472. }
  8473. this.#tempCanvas = null;
  8474. }
  8475. }
  8476. class PDFThumbnailView {
  8477. constructor({
  8478. container,
  8479. eventBus,
  8480. id,
  8481. defaultViewport,
  8482. optionalContentConfigPromise,
  8483. linkService,
  8484. renderingQueue,
  8485. maxCanvasPixels,
  8486. maxCanvasDim,
  8487. pageColors,
  8488. enableHWA
  8489. }) {
  8490. this.id = id;
  8491. this.renderingId = "thumbnail" + id;
  8492. this.pageLabel = null;
  8493. this.pdfPage = null;
  8494. this.rotation = 0;
  8495. this.viewport = defaultViewport;
  8496. this.pdfPageRotate = defaultViewport.rotation;
  8497. this._optionalContentConfigPromise = optionalContentConfigPromise || null;
  8498. this.maxCanvasPixels = maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
  8499. this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
  8500. this.pageColors = pageColors || null;
  8501. this.enableHWA = enableHWA || false;
  8502. this.eventBus = eventBus;
  8503. this.linkService = linkService;
  8504. this.renderingQueue = renderingQueue;
  8505. this.renderTask = null;
  8506. this.renderingState = RenderingStates.INITIAL;
  8507. this.resume = null;
  8508. const anchor = document.createElement("a");
  8509. anchor.href = linkService.getAnchorUrl("#page=" + id);
  8510. anchor.setAttribute("data-l10n-id", "pdfjs-thumb-page-title");
  8511. anchor.setAttribute("data-l10n-args", this.#pageL10nArgs);
  8512. anchor.onclick = function () {
  8513. linkService.goToPage(id);
  8514. return false;
  8515. };
  8516. this.anchor = anchor;
  8517. const div = document.createElement("div");
  8518. div.className = "thumbnail";
  8519. div.setAttribute("data-page-number", this.id);
  8520. this.div = div;
  8521. this.#updateDims();
  8522. const img = document.createElement("div");
  8523. img.className = "thumbnailImage";
  8524. this._placeholderImg = img;
  8525. div.append(img);
  8526. anchor.append(div);
  8527. container.append(anchor);
  8528. }
  8529. #updateDims() {
  8530. const {
  8531. width,
  8532. height
  8533. } = this.viewport;
  8534. const ratio = width / height;
  8535. this.canvasWidth = THUMBNAIL_WIDTH;
  8536. this.canvasHeight = this.canvasWidth / ratio | 0;
  8537. this.scale = this.canvasWidth / width;
  8538. const {
  8539. style
  8540. } = this.div;
  8541. style.setProperty("--thumbnail-width", `${this.canvasWidth}px`);
  8542. style.setProperty("--thumbnail-height", `${this.canvasHeight}px`);
  8543. }
  8544. setPdfPage(pdfPage) {
  8545. this.pdfPage = pdfPage;
  8546. this.pdfPageRotate = pdfPage.rotate;
  8547. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  8548. this.viewport = pdfPage.getViewport({
  8549. scale: 1,
  8550. rotation: totalRotation
  8551. });
  8552. this.reset();
  8553. }
  8554. reset() {
  8555. this.cancelRendering();
  8556. this.renderingState = RenderingStates.INITIAL;
  8557. this.div.removeAttribute("data-loaded");
  8558. this.image?.replaceWith(this._placeholderImg);
  8559. this.#updateDims();
  8560. if (this.image) {
  8561. this.image.removeAttribute("src");
  8562. delete this.image;
  8563. }
  8564. }
  8565. update({
  8566. rotation = null
  8567. }) {
  8568. if (typeof rotation === "number") {
  8569. this.rotation = rotation;
  8570. }
  8571. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  8572. this.viewport = this.viewport.clone({
  8573. scale: 1,
  8574. rotation: totalRotation
  8575. });
  8576. this.reset();
  8577. }
  8578. cancelRendering() {
  8579. if (this.renderTask) {
  8580. this.renderTask.cancel();
  8581. this.renderTask = null;
  8582. }
  8583. this.resume = null;
  8584. }
  8585. #getPageDrawContext(upscaleFactor = 1, enableHWA = this.enableHWA) {
  8586. const canvas = document.createElement("canvas");
  8587. const ctx = canvas.getContext("2d", {
  8588. alpha: false,
  8589. willReadFrequently: !enableHWA
  8590. });
  8591. const outputScale = new OutputScale();
  8592. const width = upscaleFactor * this.canvasWidth,
  8593. height = upscaleFactor * this.canvasHeight;
  8594. outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim);
  8595. canvas.width = width * outputScale.sx | 0;
  8596. canvas.height = height * outputScale.sy | 0;
  8597. const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
  8598. return {
  8599. ctx,
  8600. canvas,
  8601. transform
  8602. };
  8603. }
  8604. #convertCanvasToImage(canvas) {
  8605. if (this.renderingState !== RenderingStates.FINISHED) {
  8606. throw new Error("#convertCanvasToImage: Rendering has not finished.");
  8607. }
  8608. const reducedCanvas = this.#reduceImage(canvas);
  8609. const image = document.createElement("img");
  8610. image.className = "thumbnailImage";
  8611. image.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas");
  8612. image.setAttribute("data-l10n-args", this.#pageL10nArgs);
  8613. image.src = reducedCanvas.toDataURL();
  8614. this.image = image;
  8615. this.div.setAttribute("data-loaded", true);
  8616. this._placeholderImg.replaceWith(image);
  8617. zeroCanvas(reducedCanvas);
  8618. }
  8619. async draw() {
  8620. if (this.renderingState !== RenderingStates.INITIAL) {
  8621. console.error("Must be in new state before drawing");
  8622. return;
  8623. }
  8624. const {
  8625. pageColors,
  8626. pdfPage
  8627. } = this;
  8628. if (!pdfPage) {
  8629. this.renderingState = RenderingStates.FINISHED;
  8630. throw new Error("pdfPage is not loaded");
  8631. }
  8632. this.renderingState = RenderingStates.RUNNING;
  8633. const {
  8634. ctx,
  8635. canvas,
  8636. transform
  8637. } = this.#getPageDrawContext(DRAW_UPSCALE_FACTOR);
  8638. const drawViewport = this.viewport.clone({
  8639. scale: DRAW_UPSCALE_FACTOR * this.scale
  8640. });
  8641. const renderContinueCallback = cont => {
  8642. if (!this.renderingQueue.isHighestPriority(this)) {
  8643. this.renderingState = RenderingStates.PAUSED;
  8644. this.resume = () => {
  8645. this.renderingState = RenderingStates.RUNNING;
  8646. cont();
  8647. };
  8648. return;
  8649. }
  8650. cont();
  8651. };
  8652. const renderContext = {
  8653. canvasContext: ctx,
  8654. transform,
  8655. viewport: drawViewport,
  8656. optionalContentConfigPromise: this._optionalContentConfigPromise,
  8657. pageColors
  8658. };
  8659. const renderTask = this.renderTask = pdfPage.render(renderContext);
  8660. renderTask.onContinue = renderContinueCallback;
  8661. let error = null;
  8662. try {
  8663. await renderTask.promise;
  8664. } catch (e) {
  8665. if (e instanceof RenderingCancelledException) {
  8666. zeroCanvas(canvas);
  8667. return;
  8668. }
  8669. error = e;
  8670. } finally {
  8671. if (renderTask === this.renderTask) {
  8672. this.renderTask = null;
  8673. }
  8674. }
  8675. this.renderingState = RenderingStates.FINISHED;
  8676. this.#convertCanvasToImage(canvas);
  8677. zeroCanvas(canvas);
  8678. this.eventBus.dispatch("thumbnailrendered", {
  8679. source: this,
  8680. pageNumber: this.id,
  8681. pdfPage
  8682. });
  8683. if (error) {
  8684. throw error;
  8685. }
  8686. }
  8687. setImage(pageView) {
  8688. if (this.renderingState !== RenderingStates.INITIAL) {
  8689. return;
  8690. }
  8691. const {
  8692. thumbnailCanvas: canvas,
  8693. pdfPage,
  8694. scale
  8695. } = pageView;
  8696. if (!canvas) {
  8697. return;
  8698. }
  8699. if (!this.pdfPage) {
  8700. this.setPdfPage(pdfPage);
  8701. }
  8702. if (scale < this.scale) {
  8703. return;
  8704. }
  8705. this.renderingState = RenderingStates.FINISHED;
  8706. this.#convertCanvasToImage(canvas);
  8707. }
  8708. #getReducedImageDims(canvas) {
  8709. const width = canvas.width << MAX_NUM_SCALING_STEPS,
  8710. height = canvas.height << MAX_NUM_SCALING_STEPS;
  8711. const outputScale = new OutputScale();
  8712. outputScale.sx = outputScale.sy = 1;
  8713. outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim);
  8714. return [width * outputScale.sx | 0, height * outputScale.sy | 0];
  8715. }
  8716. #reduceImage(img) {
  8717. const {
  8718. ctx,
  8719. canvas
  8720. } = this.#getPageDrawContext(1, true);
  8721. if (img.width <= 2 * canvas.width) {
  8722. ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
  8723. return canvas;
  8724. }
  8725. let [reducedWidth, reducedHeight] = this.#getReducedImageDims(canvas);
  8726. const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(reducedWidth, reducedHeight);
  8727. while (reducedWidth > img.width || reducedHeight > img.height) {
  8728. reducedWidth >>= 1;
  8729. reducedHeight >>= 1;
  8730. }
  8731. reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight);
  8732. while (reducedWidth > 2 * canvas.width) {
  8733. reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1);
  8734. reducedWidth >>= 1;
  8735. reducedHeight >>= 1;
  8736. }
  8737. ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height);
  8738. return canvas;
  8739. }
  8740. get #pageL10nArgs() {
  8741. return JSON.stringify({
  8742. page: this.pageLabel ?? this.id
  8743. });
  8744. }
  8745. setPageLabel(label) {
  8746. this.pageLabel = typeof label === "string" ? label : null;
  8747. this.anchor.setAttribute("data-l10n-args", this.#pageL10nArgs);
  8748. if (this.renderingState !== RenderingStates.FINISHED) {
  8749. return;
  8750. }
  8751. this.image?.setAttribute("data-l10n-args", this.#pageL10nArgs);
  8752. }
  8753. }
  8754. ;// ./web/pdf_thumbnail_viewer.js
  8755. const THUMBNAIL_SCROLL_MARGIN = -19;
  8756. const THUMBNAIL_SELECTED_CLASS = "selected";
  8757. class PDFThumbnailViewer {
  8758. constructor({
  8759. container,
  8760. eventBus,
  8761. linkService,
  8762. renderingQueue,
  8763. maxCanvasPixels,
  8764. maxCanvasDim,
  8765. pageColors,
  8766. abortSignal,
  8767. enableHWA
  8768. }) {
  8769. this.container = container;
  8770. this.eventBus = eventBus;
  8771. this.linkService = linkService;
  8772. this.renderingQueue = renderingQueue;
  8773. this.maxCanvasPixels = maxCanvasPixels;
  8774. this.maxCanvasDim = maxCanvasDim;
  8775. this.pageColors = pageColors || null;
  8776. this.enableHWA = enableHWA || false;
  8777. this.scroll = watchScroll(this.container, this.#scrollUpdated.bind(this), abortSignal);
  8778. this.#resetView();
  8779. }
  8780. #scrollUpdated() {
  8781. this.renderingQueue.renderHighestPriority();
  8782. }
  8783. getThumbnail(index) {
  8784. return this._thumbnails[index];
  8785. }
  8786. #getVisibleThumbs() {
  8787. return getVisibleElements({
  8788. scrollEl: this.container,
  8789. views: this._thumbnails
  8790. });
  8791. }
  8792. scrollThumbnailIntoView(pageNumber) {
  8793. if (!this.pdfDocument) {
  8794. return;
  8795. }
  8796. const thumbnailView = this._thumbnails[pageNumber - 1];
  8797. if (!thumbnailView) {
  8798. console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.');
  8799. return;
  8800. }
  8801. if (pageNumber !== this._currentPageNumber) {
  8802. const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1];
  8803. prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS);
  8804. thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS);
  8805. }
  8806. const {
  8807. first,
  8808. last,
  8809. views
  8810. } = this.#getVisibleThumbs();
  8811. if (views.length > 0) {
  8812. let shouldScroll = false;
  8813. if (pageNumber <= first.id || pageNumber >= last.id) {
  8814. shouldScroll = true;
  8815. } else {
  8816. for (const {
  8817. id,
  8818. percent
  8819. } of views) {
  8820. if (id !== pageNumber) {
  8821. continue;
  8822. }
  8823. shouldScroll = percent < 100;
  8824. break;
  8825. }
  8826. }
  8827. if (shouldScroll) {
  8828. scrollIntoView(thumbnailView.div, {
  8829. top: THUMBNAIL_SCROLL_MARGIN
  8830. });
  8831. }
  8832. }
  8833. this._currentPageNumber = pageNumber;
  8834. }
  8835. get pagesRotation() {
  8836. return this._pagesRotation;
  8837. }
  8838. set pagesRotation(rotation) {
  8839. if (!isValidRotation(rotation)) {
  8840. throw new Error("Invalid thumbnails rotation angle.");
  8841. }
  8842. if (!this.pdfDocument) {
  8843. return;
  8844. }
  8845. if (this._pagesRotation === rotation) {
  8846. return;
  8847. }
  8848. this._pagesRotation = rotation;
  8849. const updateArgs = {
  8850. rotation
  8851. };
  8852. for (const thumbnail of this._thumbnails) {
  8853. thumbnail.update(updateArgs);
  8854. }
  8855. }
  8856. cleanup() {
  8857. for (const thumbnail of this._thumbnails) {
  8858. if (thumbnail.renderingState !== RenderingStates.FINISHED) {
  8859. thumbnail.reset();
  8860. }
  8861. }
  8862. TempImageFactory.destroyCanvas();
  8863. }
  8864. #resetView() {
  8865. this._thumbnails = [];
  8866. this._currentPageNumber = 1;
  8867. this._pageLabels = null;
  8868. this._pagesRotation = 0;
  8869. this.container.textContent = "";
  8870. }
  8871. setDocument(pdfDocument) {
  8872. if (this.pdfDocument) {
  8873. this.#cancelRendering();
  8874. this.#resetView();
  8875. }
  8876. this.pdfDocument = pdfDocument;
  8877. if (!pdfDocument) {
  8878. return;
  8879. }
  8880. const firstPagePromise = pdfDocument.getPage(1);
  8881. const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
  8882. intent: "display"
  8883. });
  8884. firstPagePromise.then(firstPdfPage => {
  8885. const pagesCount = pdfDocument.numPages;
  8886. const viewport = firstPdfPage.getViewport({
  8887. scale: 1
  8888. });
  8889. for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
  8890. const thumbnail = new PDFThumbnailView({
  8891. container: this.container,
  8892. eventBus: this.eventBus,
  8893. id: pageNum,
  8894. defaultViewport: viewport.clone(),
  8895. optionalContentConfigPromise,
  8896. linkService: this.linkService,
  8897. renderingQueue: this.renderingQueue,
  8898. maxCanvasPixels: this.maxCanvasPixels,
  8899. maxCanvasDim: this.maxCanvasDim,
  8900. pageColors: this.pageColors,
  8901. enableHWA: this.enableHWA
  8902. });
  8903. this._thumbnails.push(thumbnail);
  8904. }
  8905. this._thumbnails[0]?.setPdfPage(firstPdfPage);
  8906. const thumbnailView = this._thumbnails[this._currentPageNumber - 1];
  8907. thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS);
  8908. }).catch(reason => {
  8909. console.error("Unable to initialize thumbnail viewer", reason);
  8910. });
  8911. }
  8912. #cancelRendering() {
  8913. for (const thumbnail of this._thumbnails) {
  8914. thumbnail.cancelRendering();
  8915. }
  8916. }
  8917. setPageLabels(labels) {
  8918. if (!this.pdfDocument) {
  8919. return;
  8920. }
  8921. if (!labels) {
  8922. this._pageLabels = null;
  8923. } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
  8924. this._pageLabels = null;
  8925. console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels.");
  8926. } else {
  8927. this._pageLabels = labels;
  8928. }
  8929. for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
  8930. this._thumbnails[i].setPageLabel(this._pageLabels?.[i] ?? null);
  8931. }
  8932. }
  8933. async #ensurePdfPageLoaded(thumbView) {
  8934. if (thumbView.pdfPage) {
  8935. return thumbView.pdfPage;
  8936. }
  8937. try {
  8938. const pdfPage = await this.pdfDocument.getPage(thumbView.id);
  8939. if (!thumbView.pdfPage) {
  8940. thumbView.setPdfPage(pdfPage);
  8941. }
  8942. return pdfPage;
  8943. } catch (reason) {
  8944. console.error("Unable to get page for thumb view", reason);
  8945. return null;
  8946. }
  8947. }
  8948. #getScrollAhead(visible) {
  8949. if (visible.first?.id === 1) {
  8950. return true;
  8951. } else if (visible.last?.id === this._thumbnails.length) {
  8952. return false;
  8953. }
  8954. return this.scroll.down;
  8955. }
  8956. forceRendering() {
  8957. const visibleThumbs = this.#getVisibleThumbs();
  8958. const scrollAhead = this.#getScrollAhead(visibleThumbs);
  8959. const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead, false, true);
  8960. if (thumbView) {
  8961. this.#ensurePdfPageLoaded(thumbView).then(() => {
  8962. this.renderingQueue.renderView(thumbView);
  8963. });
  8964. return true;
  8965. }
  8966. return false;
  8967. }
  8968. }
  8969. ;// ./web/annotation_editor_layer_builder.js
  8970. class AnnotationEditorLayerBuilder {
  8971. #annotationLayer = null;
  8972. #drawLayer = null;
  8973. #onAppend = null;
  8974. #structTreeLayer = null;
  8975. #textLayer = null;
  8976. #uiManager;
  8977. constructor(options) {
  8978. this.pdfPage = options.pdfPage;
  8979. this.accessibilityManager = options.accessibilityManager;
  8980. this.l10n = options.l10n;
  8981. this.l10n ||= new genericl10n_GenericL10n();
  8982. this.annotationEditorLayer = null;
  8983. this.div = null;
  8984. this._cancelled = false;
  8985. this.#uiManager = options.uiManager;
  8986. this.#annotationLayer = options.annotationLayer || null;
  8987. this.#textLayer = options.textLayer || null;
  8988. this.#drawLayer = options.drawLayer || null;
  8989. this.#onAppend = options.onAppend || null;
  8990. this.#structTreeLayer = options.structTreeLayer || null;
  8991. }
  8992. async render({
  8993. viewport,
  8994. intent = "display"
  8995. }) {
  8996. if (intent !== "display") {
  8997. return;
  8998. }
  8999. if (this._cancelled) {
  9000. return;
  9001. }
  9002. const clonedViewport = viewport.clone({
  9003. dontFlip: true
  9004. });
  9005. if (this.div) {
  9006. this.annotationEditorLayer.update({
  9007. viewport: clonedViewport
  9008. });
  9009. this.show();
  9010. return;
  9011. }
  9012. const div = this.div = document.createElement("div");
  9013. div.className = "annotationEditorLayer";
  9014. div.hidden = true;
  9015. div.dir = this.#uiManager.direction;
  9016. this.#onAppend?.(div);
  9017. this.annotationEditorLayer = new AnnotationEditorLayer({
  9018. uiManager: this.#uiManager,
  9019. div,
  9020. structTreeLayer: this.#structTreeLayer,
  9021. accessibilityManager: this.accessibilityManager,
  9022. pageIndex: this.pdfPage.pageNumber - 1,
  9023. l10n: this.l10n,
  9024. viewport: clonedViewport,
  9025. annotationLayer: this.#annotationLayer,
  9026. textLayer: this.#textLayer,
  9027. drawLayer: this.#drawLayer
  9028. });
  9029. const parameters = {
  9030. viewport: clonedViewport,
  9031. div,
  9032. annotations: null,
  9033. intent
  9034. };
  9035. this.annotationEditorLayer.render(parameters);
  9036. this.show();
  9037. }
  9038. cancel() {
  9039. this._cancelled = true;
  9040. if (!this.div) {
  9041. return;
  9042. }
  9043. this.annotationEditorLayer.destroy();
  9044. }
  9045. hide() {
  9046. if (!this.div) {
  9047. return;
  9048. }
  9049. this.annotationEditorLayer.pause(true);
  9050. this.div.hidden = true;
  9051. }
  9052. show() {
  9053. if (!this.div || this.annotationEditorLayer.isInvisible) {
  9054. return;
  9055. }
  9056. this.div.hidden = false;
  9057. this.annotationEditorLayer.pause(false);
  9058. }
  9059. }
  9060. ;// ./web/annotation_layer_builder.js
  9061. class AnnotationLayerBuilder {
  9062. #annotations = null;
  9063. #externalHide = false;
  9064. #onAppend = null;
  9065. #eventAbortController = null;
  9066. #linksInjected = false;
  9067. constructor({
  9068. pdfPage,
  9069. linkService,
  9070. downloadManager,
  9071. annotationStorage = null,
  9072. imageResourcesPath = "",
  9073. renderForms = true,
  9074. enableScripting = false,
  9075. hasJSActionsPromise = null,
  9076. fieldObjectsPromise = null,
  9077. annotationCanvasMap = null,
  9078. accessibilityManager = null,
  9079. annotationEditorUIManager = null,
  9080. onAppend = null
  9081. }) {
  9082. this.pdfPage = pdfPage;
  9083. this.linkService = linkService;
  9084. this.downloadManager = downloadManager;
  9085. this.imageResourcesPath = imageResourcesPath;
  9086. this.renderForms = renderForms;
  9087. this.annotationStorage = annotationStorage;
  9088. this.enableScripting = enableScripting;
  9089. this._hasJSActionsPromise = hasJSActionsPromise || Promise.resolve(false);
  9090. this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null);
  9091. this._annotationCanvasMap = annotationCanvasMap;
  9092. this._accessibilityManager = accessibilityManager;
  9093. this._annotationEditorUIManager = annotationEditorUIManager;
  9094. this.#onAppend = onAppend;
  9095. this.annotationLayer = null;
  9096. this.div = null;
  9097. this._cancelled = false;
  9098. this._eventBus = linkService.eventBus;
  9099. }
  9100. async render({
  9101. viewport,
  9102. intent = "display",
  9103. structTreeLayer = null
  9104. }) {
  9105. if (this.div) {
  9106. if (this._cancelled || !this.annotationLayer) {
  9107. return;
  9108. }
  9109. this.annotationLayer.update({
  9110. viewport: viewport.clone({
  9111. dontFlip: true
  9112. })
  9113. });
  9114. return;
  9115. }
  9116. const [annotations, hasJSActions, fieldObjects] = await Promise.all([this.pdfPage.getAnnotations({
  9117. intent
  9118. }), this._hasJSActionsPromise, this._fieldObjectsPromise]);
  9119. if (this._cancelled) {
  9120. return;
  9121. }
  9122. const div = this.div = document.createElement("div");
  9123. div.className = "annotationLayer";
  9124. this.#onAppend?.(div);
  9125. if (annotations.length === 0) {
  9126. this.#annotations = annotations;
  9127. this.hide(true);
  9128. return;
  9129. }
  9130. this.#initAnnotationLayer(viewport, structTreeLayer);
  9131. await this.annotationLayer.render({
  9132. annotations,
  9133. imageResourcesPath: this.imageResourcesPath,
  9134. renderForms: this.renderForms,
  9135. linkService: this.linkService,
  9136. downloadManager: this.downloadManager,
  9137. annotationStorage: this.annotationStorage,
  9138. enableScripting: this.enableScripting,
  9139. hasJSActions,
  9140. fieldObjects
  9141. });
  9142. this.#annotations = annotations;
  9143. if (this.linkService.isInPresentationMode) {
  9144. this.#updatePresentationModeState(PresentationModeState.FULLSCREEN);
  9145. }
  9146. if (!this.#eventAbortController) {
  9147. this.#eventAbortController = new AbortController();
  9148. this._eventBus?._on("presentationmodechanged", evt => {
  9149. this.#updatePresentationModeState(evt.state);
  9150. }, {
  9151. signal: this.#eventAbortController.signal
  9152. });
  9153. }
  9154. }
  9155. #initAnnotationLayer(viewport, structTreeLayer) {
  9156. this.annotationLayer = new AnnotationLayer({
  9157. div: this.div,
  9158. accessibilityManager: this._accessibilityManager,
  9159. annotationCanvasMap: this._annotationCanvasMap,
  9160. annotationEditorUIManager: this._annotationEditorUIManager,
  9161. page: this.pdfPage,
  9162. viewport: viewport.clone({
  9163. dontFlip: true
  9164. }),
  9165. structTreeLayer
  9166. });
  9167. }
  9168. cancel() {
  9169. this._cancelled = true;
  9170. this.#eventAbortController?.abort();
  9171. this.#eventAbortController = null;
  9172. }
  9173. hide(internal = false) {
  9174. this.#externalHide = !internal;
  9175. if (!this.div) {
  9176. return;
  9177. }
  9178. this.div.hidden = true;
  9179. }
  9180. hasEditableAnnotations() {
  9181. return !!this.annotationLayer?.hasEditableAnnotations();
  9182. }
  9183. async injectLinkAnnotations({
  9184. inferredLinks,
  9185. viewport,
  9186. structTreeLayer = null
  9187. }) {
  9188. if (this.#annotations === null) {
  9189. throw new Error("`render` method must be called before `injectLinkAnnotations`.");
  9190. }
  9191. if (this._cancelled || this.#linksInjected) {
  9192. return;
  9193. }
  9194. this.#linksInjected = true;
  9195. const newLinks = this.#annotations.length ? this.#checkInferredLinks(inferredLinks) : inferredLinks;
  9196. if (!newLinks.length) {
  9197. return;
  9198. }
  9199. if (!this.annotationLayer) {
  9200. this.#initAnnotationLayer(viewport, structTreeLayer);
  9201. setLayerDimensions(this.div, viewport);
  9202. }
  9203. await this.annotationLayer.addLinkAnnotations(newLinks, this.linkService);
  9204. if (!this.#externalHide) {
  9205. this.div.hidden = false;
  9206. }
  9207. }
  9208. #updatePresentationModeState(state) {
  9209. if (!this.div) {
  9210. return;
  9211. }
  9212. let disableFormElements = false;
  9213. switch (state) {
  9214. case PresentationModeState.FULLSCREEN:
  9215. disableFormElements = true;
  9216. break;
  9217. case PresentationModeState.NORMAL:
  9218. break;
  9219. default:
  9220. return;
  9221. }
  9222. for (const section of this.div.childNodes) {
  9223. if (section.hasAttribute("data-internal-link")) {
  9224. continue;
  9225. }
  9226. section.inert = disableFormElements;
  9227. }
  9228. }
  9229. #checkInferredLinks(inferredLinks) {
  9230. function annotationRects(annot) {
  9231. if (!annot.quadPoints) {
  9232. return [annot.rect];
  9233. }
  9234. const rects = [];
  9235. for (let i = 2, ii = annot.quadPoints.length; i < ii; i += 8) {
  9236. const trX = annot.quadPoints[i];
  9237. const trY = annot.quadPoints[i + 1];
  9238. const blX = annot.quadPoints[i + 2];
  9239. const blY = annot.quadPoints[i + 3];
  9240. rects.push([blX, blY, trX, trY]);
  9241. }
  9242. return rects;
  9243. }
  9244. function intersectAnnotations(annot1, annot2) {
  9245. const intersections = [];
  9246. const annot1Rects = annotationRects(annot1);
  9247. const annot2Rects = annotationRects(annot2);
  9248. for (const rect1 of annot1Rects) {
  9249. for (const rect2 of annot2Rects) {
  9250. const intersection = Util.intersect(rect1, rect2);
  9251. if (intersection) {
  9252. intersections.push(intersection);
  9253. }
  9254. }
  9255. }
  9256. return intersections;
  9257. }
  9258. function areaRects(rects) {
  9259. let totalArea = 0;
  9260. for (const rect of rects) {
  9261. totalArea += Math.abs((rect[2] - rect[0]) * (rect[3] - rect[1]));
  9262. }
  9263. return totalArea;
  9264. }
  9265. return inferredLinks.filter(link => {
  9266. let linkAreaRects;
  9267. for (const annotation of this.#annotations) {
  9268. if (annotation.annotationType !== AnnotationType.LINK || !annotation.url) {
  9269. continue;
  9270. }
  9271. const intersections = intersectAnnotations(annotation, link);
  9272. if (intersections.length === 0) {
  9273. continue;
  9274. }
  9275. linkAreaRects ??= areaRects(annotationRects(link));
  9276. if (areaRects(intersections) / linkAreaRects > 0.5) {
  9277. return false;
  9278. }
  9279. }
  9280. return true;
  9281. });
  9282. }
  9283. }
  9284. ;// ./web/autolinker.js
  9285. function DOMRectToPDF({
  9286. width,
  9287. height,
  9288. left,
  9289. top
  9290. }, pdfPageView) {
  9291. if (width === 0 || height === 0) {
  9292. return null;
  9293. }
  9294. const pageBox = pdfPageView.textLayer.div.getBoundingClientRect();
  9295. const bottomLeft = pdfPageView.getPagePoint(left - pageBox.left, top - pageBox.top);
  9296. const topRight = pdfPageView.getPagePoint(left - pageBox.left + width, top - pageBox.top + height);
  9297. return Util.normalizeRect([bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]]);
  9298. }
  9299. function calculateLinkPosition(range, pdfPageView) {
  9300. const rangeRects = range.getClientRects();
  9301. if (rangeRects.length === 1) {
  9302. return {
  9303. rect: DOMRectToPDF(rangeRects[0], pdfPageView)
  9304. };
  9305. }
  9306. const rect = [Infinity, Infinity, -Infinity, -Infinity];
  9307. const quadPoints = [];
  9308. let i = 0;
  9309. for (const domRect of rangeRects) {
  9310. const normalized = DOMRectToPDF(domRect, pdfPageView);
  9311. if (normalized === null) {
  9312. continue;
  9313. }
  9314. quadPoints[i] = quadPoints[i + 4] = normalized[0];
  9315. quadPoints[i + 1] = quadPoints[i + 3] = normalized[3];
  9316. quadPoints[i + 2] = quadPoints[i + 6] = normalized[2];
  9317. quadPoints[i + 5] = quadPoints[i + 7] = normalized[1];
  9318. Util.rectBoundingBox(...normalized, rect);
  9319. i += 8;
  9320. }
  9321. return {
  9322. quadPoints,
  9323. rect
  9324. };
  9325. }
  9326. function textPosition(container, offset) {
  9327. let currentContainer = container;
  9328. do {
  9329. if (currentContainer.nodeType === Node.TEXT_NODE) {
  9330. const currentLength = currentContainer.textContent.length;
  9331. if (offset <= currentLength) {
  9332. return [currentContainer, offset];
  9333. }
  9334. offset -= currentLength;
  9335. } else if (currentContainer.firstChild) {
  9336. currentContainer = currentContainer.firstChild;
  9337. continue;
  9338. }
  9339. while (!currentContainer.nextSibling && currentContainer !== container) {
  9340. currentContainer = currentContainer.parentNode;
  9341. }
  9342. if (currentContainer !== container) {
  9343. currentContainer = currentContainer.nextSibling;
  9344. }
  9345. } while (currentContainer !== container);
  9346. throw new Error("Offset is bigger than container's contents length.");
  9347. }
  9348. function createLinkAnnotation({
  9349. url,
  9350. index,
  9351. length
  9352. }, pdfPageView, id) {
  9353. const highlighter = pdfPageView._textHighlighter;
  9354. const [{
  9355. begin,
  9356. end
  9357. }] = highlighter._convertMatches([index], [length]);
  9358. const range = new Range();
  9359. range.setStart(...textPosition(highlighter.textDivs[begin.divIdx], begin.offset));
  9360. range.setEnd(...textPosition(highlighter.textDivs[end.divIdx], end.offset));
  9361. return {
  9362. id: `inferred_link_${id}`,
  9363. unsafeUrl: url,
  9364. url,
  9365. annotationType: AnnotationType.LINK,
  9366. rotation: 0,
  9367. ...calculateLinkPosition(range, pdfPageView),
  9368. borderStyle: null
  9369. };
  9370. }
  9371. class Autolinker {
  9372. static #index = 0;
  9373. static #regex;
  9374. static findLinks(text) {
  9375. this.#regex ??= /\b(?:https?:\/\/|mailto:|www\.)(?:[\S--[\p{P}<>]]|\/|[\S--[\[\]]]+[\S--[\p{P}<>]])+|\b[\S--[@\p{Ps}\p{Pe}<>]]+@([\S--[\p{P}<>]]+(?:\.[\S--[\p{P}<>]]+)+)/gm;
  9376. const [normalizedText, diffs] = normalize(text);
  9377. const matches = normalizedText.matchAll(this.#regex);
  9378. const links = [];
  9379. for (const match of matches) {
  9380. const [url, emailDomain] = match;
  9381. let raw;
  9382. if (url.startsWith("www.") || url.startsWith("http://") || url.startsWith("https://")) {
  9383. raw = url;
  9384. } else if (URL.canParse(`http://${emailDomain}`)) {
  9385. raw = url.startsWith("mailto:") ? url : `mailto:${url}`;
  9386. } else {
  9387. continue;
  9388. }
  9389. const absoluteURL = createValidAbsoluteUrl(raw, null, {
  9390. addDefaultProtocol: true
  9391. });
  9392. if (absoluteURL) {
  9393. const [index, length] = getOriginalIndex(diffs, match.index, url.length);
  9394. links.push({
  9395. url: absoluteURL.href,
  9396. index,
  9397. length
  9398. });
  9399. }
  9400. }
  9401. return links;
  9402. }
  9403. static processLinks(pdfPageView) {
  9404. return this.findLinks(pdfPageView._textHighlighter.textContentItemsStr.join("\n")).map(link => createLinkAnnotation(link, pdfPageView, this.#index++));
  9405. }
  9406. }
  9407. ;// ./web/base_pdf_page_view.js
  9408. class BasePDFPageView {
  9409. #enableHWA = false;
  9410. #loadingId = null;
  9411. #renderError = null;
  9412. #renderingState = RenderingStates.INITIAL;
  9413. #showCanvas = null;
  9414. canvas = null;
  9415. div = null;
  9416. eventBus = null;
  9417. id = null;
  9418. pageColors = null;
  9419. renderingQueue = null;
  9420. renderTask = null;
  9421. resume = null;
  9422. constructor(options) {
  9423. this.#enableHWA = #enableHWA in options ? options.#enableHWA : options.enableHWA || false;
  9424. this.eventBus = options.eventBus;
  9425. this.id = options.id;
  9426. this.pageColors = options.pageColors || null;
  9427. this.renderingQueue = options.renderingQueue;
  9428. }
  9429. get renderingState() {
  9430. return this.#renderingState;
  9431. }
  9432. set renderingState(state) {
  9433. if (state === this.#renderingState) {
  9434. return;
  9435. }
  9436. this.#renderingState = state;
  9437. if (this.#loadingId) {
  9438. clearTimeout(this.#loadingId);
  9439. this.#loadingId = null;
  9440. }
  9441. switch (state) {
  9442. case RenderingStates.PAUSED:
  9443. this.div.classList.remove("loading");
  9444. break;
  9445. case RenderingStates.RUNNING:
  9446. this.div.classList.add("loadingIcon");
  9447. this.#loadingId = setTimeout(() => {
  9448. this.div.classList.add("loading");
  9449. this.#loadingId = null;
  9450. }, 0);
  9451. break;
  9452. case RenderingStates.INITIAL:
  9453. case RenderingStates.FINISHED:
  9454. this.div.classList.remove("loadingIcon", "loading");
  9455. break;
  9456. }
  9457. }
  9458. _createCanvas(onShow, hideUntilComplete = false) {
  9459. const {
  9460. pageColors
  9461. } = this;
  9462. const hasHCM = !!(pageColors?.background && pageColors?.foreground);
  9463. const prevCanvas = this.canvas;
  9464. const updateOnFirstShow = !prevCanvas && !hasHCM && !hideUntilComplete;
  9465. const canvas = this.canvas = document.createElement("canvas");
  9466. this.#showCanvas = isLastShow => {
  9467. if (updateOnFirstShow) {
  9468. onShow(canvas);
  9469. this.#showCanvas = null;
  9470. return;
  9471. }
  9472. if (!isLastShow) {
  9473. return;
  9474. }
  9475. if (prevCanvas) {
  9476. prevCanvas.replaceWith(canvas);
  9477. prevCanvas.width = prevCanvas.height = 0;
  9478. } else {
  9479. onShow(canvas);
  9480. }
  9481. };
  9482. const ctx = canvas.getContext("2d", {
  9483. alpha: false,
  9484. willReadFrequently: !this.#enableHWA
  9485. });
  9486. return {
  9487. canvas,
  9488. prevCanvas,
  9489. ctx
  9490. };
  9491. }
  9492. #renderContinueCallback = cont => {
  9493. this.#showCanvas?.(false);
  9494. if (this.renderingQueue && !this.renderingQueue.isHighestPriority(this)) {
  9495. this.renderingState = RenderingStates.PAUSED;
  9496. this.resume = () => {
  9497. this.renderingState = RenderingStates.RUNNING;
  9498. cont();
  9499. };
  9500. return;
  9501. }
  9502. cont();
  9503. };
  9504. _resetCanvas() {
  9505. const {
  9506. canvas
  9507. } = this;
  9508. if (!canvas) {
  9509. return;
  9510. }
  9511. canvas.remove();
  9512. canvas.width = canvas.height = 0;
  9513. this.canvas = null;
  9514. }
  9515. async _drawCanvas(options, onCancel, onFinish) {
  9516. const renderTask = this.renderTask = this.pdfPage.render(options);
  9517. renderTask.onContinue = this.#renderContinueCallback;
  9518. renderTask.onError = error => {
  9519. if (error instanceof RenderingCancelledException) {
  9520. onCancel();
  9521. this.#renderError = null;
  9522. }
  9523. };
  9524. let error = null;
  9525. try {
  9526. await renderTask.promise;
  9527. this.#showCanvas?.(true);
  9528. } catch (e) {
  9529. if (e instanceof RenderingCancelledException) {
  9530. return;
  9531. }
  9532. error = e;
  9533. this.#showCanvas?.(true);
  9534. } finally {
  9535. this.#renderError = error;
  9536. if (renderTask === this.renderTask) {
  9537. this.renderTask = null;
  9538. }
  9539. }
  9540. this.renderingState = RenderingStates.FINISHED;
  9541. onFinish(renderTask);
  9542. if (error) {
  9543. throw error;
  9544. }
  9545. }
  9546. cancelRendering({
  9547. cancelExtraDelay = 0
  9548. } = {}) {
  9549. if (this.renderTask) {
  9550. this.renderTask.cancel(cancelExtraDelay);
  9551. this.renderTask = null;
  9552. }
  9553. this.resume = null;
  9554. }
  9555. dispatchPageRender() {
  9556. this.eventBus.dispatch("pagerender", {
  9557. source: this,
  9558. pageNumber: this.id
  9559. });
  9560. }
  9561. dispatchPageRendered(cssTransform, isDetailView) {
  9562. this.eventBus.dispatch("pagerendered", {
  9563. source: this,
  9564. pageNumber: this.id,
  9565. cssTransform,
  9566. isDetailView,
  9567. timestamp: performance.now(),
  9568. error: this.#renderError
  9569. });
  9570. }
  9571. }
  9572. ;// ./web/draw_layer_builder.js
  9573. class DrawLayerBuilder {
  9574. #drawLayer = null;
  9575. constructor(options) {
  9576. this.pageIndex = options.pageIndex;
  9577. }
  9578. async render({
  9579. intent = "display"
  9580. }) {
  9581. if (intent !== "display" || this.#drawLayer || this._cancelled) {
  9582. return;
  9583. }
  9584. this.#drawLayer = new DrawLayer({
  9585. pageIndex: this.pageIndex
  9586. });
  9587. }
  9588. cancel() {
  9589. this._cancelled = true;
  9590. if (!this.#drawLayer) {
  9591. return;
  9592. }
  9593. this.#drawLayer.destroy();
  9594. this.#drawLayer = null;
  9595. }
  9596. setParent(parent) {
  9597. this.#drawLayer?.setParent(parent);
  9598. }
  9599. getDrawLayer() {
  9600. return this.#drawLayer;
  9601. }
  9602. }
  9603. ;// ./web/pdf_page_detail_view.js
  9604. class PDFPageDetailView extends BasePDFPageView {
  9605. #detailArea = null;
  9606. renderingCancelled = false;
  9607. constructor({
  9608. pageView
  9609. }) {
  9610. super(pageView);
  9611. this.pageView = pageView;
  9612. this.renderingId = "detail" + this.id;
  9613. this.div = pageView.div;
  9614. }
  9615. setPdfPage(pdfPage) {
  9616. this.pageView.setPdfPage(pdfPage);
  9617. }
  9618. get pdfPage() {
  9619. return this.pageView.pdfPage;
  9620. }
  9621. get renderingState() {
  9622. return super.renderingState;
  9623. }
  9624. set renderingState(value) {
  9625. this.renderingCancelled = false;
  9626. super.renderingState = value;
  9627. }
  9628. reset({
  9629. keepCanvas = false
  9630. } = {}) {
  9631. const renderingCancelled = this.renderingCancelled || this.renderingState === RenderingStates.RUNNING || this.renderingState === RenderingStates.PAUSED;
  9632. this.cancelRendering();
  9633. this.renderingState = RenderingStates.INITIAL;
  9634. this.renderingCancelled = renderingCancelled;
  9635. if (!keepCanvas) {
  9636. this._resetCanvas();
  9637. }
  9638. }
  9639. #shouldRenderDifferentArea(visibleArea) {
  9640. if (!this.#detailArea) {
  9641. return true;
  9642. }
  9643. const minDetailX = this.#detailArea.minX;
  9644. const minDetailY = this.#detailArea.minY;
  9645. const maxDetailX = this.#detailArea.width + minDetailX;
  9646. const maxDetailY = this.#detailArea.height + minDetailY;
  9647. if (visibleArea.minX < minDetailX || visibleArea.minY < minDetailY || visibleArea.maxX > maxDetailX || visibleArea.maxY > maxDetailY) {
  9648. return true;
  9649. }
  9650. const {
  9651. width: maxWidth,
  9652. height: maxHeight,
  9653. scale
  9654. } = this.pageView.viewport;
  9655. if (this.#detailArea.scale !== scale) {
  9656. return true;
  9657. }
  9658. const paddingLeftSize = visibleArea.minX - minDetailX;
  9659. const paddingRightSize = maxDetailX - visibleArea.maxX;
  9660. const paddingTopSize = visibleArea.minY - minDetailY;
  9661. const paddingBottomSize = maxDetailY - visibleArea.maxY;
  9662. const MOVEMENT_THRESHOLD = 0.5;
  9663. const ratio = (1 + MOVEMENT_THRESHOLD) / MOVEMENT_THRESHOLD;
  9664. if (minDetailX > 0 && paddingRightSize / paddingLeftSize > ratio || maxDetailX < maxWidth && paddingLeftSize / paddingRightSize > ratio || minDetailY > 0 && paddingBottomSize / paddingTopSize > ratio || maxDetailY < maxHeight && paddingTopSize / paddingBottomSize > ratio) {
  9665. return true;
  9666. }
  9667. return false;
  9668. }
  9669. update({
  9670. visibleArea = null,
  9671. underlyingViewUpdated = false
  9672. } = {}) {
  9673. if (underlyingViewUpdated) {
  9674. this.cancelRendering();
  9675. this.renderingState = RenderingStates.INITIAL;
  9676. return;
  9677. }
  9678. if (!this.#shouldRenderDifferentArea(visibleArea)) {
  9679. return;
  9680. }
  9681. const {
  9682. viewport,
  9683. maxCanvasPixels
  9684. } = this.pageView;
  9685. const visibleWidth = visibleArea.maxX - visibleArea.minX;
  9686. const visibleHeight = visibleArea.maxY - visibleArea.minY;
  9687. const visiblePixels = visibleWidth * visibleHeight * OutputScale.pixelRatio ** 2;
  9688. const maxDetailToVisibleLinearRatio = Math.sqrt(maxCanvasPixels / visiblePixels);
  9689. const maxOverflowScale = (maxDetailToVisibleLinearRatio - 1) / 2;
  9690. let overflowScale = Math.min(1, maxOverflowScale);
  9691. if (overflowScale < 0) {
  9692. overflowScale = 0;
  9693. }
  9694. const overflowWidth = visibleWidth * overflowScale;
  9695. const overflowHeight = visibleHeight * overflowScale;
  9696. const minX = Math.max(0, visibleArea.minX - overflowWidth);
  9697. const maxX = Math.min(viewport.width, visibleArea.maxX + overflowWidth);
  9698. const minY = Math.max(0, visibleArea.minY - overflowHeight);
  9699. const maxY = Math.min(viewport.height, visibleArea.maxY + overflowHeight);
  9700. const width = maxX - minX;
  9701. const height = maxY - minY;
  9702. this.#detailArea = {
  9703. minX,
  9704. minY,
  9705. width,
  9706. height,
  9707. scale: viewport.scale
  9708. };
  9709. this.reset({
  9710. keepCanvas: true
  9711. });
  9712. }
  9713. async draw() {
  9714. if (this.pageView.detailView !== this) {
  9715. return undefined;
  9716. }
  9717. const hideUntilComplete = this.pageView.renderingState === RenderingStates.FINISHED || this.renderingState === RenderingStates.FINISHED;
  9718. if (this.renderingState !== RenderingStates.INITIAL) {
  9719. console.error("Must be in new state before drawing");
  9720. this.reset();
  9721. }
  9722. const {
  9723. div,
  9724. pdfPage,
  9725. viewport
  9726. } = this.pageView;
  9727. if (!pdfPage) {
  9728. this.renderingState = RenderingStates.FINISHED;
  9729. throw new Error("pdfPage is not loaded");
  9730. }
  9731. this.renderingState = RenderingStates.RUNNING;
  9732. const canvasWrapper = this.pageView._ensureCanvasWrapper();
  9733. const {
  9734. canvas,
  9735. prevCanvas,
  9736. ctx
  9737. } = this._createCanvas(newCanvas => {
  9738. if (canvasWrapper.firstElementChild?.tagName === "CANVAS") {
  9739. canvasWrapper.firstElementChild.after(newCanvas);
  9740. } else {
  9741. canvasWrapper.prepend(newCanvas);
  9742. }
  9743. }, hideUntilComplete);
  9744. canvas.setAttribute("aria-hidden", "true");
  9745. const {
  9746. width,
  9747. height
  9748. } = viewport;
  9749. const area = this.#detailArea;
  9750. const {
  9751. pixelRatio
  9752. } = OutputScale;
  9753. const transform = [pixelRatio, 0, 0, pixelRatio, -area.minX * pixelRatio, -area.minY * pixelRatio];
  9754. canvas.width = area.width * pixelRatio;
  9755. canvas.height = area.height * pixelRatio;
  9756. const {
  9757. style
  9758. } = canvas;
  9759. style.width = `${area.width * 100 / width}%`;
  9760. style.height = `${area.height * 100 / height}%`;
  9761. style.top = `${area.minY * 100 / height}%`;
  9762. style.left = `${area.minX * 100 / width}%`;
  9763. const renderingPromise = this._drawCanvas(this.pageView._getRenderingContext(ctx, transform), () => {
  9764. this.canvas?.remove();
  9765. this.canvas = prevCanvas;
  9766. }, () => {
  9767. this.dispatchPageRendered(false, true);
  9768. });
  9769. div.setAttribute("data-loaded", true);
  9770. this.dispatchPageRender();
  9771. return renderingPromise;
  9772. }
  9773. }
  9774. ;// ./web/struct_tree_layer_builder.js
  9775. const PDF_ROLE_TO_HTML_ROLE = {
  9776. Document: null,
  9777. DocumentFragment: null,
  9778. Part: "group",
  9779. Sect: "group",
  9780. Div: "group",
  9781. Aside: "note",
  9782. NonStruct: "none",
  9783. P: null,
  9784. H: "heading",
  9785. Title: null,
  9786. FENote: "note",
  9787. Sub: "group",
  9788. Lbl: null,
  9789. Span: null,
  9790. Em: null,
  9791. Strong: null,
  9792. Link: "link",
  9793. Annot: "note",
  9794. Form: "form",
  9795. Ruby: null,
  9796. RB: null,
  9797. RT: null,
  9798. RP: null,
  9799. Warichu: null,
  9800. WT: null,
  9801. WP: null,
  9802. L: "list",
  9803. LI: "listitem",
  9804. LBody: null,
  9805. Table: "table",
  9806. TR: "row",
  9807. TH: "columnheader",
  9808. TD: "cell",
  9809. THead: "columnheader",
  9810. TBody: null,
  9811. TFoot: null,
  9812. Caption: null,
  9813. Figure: "figure",
  9814. Formula: null,
  9815. Artifact: null
  9816. };
  9817. const HEADING_PATTERN = /^H(\d+)$/;
  9818. class StructTreeLayerBuilder {
  9819. #promise;
  9820. #treeDom = null;
  9821. #treePromise;
  9822. #elementAttributes = new Map();
  9823. #rawDims;
  9824. #elementsToAddToTextLayer = null;
  9825. constructor(pdfPage, rawDims) {
  9826. this.#promise = pdfPage.getStructTree();
  9827. this.#rawDims = rawDims;
  9828. }
  9829. async render() {
  9830. if (this.#treePromise) {
  9831. return this.#treePromise;
  9832. }
  9833. const {
  9834. promise,
  9835. resolve,
  9836. reject
  9837. } = Promise.withResolvers();
  9838. this.#treePromise = promise;
  9839. try {
  9840. this.#treeDom = this.#walk(await this.#promise);
  9841. } catch (ex) {
  9842. reject(ex);
  9843. }
  9844. this.#promise = null;
  9845. this.#treeDom?.classList.add("structTree");
  9846. resolve(this.#treeDom);
  9847. return promise;
  9848. }
  9849. async getAriaAttributes(annotationId) {
  9850. try {
  9851. await this.render();
  9852. return this.#elementAttributes.get(annotationId);
  9853. } catch {}
  9854. return null;
  9855. }
  9856. hide() {
  9857. if (this.#treeDom && !this.#treeDom.hidden) {
  9858. this.#treeDom.hidden = true;
  9859. }
  9860. }
  9861. show() {
  9862. if (this.#treeDom?.hidden) {
  9863. this.#treeDom.hidden = false;
  9864. }
  9865. }
  9866. #setAttributes(structElement, htmlElement) {
  9867. const {
  9868. alt,
  9869. id,
  9870. lang
  9871. } = structElement;
  9872. if (alt !== undefined) {
  9873. let added = false;
  9874. const label = removeNullCharacters(alt);
  9875. for (const child of structElement.children) {
  9876. if (child.type === "annotation") {
  9877. let attrs = this.#elementAttributes.get(child.id);
  9878. if (!attrs) {
  9879. attrs = new Map();
  9880. this.#elementAttributes.set(child.id, attrs);
  9881. }
  9882. attrs.set("aria-label", label);
  9883. added = true;
  9884. }
  9885. }
  9886. if (!added) {
  9887. htmlElement.setAttribute("aria-label", label);
  9888. }
  9889. }
  9890. if (id !== undefined) {
  9891. htmlElement.setAttribute("aria-owns", id);
  9892. }
  9893. if (lang !== undefined) {
  9894. htmlElement.setAttribute("lang", removeNullCharacters(lang, true));
  9895. }
  9896. }
  9897. #addImageInTextLayer(node, element) {
  9898. const {
  9899. alt,
  9900. bbox,
  9901. children
  9902. } = node;
  9903. const child = children?.[0];
  9904. if (!this.#rawDims || !alt || !bbox || child?.type !== "content") {
  9905. return false;
  9906. }
  9907. const {
  9908. id
  9909. } = child;
  9910. if (!id) {
  9911. return false;
  9912. }
  9913. element.setAttribute("aria-owns", id);
  9914. const img = document.createElement("span");
  9915. (this.#elementsToAddToTextLayer ||= new Map()).set(id, img);
  9916. img.setAttribute("role", "img");
  9917. img.setAttribute("aria-label", removeNullCharacters(alt));
  9918. const {
  9919. pageHeight,
  9920. pageX,
  9921. pageY
  9922. } = this.#rawDims;
  9923. const calc = "calc(var(--total-scale-factor) *";
  9924. const {
  9925. style
  9926. } = img;
  9927. style.width = `${calc}${bbox[2] - bbox[0]}px)`;
  9928. style.height = `${calc}${bbox[3] - bbox[1]}px)`;
  9929. style.left = `${calc}${bbox[0] - pageX}px)`;
  9930. style.top = `${calc}${pageHeight - bbox[3] + pageY}px)`;
  9931. return true;
  9932. }
  9933. addElementsToTextLayer() {
  9934. if (!this.#elementsToAddToTextLayer) {
  9935. return;
  9936. }
  9937. for (const [id, img] of this.#elementsToAddToTextLayer) {
  9938. document.getElementById(id)?.append(img);
  9939. }
  9940. this.#elementsToAddToTextLayer.clear();
  9941. this.#elementsToAddToTextLayer = null;
  9942. }
  9943. #walk(node) {
  9944. if (!node) {
  9945. return null;
  9946. }
  9947. const element = document.createElement("span");
  9948. if ("role" in node) {
  9949. const {
  9950. role
  9951. } = node;
  9952. const match = role.match(HEADING_PATTERN);
  9953. if (match) {
  9954. element.setAttribute("role", "heading");
  9955. element.setAttribute("aria-level", match[1]);
  9956. } else if (PDF_ROLE_TO_HTML_ROLE[role]) {
  9957. element.setAttribute("role", PDF_ROLE_TO_HTML_ROLE[role]);
  9958. }
  9959. if (role === "Figure" && this.#addImageInTextLayer(node, element)) {
  9960. return element;
  9961. }
  9962. }
  9963. this.#setAttributes(node, element);
  9964. if (node.children) {
  9965. if (node.children.length === 1 && "id" in node.children[0]) {
  9966. this.#setAttributes(node.children[0], element);
  9967. } else {
  9968. for (const kid of node.children) {
  9969. element.append(this.#walk(kid));
  9970. }
  9971. }
  9972. }
  9973. return element;
  9974. }
  9975. }
  9976. ;// ./web/text_accessibility.js
  9977. class TextAccessibilityManager {
  9978. #enabled = false;
  9979. #textChildren = null;
  9980. #textNodes = new Map();
  9981. #waitingElements = new Map();
  9982. setTextMapping(textDivs) {
  9983. this.#textChildren = textDivs;
  9984. }
  9985. static #compareElementPositions(e1, e2) {
  9986. const rect1 = e1.getBoundingClientRect();
  9987. const rect2 = e2.getBoundingClientRect();
  9988. if (rect1.width === 0 && rect1.height === 0) {
  9989. return +1;
  9990. }
  9991. if (rect2.width === 0 && rect2.height === 0) {
  9992. return -1;
  9993. }
  9994. const top1 = rect1.y;
  9995. const bot1 = rect1.y + rect1.height;
  9996. const mid1 = rect1.y + rect1.height / 2;
  9997. const top2 = rect2.y;
  9998. const bot2 = rect2.y + rect2.height;
  9999. const mid2 = rect2.y + rect2.height / 2;
  10000. if (mid1 <= top2 && mid2 >= bot1) {
  10001. return -1;
  10002. }
  10003. if (mid2 <= top1 && mid1 >= bot2) {
  10004. return +1;
  10005. }
  10006. const centerX1 = rect1.x + rect1.width / 2;
  10007. const centerX2 = rect2.x + rect2.width / 2;
  10008. return centerX1 - centerX2;
  10009. }
  10010. enable() {
  10011. if (this.#enabled) {
  10012. throw new Error("TextAccessibilityManager is already enabled.");
  10013. }
  10014. if (!this.#textChildren) {
  10015. throw new Error("Text divs and strings have not been set.");
  10016. }
  10017. this.#enabled = true;
  10018. this.#textChildren = this.#textChildren.slice();
  10019. this.#textChildren.sort(TextAccessibilityManager.#compareElementPositions);
  10020. if (this.#textNodes.size > 0) {
  10021. const textChildren = this.#textChildren;
  10022. for (const [id, nodeIndex] of this.#textNodes) {
  10023. const element = document.getElementById(id);
  10024. if (!element) {
  10025. this.#textNodes.delete(id);
  10026. continue;
  10027. }
  10028. this.#addIdToAriaOwns(id, textChildren[nodeIndex]);
  10029. }
  10030. }
  10031. for (const [element, isRemovable] of this.#waitingElements) {
  10032. this.addPointerInTextLayer(element, isRemovable);
  10033. }
  10034. this.#waitingElements.clear();
  10035. }
  10036. disable() {
  10037. if (!this.#enabled) {
  10038. return;
  10039. }
  10040. this.#waitingElements.clear();
  10041. this.#textChildren = null;
  10042. this.#enabled = false;
  10043. }
  10044. removePointerInTextLayer(element) {
  10045. if (!this.#enabled) {
  10046. this.#waitingElements.delete(element);
  10047. return;
  10048. }
  10049. const children = this.#textChildren;
  10050. if (!children || children.length === 0) {
  10051. return;
  10052. }
  10053. const {
  10054. id
  10055. } = element;
  10056. const nodeIndex = this.#textNodes.get(id);
  10057. if (nodeIndex === undefined) {
  10058. return;
  10059. }
  10060. const node = children[nodeIndex];
  10061. this.#textNodes.delete(id);
  10062. let owns = node.getAttribute("aria-owns");
  10063. if (owns?.includes(id)) {
  10064. owns = owns.split(" ").filter(x => x !== id).join(" ");
  10065. if (owns) {
  10066. node.setAttribute("aria-owns", owns);
  10067. } else {
  10068. node.removeAttribute("aria-owns");
  10069. node.setAttribute("role", "presentation");
  10070. }
  10071. }
  10072. }
  10073. #addIdToAriaOwns(id, node) {
  10074. const owns = node.getAttribute("aria-owns");
  10075. if (!owns?.includes(id)) {
  10076. node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id);
  10077. }
  10078. node.removeAttribute("role");
  10079. }
  10080. addPointerInTextLayer(element, isRemovable) {
  10081. const {
  10082. id
  10083. } = element;
  10084. if (!id) {
  10085. return null;
  10086. }
  10087. if (!this.#enabled) {
  10088. this.#waitingElements.set(element, isRemovable);
  10089. return null;
  10090. }
  10091. if (isRemovable) {
  10092. this.removePointerInTextLayer(element);
  10093. }
  10094. const children = this.#textChildren;
  10095. if (!children || children.length === 0) {
  10096. return null;
  10097. }
  10098. const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0);
  10099. const nodeIndex = Math.max(0, index - 1);
  10100. const child = children[nodeIndex];
  10101. this.#addIdToAriaOwns(id, child);
  10102. this.#textNodes.set(id, nodeIndex);
  10103. const parent = child.parentNode;
  10104. return parent?.classList.contains("markedContent") ? parent.id : null;
  10105. }
  10106. moveElementInDOM(container, element, contentElement, isRemovable) {
  10107. const id = this.addPointerInTextLayer(contentElement, isRemovable);
  10108. if (!container.hasChildNodes()) {
  10109. container.append(element);
  10110. return id;
  10111. }
  10112. const children = Array.from(container.childNodes).filter(node => node !== element);
  10113. if (children.length === 0) {
  10114. return id;
  10115. }
  10116. const elementToCompare = contentElement || element;
  10117. const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(elementToCompare, node) < 0);
  10118. if (index === 0) {
  10119. children[0].before(element);
  10120. } else {
  10121. children[index - 1].after(element);
  10122. }
  10123. return id;
  10124. }
  10125. }
  10126. ;// ./web/text_highlighter.js
  10127. class TextHighlighter {
  10128. #eventAbortController = null;
  10129. constructor({
  10130. findController,
  10131. eventBus,
  10132. pageIndex
  10133. }) {
  10134. this.findController = findController;
  10135. this.matches = [];
  10136. this.eventBus = eventBus;
  10137. this.pageIdx = pageIndex;
  10138. this.textDivs = null;
  10139. this.textContentItemsStr = null;
  10140. this.enabled = false;
  10141. }
  10142. setTextMapping(divs, texts) {
  10143. this.textDivs = divs;
  10144. this.textContentItemsStr = texts;
  10145. }
  10146. enable() {
  10147. if (!this.textDivs || !this.textContentItemsStr) {
  10148. throw new Error("Text divs and strings have not been set.");
  10149. }
  10150. if (this.enabled) {
  10151. throw new Error("TextHighlighter is already enabled.");
  10152. }
  10153. this.enabled = true;
  10154. if (!this.#eventAbortController) {
  10155. this.#eventAbortController = new AbortController();
  10156. this.eventBus._on("updatetextlayermatches", evt => {
  10157. if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) {
  10158. this._updateMatches();
  10159. }
  10160. }, {
  10161. signal: this.#eventAbortController.signal
  10162. });
  10163. }
  10164. this._updateMatches();
  10165. }
  10166. disable() {
  10167. if (!this.enabled) {
  10168. return;
  10169. }
  10170. this.enabled = false;
  10171. this.#eventAbortController?.abort();
  10172. this.#eventAbortController = null;
  10173. this._updateMatches(true);
  10174. }
  10175. _convertMatches(matches, matchesLength) {
  10176. if (!matches) {
  10177. return [];
  10178. }
  10179. const {
  10180. textContentItemsStr
  10181. } = this;
  10182. let i = 0,
  10183. iIndex = 0;
  10184. const end = textContentItemsStr.length - 1;
  10185. const result = [];
  10186. for (let m = 0, mm = matches.length; m < mm; m++) {
  10187. let matchIdx = matches[m];
  10188. while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) {
  10189. iIndex += textContentItemsStr[i].length;
  10190. i++;
  10191. }
  10192. if (i === textContentItemsStr.length) {
  10193. console.error("Could not find a matching mapping");
  10194. }
  10195. const match = {
  10196. begin: {
  10197. divIdx: i,
  10198. offset: matchIdx - iIndex
  10199. }
  10200. };
  10201. matchIdx += matchesLength[m];
  10202. while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) {
  10203. iIndex += textContentItemsStr[i].length;
  10204. i++;
  10205. }
  10206. match.end = {
  10207. divIdx: i,
  10208. offset: matchIdx - iIndex
  10209. };
  10210. result.push(match);
  10211. }
  10212. return result;
  10213. }
  10214. _renderMatches(matches) {
  10215. if (matches.length === 0) {
  10216. return;
  10217. }
  10218. const {
  10219. findController,
  10220. pageIdx
  10221. } = this;
  10222. const {
  10223. textContentItemsStr,
  10224. textDivs
  10225. } = this;
  10226. const isSelectedPage = pageIdx === findController.selected.pageIdx;
  10227. const selectedMatchIdx = findController.selected.matchIdx;
  10228. const highlightAll = findController.state.highlightAll;
  10229. let prevEnd = null;
  10230. const infinity = {
  10231. divIdx: -1,
  10232. offset: undefined
  10233. };
  10234. function beginText(begin, className) {
  10235. const divIdx = begin.divIdx;
  10236. textDivs[divIdx].textContent = "";
  10237. return appendTextToDiv(divIdx, 0, begin.offset, className);
  10238. }
  10239. function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
  10240. let div = textDivs[divIdx];
  10241. if (div.nodeType === Node.TEXT_NODE) {
  10242. const span = document.createElement("span");
  10243. div.before(span);
  10244. span.append(div);
  10245. textDivs[divIdx] = span;
  10246. div = span;
  10247. }
  10248. const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset);
  10249. const node = document.createTextNode(content);
  10250. if (className) {
  10251. const span = document.createElement("span");
  10252. span.className = `${className} appended`;
  10253. span.append(node);
  10254. div.append(span);
  10255. if (className.includes("selected")) {
  10256. const {
  10257. left
  10258. } = span.getClientRects()[0];
  10259. const parentLeft = div.getBoundingClientRect().left;
  10260. return left - parentLeft;
  10261. }
  10262. return 0;
  10263. }
  10264. div.append(node);
  10265. return 0;
  10266. }
  10267. let i0 = selectedMatchIdx,
  10268. i1 = i0 + 1;
  10269. if (highlightAll) {
  10270. i0 = 0;
  10271. i1 = matches.length;
  10272. } else if (!isSelectedPage) {
  10273. return;
  10274. }
  10275. let lastDivIdx = -1;
  10276. let lastOffset = -1;
  10277. for (let i = i0; i < i1; i++) {
  10278. const match = matches[i];
  10279. const begin = match.begin;
  10280. if (begin.divIdx === lastDivIdx && begin.offset === lastOffset) {
  10281. continue;
  10282. }
  10283. lastDivIdx = begin.divIdx;
  10284. lastOffset = begin.offset;
  10285. const end = match.end;
  10286. const isSelected = isSelectedPage && i === selectedMatchIdx;
  10287. const highlightSuffix = isSelected ? " selected" : "";
  10288. let selectedLeft = 0;
  10289. if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
  10290. if (prevEnd !== null) {
  10291. appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
  10292. }
  10293. beginText(begin);
  10294. } else {
  10295. appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
  10296. }
  10297. if (begin.divIdx === end.divIdx) {
  10298. selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix);
  10299. } else {
  10300. selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix);
  10301. for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
  10302. textDivs[n0].className = "highlight middle" + highlightSuffix;
  10303. }
  10304. beginText(end, "highlight end" + highlightSuffix);
  10305. }
  10306. prevEnd = end;
  10307. if (isSelected) {
  10308. findController.scrollMatchIntoView({
  10309. element: textDivs[begin.divIdx],
  10310. selectedLeft,
  10311. pageIndex: pageIdx,
  10312. matchIndex: selectedMatchIdx
  10313. });
  10314. }
  10315. }
  10316. if (prevEnd) {
  10317. appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
  10318. }
  10319. }
  10320. _updateMatches(reset = false) {
  10321. if (!this.enabled && !reset) {
  10322. return;
  10323. }
  10324. const {
  10325. findController,
  10326. matches,
  10327. pageIdx
  10328. } = this;
  10329. const {
  10330. textContentItemsStr,
  10331. textDivs
  10332. } = this;
  10333. let clearedUntilDivIdx = -1;
  10334. for (const match of matches) {
  10335. const begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
  10336. for (let n = begin, end = match.end.divIdx; n <= end; n++) {
  10337. const div = textDivs[n];
  10338. div.textContent = textContentItemsStr[n];
  10339. div.className = "";
  10340. }
  10341. clearedUntilDivIdx = match.end.divIdx + 1;
  10342. }
  10343. if (!findController?.highlightMatches || reset) {
  10344. return;
  10345. }
  10346. const pageMatches = findController.pageMatches[pageIdx] || null;
  10347. const pageMatchesLength = findController.pageMatchesLength[pageIdx] || null;
  10348. this.matches = this._convertMatches(pageMatches, pageMatchesLength);
  10349. this._renderMatches(this.matches);
  10350. }
  10351. }
  10352. ;// ./web/text_layer_builder.js
  10353. class TextLayerBuilder {
  10354. #enablePermissions = false;
  10355. #onAppend = null;
  10356. #renderingDone = false;
  10357. #textLayer = null;
  10358. static #textLayers = new Map();
  10359. static #selectionChangeAbortController = null;
  10360. constructor({
  10361. pdfPage,
  10362. highlighter = null,
  10363. accessibilityManager = null,
  10364. enablePermissions = false,
  10365. onAppend = null
  10366. }) {
  10367. this.pdfPage = pdfPage;
  10368. this.highlighter = highlighter;
  10369. this.accessibilityManager = accessibilityManager;
  10370. this.#enablePermissions = enablePermissions === true;
  10371. this.#onAppend = onAppend;
  10372. this.div = document.createElement("div");
  10373. this.div.tabIndex = 0;
  10374. this.div.className = "textLayer";
  10375. }
  10376. async render({
  10377. viewport,
  10378. textContentParams = null
  10379. }) {
  10380. if (this.#renderingDone && this.#textLayer) {
  10381. this.#textLayer.update({
  10382. viewport,
  10383. onBefore: this.hide.bind(this)
  10384. });
  10385. this.show();
  10386. return;
  10387. }
  10388. this.cancel();
  10389. this.#textLayer = new TextLayer({
  10390. textContentSource: this.pdfPage.streamTextContent(textContentParams || {
  10391. includeMarkedContent: true,
  10392. disableNormalization: true
  10393. }),
  10394. container: this.div,
  10395. viewport
  10396. });
  10397. const {
  10398. textDivs,
  10399. textContentItemsStr
  10400. } = this.#textLayer;
  10401. this.highlighter?.setTextMapping(textDivs, textContentItemsStr);
  10402. this.accessibilityManager?.setTextMapping(textDivs);
  10403. await this.#textLayer.render();
  10404. this.#renderingDone = true;
  10405. const endOfContent = document.createElement("div");
  10406. endOfContent.className = "endOfContent";
  10407. this.div.append(endOfContent);
  10408. this.#bindMouse(endOfContent);
  10409. this.#onAppend?.(this.div);
  10410. this.highlighter?.enable();
  10411. this.accessibilityManager?.enable();
  10412. }
  10413. hide() {
  10414. if (!this.div.hidden && this.#renderingDone) {
  10415. this.highlighter?.disable();
  10416. this.div.hidden = true;
  10417. }
  10418. }
  10419. show() {
  10420. if (this.div.hidden && this.#renderingDone) {
  10421. this.div.hidden = false;
  10422. this.highlighter?.enable();
  10423. }
  10424. }
  10425. cancel() {
  10426. this.#textLayer?.cancel();
  10427. this.#textLayer = null;
  10428. this.highlighter?.disable();
  10429. this.accessibilityManager?.disable();
  10430. TextLayerBuilder.#removeGlobalSelectionListener(this.div);
  10431. }
  10432. #bindMouse(end) {
  10433. const {
  10434. div
  10435. } = this;
  10436. div.addEventListener("mousedown", () => {
  10437. div.classList.add("selecting");
  10438. });
  10439. div.addEventListener("copy", event => {
  10440. if (!this.#enablePermissions) {
  10441. const selection = document.getSelection();
  10442. event.clipboardData.setData("text/plain", removeNullCharacters(normalizeUnicode(selection.toString())));
  10443. }
  10444. stopEvent(event);
  10445. });
  10446. TextLayerBuilder.#textLayers.set(div, end);
  10447. TextLayerBuilder.#enableGlobalSelectionListener();
  10448. }
  10449. static #removeGlobalSelectionListener(textLayerDiv) {
  10450. this.#textLayers.delete(textLayerDiv);
  10451. if (this.#textLayers.size === 0) {
  10452. this.#selectionChangeAbortController?.abort();
  10453. this.#selectionChangeAbortController = null;
  10454. }
  10455. }
  10456. static #enableGlobalSelectionListener() {
  10457. if (this.#selectionChangeAbortController) {
  10458. return;
  10459. }
  10460. this.#selectionChangeAbortController = new AbortController();
  10461. const {
  10462. signal
  10463. } = this.#selectionChangeAbortController;
  10464. const reset = (end, textLayer) => {
  10465. textLayer.append(end);
  10466. end.style.width = "";
  10467. end.style.height = "";
  10468. textLayer.classList.remove("selecting");
  10469. };
  10470. let isPointerDown = false;
  10471. document.addEventListener("pointerdown", () => {
  10472. isPointerDown = true;
  10473. }, {
  10474. signal
  10475. });
  10476. document.addEventListener("pointerup", () => {
  10477. isPointerDown = false;
  10478. this.#textLayers.forEach(reset);
  10479. }, {
  10480. signal
  10481. });
  10482. window.addEventListener("blur", () => {
  10483. isPointerDown = false;
  10484. this.#textLayers.forEach(reset);
  10485. }, {
  10486. signal
  10487. });
  10488. document.addEventListener("keyup", () => {
  10489. if (!isPointerDown) {
  10490. this.#textLayers.forEach(reset);
  10491. }
  10492. }, {
  10493. signal
  10494. });
  10495. var isFirefox, prevRange;
  10496. document.addEventListener("selectionchange", () => {
  10497. const selection = document.getSelection();
  10498. if (selection.rangeCount === 0) {
  10499. this.#textLayers.forEach(reset);
  10500. return;
  10501. }
  10502. const activeTextLayers = new Set();
  10503. for (let i = 0; i < selection.rangeCount; i++) {
  10504. const range = selection.getRangeAt(i);
  10505. for (const textLayerDiv of this.#textLayers.keys()) {
  10506. if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) {
  10507. activeTextLayers.add(textLayerDiv);
  10508. }
  10509. }
  10510. }
  10511. for (const [textLayerDiv, endDiv] of this.#textLayers) {
  10512. if (activeTextLayers.has(textLayerDiv)) {
  10513. textLayerDiv.classList.add("selecting");
  10514. } else {
  10515. reset(endDiv, textLayerDiv);
  10516. }
  10517. }
  10518. isFirefox ??= getComputedStyle(this.#textLayers.values().next().value).getPropertyValue("-moz-user-select") === "none";
  10519. if (isFirefox) {
  10520. return;
  10521. }
  10522. const range = selection.getRangeAt(0);
  10523. const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
  10524. let anchor = modifyStart ? range.startContainer : range.endContainer;
  10525. if (anchor.nodeType === Node.TEXT_NODE) {
  10526. anchor = anchor.parentNode;
  10527. }
  10528. const parentTextLayer = anchor.parentElement?.closest(".textLayer");
  10529. const endDiv = this.#textLayers.get(parentTextLayer);
  10530. if (endDiv) {
  10531. endDiv.style.width = parentTextLayer.style.width;
  10532. endDiv.style.height = parentTextLayer.style.height;
  10533. anchor.parentElement.insertBefore(endDiv, modifyStart ? anchor : anchor.nextSibling);
  10534. }
  10535. prevRange = range.cloneRange();
  10536. }, {
  10537. signal
  10538. });
  10539. }
  10540. }
  10541. ;// ./web/pdf_page_view.js
  10542. const DEFAULT_LAYER_PROPERTIES = null;
  10543. const LAYERS_ORDER = new Map([["canvasWrapper", 0], ["textLayer", 1], ["annotationLayer", 2], ["annotationEditorLayer", 3], ["xfaLayer", 3]]);
  10544. class PDFPageView extends BasePDFPageView {
  10545. #annotationMode = AnnotationMode.ENABLE_FORMS;
  10546. #canvasWrapper = null;
  10547. #enableAutoLinking = true;
  10548. #hasRestrictedScaling = false;
  10549. #isEditing = false;
  10550. #layerProperties = null;
  10551. #needsRestrictedScaling = false;
  10552. #originalViewport = null;
  10553. #previousRotation = null;
  10554. #scaleRoundX = 1;
  10555. #scaleRoundY = 1;
  10556. #textLayerMode = TextLayerMode.ENABLE;
  10557. #userUnit = 1;
  10558. #useThumbnailCanvas = {
  10559. directDrawing: true,
  10560. initialOptionalContent: true,
  10561. regularAnnotations: true
  10562. };
  10563. #layers = [null, null, null, null];
  10564. constructor(options) {
  10565. super(options);
  10566. const container = options.container;
  10567. const defaultViewport = options.defaultViewport;
  10568. this.renderingId = "page" + this.id;
  10569. this.#layerProperties = options.layerProperties || DEFAULT_LAYER_PROPERTIES;
  10570. this.pdfPage = null;
  10571. this.pageLabel = null;
  10572. this.rotation = 0;
  10573. this.scale = options.scale || DEFAULT_SCALE;
  10574. this.viewport = defaultViewport;
  10575. this.pdfPageRotate = defaultViewport.rotation;
  10576. this._optionalContentConfigPromise = options.optionalContentConfigPromise || null;
  10577. this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
  10578. this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
  10579. this.imageResourcesPath = options.imageResourcesPath || "";
  10580. this.enableDetailCanvas = options.enableDetailCanvas ?? true;
  10581. this.maxCanvasPixels = options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
  10582. this.maxCanvasDim = options.maxCanvasDim || AppOptions.get("maxCanvasDim");
  10583. this.#enableAutoLinking = options.enableAutoLinking !== false;
  10584. this.l10n = options.l10n;
  10585. this.l10n ||= new genericl10n_GenericL10n();
  10586. this._isStandalone = !this.renderingQueue?.hasViewer();
  10587. this._container = container;
  10588. this._annotationCanvasMap = null;
  10589. this.annotationLayer = null;
  10590. this.annotationEditorLayer = null;
  10591. this.textLayer = null;
  10592. this.xfaLayer = null;
  10593. this.structTreeLayer = null;
  10594. this.drawLayer = null;
  10595. this.detailView = null;
  10596. const div = document.createElement("div");
  10597. div.className = "page";
  10598. div.setAttribute("data-page-number", this.id);
  10599. div.setAttribute("role", "region");
  10600. div.setAttribute("data-l10n-id", "pdfjs-page-landmark");
  10601. div.setAttribute("data-l10n-args", JSON.stringify({
  10602. page: this.id
  10603. }));
  10604. this.div = div;
  10605. this.#setDimensions();
  10606. container?.append(div);
  10607. if (this._isStandalone) {
  10608. container?.style.setProperty("--scale-factor", this.scale * PixelsPerInch.PDF_TO_CSS_UNITS);
  10609. if (this.pageColors?.background) {
  10610. container?.style.setProperty("--page-bg-color", this.pageColors.background);
  10611. }
  10612. const {
  10613. optionalContentConfigPromise
  10614. } = options;
  10615. if (optionalContentConfigPromise) {
  10616. optionalContentConfigPromise.then(optionalContentConfig => {
  10617. if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
  10618. return;
  10619. }
  10620. this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
  10621. });
  10622. }
  10623. if (!options.l10n) {
  10624. this.l10n.translate(this.div);
  10625. }
  10626. }
  10627. }
  10628. #addLayer(div, name) {
  10629. const pos = LAYERS_ORDER.get(name);
  10630. const oldDiv = this.#layers[pos];
  10631. this.#layers[pos] = div;
  10632. if (oldDiv) {
  10633. oldDiv.replaceWith(div);
  10634. return;
  10635. }
  10636. for (let i = pos - 1; i >= 0; i--) {
  10637. const layer = this.#layers[i];
  10638. if (layer) {
  10639. layer.after(div);
  10640. return;
  10641. }
  10642. }
  10643. this.div.prepend(div);
  10644. }
  10645. #setDimensions() {
  10646. const {
  10647. div,
  10648. viewport
  10649. } = this;
  10650. if (viewport.userUnit !== this.#userUnit) {
  10651. if (viewport.userUnit !== 1) {
  10652. div.style.setProperty("--user-unit", viewport.userUnit);
  10653. } else {
  10654. div.style.removeProperty("--user-unit");
  10655. }
  10656. this.#userUnit = viewport.userUnit;
  10657. }
  10658. if (this.pdfPage) {
  10659. if (this.#previousRotation === viewport.rotation) {
  10660. return;
  10661. }
  10662. this.#previousRotation = viewport.rotation;
  10663. }
  10664. setLayerDimensions(div, viewport, true, false);
  10665. }
  10666. setPdfPage(pdfPage) {
  10667. if (this._isStandalone && (this.pageColors?.foreground === "CanvasText" || this.pageColors?.background === "Canvas")) {
  10668. this._container?.style.setProperty("--hcm-highlight-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight"));
  10669. this._container?.style.setProperty("--hcm-highlight-selected-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "Highlight"));
  10670. }
  10671. this.pdfPage = pdfPage;
  10672. this.pdfPageRotate = pdfPage.rotate;
  10673. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  10674. this.viewport = pdfPage.getViewport({
  10675. scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS,
  10676. rotation: totalRotation
  10677. });
  10678. this.#setDimensions();
  10679. this.reset();
  10680. }
  10681. destroy() {
  10682. this.reset();
  10683. this.pdfPage?.cleanup();
  10684. }
  10685. hasEditableAnnotations() {
  10686. return !!this.annotationLayer?.hasEditableAnnotations();
  10687. }
  10688. get _textHighlighter() {
  10689. return shadow(this, "_textHighlighter", new TextHighlighter({
  10690. pageIndex: this.id - 1,
  10691. eventBus: this.eventBus,
  10692. findController: this.#layerProperties.findController
  10693. }));
  10694. }
  10695. #dispatchLayerRendered(name, error) {
  10696. this.eventBus.dispatch(name, {
  10697. source: this,
  10698. pageNumber: this.id,
  10699. error
  10700. });
  10701. }
  10702. async #renderAnnotationLayer() {
  10703. let error = null;
  10704. try {
  10705. await this.annotationLayer.render({
  10706. viewport: this.viewport,
  10707. intent: "display",
  10708. structTreeLayer: this.structTreeLayer
  10709. });
  10710. } catch (ex) {
  10711. console.error("#renderAnnotationLayer:", ex);
  10712. error = ex;
  10713. } finally {
  10714. this.#dispatchLayerRendered("annotationlayerrendered", error);
  10715. }
  10716. }
  10717. async #renderAnnotationEditorLayer() {
  10718. let error = null;
  10719. try {
  10720. await this.annotationEditorLayer.render({
  10721. viewport: this.viewport,
  10722. intent: "display"
  10723. });
  10724. } catch (ex) {
  10725. console.error("#renderAnnotationEditorLayer:", ex);
  10726. error = ex;
  10727. } finally {
  10728. this.#dispatchLayerRendered("annotationeditorlayerrendered", error);
  10729. }
  10730. }
  10731. async #renderDrawLayer() {
  10732. try {
  10733. await this.drawLayer.render({
  10734. intent: "display"
  10735. });
  10736. } catch (ex) {
  10737. console.error("#renderDrawLayer:", ex);
  10738. }
  10739. }
  10740. async #renderXfaLayer() {
  10741. let error = null;
  10742. try {
  10743. const result = await this.xfaLayer.render({
  10744. viewport: this.viewport,
  10745. intent: "display"
  10746. });
  10747. if (result?.textDivs && this._textHighlighter) {
  10748. this.#buildXfaTextContentItems(result.textDivs);
  10749. }
  10750. } catch (ex) {
  10751. console.error("#renderXfaLayer:", ex);
  10752. error = ex;
  10753. } finally {
  10754. if (this.xfaLayer?.div) {
  10755. this.l10n.pause();
  10756. this.#addLayer(this.xfaLayer.div, "xfaLayer");
  10757. this.l10n.resume();
  10758. }
  10759. this.#dispatchLayerRendered("xfalayerrendered", error);
  10760. }
  10761. }
  10762. async #renderTextLayer() {
  10763. if (!this.textLayer) {
  10764. return;
  10765. }
  10766. let error = null;
  10767. try {
  10768. await this.textLayer.render({
  10769. viewport: this.viewport
  10770. });
  10771. } catch (ex) {
  10772. if (ex instanceof AbortException) {
  10773. return;
  10774. }
  10775. console.error("#renderTextLayer:", ex);
  10776. error = ex;
  10777. }
  10778. this.#dispatchLayerRendered("textlayerrendered", error);
  10779. this.#renderStructTreeLayer();
  10780. }
  10781. async #renderStructTreeLayer() {
  10782. if (!this.textLayer) {
  10783. return;
  10784. }
  10785. const treeDom = await this.structTreeLayer?.render();
  10786. if (treeDom) {
  10787. this.l10n.pause();
  10788. this.structTreeLayer?.addElementsToTextLayer();
  10789. if (this.canvas && treeDom.parentNode !== this.canvas) {
  10790. this.canvas.append(treeDom);
  10791. }
  10792. this.l10n.resume();
  10793. }
  10794. this.structTreeLayer?.show();
  10795. }
  10796. async #buildXfaTextContentItems(textDivs) {
  10797. const text = await this.pdfPage.getTextContent();
  10798. const items = [];
  10799. for (const item of text.items) {
  10800. items.push(item.str);
  10801. }
  10802. this._textHighlighter.setTextMapping(textDivs, items);
  10803. this._textHighlighter.enable();
  10804. }
  10805. async #injectLinkAnnotations(textLayerPromise) {
  10806. let error = null;
  10807. try {
  10808. await textLayerPromise;
  10809. if (!this.annotationLayer) {
  10810. return;
  10811. }
  10812. await this.annotationLayer.injectLinkAnnotations({
  10813. inferredLinks: Autolinker.processLinks(this),
  10814. viewport: this.viewport,
  10815. structTreeLayer: this.structTreeLayer
  10816. });
  10817. } catch (ex) {
  10818. console.error("#injectLinkAnnotations:", ex);
  10819. error = ex;
  10820. }
  10821. }
  10822. _resetCanvas() {
  10823. super._resetCanvas();
  10824. this.#originalViewport = null;
  10825. }
  10826. reset({
  10827. keepAnnotationLayer = false,
  10828. keepAnnotationEditorLayer = false,
  10829. keepXfaLayer = false,
  10830. keepTextLayer = false,
  10831. keepCanvasWrapper = false,
  10832. preserveDetailViewState = false
  10833. } = {}) {
  10834. this.cancelRendering({
  10835. keepAnnotationLayer,
  10836. keepAnnotationEditorLayer,
  10837. keepXfaLayer,
  10838. keepTextLayer
  10839. });
  10840. this.renderingState = RenderingStates.INITIAL;
  10841. const div = this.div;
  10842. const childNodes = div.childNodes,
  10843. annotationLayerNode = keepAnnotationLayer && this.annotationLayer?.div || null,
  10844. annotationEditorLayerNode = keepAnnotationEditorLayer && this.annotationEditorLayer?.div || null,
  10845. xfaLayerNode = keepXfaLayer && this.xfaLayer?.div || null,
  10846. textLayerNode = keepTextLayer && this.textLayer?.div || null,
  10847. canvasWrapperNode = keepCanvasWrapper && this.#canvasWrapper || null;
  10848. for (let i = childNodes.length - 1; i >= 0; i--) {
  10849. const node = childNodes[i];
  10850. switch (node) {
  10851. case annotationLayerNode:
  10852. case annotationEditorLayerNode:
  10853. case xfaLayerNode:
  10854. case textLayerNode:
  10855. case canvasWrapperNode:
  10856. continue;
  10857. }
  10858. node.remove();
  10859. const layerIndex = this.#layers.indexOf(node);
  10860. if (layerIndex >= 0) {
  10861. this.#layers[layerIndex] = null;
  10862. }
  10863. }
  10864. div.removeAttribute("data-loaded");
  10865. if (annotationLayerNode) {
  10866. this.annotationLayer.hide();
  10867. }
  10868. if (annotationEditorLayerNode) {
  10869. this.annotationEditorLayer.hide();
  10870. }
  10871. if (xfaLayerNode) {
  10872. this.xfaLayer.hide();
  10873. }
  10874. if (textLayerNode) {
  10875. this.textLayer.hide();
  10876. }
  10877. this.structTreeLayer?.hide();
  10878. if (!keepCanvasWrapper && this.#canvasWrapper) {
  10879. this.#canvasWrapper = null;
  10880. this._resetCanvas();
  10881. }
  10882. if (!preserveDetailViewState) {
  10883. this.detailView?.reset({
  10884. keepCanvas: keepCanvasWrapper
  10885. });
  10886. if (!keepCanvasWrapper) {
  10887. this.detailView = null;
  10888. }
  10889. }
  10890. }
  10891. toggleEditingMode(isEditing) {
  10892. this.#isEditing = isEditing;
  10893. if (!this.hasEditableAnnotations()) {
  10894. return;
  10895. }
  10896. this.reset({
  10897. keepAnnotationLayer: true,
  10898. keepAnnotationEditorLayer: true,
  10899. keepXfaLayer: true,
  10900. keepTextLayer: true,
  10901. keepCanvasWrapper: true
  10902. });
  10903. }
  10904. updateVisibleArea(visibleArea) {
  10905. if (this.enableDetailCanvas) {
  10906. if (this.#needsRestrictedScaling && this.maxCanvasPixels > 0 && visibleArea) {
  10907. this.detailView ??= new PDFPageDetailView({
  10908. pageView: this
  10909. });
  10910. this.detailView.update({
  10911. visibleArea
  10912. });
  10913. } else if (this.detailView) {
  10914. this.detailView.reset();
  10915. this.detailView = null;
  10916. }
  10917. }
  10918. }
  10919. update({
  10920. scale = 0,
  10921. rotation = null,
  10922. optionalContentConfigPromise = null,
  10923. drawingDelay = -1
  10924. }) {
  10925. this.scale = scale || this.scale;
  10926. if (typeof rotation === "number") {
  10927. this.rotation = rotation;
  10928. }
  10929. if (optionalContentConfigPromise instanceof Promise) {
  10930. this._optionalContentConfigPromise = optionalContentConfigPromise;
  10931. optionalContentConfigPromise.then(optionalContentConfig => {
  10932. if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
  10933. return;
  10934. }
  10935. this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
  10936. });
  10937. }
  10938. this.#useThumbnailCanvas.directDrawing = true;
  10939. const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
  10940. this.viewport = this.viewport.clone({
  10941. scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS,
  10942. rotation: totalRotation
  10943. });
  10944. this.#setDimensions();
  10945. if (this._isStandalone) {
  10946. this._container?.style.setProperty("--scale-factor", this.viewport.scale);
  10947. }
  10948. this.#computeScale();
  10949. if (this.canvas) {
  10950. const onlyCssZoom = this.#hasRestrictedScaling && this.#needsRestrictedScaling;
  10951. const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000;
  10952. if (postponeDrawing || onlyCssZoom) {
  10953. if (postponeDrawing && !onlyCssZoom && this.renderingState !== RenderingStates.FINISHED) {
  10954. this.cancelRendering({
  10955. keepAnnotationLayer: true,
  10956. keepAnnotationEditorLayer: true,
  10957. keepXfaLayer: true,
  10958. keepTextLayer: true,
  10959. cancelExtraDelay: drawingDelay
  10960. });
  10961. this.renderingState = RenderingStates.FINISHED;
  10962. this.#useThumbnailCanvas.directDrawing = false;
  10963. }
  10964. this.cssTransform({
  10965. redrawAnnotationLayer: true,
  10966. redrawAnnotationEditorLayer: true,
  10967. redrawXfaLayer: true,
  10968. redrawTextLayer: !postponeDrawing,
  10969. hideTextLayer: postponeDrawing
  10970. });
  10971. if (!postponeDrawing) {
  10972. this.detailView?.update({
  10973. underlyingViewUpdated: true
  10974. });
  10975. this.dispatchPageRendered(true, false);
  10976. }
  10977. return;
  10978. }
  10979. }
  10980. this.cssTransform({});
  10981. this.reset({
  10982. keepAnnotationLayer: true,
  10983. keepAnnotationEditorLayer: true,
  10984. keepXfaLayer: true,
  10985. keepTextLayer: true,
  10986. keepCanvasWrapper: true,
  10987. preserveDetailViewState: true
  10988. });
  10989. this.detailView?.update({
  10990. underlyingViewUpdated: true
  10991. });
  10992. }
  10993. #computeScale() {
  10994. const {
  10995. width,
  10996. height
  10997. } = this.viewport;
  10998. const outputScale = this.outputScale = new OutputScale();
  10999. if (this.maxCanvasPixels === 0) {
  11000. const invScale = 1 / this.scale;
  11001. outputScale.sx *= invScale;
  11002. outputScale.sy *= invScale;
  11003. this.#needsRestrictedScaling = true;
  11004. } else {
  11005. this.#needsRestrictedScaling = outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim);
  11006. }
  11007. }
  11008. cancelRendering({
  11009. keepAnnotationLayer = false,
  11010. keepAnnotationEditorLayer = false,
  11011. keepXfaLayer = false,
  11012. keepTextLayer = false,
  11013. cancelExtraDelay = 0
  11014. } = {}) {
  11015. super.cancelRendering({
  11016. cancelExtraDelay
  11017. });
  11018. if (this.textLayer && (!keepTextLayer || !this.textLayer.div)) {
  11019. this.textLayer.cancel();
  11020. this.textLayer = null;
  11021. }
  11022. if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) {
  11023. this.annotationLayer.cancel();
  11024. this.annotationLayer = null;
  11025. this._annotationCanvasMap = null;
  11026. }
  11027. if (this.structTreeLayer && !this.textLayer) {
  11028. this.structTreeLayer = null;
  11029. }
  11030. if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)) {
  11031. if (this.drawLayer) {
  11032. this.drawLayer.cancel();
  11033. this.drawLayer = null;
  11034. }
  11035. this.annotationEditorLayer.cancel();
  11036. this.annotationEditorLayer = null;
  11037. }
  11038. if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) {
  11039. this.xfaLayer.cancel();
  11040. this.xfaLayer = null;
  11041. this._textHighlighter?.disable();
  11042. }
  11043. }
  11044. cssTransform({
  11045. redrawAnnotationLayer = false,
  11046. redrawAnnotationEditorLayer = false,
  11047. redrawXfaLayer = false,
  11048. redrawTextLayer = false,
  11049. hideTextLayer = false
  11050. }) {
  11051. const {
  11052. canvas
  11053. } = this;
  11054. if (!canvas) {
  11055. return;
  11056. }
  11057. const originalViewport = this.#originalViewport;
  11058. if (this.viewport !== originalViewport) {
  11059. const relativeRotation = (360 + this.viewport.rotation - originalViewport.rotation) % 360;
  11060. if (relativeRotation === 90 || relativeRotation === 270) {
  11061. const {
  11062. width,
  11063. height
  11064. } = this.viewport;
  11065. const scaleX = height / width;
  11066. const scaleY = width / height;
  11067. canvas.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX},${scaleY})`;
  11068. } else {
  11069. canvas.style.transform = relativeRotation === 0 ? "" : `rotate(${relativeRotation}deg)`;
  11070. }
  11071. }
  11072. if (redrawAnnotationLayer && this.annotationLayer) {
  11073. this.#renderAnnotationLayer();
  11074. }
  11075. if (redrawAnnotationEditorLayer && this.annotationEditorLayer) {
  11076. if (this.drawLayer) {
  11077. this.#renderDrawLayer();
  11078. }
  11079. this.#renderAnnotationEditorLayer();
  11080. }
  11081. if (redrawXfaLayer && this.xfaLayer) {
  11082. this.#renderXfaLayer();
  11083. }
  11084. if (this.textLayer) {
  11085. if (hideTextLayer) {
  11086. this.textLayer.hide();
  11087. this.structTreeLayer?.hide();
  11088. } else if (redrawTextLayer) {
  11089. this.#renderTextLayer();
  11090. }
  11091. }
  11092. }
  11093. get width() {
  11094. return this.viewport.width;
  11095. }
  11096. get height() {
  11097. return this.viewport.height;
  11098. }
  11099. getPagePoint(x, y) {
  11100. return this.viewport.convertToPdfPoint(x, y);
  11101. }
  11102. _ensureCanvasWrapper() {
  11103. let canvasWrapper = this.#canvasWrapper;
  11104. if (!canvasWrapper) {
  11105. canvasWrapper = this.#canvasWrapper = document.createElement("div");
  11106. canvasWrapper.classList.add("canvasWrapper");
  11107. this.#addLayer(canvasWrapper, "canvasWrapper");
  11108. }
  11109. return canvasWrapper;
  11110. }
  11111. _getRenderingContext(canvasContext, transform) {
  11112. return {
  11113. canvasContext,
  11114. transform,
  11115. viewport: this.viewport,
  11116. annotationMode: this.#annotationMode,
  11117. optionalContentConfigPromise: this._optionalContentConfigPromise,
  11118. annotationCanvasMap: this._annotationCanvasMap,
  11119. pageColors: this.pageColors,
  11120. isEditing: this.#isEditing
  11121. };
  11122. }
  11123. async draw() {
  11124. if (this.renderingState !== RenderingStates.INITIAL) {
  11125. console.error("Must be in new state before drawing");
  11126. this.reset();
  11127. }
  11128. const {
  11129. div,
  11130. l10n,
  11131. pdfPage,
  11132. viewport
  11133. } = this;
  11134. if (!pdfPage) {
  11135. this.renderingState = RenderingStates.FINISHED;
  11136. throw new Error("pdfPage is not loaded");
  11137. }
  11138. this.renderingState = RenderingStates.RUNNING;
  11139. const canvasWrapper = this._ensureCanvasWrapper();
  11140. if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) {
  11141. this._accessibilityManager ||= new TextAccessibilityManager();
  11142. this.textLayer = new TextLayerBuilder({
  11143. pdfPage,
  11144. highlighter: this._textHighlighter,
  11145. accessibilityManager: this._accessibilityManager,
  11146. enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS,
  11147. onAppend: textLayerDiv => {
  11148. this.l10n.pause();
  11149. this.#addLayer(textLayerDiv, "textLayer");
  11150. this.l10n.resume();
  11151. }
  11152. });
  11153. }
  11154. if (!this.annotationLayer && this.#annotationMode !== AnnotationMode.DISABLE) {
  11155. const {
  11156. annotationStorage,
  11157. annotationEditorUIManager,
  11158. downloadManager,
  11159. enableScripting,
  11160. fieldObjectsPromise,
  11161. hasJSActionsPromise,
  11162. linkService
  11163. } = this.#layerProperties;
  11164. this._annotationCanvasMap ||= new Map();
  11165. this.annotationLayer = new AnnotationLayerBuilder({
  11166. pdfPage,
  11167. annotationStorage,
  11168. imageResourcesPath: this.imageResourcesPath,
  11169. renderForms: this.#annotationMode === AnnotationMode.ENABLE_FORMS,
  11170. linkService,
  11171. downloadManager,
  11172. enableScripting,
  11173. hasJSActionsPromise,
  11174. fieldObjectsPromise,
  11175. annotationCanvasMap: this._annotationCanvasMap,
  11176. accessibilityManager: this._accessibilityManager,
  11177. annotationEditorUIManager,
  11178. onAppend: annotationLayerDiv => {
  11179. this.#addLayer(annotationLayerDiv, "annotationLayer");
  11180. }
  11181. });
  11182. }
  11183. const {
  11184. width,
  11185. height
  11186. } = viewport;
  11187. this.#originalViewport = viewport;
  11188. const {
  11189. canvas,
  11190. prevCanvas,
  11191. ctx
  11192. } = this._createCanvas(newCanvas => {
  11193. canvasWrapper.prepend(newCanvas);
  11194. });
  11195. canvas.setAttribute("role", "presentation");
  11196. if (!this.outputScale) {
  11197. this.#computeScale();
  11198. }
  11199. const {
  11200. outputScale
  11201. } = this;
  11202. this.#hasRestrictedScaling = this.#needsRestrictedScaling;
  11203. const sfx = approximateFraction(outputScale.sx);
  11204. const sfy = approximateFraction(outputScale.sy);
  11205. const canvasWidth = canvas.width = floorToDivide(calcRound(width * outputScale.sx), sfx[0]);
  11206. const canvasHeight = canvas.height = floorToDivide(calcRound(height * outputScale.sy), sfy[0]);
  11207. const pageWidth = floorToDivide(calcRound(width), sfx[1]);
  11208. const pageHeight = floorToDivide(calcRound(height), sfy[1]);
  11209. outputScale.sx = canvasWidth / pageWidth;
  11210. outputScale.sy = canvasHeight / pageHeight;
  11211. if (this.#scaleRoundX !== sfx[1]) {
  11212. div.style.setProperty("--scale-round-x", `${sfx[1]}px`);
  11213. this.#scaleRoundX = sfx[1];
  11214. }
  11215. if (this.#scaleRoundY !== sfy[1]) {
  11216. div.style.setProperty("--scale-round-y", `${sfy[1]}px`);
  11217. this.#scaleRoundY = sfy[1];
  11218. }
  11219. const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
  11220. const resultPromise = this._drawCanvas(this._getRenderingContext(ctx, transform), () => {
  11221. prevCanvas?.remove();
  11222. this._resetCanvas();
  11223. }, renderTask => {
  11224. this.#useThumbnailCanvas.regularAnnotations = !renderTask.separateAnnots;
  11225. this.dispatchPageRendered(false, false);
  11226. }).then(async () => {
  11227. this.structTreeLayer ||= new StructTreeLayerBuilder(pdfPage, viewport.rawDims);
  11228. const textLayerPromise = this.#renderTextLayer();
  11229. if (this.annotationLayer) {
  11230. await this.#renderAnnotationLayer();
  11231. if (this.#enableAutoLinking && this.annotationLayer && this.textLayer) {
  11232. await this.#injectLinkAnnotations(textLayerPromise);
  11233. }
  11234. }
  11235. const {
  11236. annotationEditorUIManager
  11237. } = this.#layerProperties;
  11238. if (!annotationEditorUIManager) {
  11239. return;
  11240. }
  11241. this.drawLayer ||= new DrawLayerBuilder({
  11242. pageIndex: this.id
  11243. });
  11244. await this.#renderDrawLayer();
  11245. this.drawLayer.setParent(canvasWrapper);
  11246. this.annotationEditorLayer ||= new AnnotationEditorLayerBuilder({
  11247. uiManager: annotationEditorUIManager,
  11248. pdfPage,
  11249. l10n,
  11250. structTreeLayer: this.structTreeLayer,
  11251. accessibilityManager: this._accessibilityManager,
  11252. annotationLayer: this.annotationLayer?.annotationLayer,
  11253. textLayer: this.textLayer,
  11254. drawLayer: this.drawLayer.getDrawLayer(),
  11255. onAppend: annotationEditorLayerDiv => {
  11256. this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer");
  11257. }
  11258. });
  11259. this.#renderAnnotationEditorLayer();
  11260. });
  11261. if (pdfPage.isPureXfa) {
  11262. if (!this.xfaLayer) {
  11263. const {
  11264. annotationStorage,
  11265. linkService
  11266. } = this.#layerProperties;
  11267. this.xfaLayer = new XfaLayerBuilder({
  11268. pdfPage,
  11269. annotationStorage,
  11270. linkService
  11271. });
  11272. }
  11273. this.#renderXfaLayer();
  11274. }
  11275. div.setAttribute("data-loaded", true);
  11276. this.dispatchPageRender();
  11277. return resultPromise;
  11278. }
  11279. setPageLabel(label) {
  11280. this.pageLabel = typeof label === "string" ? label : null;
  11281. this.div.setAttribute("data-l10n-args", JSON.stringify({
  11282. page: this.pageLabel ?? this.id
  11283. }));
  11284. if (this.pageLabel !== null) {
  11285. this.div.setAttribute("data-page-label", this.pageLabel);
  11286. } else {
  11287. this.div.removeAttribute("data-page-label");
  11288. }
  11289. }
  11290. get thumbnailCanvas() {
  11291. const {
  11292. directDrawing,
  11293. initialOptionalContent,
  11294. regularAnnotations
  11295. } = this.#useThumbnailCanvas;
  11296. return directDrawing && initialOptionalContent && regularAnnotations ? this.canvas : null;
  11297. }
  11298. }
  11299. ;// ./web/pdf_viewer.js
  11300. const DEFAULT_CACHE_SIZE = 10;
  11301. const PagesCountLimit = {
  11302. FORCE_SCROLL_MODE_PAGE: 10000,
  11303. FORCE_LAZY_PAGE_INIT: 5000,
  11304. PAUSE_EAGER_PAGE_INIT: 250
  11305. };
  11306. function isValidAnnotationEditorMode(mode) {
  11307. return Object.values(AnnotationEditorType).includes(mode) && mode !== AnnotationEditorType.DISABLE;
  11308. }
  11309. class PDFPageViewBuffer {
  11310. #buf = new Set();
  11311. #size = 0;
  11312. constructor(size) {
  11313. this.#size = size;
  11314. }
  11315. push(view) {
  11316. const buf = this.#buf;
  11317. if (buf.has(view)) {
  11318. buf.delete(view);
  11319. }
  11320. buf.add(view);
  11321. if (buf.size > this.#size) {
  11322. this.#destroyFirstView();
  11323. }
  11324. }
  11325. resize(newSize, idsToKeep = null) {
  11326. this.#size = newSize;
  11327. const buf = this.#buf;
  11328. if (idsToKeep) {
  11329. const ii = buf.size;
  11330. let i = 1;
  11331. for (const view of buf) {
  11332. if (idsToKeep.has(view.id)) {
  11333. buf.delete(view);
  11334. buf.add(view);
  11335. }
  11336. if (++i > ii) {
  11337. break;
  11338. }
  11339. }
  11340. }
  11341. while (buf.size > this.#size) {
  11342. this.#destroyFirstView();
  11343. }
  11344. }
  11345. has(view) {
  11346. return this.#buf.has(view);
  11347. }
  11348. [Symbol.iterator]() {
  11349. return this.#buf.keys();
  11350. }
  11351. #destroyFirstView() {
  11352. const firstView = this.#buf.keys().next().value;
  11353. firstView?.destroy();
  11354. this.#buf.delete(firstView);
  11355. }
  11356. }
  11357. class PDFViewer {
  11358. #buffer = null;
  11359. #altTextManager = null;
  11360. #annotationEditorHighlightColors = null;
  11361. #annotationEditorMode = AnnotationEditorType.NONE;
  11362. #annotationEditorUIManager = null;
  11363. #annotationMode = AnnotationMode.ENABLE_FORMS;
  11364. #containerTopLeft = null;
  11365. #editorUndoBar = null;
  11366. #enableHWA = false;
  11367. #enableHighlightFloatingButton = false;
  11368. #enablePermissions = false;
  11369. #enableUpdatedAddImage = false;
  11370. #enableNewAltTextWhenAddingImage = false;
  11371. #enableAutoLinking = true;
  11372. #eventAbortController = null;
  11373. #mlManager = null;
  11374. #scrollTimeoutId = null;
  11375. #switchAnnotationEditorModeAC = null;
  11376. #switchAnnotationEditorModeTimeoutId = null;
  11377. #getAllTextInProgress = false;
  11378. #hiddenCopyElement = null;
  11379. #interruptCopyCondition = false;
  11380. #previousContainerHeight = 0;
  11381. #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this));
  11382. #scrollModePageState = null;
  11383. #scaleTimeoutId = null;
  11384. #signatureManager = null;
  11385. #supportsPinchToZoom = true;
  11386. #textLayerMode = TextLayerMode.ENABLE;
  11387. constructor(options) {
  11388. const viewerVersion = "5.1.91";
  11389. if (version !== viewerVersion) {
  11390. throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`);
  11391. }
  11392. this.container = options.container;
  11393. this.viewer = options.viewer || options.container.firstElementChild;
  11394. if (this.container?.tagName !== "DIV" || this.viewer?.tagName !== "DIV") {
  11395. throw new Error("Invalid `container` and/or `viewer` option.");
  11396. }
  11397. if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") {
  11398. throw new Error("The `container` must be absolutely positioned.");
  11399. }
  11400. this.#resizeObserver.observe(this.container);
  11401. this.eventBus = options.eventBus;
  11402. this.linkService = options.linkService || new SimpleLinkService();
  11403. this.downloadManager = options.downloadManager || null;
  11404. this.findController = options.findController || null;
  11405. this.#altTextManager = options.altTextManager || null;
  11406. this.#signatureManager = options.signatureManager || null;
  11407. this.#editorUndoBar = options.editorUndoBar || null;
  11408. if (this.findController) {
  11409. this.findController.onIsPageVisible = pageNumber => this._getVisiblePages().ids.has(pageNumber);
  11410. }
  11411. this._scriptingManager = options.scriptingManager || null;
  11412. this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
  11413. this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
  11414. this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE;
  11415. this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null;
  11416. this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true;
  11417. this.#enableUpdatedAddImage = options.enableUpdatedAddImage === true;
  11418. this.#enableNewAltTextWhenAddingImage = options.enableNewAltTextWhenAddingImage === true;
  11419. this.imageResourcesPath = options.imageResourcesPath || "";
  11420. this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
  11421. this.removePageBorders = options.removePageBorders || false;
  11422. this.maxCanvasPixels = options.maxCanvasPixels;
  11423. this.maxCanvasDim = options.maxCanvasDim;
  11424. this.enableDetailCanvas = options.enableDetailCanvas ?? true;
  11425. this.l10n = options.l10n;
  11426. this.l10n ||= new genericl10n_GenericL10n();
  11427. this.#enablePermissions = options.enablePermissions || false;
  11428. this.pageColors = options.pageColors || null;
  11429. this.#mlManager = options.mlManager || null;
  11430. this.#enableHWA = options.enableHWA || false;
  11431. this.#supportsPinchToZoom = options.supportsPinchToZoom !== false;
  11432. this.#enableAutoLinking = options.enableAutoLinking !== false;
  11433. this.defaultRenderingQueue = !options.renderingQueue;
  11434. if (this.defaultRenderingQueue) {
  11435. this.renderingQueue = new PDFRenderingQueue();
  11436. this.renderingQueue.setViewer(this);
  11437. } else {
  11438. this.renderingQueue = options.renderingQueue;
  11439. }
  11440. const {
  11441. abortSignal
  11442. } = options;
  11443. abortSignal?.addEventListener("abort", () => {
  11444. this.#resizeObserver.disconnect();
  11445. this.#resizeObserver = null;
  11446. }, {
  11447. once: true
  11448. });
  11449. this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this), abortSignal);
  11450. this.presentationModeState = PresentationModeState.UNKNOWN;
  11451. this._resetView();
  11452. if (this.removePageBorders) {
  11453. this.viewer.classList.add("removePageBorders");
  11454. }
  11455. this.#updateContainerHeightCss();
  11456. this.eventBus._on("thumbnailrendered", ({
  11457. pageNumber,
  11458. pdfPage
  11459. }) => {
  11460. const pageView = this._pages[pageNumber - 1];
  11461. if (!this.#buffer.has(pageView)) {
  11462. pdfPage?.cleanup();
  11463. }
  11464. });
  11465. if (!options.l10n) {
  11466. this.l10n.translate(this.container);
  11467. }
  11468. }
  11469. get pagesCount() {
  11470. return this._pages.length;
  11471. }
  11472. getPageView(index) {
  11473. return this._pages[index];
  11474. }
  11475. getCachedPageViews() {
  11476. return new Set(this.#buffer);
  11477. }
  11478. get pageViewsReady() {
  11479. return this._pages.every(pageView => pageView?.pdfPage);
  11480. }
  11481. get renderForms() {
  11482. return this.#annotationMode === AnnotationMode.ENABLE_FORMS;
  11483. }
  11484. get enableScripting() {
  11485. return !!this._scriptingManager;
  11486. }
  11487. get currentPageNumber() {
  11488. return this._currentPageNumber;
  11489. }
  11490. set currentPageNumber(val) {
  11491. if (!Number.isInteger(val)) {
  11492. throw new Error("Invalid page number.");
  11493. }
  11494. if (!this.pdfDocument) {
  11495. return;
  11496. }
  11497. if (!this._setCurrentPageNumber(val, true)) {
  11498. console.error(`currentPageNumber: "${val}" is not a valid page.`);
  11499. }
  11500. }
  11501. _setCurrentPageNumber(val, resetCurrentPageView = false) {
  11502. if (this._currentPageNumber === val) {
  11503. if (resetCurrentPageView) {
  11504. this.#resetCurrentPageView();
  11505. }
  11506. return true;
  11507. }
  11508. if (!(0 < val && val <= this.pagesCount)) {
  11509. return false;
  11510. }
  11511. const previous = this._currentPageNumber;
  11512. this._currentPageNumber = val;
  11513. this.eventBus.dispatch("pagechanging", {
  11514. source: this,
  11515. pageNumber: val,
  11516. pageLabel: this._pageLabels?.[val - 1] ?? null,
  11517. previous
  11518. });
  11519. if (resetCurrentPageView) {
  11520. this.#resetCurrentPageView();
  11521. }
  11522. return true;
  11523. }
  11524. get currentPageLabel() {
  11525. return this._pageLabels?.[this._currentPageNumber - 1] ?? null;
  11526. }
  11527. set currentPageLabel(val) {
  11528. if (!this.pdfDocument) {
  11529. return;
  11530. }
  11531. let page = val | 0;
  11532. if (this._pageLabels) {
  11533. const i = this._pageLabels.indexOf(val);
  11534. if (i >= 0) {
  11535. page = i + 1;
  11536. }
  11537. }
  11538. if (!this._setCurrentPageNumber(page, true)) {
  11539. console.error(`currentPageLabel: "${val}" is not a valid page.`);
  11540. }
  11541. }
  11542. get currentScale() {
  11543. return this._currentScale !== UNKNOWN_SCALE ? this._currentScale : DEFAULT_SCALE;
  11544. }
  11545. set currentScale(val) {
  11546. if (isNaN(val)) {
  11547. throw new Error("Invalid numeric scale.");
  11548. }
  11549. if (!this.pdfDocument) {
  11550. return;
  11551. }
  11552. this.#setScale(val, {
  11553. noScroll: false
  11554. });
  11555. }
  11556. get currentScaleValue() {
  11557. return this._currentScaleValue;
  11558. }
  11559. set currentScaleValue(val) {
  11560. if (!this.pdfDocument) {
  11561. return;
  11562. }
  11563. this.#setScale(val, {
  11564. noScroll: false
  11565. });
  11566. }
  11567. get pagesRotation() {
  11568. return this._pagesRotation;
  11569. }
  11570. set pagesRotation(rotation) {
  11571. if (!isValidRotation(rotation)) {
  11572. throw new Error("Invalid pages rotation angle.");
  11573. }
  11574. if (!this.pdfDocument) {
  11575. return;
  11576. }
  11577. rotation %= 360;
  11578. if (rotation < 0) {
  11579. rotation += 360;
  11580. }
  11581. if (this._pagesRotation === rotation) {
  11582. return;
  11583. }
  11584. this._pagesRotation = rotation;
  11585. const pageNumber = this._currentPageNumber;
  11586. this.refresh(true, {
  11587. rotation
  11588. });
  11589. if (this._currentScaleValue) {
  11590. this.#setScale(this._currentScaleValue, {
  11591. noScroll: true
  11592. });
  11593. }
  11594. this.eventBus.dispatch("rotationchanging", {
  11595. source: this,
  11596. pagesRotation: rotation,
  11597. pageNumber
  11598. });
  11599. if (this.defaultRenderingQueue) {
  11600. this.update();
  11601. }
  11602. }
  11603. get firstPagePromise() {
  11604. return this.pdfDocument ? this._firstPageCapability.promise : null;
  11605. }
  11606. get onePageRendered() {
  11607. return this.pdfDocument ? this._onePageRenderedCapability.promise : null;
  11608. }
  11609. get pagesPromise() {
  11610. return this.pdfDocument ? this._pagesCapability.promise : null;
  11611. }
  11612. get _layerProperties() {
  11613. const self = this;
  11614. return shadow(this, "_layerProperties", {
  11615. get annotationEditorUIManager() {
  11616. return self.#annotationEditorUIManager;
  11617. },
  11618. get annotationStorage() {
  11619. return self.pdfDocument?.annotationStorage;
  11620. },
  11621. get downloadManager() {
  11622. return self.downloadManager;
  11623. },
  11624. get enableScripting() {
  11625. return !!self._scriptingManager;
  11626. },
  11627. get fieldObjectsPromise() {
  11628. return self.pdfDocument?.getFieldObjects();
  11629. },
  11630. get findController() {
  11631. return self.findController;
  11632. },
  11633. get hasJSActionsPromise() {
  11634. return self.pdfDocument?.hasJSActions();
  11635. },
  11636. get linkService() {
  11637. return self.linkService;
  11638. }
  11639. });
  11640. }
  11641. #initializePermissions(permissions) {
  11642. const params = {
  11643. annotationEditorMode: this.#annotationEditorMode,
  11644. annotationMode: this.#annotationMode,
  11645. textLayerMode: this.#textLayerMode
  11646. };
  11647. if (!permissions) {
  11648. return params;
  11649. }
  11650. if (!permissions.includes(PermissionFlag.COPY) && this.#textLayerMode === TextLayerMode.ENABLE) {
  11651. params.textLayerMode = TextLayerMode.ENABLE_PERMISSIONS;
  11652. }
  11653. if (!permissions.includes(PermissionFlag.MODIFY_CONTENTS)) {
  11654. params.annotationEditorMode = AnnotationEditorType.DISABLE;
  11655. }
  11656. if (!permissions.includes(PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.includes(PermissionFlag.FILL_INTERACTIVE_FORMS) && this.#annotationMode === AnnotationMode.ENABLE_FORMS) {
  11657. params.annotationMode = AnnotationMode.ENABLE;
  11658. }
  11659. return params;
  11660. }
  11661. async #onePageRenderedOrForceFetch(signal) {
  11662. if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) {
  11663. return;
  11664. }
  11665. const hiddenCapability = Promise.withResolvers(),
  11666. ac = new AbortController();
  11667. document.addEventListener("visibilitychange", () => {
  11668. if (document.visibilityState === "hidden") {
  11669. hiddenCapability.resolve();
  11670. }
  11671. }, {
  11672. signal: AbortSignal.any([signal, ac.signal])
  11673. });
  11674. await Promise.race([this._onePageRenderedCapability.promise, hiddenCapability.promise]);
  11675. ac.abort();
  11676. }
  11677. async getAllText() {
  11678. const texts = [];
  11679. const buffer = [];
  11680. for (let pageNum = 1, pagesCount = this.pdfDocument.numPages; pageNum <= pagesCount; ++pageNum) {
  11681. if (this.#interruptCopyCondition) {
  11682. return null;
  11683. }
  11684. buffer.length = 0;
  11685. const page = await this.pdfDocument.getPage(pageNum);
  11686. const {
  11687. items
  11688. } = await page.getTextContent();
  11689. for (const item of items) {
  11690. if (item.str) {
  11691. buffer.push(item.str);
  11692. }
  11693. if (item.hasEOL) {
  11694. buffer.push("\n");
  11695. }
  11696. }
  11697. texts.push(removeNullCharacters(buffer.join("")));
  11698. }
  11699. return texts.join("\n");
  11700. }
  11701. #copyCallback(textLayerMode, event) {
  11702. const selection = document.getSelection();
  11703. const {
  11704. focusNode,
  11705. anchorNode
  11706. } = selection;
  11707. if (anchorNode && focusNode && selection.containsNode(this.#hiddenCopyElement)) {
  11708. if (this.#getAllTextInProgress || textLayerMode === TextLayerMode.ENABLE_PERMISSIONS) {
  11709. stopEvent(event);
  11710. return;
  11711. }
  11712. this.#getAllTextInProgress = true;
  11713. const {
  11714. classList
  11715. } = this.viewer;
  11716. classList.add("copyAll");
  11717. const ac = new AbortController();
  11718. window.addEventListener("keydown", ev => this.#interruptCopyCondition = ev.key === "Escape", {
  11719. signal: ac.signal
  11720. });
  11721. this.getAllText().then(async text => {
  11722. if (text !== null) {
  11723. await navigator.clipboard.writeText(text);
  11724. }
  11725. }).catch(reason => {
  11726. console.warn(`Something goes wrong when extracting the text: ${reason.message}`);
  11727. }).finally(() => {
  11728. this.#getAllTextInProgress = false;
  11729. this.#interruptCopyCondition = false;
  11730. ac.abort();
  11731. classList.remove("copyAll");
  11732. });
  11733. stopEvent(event);
  11734. }
  11735. }
  11736. setDocument(pdfDocument) {
  11737. if (this.pdfDocument) {
  11738. this.eventBus.dispatch("pagesdestroy", {
  11739. source: this
  11740. });
  11741. this._cancelRendering();
  11742. this._resetView();
  11743. this.findController?.setDocument(null);
  11744. this._scriptingManager?.setDocument(null);
  11745. this.#annotationEditorUIManager?.destroy();
  11746. this.#annotationEditorUIManager = null;
  11747. }
  11748. this.pdfDocument = pdfDocument;
  11749. if (!pdfDocument) {
  11750. return;
  11751. }
  11752. const pagesCount = pdfDocument.numPages;
  11753. const firstPagePromise = pdfDocument.getPage(1);
  11754. const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
  11755. intent: "display"
  11756. });
  11757. const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve();
  11758. const {
  11759. eventBus,
  11760. pageColors,
  11761. viewer
  11762. } = this;
  11763. this.#eventAbortController = new AbortController();
  11764. const {
  11765. signal
  11766. } = this.#eventAbortController;
  11767. if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
  11768. console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document.");
  11769. const mode = this._scrollMode = ScrollMode.PAGE;
  11770. eventBus.dispatch("scrollmodechanged", {
  11771. source: this,
  11772. mode
  11773. });
  11774. }
  11775. this._pagesCapability.promise.then(() => {
  11776. eventBus.dispatch("pagesloaded", {
  11777. source: this,
  11778. pagesCount
  11779. });
  11780. }, () => {});
  11781. const onBeforeDraw = evt => {
  11782. const pageView = this._pages[evt.pageNumber - 1];
  11783. if (!pageView) {
  11784. return;
  11785. }
  11786. this.#buffer.push(pageView);
  11787. };
  11788. eventBus._on("pagerender", onBeforeDraw, {
  11789. signal
  11790. });
  11791. const onAfterDraw = evt => {
  11792. if (evt.cssTransform || evt.isDetailView) {
  11793. return;
  11794. }
  11795. this._onePageRenderedCapability.resolve({
  11796. timestamp: evt.timestamp
  11797. });
  11798. eventBus._off("pagerendered", onAfterDraw);
  11799. };
  11800. eventBus._on("pagerendered", onAfterDraw, {
  11801. signal
  11802. });
  11803. Promise.all([firstPagePromise, permissionsPromise]).then(([firstPdfPage, permissions]) => {
  11804. if (pdfDocument !== this.pdfDocument) {
  11805. return;
  11806. }
  11807. this._firstPageCapability.resolve(firstPdfPage);
  11808. this._optionalContentConfigPromise = optionalContentConfigPromise;
  11809. const {
  11810. annotationEditorMode,
  11811. annotationMode,
  11812. textLayerMode
  11813. } = this.#initializePermissions(permissions);
  11814. if (textLayerMode !== TextLayerMode.DISABLE) {
  11815. const element = this.#hiddenCopyElement = document.createElement("div");
  11816. element.id = "hiddenCopyElement";
  11817. viewer.before(element);
  11818. }
  11819. if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
  11820. const mode = annotationEditorMode;
  11821. if (pdfDocument.isPureXfa) {
  11822. console.warn("Warning: XFA-editing is not implemented.");
  11823. } else if (isValidAnnotationEditorMode(mode)) {
  11824. this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, viewer, this.#altTextManager, this.#signatureManager, eventBus, pdfDocument, pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#enableUpdatedAddImage, this.#enableNewAltTextWhenAddingImage, this.#mlManager, this.#editorUndoBar, this.#supportsPinchToZoom);
  11825. eventBus.dispatch("annotationeditoruimanager", {
  11826. source: this,
  11827. uiManager: this.#annotationEditorUIManager
  11828. });
  11829. if (mode !== AnnotationEditorType.NONE) {
  11830. this.#preloadEditingData(mode);
  11831. this.#annotationEditorUIManager.updateMode(mode);
  11832. }
  11833. } else {
  11834. console.error(`Invalid AnnotationEditor mode: ${mode}`);
  11835. }
  11836. }
  11837. const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : viewer;
  11838. const scale = this.currentScale;
  11839. const viewport = firstPdfPage.getViewport({
  11840. scale: scale * PixelsPerInch.PDF_TO_CSS_UNITS
  11841. });
  11842. viewer.style.setProperty("--scale-factor", viewport.scale);
  11843. if (pageColors?.background) {
  11844. viewer.style.setProperty("--page-bg-color", pageColors.background);
  11845. }
  11846. if (pageColors?.foreground === "CanvasText" || pageColors?.background === "Canvas") {
  11847. viewer.style.setProperty("--hcm-highlight-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight"));
  11848. viewer.style.setProperty("--hcm-highlight-selected-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "ButtonText"));
  11849. }
  11850. for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
  11851. const pageView = new PDFPageView({
  11852. container: viewerElement,
  11853. eventBus,
  11854. id: pageNum,
  11855. scale,
  11856. defaultViewport: viewport.clone(),
  11857. optionalContentConfigPromise,
  11858. renderingQueue: this.renderingQueue,
  11859. textLayerMode,
  11860. annotationMode,
  11861. imageResourcesPath: this.imageResourcesPath,
  11862. maxCanvasPixels: this.maxCanvasPixels,
  11863. maxCanvasDim: this.maxCanvasDim,
  11864. enableDetailCanvas: this.enableDetailCanvas,
  11865. pageColors,
  11866. l10n: this.l10n,
  11867. layerProperties: this._layerProperties,
  11868. enableHWA: this.#enableHWA,
  11869. enableAutoLinking: this.#enableAutoLinking
  11870. });
  11871. this._pages.push(pageView);
  11872. }
  11873. this._pages[0]?.setPdfPage(firstPdfPage);
  11874. if (this._scrollMode === ScrollMode.PAGE) {
  11875. this.#ensurePageViewVisible();
  11876. } else if (this._spreadMode !== SpreadMode.NONE) {
  11877. this._updateSpreadMode();
  11878. }
  11879. this.#onePageRenderedOrForceFetch(signal).then(async () => {
  11880. if (pdfDocument !== this.pdfDocument) {
  11881. return;
  11882. }
  11883. this.findController?.setDocument(pdfDocument);
  11884. this._scriptingManager?.setDocument(pdfDocument);
  11885. if (this.#hiddenCopyElement) {
  11886. document.addEventListener("copy", this.#copyCallback.bind(this, textLayerMode), {
  11887. signal
  11888. });
  11889. }
  11890. if (this.#annotationEditorUIManager) {
  11891. eventBus.dispatch("annotationeditormodechanged", {
  11892. source: this,
  11893. mode: this.#annotationEditorMode
  11894. });
  11895. }
  11896. if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT) {
  11897. this._pagesCapability.resolve();
  11898. return;
  11899. }
  11900. let getPagesLeft = pagesCount - 1;
  11901. if (getPagesLeft <= 0) {
  11902. this._pagesCapability.resolve();
  11903. return;
  11904. }
  11905. for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) {
  11906. const promise = pdfDocument.getPage(pageNum).then(pdfPage => {
  11907. const pageView = this._pages[pageNum - 1];
  11908. if (!pageView.pdfPage) {
  11909. pageView.setPdfPage(pdfPage);
  11910. }
  11911. if (--getPagesLeft === 0) {
  11912. this._pagesCapability.resolve();
  11913. }
  11914. }, reason => {
  11915. console.error(`Unable to get page ${pageNum} to initialize viewer`, reason);
  11916. if (--getPagesLeft === 0) {
  11917. this._pagesCapability.resolve();
  11918. }
  11919. });
  11920. if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) {
  11921. await promise;
  11922. }
  11923. }
  11924. });
  11925. eventBus.dispatch("pagesinit", {
  11926. source: this
  11927. });
  11928. pdfDocument.getMetadata().then(({
  11929. info
  11930. }) => {
  11931. if (pdfDocument !== this.pdfDocument) {
  11932. return;
  11933. }
  11934. if (info.Language) {
  11935. viewer.lang = info.Language;
  11936. }
  11937. });
  11938. if (this.defaultRenderingQueue) {
  11939. this.update();
  11940. }
  11941. }).catch(reason => {
  11942. console.error("Unable to initialize viewer", reason);
  11943. this._pagesCapability.reject(reason);
  11944. });
  11945. }
  11946. setPageLabels(labels) {
  11947. if (!this.pdfDocument) {
  11948. return;
  11949. }
  11950. if (!labels) {
  11951. this._pageLabels = null;
  11952. } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
  11953. this._pageLabels = null;
  11954. console.error(`setPageLabels: Invalid page labels.`);
  11955. } else {
  11956. this._pageLabels = labels;
  11957. }
  11958. for (let i = 0, ii = this._pages.length; i < ii; i++) {
  11959. this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null);
  11960. }
  11961. }
  11962. _resetView() {
  11963. this._pages = [];
  11964. this._currentPageNumber = 1;
  11965. this._currentScale = UNKNOWN_SCALE;
  11966. this._currentScaleValue = null;
  11967. this._pageLabels = null;
  11968. this.#buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
  11969. this._location = null;
  11970. this._pagesRotation = 0;
  11971. this._optionalContentConfigPromise = null;
  11972. this._firstPageCapability = Promise.withResolvers();
  11973. this._onePageRenderedCapability = Promise.withResolvers();
  11974. this._pagesCapability = Promise.withResolvers();
  11975. this._scrollMode = ScrollMode.VERTICAL;
  11976. this._previousScrollMode = ScrollMode.UNKNOWN;
  11977. this._spreadMode = SpreadMode.NONE;
  11978. this.#scrollModePageState = {
  11979. previousPageNumber: 1,
  11980. scrollDown: true,
  11981. pages: []
  11982. };
  11983. this.#eventAbortController?.abort();
  11984. this.#eventAbortController = null;
  11985. this.viewer.textContent = "";
  11986. this._updateScrollMode();
  11987. this.viewer.removeAttribute("lang");
  11988. this.#hiddenCopyElement?.remove();
  11989. this.#hiddenCopyElement = null;
  11990. this.#cleanupTimeouts();
  11991. this.#cleanupSwitchAnnotationEditorMode();
  11992. }
  11993. #ensurePageViewVisible() {
  11994. if (this._scrollMode !== ScrollMode.PAGE) {
  11995. throw new Error("#ensurePageViewVisible: Invalid scrollMode value.");
  11996. }
  11997. const pageNumber = this._currentPageNumber,
  11998. state = this.#scrollModePageState,
  11999. viewer = this.viewer;
  12000. viewer.textContent = "";
  12001. state.pages.length = 0;
  12002. if (this._spreadMode === SpreadMode.NONE && !this.isInPresentationMode) {
  12003. const pageView = this._pages[pageNumber - 1];
  12004. viewer.append(pageView.div);
  12005. state.pages.push(pageView);
  12006. } else {
  12007. const pageIndexSet = new Set(),
  12008. parity = this._spreadMode - 1;
  12009. if (parity === -1) {
  12010. pageIndexSet.add(pageNumber - 1);
  12011. } else if (pageNumber % 2 !== parity) {
  12012. pageIndexSet.add(pageNumber - 1);
  12013. pageIndexSet.add(pageNumber);
  12014. } else {
  12015. pageIndexSet.add(pageNumber - 2);
  12016. pageIndexSet.add(pageNumber - 1);
  12017. }
  12018. const spread = document.createElement("div");
  12019. spread.className = "spread";
  12020. if (this.isInPresentationMode) {
  12021. const dummyPage = document.createElement("div");
  12022. dummyPage.className = "dummyPage";
  12023. spread.append(dummyPage);
  12024. }
  12025. for (const i of pageIndexSet) {
  12026. const pageView = this._pages[i];
  12027. if (!pageView) {
  12028. continue;
  12029. }
  12030. spread.append(pageView.div);
  12031. state.pages.push(pageView);
  12032. }
  12033. viewer.append(spread);
  12034. }
  12035. state.scrollDown = pageNumber >= state.previousPageNumber;
  12036. state.previousPageNumber = pageNumber;
  12037. }
  12038. _scrollUpdate() {
  12039. if (this.pagesCount === 0) {
  12040. return;
  12041. }
  12042. if (this.#scrollTimeoutId) {
  12043. clearTimeout(this.#scrollTimeoutId);
  12044. }
  12045. this.#scrollTimeoutId = setTimeout(() => {
  12046. this.#scrollTimeoutId = null;
  12047. this.update();
  12048. }, 100);
  12049. this.update();
  12050. }
  12051. #scrollIntoView(pageView, pageSpot = null) {
  12052. const {
  12053. div,
  12054. id
  12055. } = pageView;
  12056. if (this._currentPageNumber !== id) {
  12057. this._setCurrentPageNumber(id);
  12058. }
  12059. if (this._scrollMode === ScrollMode.PAGE) {
  12060. this.#ensurePageViewVisible();
  12061. this.update();
  12062. }
  12063. if (!pageSpot && !this.isInPresentationMode) {
  12064. const left = div.offsetLeft + div.clientLeft,
  12065. right = left + div.clientWidth;
  12066. const {
  12067. scrollLeft,
  12068. clientWidth
  12069. } = this.container;
  12070. if (this._scrollMode === ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) {
  12071. pageSpot = {
  12072. left: 0,
  12073. top: 0
  12074. };
  12075. }
  12076. }
  12077. scrollIntoView(div, pageSpot);
  12078. if (!this._currentScaleValue && this._location) {
  12079. this._location = null;
  12080. }
  12081. }
  12082. #isSameScale(newScale) {
  12083. return newScale === this._currentScale || Math.abs(newScale - this._currentScale) < 1e-15;
  12084. }
  12085. #setScaleUpdatePages(newScale, newValue, {
  12086. noScroll = false,
  12087. preset = false,
  12088. drawingDelay = -1,
  12089. origin = null
  12090. }) {
  12091. this._currentScaleValue = newValue.toString();
  12092. if (this.#isSameScale(newScale)) {
  12093. if (preset) {
  12094. this.eventBus.dispatch("scalechanging", {
  12095. source: this,
  12096. scale: newScale,
  12097. presetValue: newValue
  12098. });
  12099. }
  12100. return;
  12101. }
  12102. this.viewer.style.setProperty("--scale-factor", newScale * PixelsPerInch.PDF_TO_CSS_UNITS);
  12103. const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000;
  12104. this.refresh(true, {
  12105. scale: newScale,
  12106. drawingDelay: postponeDrawing ? drawingDelay : -1
  12107. });
  12108. if (postponeDrawing) {
  12109. this.#scaleTimeoutId = setTimeout(() => {
  12110. this.#scaleTimeoutId = null;
  12111. this.refresh();
  12112. }, drawingDelay);
  12113. }
  12114. const previousScale = this._currentScale;
  12115. this._currentScale = newScale;
  12116. if (!noScroll) {
  12117. let page = this._currentPageNumber,
  12118. dest;
  12119. if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) {
  12120. page = this._location.pageNumber;
  12121. dest = [null, {
  12122. name: "XYZ"
  12123. }, this._location.left, this._location.top, null];
  12124. }
  12125. this.scrollPageIntoView({
  12126. pageNumber: page,
  12127. destArray: dest,
  12128. allowNegativeOffset: true
  12129. });
  12130. if (Array.isArray(origin)) {
  12131. const scaleDiff = newScale / previousScale - 1;
  12132. const [top, left] = this.containerTopLeft;
  12133. this.container.scrollLeft += (origin[0] - left) * scaleDiff;
  12134. this.container.scrollTop += (origin[1] - top) * scaleDiff;
  12135. }
  12136. }
  12137. this.eventBus.dispatch("scalechanging", {
  12138. source: this,
  12139. scale: newScale,
  12140. presetValue: preset ? newValue : undefined
  12141. });
  12142. if (this.defaultRenderingQueue) {
  12143. this.update();
  12144. }
  12145. }
  12146. get #pageWidthScaleFactor() {
  12147. if (this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL) {
  12148. return 2;
  12149. }
  12150. return 1;
  12151. }
  12152. #setScale(value, options) {
  12153. let scale = parseFloat(value);
  12154. if (scale > 0) {
  12155. options.preset = false;
  12156. this.#setScaleUpdatePages(scale, value, options);
  12157. } else {
  12158. const currentPage = this._pages[this._currentPageNumber - 1];
  12159. if (!currentPage) {
  12160. return;
  12161. }
  12162. let hPadding = SCROLLBAR_PADDING,
  12163. vPadding = VERTICAL_PADDING;
  12164. if (this.isInPresentationMode) {
  12165. hPadding = vPadding = 4;
  12166. if (this._spreadMode !== SpreadMode.NONE) {
  12167. hPadding *= 2;
  12168. }
  12169. } else if (this.removePageBorders) {
  12170. hPadding = vPadding = 0;
  12171. } else if (this._scrollMode === ScrollMode.HORIZONTAL) {
  12172. [hPadding, vPadding] = [vPadding, hPadding];
  12173. }
  12174. const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this.#pageWidthScaleFactor;
  12175. const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale;
  12176. switch (value) {
  12177. case "page-actual":
  12178. scale = 1;
  12179. break;
  12180. case "page-width":
  12181. scale = pageWidthScale;
  12182. break;
  12183. case "page-height":
  12184. scale = pageHeightScale;
  12185. break;
  12186. case "page-fit":
  12187. scale = Math.min(pageWidthScale, pageHeightScale);
  12188. break;
  12189. case "auto":
  12190. const horizontalScale = isPortraitOrientation(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale);
  12191. scale = Math.min(MAX_AUTO_SCALE, horizontalScale);
  12192. break;
  12193. default:
  12194. console.error(`#setScale: "${value}" is an unknown zoom value.`);
  12195. return;
  12196. }
  12197. options.preset = true;
  12198. this.#setScaleUpdatePages(scale, value, options);
  12199. }
  12200. }
  12201. #resetCurrentPageView() {
  12202. const pageView = this._pages[this._currentPageNumber - 1];
  12203. if (this.isInPresentationMode) {
  12204. this.#setScale(this._currentScaleValue, {
  12205. noScroll: true
  12206. });
  12207. }
  12208. this.#scrollIntoView(pageView);
  12209. }
  12210. pageLabelToPageNumber(label) {
  12211. if (!this._pageLabels) {
  12212. return null;
  12213. }
  12214. const i = this._pageLabels.indexOf(label);
  12215. if (i < 0) {
  12216. return null;
  12217. }
  12218. return i + 1;
  12219. }
  12220. scrollPageIntoView({
  12221. pageNumber,
  12222. destArray = null,
  12223. allowNegativeOffset = false,
  12224. ignoreDestinationZoom = false
  12225. }) {
  12226. if (!this.pdfDocument) {
  12227. return;
  12228. }
  12229. const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1];
  12230. if (!pageView) {
  12231. console.error(`scrollPageIntoView: "${pageNumber}" is not a valid pageNumber parameter.`);
  12232. return;
  12233. }
  12234. if (this.isInPresentationMode || !destArray) {
  12235. this._setCurrentPageNumber(pageNumber, true);
  12236. return;
  12237. }
  12238. let x = 0,
  12239. y = 0;
  12240. let width = 0,
  12241. height = 0,
  12242. widthScale,
  12243. heightScale;
  12244. const changeOrientation = pageView.rotation % 180 !== 0;
  12245. const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS;
  12246. const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS;
  12247. let scale = 0;
  12248. switch (destArray[1].name) {
  12249. case "XYZ":
  12250. x = destArray[2];
  12251. y = destArray[3];
  12252. scale = destArray[4];
  12253. x = x !== null ? x : 0;
  12254. y = y !== null ? y : pageHeight;
  12255. break;
  12256. case "Fit":
  12257. case "FitB":
  12258. scale = "page-fit";
  12259. break;
  12260. case "FitH":
  12261. case "FitBH":
  12262. y = destArray[2];
  12263. scale = "page-width";
  12264. if (y === null && this._location) {
  12265. x = this._location.left;
  12266. y = this._location.top;
  12267. } else if (typeof y !== "number" || y < 0) {
  12268. y = pageHeight;
  12269. }
  12270. break;
  12271. case "FitV":
  12272. case "FitBV":
  12273. x = destArray[2];
  12274. width = pageWidth;
  12275. height = pageHeight;
  12276. scale = "page-height";
  12277. break;
  12278. case "FitR":
  12279. x = destArray[2];
  12280. y = destArray[3];
  12281. width = destArray[4] - x;
  12282. height = destArray[5] - y;
  12283. let hPadding = SCROLLBAR_PADDING,
  12284. vPadding = VERTICAL_PADDING;
  12285. if (this.removePageBorders) {
  12286. hPadding = vPadding = 0;
  12287. }
  12288. widthScale = (this.container.clientWidth - hPadding) / width / PixelsPerInch.PDF_TO_CSS_UNITS;
  12289. heightScale = (this.container.clientHeight - vPadding) / height / PixelsPerInch.PDF_TO_CSS_UNITS;
  12290. scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
  12291. break;
  12292. default:
  12293. console.error(`scrollPageIntoView: "${destArray[1].name}" is not a valid destination type.`);
  12294. return;
  12295. }
  12296. if (!ignoreDestinationZoom) {
  12297. if (scale && scale !== this._currentScale) {
  12298. this.currentScaleValue = scale;
  12299. } else if (this._currentScale === UNKNOWN_SCALE) {
  12300. this.currentScaleValue = DEFAULT_SCALE_VALUE;
  12301. }
  12302. }
  12303. if (scale === "page-fit" && !destArray[4]) {
  12304. this.#scrollIntoView(pageView);
  12305. return;
  12306. }
  12307. const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)];
  12308. let left = Math.min(boundingRect[0][0], boundingRect[1][0]);
  12309. let top = Math.min(boundingRect[0][1], boundingRect[1][1]);
  12310. if (!allowNegativeOffset) {
  12311. left = Math.max(left, 0);
  12312. top = Math.max(top, 0);
  12313. }
  12314. this.#scrollIntoView(pageView, {
  12315. left,
  12316. top
  12317. });
  12318. }
  12319. _updateLocation(firstPage) {
  12320. const currentScale = this._currentScale;
  12321. const currentScaleValue = this._currentScaleValue;
  12322. const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue;
  12323. const pageNumber = firstPage.id;
  12324. const currentPageView = this._pages[pageNumber - 1];
  12325. const container = this.container;
  12326. const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y);
  12327. const intLeft = Math.round(topLeft[0]);
  12328. const intTop = Math.round(topLeft[1]);
  12329. let pdfOpenParams = `#page=${pageNumber}`;
  12330. if (!this.isInPresentationMode) {
  12331. pdfOpenParams += `&zoom=${normalizedScaleValue},${intLeft},${intTop}`;
  12332. }
  12333. this._location = {
  12334. pageNumber,
  12335. scale: normalizedScaleValue,
  12336. top: intTop,
  12337. left: intLeft,
  12338. rotation: this._pagesRotation,
  12339. pdfOpenParams
  12340. };
  12341. }
  12342. update() {
  12343. const visible = this._getVisiblePages();
  12344. const visiblePages = visible.views,
  12345. numVisiblePages = visiblePages.length;
  12346. if (numVisiblePages === 0) {
  12347. return;
  12348. }
  12349. const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
  12350. this.#buffer.resize(newCacheSize, visible.ids);
  12351. for (const {
  12352. view,
  12353. visibleArea
  12354. } of visiblePages) {
  12355. view.updateVisibleArea(visibleArea);
  12356. }
  12357. for (const view of this.#buffer) {
  12358. if (!visible.ids.has(view.id)) {
  12359. view.updateVisibleArea(null);
  12360. }
  12361. }
  12362. this.renderingQueue.renderHighestPriority(visible);
  12363. const isSimpleLayout = this._spreadMode === SpreadMode.NONE && (this._scrollMode === ScrollMode.PAGE || this._scrollMode === ScrollMode.VERTICAL);
  12364. const currentId = this._currentPageNumber;
  12365. let stillFullyVisible = false;
  12366. for (const page of visiblePages) {
  12367. if (page.percent < 100) {
  12368. break;
  12369. }
  12370. if (page.id === currentId && isSimpleLayout) {
  12371. stillFullyVisible = true;
  12372. break;
  12373. }
  12374. }
  12375. this._setCurrentPageNumber(stillFullyVisible ? currentId : visiblePages[0].id);
  12376. this._updateLocation(visible.first);
  12377. this.eventBus.dispatch("updateviewarea", {
  12378. source: this,
  12379. location: this._location
  12380. });
  12381. }
  12382. #switchToEditAnnotationMode() {
  12383. const visible = this._getVisiblePages();
  12384. const pagesToRefresh = [];
  12385. const {
  12386. ids,
  12387. views
  12388. } = visible;
  12389. for (const page of views) {
  12390. const {
  12391. view
  12392. } = page;
  12393. if (!view.hasEditableAnnotations()) {
  12394. ids.delete(view.id);
  12395. continue;
  12396. }
  12397. pagesToRefresh.push(page);
  12398. }
  12399. if (pagesToRefresh.length === 0) {
  12400. return null;
  12401. }
  12402. this.renderingQueue.renderHighestPriority({
  12403. first: pagesToRefresh[0],
  12404. last: pagesToRefresh.at(-1),
  12405. views: pagesToRefresh,
  12406. ids
  12407. });
  12408. return ids;
  12409. }
  12410. containsElement(element) {
  12411. return this.container.contains(element);
  12412. }
  12413. focus() {
  12414. this.container.focus();
  12415. }
  12416. get _isContainerRtl() {
  12417. return getComputedStyle(this.container).direction === "rtl";
  12418. }
  12419. get isInPresentationMode() {
  12420. return this.presentationModeState === PresentationModeState.FULLSCREEN;
  12421. }
  12422. get isChangingPresentationMode() {
  12423. return this.presentationModeState === PresentationModeState.CHANGING;
  12424. }
  12425. get isHorizontalScrollbarEnabled() {
  12426. return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth;
  12427. }
  12428. get isVerticalScrollbarEnabled() {
  12429. return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight;
  12430. }
  12431. _getVisiblePages() {
  12432. const views = this._scrollMode === ScrollMode.PAGE ? this.#scrollModePageState.pages : this._pages,
  12433. horizontal = this._scrollMode === ScrollMode.HORIZONTAL,
  12434. rtl = horizontal && this._isContainerRtl;
  12435. return getVisibleElements({
  12436. scrollEl: this.container,
  12437. views,
  12438. sortByVisibility: true,
  12439. horizontal,
  12440. rtl
  12441. });
  12442. }
  12443. cleanup() {
  12444. for (const pageView of this._pages) {
  12445. if (pageView.renderingState !== RenderingStates.FINISHED) {
  12446. pageView.reset();
  12447. }
  12448. }
  12449. }
  12450. _cancelRendering() {
  12451. for (const pageView of this._pages) {
  12452. pageView.cancelRendering();
  12453. }
  12454. }
  12455. async #ensurePdfPageLoaded(pageView) {
  12456. if (pageView.pdfPage) {
  12457. return pageView.pdfPage;
  12458. }
  12459. try {
  12460. const pdfPage = await this.pdfDocument.getPage(pageView.id);
  12461. if (!pageView.pdfPage) {
  12462. pageView.setPdfPage(pdfPage);
  12463. }
  12464. return pdfPage;
  12465. } catch (reason) {
  12466. console.error("Unable to get page for page view", reason);
  12467. return null;
  12468. }
  12469. }
  12470. #getScrollAhead(visible) {
  12471. if (visible.first?.id === 1) {
  12472. return true;
  12473. } else if (visible.last?.id === this.pagesCount) {
  12474. return false;
  12475. }
  12476. switch (this._scrollMode) {
  12477. case ScrollMode.PAGE:
  12478. return this.#scrollModePageState.scrollDown;
  12479. case ScrollMode.HORIZONTAL:
  12480. return this.scroll.right;
  12481. }
  12482. return this.scroll.down;
  12483. }
  12484. forceRendering(currentlyVisiblePages) {
  12485. const visiblePages = currentlyVisiblePages || this._getVisiblePages();
  12486. const scrollAhead = this.#getScrollAhead(visiblePages);
  12487. const preRenderExtra = this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL;
  12488. const ignoreDetailViews = this.#scaleTimeoutId !== null || this.#scrollTimeoutId !== null && visiblePages.views.some(page => page.detailView?.renderingCancelled);
  12489. const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead, preRenderExtra, ignoreDetailViews);
  12490. if (pageView) {
  12491. this.#ensurePdfPageLoaded(pageView).then(() => {
  12492. this.renderingQueue.renderView(pageView);
  12493. });
  12494. return true;
  12495. }
  12496. return false;
  12497. }
  12498. get hasEqualPageSizes() {
  12499. const firstPageView = this._pages[0];
  12500. for (let i = 1, ii = this._pages.length; i < ii; ++i) {
  12501. const pageView = this._pages[i];
  12502. if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) {
  12503. return false;
  12504. }
  12505. }
  12506. return true;
  12507. }
  12508. getPagesOverview() {
  12509. let initialOrientation;
  12510. return this._pages.map(pageView => {
  12511. const viewport = pageView.pdfPage.getViewport({
  12512. scale: 1
  12513. });
  12514. const orientation = isPortraitOrientation(viewport);
  12515. if (initialOrientation === undefined) {
  12516. initialOrientation = orientation;
  12517. } else if (this.enablePrintAutoRotate && orientation !== initialOrientation) {
  12518. return {
  12519. width: viewport.height,
  12520. height: viewport.width,
  12521. rotation: (viewport.rotation - 90) % 360
  12522. };
  12523. }
  12524. return {
  12525. width: viewport.width,
  12526. height: viewport.height,
  12527. rotation: viewport.rotation
  12528. };
  12529. });
  12530. }
  12531. get optionalContentConfigPromise() {
  12532. if (!this.pdfDocument) {
  12533. return Promise.resolve(null);
  12534. }
  12535. if (!this._optionalContentConfigPromise) {
  12536. console.error("optionalContentConfigPromise: Not initialized yet.");
  12537. return this.pdfDocument.getOptionalContentConfig({
  12538. intent: "display"
  12539. });
  12540. }
  12541. return this._optionalContentConfigPromise;
  12542. }
  12543. set optionalContentConfigPromise(promise) {
  12544. if (!(promise instanceof Promise)) {
  12545. throw new Error(`Invalid optionalContentConfigPromise: ${promise}`);
  12546. }
  12547. if (!this.pdfDocument) {
  12548. return;
  12549. }
  12550. if (!this._optionalContentConfigPromise) {
  12551. return;
  12552. }
  12553. this._optionalContentConfigPromise = promise;
  12554. this.refresh(false, {
  12555. optionalContentConfigPromise: promise
  12556. });
  12557. this.eventBus.dispatch("optionalcontentconfigchanged", {
  12558. source: this,
  12559. promise
  12560. });
  12561. }
  12562. get scrollMode() {
  12563. return this._scrollMode;
  12564. }
  12565. set scrollMode(mode) {
  12566. if (this._scrollMode === mode) {
  12567. return;
  12568. }
  12569. if (!isValidScrollMode(mode)) {
  12570. throw new Error(`Invalid scroll mode: ${mode}`);
  12571. }
  12572. if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
  12573. return;
  12574. }
  12575. this._previousScrollMode = this._scrollMode;
  12576. this._scrollMode = mode;
  12577. this.eventBus.dispatch("scrollmodechanged", {
  12578. source: this,
  12579. mode
  12580. });
  12581. this._updateScrollMode(this._currentPageNumber);
  12582. }
  12583. _updateScrollMode(pageNumber = null) {
  12584. const scrollMode = this._scrollMode,
  12585. viewer = this.viewer;
  12586. viewer.classList.toggle("scrollHorizontal", scrollMode === ScrollMode.HORIZONTAL);
  12587. viewer.classList.toggle("scrollWrapped", scrollMode === ScrollMode.WRAPPED);
  12588. if (!this.pdfDocument || !pageNumber) {
  12589. return;
  12590. }
  12591. if (scrollMode === ScrollMode.PAGE) {
  12592. this.#ensurePageViewVisible();
  12593. } else if (this._previousScrollMode === ScrollMode.PAGE) {
  12594. this._updateSpreadMode();
  12595. }
  12596. if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
  12597. this.#setScale(this._currentScaleValue, {
  12598. noScroll: true
  12599. });
  12600. }
  12601. this._setCurrentPageNumber(pageNumber, true);
  12602. this.update();
  12603. }
  12604. get spreadMode() {
  12605. return this._spreadMode;
  12606. }
  12607. set spreadMode(mode) {
  12608. if (this._spreadMode === mode) {
  12609. return;
  12610. }
  12611. if (!isValidSpreadMode(mode)) {
  12612. throw new Error(`Invalid spread mode: ${mode}`);
  12613. }
  12614. this._spreadMode = mode;
  12615. this.eventBus.dispatch("spreadmodechanged", {
  12616. source: this,
  12617. mode
  12618. });
  12619. this._updateSpreadMode(this._currentPageNumber);
  12620. }
  12621. _updateSpreadMode(pageNumber = null) {
  12622. if (!this.pdfDocument) {
  12623. return;
  12624. }
  12625. const viewer = this.viewer,
  12626. pages = this._pages;
  12627. if (this._scrollMode === ScrollMode.PAGE) {
  12628. this.#ensurePageViewVisible();
  12629. } else {
  12630. viewer.textContent = "";
  12631. if (this._spreadMode === SpreadMode.NONE) {
  12632. for (const pageView of this._pages) {
  12633. viewer.append(pageView.div);
  12634. }
  12635. } else {
  12636. const parity = this._spreadMode - 1;
  12637. let spread = null;
  12638. for (let i = 0, ii = pages.length; i < ii; ++i) {
  12639. if (spread === null) {
  12640. spread = document.createElement("div");
  12641. spread.className = "spread";
  12642. viewer.append(spread);
  12643. } else if (i % 2 === parity) {
  12644. spread = spread.cloneNode(false);
  12645. viewer.append(spread);
  12646. }
  12647. spread.append(pages[i].div);
  12648. }
  12649. }
  12650. }
  12651. if (!pageNumber) {
  12652. return;
  12653. }
  12654. if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
  12655. this.#setScale(this._currentScaleValue, {
  12656. noScroll: true
  12657. });
  12658. }
  12659. this._setCurrentPageNumber(pageNumber, true);
  12660. this.update();
  12661. }
  12662. _getPageAdvance(currentPageNumber, previous = false) {
  12663. switch (this._scrollMode) {
  12664. case ScrollMode.WRAPPED:
  12665. {
  12666. const {
  12667. views
  12668. } = this._getVisiblePages(),
  12669. pageLayout = new Map();
  12670. for (const {
  12671. id,
  12672. y,
  12673. percent,
  12674. widthPercent
  12675. } of views) {
  12676. if (percent === 0 || widthPercent < 100) {
  12677. continue;
  12678. }
  12679. let yArray = pageLayout.get(y);
  12680. if (!yArray) {
  12681. pageLayout.set(y, yArray ||= []);
  12682. }
  12683. yArray.push(id);
  12684. }
  12685. for (const yArray of pageLayout.values()) {
  12686. const currentIndex = yArray.indexOf(currentPageNumber);
  12687. if (currentIndex === -1) {
  12688. continue;
  12689. }
  12690. const numPages = yArray.length;
  12691. if (numPages === 1) {
  12692. break;
  12693. }
  12694. if (previous) {
  12695. for (let i = currentIndex - 1, ii = 0; i >= ii; i--) {
  12696. const currentId = yArray[i],
  12697. expectedId = yArray[i + 1] - 1;
  12698. if (currentId < expectedId) {
  12699. return currentPageNumber - expectedId;
  12700. }
  12701. }
  12702. } else {
  12703. for (let i = currentIndex + 1, ii = numPages; i < ii; i++) {
  12704. const currentId = yArray[i],
  12705. expectedId = yArray[i - 1] + 1;
  12706. if (currentId > expectedId) {
  12707. return expectedId - currentPageNumber;
  12708. }
  12709. }
  12710. }
  12711. if (previous) {
  12712. const firstId = yArray[0];
  12713. if (firstId < currentPageNumber) {
  12714. return currentPageNumber - firstId + 1;
  12715. }
  12716. } else {
  12717. const lastId = yArray[numPages - 1];
  12718. if (lastId > currentPageNumber) {
  12719. return lastId - currentPageNumber + 1;
  12720. }
  12721. }
  12722. break;
  12723. }
  12724. break;
  12725. }
  12726. case ScrollMode.HORIZONTAL:
  12727. {
  12728. break;
  12729. }
  12730. case ScrollMode.PAGE:
  12731. case ScrollMode.VERTICAL:
  12732. {
  12733. if (this._spreadMode === SpreadMode.NONE) {
  12734. break;
  12735. }
  12736. const parity = this._spreadMode - 1;
  12737. if (previous && currentPageNumber % 2 !== parity) {
  12738. break;
  12739. } else if (!previous && currentPageNumber % 2 === parity) {
  12740. break;
  12741. }
  12742. const {
  12743. views
  12744. } = this._getVisiblePages(),
  12745. expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1;
  12746. for (const {
  12747. id,
  12748. percent,
  12749. widthPercent
  12750. } of views) {
  12751. if (id !== expectedId) {
  12752. continue;
  12753. }
  12754. if (percent > 0 && widthPercent === 100) {
  12755. return 2;
  12756. }
  12757. break;
  12758. }
  12759. break;
  12760. }
  12761. }
  12762. return 1;
  12763. }
  12764. nextPage() {
  12765. const currentPageNumber = this._currentPageNumber,
  12766. pagesCount = this.pagesCount;
  12767. if (currentPageNumber >= pagesCount) {
  12768. return false;
  12769. }
  12770. const advance = this._getPageAdvance(currentPageNumber, false) || 1;
  12771. this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount);
  12772. return true;
  12773. }
  12774. previousPage() {
  12775. const currentPageNumber = this._currentPageNumber;
  12776. if (currentPageNumber <= 1) {
  12777. return false;
  12778. }
  12779. const advance = this._getPageAdvance(currentPageNumber, true) || 1;
  12780. this.currentPageNumber = Math.max(currentPageNumber - advance, 1);
  12781. return true;
  12782. }
  12783. updateScale({
  12784. drawingDelay,
  12785. scaleFactor = null,
  12786. steps = null,
  12787. origin
  12788. }) {
  12789. if (steps === null && scaleFactor === null) {
  12790. throw new Error("Invalid updateScale options: either `steps` or `scaleFactor` must be provided.");
  12791. }
  12792. if (!this.pdfDocument) {
  12793. return;
  12794. }
  12795. let newScale = this._currentScale;
  12796. if (scaleFactor > 0 && scaleFactor !== 1) {
  12797. newScale = Math.round(newScale * scaleFactor * 100) / 100;
  12798. } else if (steps) {
  12799. const delta = steps > 0 ? DEFAULT_SCALE_DELTA : 1 / DEFAULT_SCALE_DELTA;
  12800. const round = steps > 0 ? Math.ceil : Math.floor;
  12801. steps = Math.abs(steps);
  12802. do {
  12803. newScale = round((newScale * delta).toFixed(2) * 10) / 10;
  12804. } while (--steps > 0);
  12805. }
  12806. newScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale));
  12807. this.#setScale(newScale, {
  12808. noScroll: false,
  12809. drawingDelay,
  12810. origin
  12811. });
  12812. }
  12813. increaseScale(options = {}) {
  12814. this.updateScale({
  12815. ...options,
  12816. steps: options.steps ?? 1
  12817. });
  12818. }
  12819. decreaseScale(options = {}) {
  12820. this.updateScale({
  12821. ...options,
  12822. steps: -(options.steps ?? 1)
  12823. });
  12824. }
  12825. #updateContainerHeightCss(height = this.container.clientHeight) {
  12826. if (height !== this.#previousContainerHeight) {
  12827. this.#previousContainerHeight = height;
  12828. docStyle.setProperty("--viewer-container-height", `${height}px`);
  12829. }
  12830. }
  12831. #resizeObserverCallback(entries) {
  12832. for (const entry of entries) {
  12833. if (entry.target === this.container) {
  12834. this.#updateContainerHeightCss(Math.floor(entry.borderBoxSize[0].blockSize));
  12835. this.#containerTopLeft = null;
  12836. break;
  12837. }
  12838. }
  12839. }
  12840. get containerTopLeft() {
  12841. return this.#containerTopLeft ||= [this.container.offsetTop, this.container.offsetLeft];
  12842. }
  12843. #cleanupTimeouts() {
  12844. if (this.#scaleTimeoutId !== null) {
  12845. clearTimeout(this.#scaleTimeoutId);
  12846. this.#scaleTimeoutId = null;
  12847. }
  12848. if (this.#scrollTimeoutId !== null) {
  12849. clearTimeout(this.#scrollTimeoutId);
  12850. this.#scrollTimeoutId = null;
  12851. }
  12852. }
  12853. #cleanupSwitchAnnotationEditorMode() {
  12854. this.#switchAnnotationEditorModeAC?.abort();
  12855. this.#switchAnnotationEditorModeAC = null;
  12856. if (this.#switchAnnotationEditorModeTimeoutId !== null) {
  12857. clearTimeout(this.#switchAnnotationEditorModeTimeoutId);
  12858. this.#switchAnnotationEditorModeTimeoutId = null;
  12859. }
  12860. }
  12861. #preloadEditingData(mode) {
  12862. switch (mode) {
  12863. case AnnotationEditorType.STAMP:
  12864. this.#mlManager?.loadModel("altText");
  12865. break;
  12866. case AnnotationEditorType.SIGNATURE:
  12867. this.#signatureManager?.loadSignatures();
  12868. break;
  12869. }
  12870. }
  12871. get annotationEditorMode() {
  12872. return this.#annotationEditorUIManager ? this.#annotationEditorMode : AnnotationEditorType.DISABLE;
  12873. }
  12874. set annotationEditorMode({
  12875. mode,
  12876. editId = null,
  12877. isFromKeyboard = false
  12878. }) {
  12879. if (!this.#annotationEditorUIManager) {
  12880. throw new Error(`The AnnotationEditor is not enabled.`);
  12881. }
  12882. if (this.#annotationEditorMode === mode) {
  12883. return;
  12884. }
  12885. if (!isValidAnnotationEditorMode(mode)) {
  12886. throw new Error(`Invalid AnnotationEditor mode: ${mode}`);
  12887. }
  12888. if (!this.pdfDocument) {
  12889. return;
  12890. }
  12891. this.#preloadEditingData(mode);
  12892. const {
  12893. eventBus,
  12894. pdfDocument
  12895. } = this;
  12896. const updater = async () => {
  12897. this.#cleanupSwitchAnnotationEditorMode();
  12898. this.#annotationEditorMode = mode;
  12899. await this.#annotationEditorUIManager.updateMode(mode, editId, isFromKeyboard);
  12900. if (mode !== this.#annotationEditorMode || pdfDocument !== this.pdfDocument) {
  12901. return;
  12902. }
  12903. eventBus.dispatch("annotationeditormodechanged", {
  12904. source: this,
  12905. mode
  12906. });
  12907. };
  12908. if (mode === AnnotationEditorType.NONE || this.#annotationEditorMode === AnnotationEditorType.NONE) {
  12909. const isEditing = mode !== AnnotationEditorType.NONE;
  12910. if (!isEditing) {
  12911. this.pdfDocument.annotationStorage.resetModifiedIds();
  12912. }
  12913. for (const pageView of this._pages) {
  12914. pageView.toggleEditingMode(isEditing);
  12915. }
  12916. const idsToRefresh = this.#switchToEditAnnotationMode();
  12917. if (isEditing && idsToRefresh) {
  12918. this.#cleanupSwitchAnnotationEditorMode();
  12919. this.#switchAnnotationEditorModeAC = new AbortController();
  12920. const signal = AbortSignal.any([this.#eventAbortController.signal, this.#switchAnnotationEditorModeAC.signal]);
  12921. eventBus._on("pagerendered", ({
  12922. pageNumber
  12923. }) => {
  12924. idsToRefresh.delete(pageNumber);
  12925. if (idsToRefresh.size === 0) {
  12926. this.#switchAnnotationEditorModeTimeoutId = setTimeout(updater, 0);
  12927. }
  12928. }, {
  12929. signal
  12930. });
  12931. return;
  12932. }
  12933. }
  12934. updater();
  12935. }
  12936. refresh(noUpdate = false, updateArgs = Object.create(null)) {
  12937. if (!this.pdfDocument) {
  12938. return;
  12939. }
  12940. for (const pageView of this._pages) {
  12941. pageView.update(updateArgs);
  12942. }
  12943. this.#cleanupTimeouts();
  12944. if (!noUpdate) {
  12945. this.update();
  12946. }
  12947. }
  12948. }
  12949. ;// ./web/secondary_toolbar.js
  12950. class SecondaryToolbar {
  12951. #opts;
  12952. constructor(options, eventBus) {
  12953. this.#opts = options;
  12954. const buttons = [{
  12955. element: options.presentationModeButton,
  12956. eventName: "presentationmode",
  12957. close: true
  12958. }, {
  12959. element: options.printButton,
  12960. eventName: "print",
  12961. close: true
  12962. }, {
  12963. element: options.downloadButton,
  12964. eventName: "download",
  12965. close: true
  12966. }, {
  12967. element: options.viewBookmarkButton,
  12968. eventName: null,
  12969. close: true
  12970. }, {
  12971. element: options.firstPageButton,
  12972. eventName: "firstpage",
  12973. close: true
  12974. }, {
  12975. element: options.lastPageButton,
  12976. eventName: "lastpage",
  12977. close: true
  12978. }, {
  12979. element: options.pageRotateCwButton,
  12980. eventName: "rotatecw",
  12981. close: false
  12982. }, {
  12983. element: options.pageRotateCcwButton,
  12984. eventName: "rotateccw",
  12985. close: false
  12986. }, {
  12987. element: options.cursorSelectToolButton,
  12988. eventName: "switchcursortool",
  12989. eventDetails: {
  12990. tool: CursorTool.SELECT
  12991. },
  12992. close: true
  12993. }, {
  12994. element: options.cursorHandToolButton,
  12995. eventName: "switchcursortool",
  12996. eventDetails: {
  12997. tool: CursorTool.HAND
  12998. },
  12999. close: true
  13000. }, {
  13001. element: options.scrollPageButton,
  13002. eventName: "switchscrollmode",
  13003. eventDetails: {
  13004. mode: ScrollMode.PAGE
  13005. },
  13006. close: true
  13007. }, {
  13008. element: options.scrollVerticalButton,
  13009. eventName: "switchscrollmode",
  13010. eventDetails: {
  13011. mode: ScrollMode.VERTICAL
  13012. },
  13013. close: true
  13014. }, {
  13015. element: options.scrollHorizontalButton,
  13016. eventName: "switchscrollmode",
  13017. eventDetails: {
  13018. mode: ScrollMode.HORIZONTAL
  13019. },
  13020. close: true
  13021. }, {
  13022. element: options.scrollWrappedButton,
  13023. eventName: "switchscrollmode",
  13024. eventDetails: {
  13025. mode: ScrollMode.WRAPPED
  13026. },
  13027. close: true
  13028. }, {
  13029. element: options.spreadNoneButton,
  13030. eventName: "switchspreadmode",
  13031. eventDetails: {
  13032. mode: SpreadMode.NONE
  13033. },
  13034. close: true
  13035. }, {
  13036. element: options.spreadOddButton,
  13037. eventName: "switchspreadmode",
  13038. eventDetails: {
  13039. mode: SpreadMode.ODD
  13040. },
  13041. close: true
  13042. }, {
  13043. element: options.spreadEvenButton,
  13044. eventName: "switchspreadmode",
  13045. eventDetails: {
  13046. mode: SpreadMode.EVEN
  13047. },
  13048. close: true
  13049. }, {
  13050. element: options.imageAltTextSettingsButton,
  13051. eventName: "imagealttextsettings",
  13052. close: true
  13053. }, {
  13054. element: options.documentPropertiesButton,
  13055. eventName: "documentproperties",
  13056. close: true
  13057. }];
  13058. buttons.push({
  13059. element: options.openFileButton,
  13060. eventName: "openfile",
  13061. close: true
  13062. });
  13063. this.eventBus = eventBus;
  13064. this.opened = false;
  13065. this.#bindListeners(buttons);
  13066. this.reset();
  13067. }
  13068. get isOpen() {
  13069. return this.opened;
  13070. }
  13071. setPageNumber(pageNumber) {
  13072. this.pageNumber = pageNumber;
  13073. this.#updateUIState();
  13074. }
  13075. setPagesCount(pagesCount) {
  13076. this.pagesCount = pagesCount;
  13077. this.#updateUIState();
  13078. }
  13079. reset() {
  13080. this.pageNumber = 0;
  13081. this.pagesCount = 0;
  13082. this.#updateUIState();
  13083. this.eventBus.dispatch("switchcursortool", {
  13084. source: this,
  13085. reset: true
  13086. });
  13087. this.#scrollModeChanged({
  13088. mode: ScrollMode.VERTICAL
  13089. });
  13090. this.#spreadModeChanged({
  13091. mode: SpreadMode.NONE
  13092. });
  13093. }
  13094. #updateUIState() {
  13095. const {
  13096. firstPageButton,
  13097. lastPageButton,
  13098. pageRotateCwButton,
  13099. pageRotateCcwButton
  13100. } = this.#opts;
  13101. firstPageButton.disabled = this.pageNumber <= 1;
  13102. lastPageButton.disabled = this.pageNumber >= this.pagesCount;
  13103. pageRotateCwButton.disabled = this.pagesCount === 0;
  13104. pageRotateCcwButton.disabled = this.pagesCount === 0;
  13105. }
  13106. #bindListeners(buttons) {
  13107. const {
  13108. eventBus
  13109. } = this;
  13110. const {
  13111. toggleButton
  13112. } = this.#opts;
  13113. toggleButton.addEventListener("click", this.toggle.bind(this));
  13114. for (const {
  13115. element,
  13116. eventName,
  13117. close,
  13118. eventDetails
  13119. } of buttons) {
  13120. element.addEventListener("click", evt => {
  13121. if (eventName !== null) {
  13122. eventBus.dispatch(eventName, {
  13123. source: this,
  13124. ...eventDetails
  13125. });
  13126. }
  13127. if (close) {
  13128. this.close();
  13129. }
  13130. eventBus.dispatch("reporttelemetry", {
  13131. source: this,
  13132. details: {
  13133. type: "buttons",
  13134. data: {
  13135. id: element.id
  13136. }
  13137. }
  13138. });
  13139. });
  13140. }
  13141. eventBus._on("cursortoolchanged", this.#cursorToolChanged.bind(this));
  13142. eventBus._on("scrollmodechanged", this.#scrollModeChanged.bind(this));
  13143. eventBus._on("spreadmodechanged", this.#spreadModeChanged.bind(this));
  13144. }
  13145. #cursorToolChanged({
  13146. tool,
  13147. disabled
  13148. }) {
  13149. const {
  13150. cursorSelectToolButton,
  13151. cursorHandToolButton
  13152. } = this.#opts;
  13153. toggleCheckedBtn(cursorSelectToolButton, tool === CursorTool.SELECT);
  13154. toggleCheckedBtn(cursorHandToolButton, tool === CursorTool.HAND);
  13155. cursorSelectToolButton.disabled = disabled;
  13156. cursorHandToolButton.disabled = disabled;
  13157. }
  13158. #scrollModeChanged({
  13159. mode
  13160. }) {
  13161. const {
  13162. scrollPageButton,
  13163. scrollVerticalButton,
  13164. scrollHorizontalButton,
  13165. scrollWrappedButton,
  13166. spreadNoneButton,
  13167. spreadOddButton,
  13168. spreadEvenButton
  13169. } = this.#opts;
  13170. toggleCheckedBtn(scrollPageButton, mode === ScrollMode.PAGE);
  13171. toggleCheckedBtn(scrollVerticalButton, mode === ScrollMode.VERTICAL);
  13172. toggleCheckedBtn(scrollHorizontalButton, mode === ScrollMode.HORIZONTAL);
  13173. toggleCheckedBtn(scrollWrappedButton, mode === ScrollMode.WRAPPED);
  13174. const forceScrollModePage = this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE;
  13175. scrollPageButton.disabled = forceScrollModePage;
  13176. scrollVerticalButton.disabled = forceScrollModePage;
  13177. scrollHorizontalButton.disabled = forceScrollModePage;
  13178. scrollWrappedButton.disabled = forceScrollModePage;
  13179. const isHorizontal = mode === ScrollMode.HORIZONTAL;
  13180. spreadNoneButton.disabled = isHorizontal;
  13181. spreadOddButton.disabled = isHorizontal;
  13182. spreadEvenButton.disabled = isHorizontal;
  13183. }
  13184. #spreadModeChanged({
  13185. mode
  13186. }) {
  13187. const {
  13188. spreadNoneButton,
  13189. spreadOddButton,
  13190. spreadEvenButton
  13191. } = this.#opts;
  13192. toggleCheckedBtn(spreadNoneButton, mode === SpreadMode.NONE);
  13193. toggleCheckedBtn(spreadOddButton, mode === SpreadMode.ODD);
  13194. toggleCheckedBtn(spreadEvenButton, mode === SpreadMode.EVEN);
  13195. }
  13196. open() {
  13197. if (this.opened) {
  13198. return;
  13199. }
  13200. this.opened = true;
  13201. const {
  13202. toggleButton,
  13203. toolbar
  13204. } = this.#opts;
  13205. toggleExpandedBtn(toggleButton, true, toolbar);
  13206. }
  13207. close() {
  13208. if (!this.opened) {
  13209. return;
  13210. }
  13211. this.opened = false;
  13212. const {
  13213. toggleButton,
  13214. toolbar
  13215. } = this.#opts;
  13216. toggleExpandedBtn(toggleButton, false, toolbar);
  13217. }
  13218. toggle() {
  13219. if (this.opened) {
  13220. this.close();
  13221. } else {
  13222. this.open();
  13223. }
  13224. }
  13225. }
  13226. ;// ./web/signature_manager.js
  13227. const DEFAULT_HEIGHT_IN_PAGE = 40;
  13228. class SignatureManager {
  13229. #addButton;
  13230. #tabsToAltText = null;
  13231. #clearButton;
  13232. #clearDescription;
  13233. #currentEditor;
  13234. #description;
  13235. #dialog;
  13236. #drawCurves = null;
  13237. #drawPlaceholder;
  13238. #drawPath = null;
  13239. #drawPathString = "";
  13240. #drawPoints = null;
  13241. #drawSVG;
  13242. #drawThickness;
  13243. #errorBar;
  13244. #extractedSignatureData = null;
  13245. #imagePath = null;
  13246. #imagePicker;
  13247. #imagePickerLink;
  13248. #imagePlaceholder;
  13249. #imageSVG;
  13250. #saveCheckbox;
  13251. #saveContainer;
  13252. #tabButtons;
  13253. #addSignatureToolbarButton;
  13254. #loadSignaturesPromise = null;
  13255. #typeInput;
  13256. #currentTab = null;
  13257. #currentTabAC = null;
  13258. #hasDescriptionChanged = false;
  13259. #eventBus;
  13260. #l10n;
  13261. #overlayManager;
  13262. #editDescriptionDialog;
  13263. #signatureStorage;
  13264. #uiManager = null;
  13265. static #l10nDescription = null;
  13266. constructor({
  13267. dialog,
  13268. panels,
  13269. typeButton,
  13270. typeInput,
  13271. drawButton,
  13272. drawPlaceholder,
  13273. drawSVG,
  13274. drawThickness,
  13275. imageButton,
  13276. imageSVG,
  13277. imagePlaceholder,
  13278. imagePicker,
  13279. imagePickerLink,
  13280. description,
  13281. clearButton,
  13282. cancelButton,
  13283. addButton,
  13284. errorCloseButton,
  13285. errorBar,
  13286. saveCheckbox,
  13287. saveContainer
  13288. }, editSignatureElements, addSignatureToolbarButton, overlayManager, l10n, signatureStorage, eventBus) {
  13289. this.#addButton = addButton;
  13290. this.#clearButton = clearButton;
  13291. this.#clearDescription = description.lastElementChild;
  13292. this.#description = description.firstElementChild;
  13293. this.#dialog = dialog;
  13294. this.#drawSVG = drawSVG;
  13295. this.#drawPlaceholder = drawPlaceholder;
  13296. this.#drawThickness = drawThickness;
  13297. this.#errorBar = errorBar;
  13298. this.#imageSVG = imageSVG;
  13299. this.#imagePlaceholder = imagePlaceholder;
  13300. this.#imagePicker = imagePicker;
  13301. this.#imagePickerLink = imagePickerLink;
  13302. this.#overlayManager = overlayManager;
  13303. this.#saveCheckbox = saveCheckbox;
  13304. this.#saveContainer = saveContainer;
  13305. this.#addSignatureToolbarButton = addSignatureToolbarButton;
  13306. this.#typeInput = typeInput;
  13307. this.#l10n = l10n;
  13308. this.#signatureStorage = signatureStorage;
  13309. this.#eventBus = eventBus;
  13310. this.#editDescriptionDialog = new EditDescriptionDialog(editSignatureElements, overlayManager);
  13311. SignatureManager.#l10nDescription ||= Object.freeze({
  13312. signature: "pdfjs-editor-add-signature-description-default-when-drawing"
  13313. });
  13314. dialog.addEventListener("close", this.#close.bind(this));
  13315. dialog.addEventListener("contextmenu", e => {
  13316. const {
  13317. target
  13318. } = e;
  13319. if (target !== this.#typeInput && target !== this.#description) {
  13320. e.preventDefault();
  13321. }
  13322. });
  13323. dialog.addEventListener("drop", e => {
  13324. stopEvent(e);
  13325. });
  13326. cancelButton.addEventListener("click", this.#cancel.bind(this));
  13327. addButton.addEventListener("click", this.#add.bind(this));
  13328. clearButton.addEventListener("click", () => {
  13329. this.#reportTelemetry({
  13330. type: "signature",
  13331. action: "pdfjs.signature.clear",
  13332. data: {
  13333. type: this.#currentTab
  13334. }
  13335. });
  13336. this.#initTab(null);
  13337. }, {
  13338. passive: true
  13339. });
  13340. this.#description.addEventListener("input", () => {
  13341. this.#clearDescription.disabled = this.#description.value === "";
  13342. }, {
  13343. passive: true
  13344. });
  13345. this.#clearDescription.addEventListener("click", () => {
  13346. this.#description.value = "";
  13347. this.#clearDescription.disabled = true;
  13348. }, {
  13349. passive: true
  13350. });
  13351. errorCloseButton.addEventListener("click", () => {
  13352. errorBar.hidden = true;
  13353. }, {
  13354. passive: true
  13355. });
  13356. this.#initTabButtons(typeButton, drawButton, imageButton, panels);
  13357. imagePicker.accept = SupportedImageMimeTypes.join(",");
  13358. eventBus._on("storedsignatureschanged", this.#signaturesChanged.bind(this));
  13359. overlayManager.register(dialog);
  13360. }
  13361. #initTabButtons(typeButton, drawButton, imageButton, panels) {
  13362. const buttons = this.#tabButtons = new Map([["type", typeButton], ["draw", drawButton], ["image", imageButton]]);
  13363. const tabCallback = e => {
  13364. for (const [name, button] of buttons) {
  13365. if (button === e.target) {
  13366. button.setAttribute("aria-selected", true);
  13367. button.setAttribute("tabindex", 0);
  13368. panels.setAttribute("data-selected", name);
  13369. this.#initTab(name);
  13370. } else {
  13371. button.setAttribute("aria-selected", false);
  13372. button.setAttribute("tabindex", -1);
  13373. }
  13374. }
  13375. };
  13376. const buttonsArray = Array.from(buttons.values());
  13377. for (let i = 0, ii = buttonsArray.length; i < ii; i++) {
  13378. const button = buttonsArray[i];
  13379. button.addEventListener("click", tabCallback, {
  13380. passive: true
  13381. });
  13382. button.addEventListener("keydown", ({
  13383. key
  13384. }) => {
  13385. if (key !== "ArrowLeft" && key !== "ArrowRight") {
  13386. return;
  13387. }
  13388. buttonsArray[i + (key === "ArrowLeft" ? -1 : 1)]?.focus();
  13389. }, {
  13390. passive: true
  13391. });
  13392. }
  13393. }
  13394. #resetCommon() {
  13395. this.#hasDescriptionChanged = false;
  13396. this.#description.value = "";
  13397. if (this.#currentTab) {
  13398. this.#tabsToAltText.get(this.#currentTab).value = "";
  13399. }
  13400. }
  13401. #resetTab(name) {
  13402. switch (name) {
  13403. case "type":
  13404. this.#typeInput.value = "";
  13405. break;
  13406. case "draw":
  13407. this.#drawCurves = null;
  13408. this.#drawPoints = null;
  13409. this.#drawPathString = "";
  13410. this.#drawPath?.remove();
  13411. this.#drawPath = null;
  13412. this.#drawPlaceholder.hidden = false;
  13413. this.#drawThickness.value = 1;
  13414. break;
  13415. case "image":
  13416. this.#imagePlaceholder.hidden = false;
  13417. this.#imagePath?.remove();
  13418. this.#imagePath = null;
  13419. break;
  13420. }
  13421. }
  13422. #initTab(name) {
  13423. if (name && this.#currentTab === name) {
  13424. return;
  13425. }
  13426. if (this.#currentTab) {
  13427. this.#tabsToAltText.get(this.#currentTab).value = this.#description.value;
  13428. }
  13429. if (name) {
  13430. this.#currentTab = name;
  13431. }
  13432. this.#errorBar.hidden = true;
  13433. const reset = !name;
  13434. if (reset) {
  13435. this.#resetCommon();
  13436. } else {
  13437. this.#description.value = this.#tabsToAltText.get(this.#currentTab).value;
  13438. }
  13439. this.#clearDescription.disabled = this.#description.value === "";
  13440. this.#currentTabAC?.abort();
  13441. this.#currentTabAC = new AbortController();
  13442. switch (this.#currentTab) {
  13443. case "type":
  13444. this.#initTypeTab(reset);
  13445. break;
  13446. case "draw":
  13447. this.#initDrawTab(reset);
  13448. break;
  13449. case "image":
  13450. this.#initImageTab(reset);
  13451. break;
  13452. }
  13453. }
  13454. #disableButtons(value) {
  13455. this.#saveCheckbox.disabled = this.#clearButton.disabled = this.#addButton.disabled = this.#description.disabled = !value;
  13456. }
  13457. #initTypeTab(reset) {
  13458. if (reset) {
  13459. this.#resetTab("type");
  13460. }
  13461. this.#disableButtons(this.#typeInput.value);
  13462. const {
  13463. signal
  13464. } = this.#currentTabAC;
  13465. const options = {
  13466. passive: true,
  13467. signal
  13468. };
  13469. this.#typeInput.addEventListener("input", () => {
  13470. const {
  13471. value
  13472. } = this.#typeInput;
  13473. if (!this.#hasDescriptionChanged) {
  13474. this.#tabsToAltText.get("type").default = this.#description.value = value;
  13475. this.#clearDescription.disabled = value === "";
  13476. }
  13477. this.#disableButtons(value);
  13478. }, options);
  13479. this.#description.addEventListener("input", () => {
  13480. this.#hasDescriptionChanged = this.#typeInput.value !== this.#description.value;
  13481. }, options);
  13482. }
  13483. #initDrawTab(reset) {
  13484. if (reset) {
  13485. this.#resetTab("draw");
  13486. }
  13487. this.#disableButtons(this.#drawPath);
  13488. const {
  13489. signal
  13490. } = this.#currentTabAC;
  13491. const options = {
  13492. signal
  13493. };
  13494. let currentPointerId = NaN;
  13495. const drawCallback = e => {
  13496. const {
  13497. pointerId
  13498. } = e;
  13499. if (!isNaN(currentPointerId) && currentPointerId !== pointerId) {
  13500. return;
  13501. }
  13502. currentPointerId = pointerId;
  13503. e.preventDefault();
  13504. this.#drawSVG.setPointerCapture(pointerId);
  13505. const {
  13506. width: drawWidth,
  13507. height: drawHeight
  13508. } = this.#drawSVG.getBoundingClientRect();
  13509. let {
  13510. offsetX,
  13511. offsetY
  13512. } = e;
  13513. offsetX = Math.round(offsetX);
  13514. offsetY = Math.round(offsetY);
  13515. if (e.target === this.#drawPlaceholder) {
  13516. this.#drawPlaceholder.hidden = true;
  13517. }
  13518. if (!this.#drawCurves) {
  13519. this.#drawCurves = {
  13520. width: drawWidth,
  13521. height: drawHeight,
  13522. thickness: parseInt(this.#drawThickness.value),
  13523. curves: []
  13524. };
  13525. this.#disableButtons(true);
  13526. const svgFactory = new DOMSVGFactory();
  13527. const path = this.#drawPath = svgFactory.createElement("path");
  13528. path.setAttribute("stroke-width", this.#drawThickness.value);
  13529. this.#drawSVG.append(path);
  13530. this.#drawSVG.addEventListener("pointerdown", drawCallback, options);
  13531. this.#drawPlaceholder.removeEventListener("pointerdown", drawCallback);
  13532. if (this.#description.value === "") {
  13533. this.#l10n.get(SignatureManager.#l10nDescription.signature).then(description => {
  13534. this.#tabsToAltText.get("draw").default = description;
  13535. this.#description.value ||= description;
  13536. this.#clearDescription.disabled = this.#description.value === "";
  13537. });
  13538. }
  13539. }
  13540. this.#drawPoints = [offsetX, offsetY];
  13541. this.#drawCurves.curves.push({
  13542. points: this.#drawPoints
  13543. });
  13544. this.#drawPathString += `M ${offsetX} ${offsetY}`;
  13545. this.#drawPath.setAttribute("d", this.#drawPathString);
  13546. const finishDrawAC = new AbortController();
  13547. const listenerDrawOptions = {
  13548. signal: AbortSignal.any([signal, finishDrawAC.signal])
  13549. };
  13550. this.#drawSVG.addEventListener("contextmenu", noContextMenu, listenerDrawOptions);
  13551. this.#drawSVG.addEventListener("pointermove", evt => {
  13552. evt.preventDefault();
  13553. let {
  13554. offsetX: x,
  13555. offsetY: y
  13556. } = evt;
  13557. x = Math.round(x);
  13558. y = Math.round(y);
  13559. const drawPoints = this.#drawPoints;
  13560. if (x < 0 || y < 0 || x > drawWidth || y > drawHeight || x === drawPoints.at(-2) && y === drawPoints.at(-1)) {
  13561. return;
  13562. }
  13563. if (drawPoints.length >= 4) {
  13564. const [x1, y1, x2, y2] = drawPoints.slice(-4);
  13565. this.#drawPathString += `C${(x1 + 5 * x2) / 6} ${(y1 + 5 * y2) / 6} ${(5 * x2 + x) / 6} ${(5 * y2 + y) / 6} ${(x2 + x) / 2} ${(y2 + y) / 2}`;
  13566. } else {
  13567. this.#drawPathString += `L${x} ${y}`;
  13568. }
  13569. drawPoints.push(x, y);
  13570. this.#drawPath.setAttribute("d", this.#drawPathString);
  13571. }, listenerDrawOptions);
  13572. this.#drawSVG.addEventListener("pointerup", evt => {
  13573. const {
  13574. pointerId: pId
  13575. } = evt;
  13576. if (!isNaN(currentPointerId) && currentPointerId !== pId) {
  13577. return;
  13578. }
  13579. currentPointerId = NaN;
  13580. evt.preventDefault();
  13581. this.#drawSVG.releasePointerCapture(pId);
  13582. finishDrawAC.abort();
  13583. if (this.#drawPoints.length === 2) {
  13584. this.#drawPathString += `L${this.#drawPoints[0]} ${this.#drawPoints[1]}`;
  13585. this.#drawPath.setAttribute("d", this.#drawPathString);
  13586. }
  13587. }, listenerDrawOptions);
  13588. };
  13589. if (this.#drawCurves) {
  13590. this.#drawSVG.addEventListener("pointerdown", drawCallback, options);
  13591. } else {
  13592. this.#drawPlaceholder.addEventListener("pointerdown", drawCallback, options);
  13593. }
  13594. this.#drawThickness.addEventListener("input", () => {
  13595. const {
  13596. value: thickness
  13597. } = this.#drawThickness;
  13598. this.#drawThickness.setAttribute("data-l10n-args", JSON.stringify({
  13599. thickness
  13600. }));
  13601. if (!this.#drawCurves) {
  13602. return;
  13603. }
  13604. this.#drawPath.setAttribute("stroke-width", thickness);
  13605. this.#drawCurves.thickness = thickness;
  13606. }, options);
  13607. }
  13608. #initImageTab(reset) {
  13609. if (reset) {
  13610. this.#resetTab("image");
  13611. }
  13612. this.#disableButtons(this.#imagePath);
  13613. const {
  13614. signal
  13615. } = this.#currentTabAC;
  13616. const options = {
  13617. signal
  13618. };
  13619. const passiveOptions = {
  13620. passive: true,
  13621. signal
  13622. };
  13623. this.#imagePickerLink.addEventListener("keydown", e => {
  13624. const {
  13625. key
  13626. } = e;
  13627. if (key === "Enter" || key === " ") {
  13628. stopEvent(e);
  13629. this.#imagePicker.click();
  13630. }
  13631. }, options);
  13632. this.#imagePicker.addEventListener("click", () => {
  13633. this.#dialog.classList.toggle("waiting", true);
  13634. }, passiveOptions);
  13635. this.#imagePicker.addEventListener("change", async () => {
  13636. const file = this.#imagePicker.files?.[0];
  13637. if (!file || !SupportedImageMimeTypes.includes(file.type)) {
  13638. this.#errorBar.hidden = false;
  13639. this.#dialog.classList.toggle("waiting", false);
  13640. return;
  13641. }
  13642. await this.#extractSignature(file);
  13643. }, passiveOptions);
  13644. this.#imagePicker.addEventListener("cancel", () => {
  13645. this.#dialog.classList.toggle("waiting", false);
  13646. }, passiveOptions);
  13647. this.#imagePlaceholder.addEventListener("dragover", e => {
  13648. const {
  13649. dataTransfer
  13650. } = e;
  13651. for (const {
  13652. type
  13653. } of dataTransfer.items) {
  13654. if (!SupportedImageMimeTypes.includes(type)) {
  13655. continue;
  13656. }
  13657. dataTransfer.dropEffect = dataTransfer.effectAllowed === "copy" ? "copy" : "move";
  13658. stopEvent(e);
  13659. return;
  13660. }
  13661. dataTransfer.dropEffect = "none";
  13662. }, options);
  13663. this.#imagePlaceholder.addEventListener("drop", e => {
  13664. const {
  13665. dataTransfer: {
  13666. files
  13667. }
  13668. } = e;
  13669. if (!files?.length) {
  13670. return;
  13671. }
  13672. for (const file of files) {
  13673. if (SupportedImageMimeTypes.includes(file.type)) {
  13674. this.#extractSignature(file);
  13675. break;
  13676. }
  13677. }
  13678. stopEvent(e);
  13679. this.#dialog.classList.toggle("waiting", true);
  13680. }, options);
  13681. }
  13682. async #extractSignature(file) {
  13683. let data;
  13684. try {
  13685. data = await this.#uiManager.imageManager.getFromFile(file);
  13686. } catch (e) {
  13687. console.error("SignatureManager.#extractSignature.", e);
  13688. }
  13689. if (!data) {
  13690. this.#errorBar.hidden = false;
  13691. this.#dialog.classList.toggle("waiting", false);
  13692. return;
  13693. }
  13694. const {
  13695. outline
  13696. } = this.#extractedSignatureData = this.#currentEditor.getFromImage(data.bitmap);
  13697. if (!outline) {
  13698. this.#dialog.classList.toggle("waiting", false);
  13699. return;
  13700. }
  13701. this.#imagePlaceholder.hidden = true;
  13702. this.#disableButtons(true);
  13703. const svgFactory = new DOMSVGFactory();
  13704. const path = this.#imagePath = svgFactory.createElement("path");
  13705. this.#imageSVG.setAttribute("viewBox", outline.viewBox);
  13706. this.#imageSVG.setAttribute("preserveAspectRatio", "xMidYMid meet");
  13707. this.#imageSVG.append(path);
  13708. path.setAttribute("d", outline.toSVGPath());
  13709. this.#tabsToAltText.get("image").default = file.name;
  13710. if (this.#description.value === "") {
  13711. this.#description.value = file.name || "";
  13712. this.#clearDescription.disabled = this.#description.value === "";
  13713. }
  13714. this.#dialog.classList.toggle("waiting", false);
  13715. }
  13716. #getOutlineForType() {
  13717. return this.#currentEditor.getFromText(this.#typeInput.value, window.getComputedStyle(this.#typeInput));
  13718. }
  13719. #getOutlineForDraw() {
  13720. const {
  13721. width,
  13722. height
  13723. } = this.#drawSVG.getBoundingClientRect();
  13724. return this.#currentEditor.getDrawnSignature(this.#drawCurves, width, height);
  13725. }
  13726. #reportTelemetry(data) {
  13727. this.#eventBus.dispatch("reporttelemetry", {
  13728. source: this,
  13729. details: {
  13730. type: "editing",
  13731. data
  13732. }
  13733. });
  13734. }
  13735. #addToolbarButton(signatureData, uuid, description) {
  13736. const {
  13737. curves,
  13738. areContours,
  13739. thickness,
  13740. width,
  13741. height
  13742. } = signatureData;
  13743. const maxDim = Math.max(width, height);
  13744. const outlineData = SignatureExtractor.processDrawnLines({
  13745. lines: {
  13746. curves,
  13747. thickness,
  13748. width,
  13749. height
  13750. },
  13751. pageWidth: maxDim,
  13752. pageHeight: maxDim,
  13753. rotation: 0,
  13754. innerMargin: 0,
  13755. mustSmooth: false,
  13756. areContours
  13757. });
  13758. if (!outlineData) {
  13759. return;
  13760. }
  13761. const {
  13762. outline
  13763. } = outlineData;
  13764. const svgFactory = new DOMSVGFactory();
  13765. const div = document.createElement("div");
  13766. const button = document.createElement("button");
  13767. button.addEventListener("click", () => {
  13768. this.#eventBus.dispatch("switchannotationeditorparams", {
  13769. source: this,
  13770. type: AnnotationEditorParamsType.CREATE,
  13771. value: {
  13772. signatureData: {
  13773. lines: {
  13774. curves,
  13775. thickness,
  13776. width,
  13777. height
  13778. },
  13779. mustSmooth: false,
  13780. areContours,
  13781. description,
  13782. uuid,
  13783. heightInPage: DEFAULT_HEIGHT_IN_PAGE
  13784. }
  13785. }
  13786. });
  13787. });
  13788. div.append(button);
  13789. div.classList.add("toolbarAddSignatureButtonContainer");
  13790. const svg = svgFactory.create(1, 1, true);
  13791. button.append(svg);
  13792. const span = document.createElement("span");
  13793. span.ariaHidden = true;
  13794. button.append(span);
  13795. button.classList.add("toolbarAddSignatureButton");
  13796. button.type = "button";
  13797. span.textContent = description;
  13798. button.setAttribute("data-l10n-id", "pdfjs-editor-add-saved-signature-button");
  13799. button.setAttribute("data-l10n-args", JSON.stringify({
  13800. description
  13801. }));
  13802. button.tabIndex = 0;
  13803. const path = svgFactory.createElement("path");
  13804. svg.append(path);
  13805. svg.setAttribute("viewBox", outline.viewBox);
  13806. svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
  13807. if (areContours) {
  13808. path.classList.add("contours");
  13809. }
  13810. path.setAttribute("d", outline.toSVGPath());
  13811. const deleteButton = document.createElement("button");
  13812. div.append(deleteButton);
  13813. deleteButton.classList.add("toolbarButton", "deleteButton");
  13814. deleteButton.setAttribute("data-l10n-id", "pdfjs-editor-delete-signature-button1");
  13815. deleteButton.type = "button";
  13816. deleteButton.tabIndex = 0;
  13817. deleteButton.addEventListener("click", async () => {
  13818. if (await this.#signatureStorage.delete(uuid)) {
  13819. div.remove();
  13820. this.#reportTelemetry({
  13821. type: "signature",
  13822. action: "pdfjs.signature.delete_saved",
  13823. data: {
  13824. savedCount: await this.#signatureStorage.size()
  13825. }
  13826. });
  13827. }
  13828. });
  13829. const deleteSpan = document.createElement("span");
  13830. deleteButton.append(deleteSpan);
  13831. deleteSpan.setAttribute("data-l10n-id", "pdfjs-editor-delete-signature-button-label1");
  13832. this.#addSignatureToolbarButton.before(div);
  13833. }
  13834. async #signaturesChanged() {
  13835. const parent = this.#addSignatureToolbarButton.parentElement;
  13836. while (parent.firstElementChild !== this.#addSignatureToolbarButton) {
  13837. parent.firstElementChild.remove();
  13838. }
  13839. this.#loadSignaturesPromise = null;
  13840. await this.loadSignatures(true);
  13841. }
  13842. getSignature(params) {
  13843. return this.open(params);
  13844. }
  13845. async loadSignatures(reload = false) {
  13846. if (!this.#addSignatureToolbarButton || !reload && this.#addSignatureToolbarButton.previousElementSibling || !this.#signatureStorage) {
  13847. return;
  13848. }
  13849. if (!this.#loadSignaturesPromise) {
  13850. this.#loadSignaturesPromise = this.#signatureStorage.getAll().then(async signatures => [signatures, await Promise.all(Array.from(signatures.values(), ({
  13851. signatureData
  13852. }) => SignatureExtractor.decompressSignature(signatureData)))]);
  13853. if (!reload) {
  13854. return;
  13855. }
  13856. }
  13857. const [signatures, signaturesData] = await this.#loadSignaturesPromise;
  13858. this.#loadSignaturesPromise = null;
  13859. let i = 0;
  13860. for (const [uuid, {
  13861. description
  13862. }] of signatures) {
  13863. const data = signaturesData[i++];
  13864. if (!data) {
  13865. continue;
  13866. }
  13867. data.curves = data.outlines.map(points => ({
  13868. points
  13869. }));
  13870. delete data.outlines;
  13871. this.#addToolbarButton(data, uuid, description);
  13872. }
  13873. }
  13874. async renderEditButton(editor) {
  13875. const button = document.createElement("button");
  13876. button.classList.add("altText", "editDescription");
  13877. button.tabIndex = 0;
  13878. button.title = editor.description;
  13879. const span = document.createElement("span");
  13880. button.append(span);
  13881. span.setAttribute("data-l10n-id", "pdfjs-editor-add-signature-edit-button-label");
  13882. button.addEventListener("click", () => {
  13883. this.#editDescriptionDialog.open(editor);
  13884. }, {
  13885. passive: true
  13886. });
  13887. return button;
  13888. }
  13889. async open({
  13890. uiManager,
  13891. editor
  13892. }) {
  13893. this.#tabsToAltText ||= new Map(this.#tabButtons.keys().map(name => [name, {
  13894. value: "",
  13895. default: ""
  13896. }]));
  13897. this.#uiManager = uiManager;
  13898. this.#currentEditor = editor;
  13899. this.#uiManager.removeEditListeners();
  13900. const isStorageFull = await this.#signatureStorage.isFull();
  13901. this.#saveContainer.classList.toggle("fullStorage", isStorageFull);
  13902. this.#saveCheckbox.checked = !isStorageFull;
  13903. await this.#overlayManager.open(this.#dialog);
  13904. const tabType = this.#tabButtons.get("type");
  13905. tabType.focus();
  13906. tabType.click();
  13907. }
  13908. #cancel() {
  13909. this.#finish();
  13910. }
  13911. #finish() {
  13912. this.#overlayManager.closeIfActive(this.#dialog);
  13913. }
  13914. #close() {
  13915. if (this.#currentEditor._drawId === null) {
  13916. this.#currentEditor.remove();
  13917. }
  13918. this.#uiManager?.addEditListeners();
  13919. this.#currentTabAC?.abort();
  13920. this.#currentTabAC = null;
  13921. this.#uiManager = null;
  13922. this.#currentEditor = null;
  13923. this.#resetCommon();
  13924. for (const [name] of this.#tabButtons) {
  13925. this.#resetTab(name);
  13926. }
  13927. this.#disableButtons(false);
  13928. this.#currentTab = null;
  13929. this.#tabsToAltText = null;
  13930. }
  13931. async #add() {
  13932. let data;
  13933. const type = this.#currentTab;
  13934. switch (type) {
  13935. case "type":
  13936. data = this.#getOutlineForType();
  13937. break;
  13938. case "draw":
  13939. data = this.#getOutlineForDraw();
  13940. break;
  13941. case "image":
  13942. data = this.#extractedSignatureData;
  13943. break;
  13944. }
  13945. let uuid = null;
  13946. const description = this.#description.value;
  13947. if (this.#saveCheckbox.checked) {
  13948. const {
  13949. newCurves,
  13950. areContours,
  13951. thickness,
  13952. width,
  13953. height
  13954. } = data;
  13955. const signatureData = await SignatureExtractor.compressSignature({
  13956. outlines: newCurves,
  13957. areContours,
  13958. thickness,
  13959. width,
  13960. height
  13961. });
  13962. uuid = await this.#signatureStorage.create({
  13963. description,
  13964. signatureData
  13965. });
  13966. if (uuid) {
  13967. this.#addToolbarButton({
  13968. curves: newCurves.map(points => ({
  13969. points
  13970. })),
  13971. areContours,
  13972. thickness,
  13973. width,
  13974. height
  13975. }, uuid, description);
  13976. } else {
  13977. console.warn("SignatureManager.add: cannot save the signature.");
  13978. }
  13979. }
  13980. const altText = this.#tabsToAltText.get(type);
  13981. this.#reportTelemetry({
  13982. type: "signature",
  13983. action: "pdfjs.signature.created",
  13984. data: {
  13985. type,
  13986. saved: !!uuid,
  13987. savedCount: await this.#signatureStorage.size(),
  13988. descriptionChanged: description !== altText.default
  13989. }
  13990. });
  13991. this.#currentEditor.addSignature(data, DEFAULT_HEIGHT_IN_PAGE, this.#description.value, uuid);
  13992. this.#finish();
  13993. }
  13994. destroy() {
  13995. this.#uiManager = null;
  13996. this.#finish();
  13997. }
  13998. }
  13999. class EditDescriptionDialog {
  14000. #currentEditor;
  14001. #previousDescription;
  14002. #description;
  14003. #dialog;
  14004. #overlayManager;
  14005. #signatureSVG;
  14006. #uiManager;
  14007. constructor({
  14008. dialog,
  14009. description,
  14010. cancelButton,
  14011. updateButton,
  14012. editSignatureView
  14013. }, overlayManager) {
  14014. const descriptionInput = this.#description = description.firstElementChild;
  14015. this.#signatureSVG = editSignatureView;
  14016. this.#dialog = dialog;
  14017. this.#overlayManager = overlayManager;
  14018. dialog.addEventListener("close", this.#close.bind(this));
  14019. dialog.addEventListener("contextmenu", e => {
  14020. if (e.target !== this.#description) {
  14021. e.preventDefault();
  14022. }
  14023. });
  14024. cancelButton.addEventListener("click", this.#cancel.bind(this));
  14025. updateButton.addEventListener("click", this.#update.bind(this));
  14026. const clearDescription = description.lastElementChild;
  14027. clearDescription.addEventListener("click", () => {
  14028. descriptionInput.value = "";
  14029. clearDescription.disabled = true;
  14030. updateButton.disabled = this.#previousDescription === "";
  14031. });
  14032. descriptionInput.addEventListener("input", () => {
  14033. const {
  14034. value
  14035. } = descriptionInput;
  14036. clearDescription.disabled = value === "";
  14037. updateButton.disabled = value === this.#previousDescription;
  14038. editSignatureView.setAttribute("aria-label", value);
  14039. }, {
  14040. passive: true
  14041. });
  14042. overlayManager.register(dialog);
  14043. }
  14044. async open(editor) {
  14045. this.#uiManager = editor._uiManager;
  14046. this.#currentEditor = editor;
  14047. this.#previousDescription = this.#description.value = editor.description;
  14048. this.#description.dispatchEvent(new Event("input"));
  14049. this.#uiManager.removeEditListeners();
  14050. const {
  14051. areContours,
  14052. outline
  14053. } = editor.getSignaturePreview();
  14054. const svgFactory = new DOMSVGFactory();
  14055. const path = svgFactory.createElement("path");
  14056. this.#signatureSVG.append(path);
  14057. this.#signatureSVG.setAttribute("viewBox", outline.viewBox);
  14058. path.setAttribute("d", outline.toSVGPath());
  14059. if (areContours) {
  14060. path.classList.add("contours");
  14061. }
  14062. await this.#overlayManager.open(this.#dialog);
  14063. }
  14064. async #update() {
  14065. this.#currentEditor._reportTelemetry({
  14066. action: "pdfjs.signature.edit_description",
  14067. data: {
  14068. hasBeenChanged: true
  14069. }
  14070. });
  14071. this.#currentEditor.description = this.#description.value;
  14072. this.#finish();
  14073. }
  14074. #cancel() {
  14075. this.#currentEditor._reportTelemetry({
  14076. action: "pdfjs.signature.edit_description",
  14077. data: {
  14078. hasBeenChanged: false
  14079. }
  14080. });
  14081. this.#finish();
  14082. }
  14083. #finish() {
  14084. this.#overlayManager.closeIfActive(this.#dialog);
  14085. }
  14086. #close() {
  14087. this.#uiManager?.addEditListeners();
  14088. this.#uiManager = null;
  14089. this.#currentEditor = null;
  14090. this.#signatureSVG.firstElementChild.remove();
  14091. }
  14092. }
  14093. ;// ./web/toolbar.js
  14094. class Toolbar {
  14095. #colorPicker = null;
  14096. #opts;
  14097. constructor(options, eventBus, toolbarDensity = 0) {
  14098. this.#opts = options;
  14099. this.eventBus = eventBus;
  14100. const buttons = [{
  14101. element: options.previous,
  14102. eventName: "previouspage"
  14103. }, {
  14104. element: options.next,
  14105. eventName: "nextpage"
  14106. }, {
  14107. element: options.zoomIn,
  14108. eventName: "zoomin"
  14109. }, {
  14110. element: options.zoomOut,
  14111. eventName: "zoomout"
  14112. }, {
  14113. element: options.print,
  14114. eventName: "print"
  14115. }, {
  14116. element: options.download,
  14117. eventName: "download"
  14118. }, {
  14119. element: options.editorFreeTextButton,
  14120. eventName: "switchannotationeditormode",
  14121. eventDetails: {
  14122. get mode() {
  14123. const {
  14124. classList
  14125. } = options.editorFreeTextButton;
  14126. return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.FREETEXT;
  14127. }
  14128. }
  14129. }, {
  14130. element: options.editorHighlightButton,
  14131. eventName: "switchannotationeditormode",
  14132. eventDetails: {
  14133. get mode() {
  14134. const {
  14135. classList
  14136. } = options.editorHighlightButton;
  14137. return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.HIGHLIGHT;
  14138. }
  14139. }
  14140. }, {
  14141. element: options.editorInkButton,
  14142. eventName: "switchannotationeditormode",
  14143. eventDetails: {
  14144. get mode() {
  14145. const {
  14146. classList
  14147. } = options.editorInkButton;
  14148. return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.INK;
  14149. }
  14150. }
  14151. }, {
  14152. element: options.editorStampButton,
  14153. eventName: "switchannotationeditormode",
  14154. eventDetails: {
  14155. get mode() {
  14156. const {
  14157. classList
  14158. } = options.editorStampButton;
  14159. return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.STAMP;
  14160. }
  14161. },
  14162. telemetry: {
  14163. type: "editing",
  14164. data: {
  14165. action: "pdfjs.image.icon_click"
  14166. }
  14167. }
  14168. }, {
  14169. element: options.editorSignatureButton,
  14170. eventName: "switchannotationeditormode",
  14171. eventDetails: {
  14172. get mode() {
  14173. const {
  14174. classList
  14175. } = options.editorSignatureButton;
  14176. return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.SIGNATURE;
  14177. }
  14178. }
  14179. }];
  14180. this.#bindListeners(buttons);
  14181. this.#updateToolbarDensity({
  14182. value: toolbarDensity
  14183. });
  14184. this.reset();
  14185. }
  14186. #updateToolbarDensity({
  14187. value
  14188. }) {
  14189. let name = "normal";
  14190. switch (value) {
  14191. case 1:
  14192. name = "compact";
  14193. break;
  14194. case 2:
  14195. name = "touch";
  14196. break;
  14197. }
  14198. document.documentElement.setAttribute("data-toolbar-density", name);
  14199. }
  14200. setPageNumber(pageNumber, pageLabel) {
  14201. this.pageNumber = pageNumber;
  14202. this.pageLabel = pageLabel;
  14203. this.#updateUIState(false);
  14204. }
  14205. setPagesCount(pagesCount, hasPageLabels) {
  14206. this.pagesCount = pagesCount;
  14207. this.hasPageLabels = hasPageLabels;
  14208. this.#updateUIState(true);
  14209. }
  14210. setPageScale(pageScaleValue, pageScale) {
  14211. this.pageScaleValue = (pageScaleValue || pageScale).toString();
  14212. this.pageScale = pageScale;
  14213. this.#updateUIState(false);
  14214. }
  14215. reset() {
  14216. this.#colorPicker = null;
  14217. this.pageNumber = 0;
  14218. this.pageLabel = null;
  14219. this.hasPageLabels = false;
  14220. this.pagesCount = 0;
  14221. this.pageScaleValue = DEFAULT_SCALE_VALUE;
  14222. this.pageScale = DEFAULT_SCALE;
  14223. this.#updateUIState(true);
  14224. this.updateLoadingIndicatorState();
  14225. this.#editorModeChanged({
  14226. mode: AnnotationEditorType.DISABLE
  14227. });
  14228. }
  14229. #bindListeners(buttons) {
  14230. const {
  14231. eventBus
  14232. } = this;
  14233. const {
  14234. editorHighlightColorPicker,
  14235. editorHighlightButton,
  14236. pageNumber,
  14237. scaleSelect
  14238. } = this.#opts;
  14239. const self = this;
  14240. for (const {
  14241. element,
  14242. eventName,
  14243. eventDetails,
  14244. telemetry
  14245. } of buttons) {
  14246. element.addEventListener("click", evt => {
  14247. if (eventName !== null) {
  14248. eventBus.dispatch(eventName, {
  14249. source: this,
  14250. ...eventDetails,
  14251. isFromKeyboard: evt.detail === 0
  14252. });
  14253. }
  14254. if (telemetry) {
  14255. eventBus.dispatch("reporttelemetry", {
  14256. source: this,
  14257. details: telemetry
  14258. });
  14259. }
  14260. });
  14261. }
  14262. pageNumber.addEventListener("click", function () {
  14263. this.select();
  14264. });
  14265. pageNumber.addEventListener("change", function () {
  14266. eventBus.dispatch("pagenumberchanged", {
  14267. source: self,
  14268. value: this.value
  14269. });
  14270. });
  14271. scaleSelect.addEventListener("change", function () {
  14272. if (this.value === "custom") {
  14273. return;
  14274. }
  14275. eventBus.dispatch("scalechanged", {
  14276. source: self,
  14277. value: this.value
  14278. });
  14279. });
  14280. scaleSelect.addEventListener("click", function ({
  14281. target
  14282. }) {
  14283. if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") {
  14284. this.blur();
  14285. }
  14286. });
  14287. scaleSelect.oncontextmenu = noContextMenu;
  14288. eventBus._on("annotationeditormodechanged", this.#editorModeChanged.bind(this));
  14289. eventBus._on("showannotationeditorui", ({
  14290. mode
  14291. }) => {
  14292. switch (mode) {
  14293. case AnnotationEditorType.HIGHLIGHT:
  14294. editorHighlightButton.click();
  14295. break;
  14296. }
  14297. });
  14298. eventBus._on("toolbardensity", this.#updateToolbarDensity.bind(this));
  14299. if (editorHighlightColorPicker) {
  14300. eventBus._on("annotationeditoruimanager", ({
  14301. uiManager
  14302. }) => {
  14303. const cp = this.#colorPicker = new ColorPicker({
  14304. uiManager
  14305. });
  14306. uiManager.setMainHighlightColorPicker(cp);
  14307. editorHighlightColorPicker.append(cp.renderMainDropdown());
  14308. });
  14309. eventBus._on("mainhighlightcolorpickerupdatecolor", ({
  14310. value
  14311. }) => {
  14312. this.#colorPicker?.updateColor(value);
  14313. });
  14314. }
  14315. }
  14316. #editorModeChanged({
  14317. mode
  14318. }) {
  14319. const {
  14320. editorFreeTextButton,
  14321. editorFreeTextParamsToolbar,
  14322. editorHighlightButton,
  14323. editorHighlightParamsToolbar,
  14324. editorInkButton,
  14325. editorInkParamsToolbar,
  14326. editorStampButton,
  14327. editorStampParamsToolbar,
  14328. editorSignatureButton,
  14329. editorSignatureParamsToolbar
  14330. } = this.#opts;
  14331. toggleExpandedBtn(editorFreeTextButton, mode === AnnotationEditorType.FREETEXT, editorFreeTextParamsToolbar);
  14332. toggleExpandedBtn(editorHighlightButton, mode === AnnotationEditorType.HIGHLIGHT, editorHighlightParamsToolbar);
  14333. toggleExpandedBtn(editorInkButton, mode === AnnotationEditorType.INK, editorInkParamsToolbar);
  14334. toggleExpandedBtn(editorStampButton, mode === AnnotationEditorType.STAMP, editorStampParamsToolbar);
  14335. toggleExpandedBtn(editorSignatureButton, mode === AnnotationEditorType.SIGNATURE, editorSignatureParamsToolbar);
  14336. const isDisable = mode === AnnotationEditorType.DISABLE;
  14337. editorFreeTextButton.disabled = isDisable;
  14338. editorHighlightButton.disabled = isDisable;
  14339. editorInkButton.disabled = isDisable;
  14340. editorStampButton.disabled = isDisable;
  14341. editorSignatureButton.disabled = isDisable;
  14342. }
  14343. #updateUIState(resetNumPages = false) {
  14344. const {
  14345. pageNumber,
  14346. pagesCount,
  14347. pageScaleValue,
  14348. pageScale
  14349. } = this;
  14350. const opts = this.#opts;
  14351. if (resetNumPages) {
  14352. if (this.hasPageLabels) {
  14353. opts.pageNumber.type = "text";
  14354. opts.numPages.setAttribute("data-l10n-id", "pdfjs-page-of-pages");
  14355. } else {
  14356. opts.pageNumber.type = "number";
  14357. opts.numPages.setAttribute("data-l10n-id", "pdfjs-of-pages");
  14358. opts.numPages.setAttribute("data-l10n-args", JSON.stringify({
  14359. pagesCount
  14360. }));
  14361. }
  14362. opts.pageNumber.max = pagesCount;
  14363. }
  14364. if (this.hasPageLabels) {
  14365. opts.pageNumber.value = this.pageLabel;
  14366. opts.numPages.setAttribute("data-l10n-args", JSON.stringify({
  14367. pageNumber,
  14368. pagesCount
  14369. }));
  14370. } else {
  14371. opts.pageNumber.value = pageNumber;
  14372. }
  14373. opts.previous.disabled = pageNumber <= 1;
  14374. opts.next.disabled = pageNumber >= pagesCount;
  14375. opts.zoomOut.disabled = pageScale <= MIN_SCALE;
  14376. opts.zoomIn.disabled = pageScale >= MAX_SCALE;
  14377. let predefinedValueFound = false;
  14378. for (const option of opts.scaleSelect.options) {
  14379. if (option.value !== pageScaleValue) {
  14380. option.selected = false;
  14381. continue;
  14382. }
  14383. option.selected = true;
  14384. predefinedValueFound = true;
  14385. }
  14386. if (!predefinedValueFound) {
  14387. opts.customScaleOption.selected = true;
  14388. opts.customScaleOption.setAttribute("data-l10n-args", JSON.stringify({
  14389. scale: Math.round(pageScale * 10000) / 100
  14390. }));
  14391. }
  14392. }
  14393. updateLoadingIndicatorState(loading = false) {
  14394. const {
  14395. pageNumber
  14396. } = this.#opts;
  14397. pageNumber.classList.toggle("loading", loading);
  14398. }
  14399. }
  14400. ;// ./web/view_history.js
  14401. const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;
  14402. class ViewHistory {
  14403. constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
  14404. this.fingerprint = fingerprint;
  14405. this.cacheSize = cacheSize;
  14406. this._initializedPromise = this._readFromStorage().then(databaseStr => {
  14407. const database = JSON.parse(databaseStr || "{}");
  14408. let index = -1;
  14409. if (!Array.isArray(database.files)) {
  14410. database.files = [];
  14411. } else {
  14412. while (database.files.length >= this.cacheSize) {
  14413. database.files.shift();
  14414. }
  14415. for (let i = 0, ii = database.files.length; i < ii; i++) {
  14416. const branch = database.files[i];
  14417. if (branch.fingerprint === this.fingerprint) {
  14418. index = i;
  14419. break;
  14420. }
  14421. }
  14422. }
  14423. if (index === -1) {
  14424. index = database.files.push({
  14425. fingerprint: this.fingerprint
  14426. }) - 1;
  14427. }
  14428. this.file = database.files[index];
  14429. this.database = database;
  14430. });
  14431. }
  14432. async _writeToStorage() {
  14433. const databaseStr = JSON.stringify(this.database);
  14434. localStorage.setItem("pdfjs.history", databaseStr);
  14435. }
  14436. async _readFromStorage() {
  14437. return localStorage.getItem("pdfjs.history");
  14438. }
  14439. async set(name, val) {
  14440. await this._initializedPromise;
  14441. this.file[name] = val;
  14442. return this._writeToStorage();
  14443. }
  14444. async setMultiple(properties) {
  14445. await this._initializedPromise;
  14446. for (const name in properties) {
  14447. this.file[name] = properties[name];
  14448. }
  14449. return this._writeToStorage();
  14450. }
  14451. async get(name, defaultValue) {
  14452. await this._initializedPromise;
  14453. const val = this.file[name];
  14454. return val !== undefined ? val : defaultValue;
  14455. }
  14456. async getMultiple(properties) {
  14457. await this._initializedPromise;
  14458. const values = Object.create(null);
  14459. for (const name in properties) {
  14460. const val = this.file[name];
  14461. values[name] = val !== undefined ? val : properties[name];
  14462. }
  14463. return values;
  14464. }
  14465. }
  14466. ;// ./web/app.js
  14467. const FORCE_PAGES_LOADED_TIMEOUT = 10000;
  14468. const ViewOnLoad = {
  14469. UNKNOWN: -1,
  14470. PREVIOUS: 0,
  14471. INITIAL: 1
  14472. };
  14473. const PDFViewerApplication = {
  14474. initialBookmark: document.location.hash.substring(1),
  14475. _initializedCapability: {
  14476. ...Promise.withResolvers(),
  14477. settled: false
  14478. },
  14479. appConfig: null,
  14480. pdfDocument: null,
  14481. pdfLoadingTask: null,
  14482. printService: null,
  14483. pdfViewer: null,
  14484. pdfThumbnailViewer: null,
  14485. pdfRenderingQueue: null,
  14486. pdfPresentationMode: null,
  14487. pdfDocumentProperties: null,
  14488. pdfLinkService: null,
  14489. pdfHistory: null,
  14490. pdfSidebar: null,
  14491. pdfOutlineViewer: null,
  14492. pdfAttachmentViewer: null,
  14493. pdfLayerViewer: null,
  14494. pdfCursorTools: null,
  14495. pdfScriptingManager: null,
  14496. store: null,
  14497. downloadManager: null,
  14498. overlayManager: null,
  14499. preferences: new Preferences(),
  14500. toolbar: null,
  14501. secondaryToolbar: null,
  14502. eventBus: null,
  14503. l10n: null,
  14504. annotationEditorParams: null,
  14505. imageAltTextSettings: null,
  14506. isInitialViewSet: false,
  14507. isViewerEmbedded: window.parent !== window,
  14508. url: "",
  14509. baseUrl: "",
  14510. mlManager: null,
  14511. _downloadUrl: "",
  14512. _eventBusAbortController: null,
  14513. _windowAbortController: null,
  14514. _globalAbortController: new AbortController(),
  14515. documentInfo: null,
  14516. metadata: null,
  14517. _contentDispositionFilename: null,
  14518. _contentLength: null,
  14519. _saveInProgress: false,
  14520. _wheelUnusedTicks: 0,
  14521. _wheelUnusedFactor: 1,
  14522. _touchManager: null,
  14523. _touchUnusedTicks: 0,
  14524. _touchUnusedFactor: 1,
  14525. _PDFBug: null,
  14526. _hasAnnotationEditors: false,
  14527. _title: document.title,
  14528. _printAnnotationStoragePromise: null,
  14529. _isCtrlKeyDown: false,
  14530. _caretBrowsing: null,
  14531. _isScrolling: false,
  14532. editorUndoBar: null,
  14533. async initialize(appConfig) {
  14534. this.appConfig = appConfig;
  14535. try {
  14536. await this.preferences.initializedPromise;
  14537. } catch (ex) {
  14538. console.error("initialize:", ex);
  14539. }
  14540. if (AppOptions.get("pdfBugEnabled")) {
  14541. await this._parseHashParams();
  14542. }
  14543. let mode;
  14544. switch (AppOptions.get("viewerCssTheme")) {
  14545. case 1:
  14546. mode = "is-light";
  14547. break;
  14548. case 2:
  14549. mode = "is-dark";
  14550. break;
  14551. }
  14552. if (mode) {
  14553. document.documentElement.classList.add(mode);
  14554. }
  14555. this.l10n = await this.externalServices.createL10n();
  14556. document.getElementsByTagName("html")[0].dir = this.l10n.getDirection();
  14557. this.l10n.translate(appConfig.appContainer || document.documentElement);
  14558. if (this.isViewerEmbedded && AppOptions.get("externalLinkTarget") === LinkTarget.NONE) {
  14559. AppOptions.set("externalLinkTarget", LinkTarget.TOP);
  14560. }
  14561. await this._initializeViewerComponents();
  14562. this.bindEvents();
  14563. this.bindWindowEvents();
  14564. this._initializedCapability.settled = true;
  14565. this._initializedCapability.resolve();
  14566. },
  14567. async _parseHashParams() {
  14568. const hash = document.location.hash.substring(1);
  14569. if (!hash) {
  14570. return;
  14571. }
  14572. const {
  14573. mainContainer,
  14574. viewerContainer
  14575. } = this.appConfig,
  14576. params = parseQueryString(hash);
  14577. const loadPDFBug = async () => {
  14578. if (this._PDFBug) {
  14579. return;
  14580. }
  14581. const {
  14582. PDFBug
  14583. } = await import(
  14584. /*webpackIgnore: true*/
  14585. /*@vite-ignore*/
  14586. AppOptions.get("debuggerSrc"));
  14587. this._PDFBug = PDFBug;
  14588. };
  14589. if (params.get("disableworker") === "true") {
  14590. try {
  14591. GlobalWorkerOptions.workerSrc ||= AppOptions.get("workerSrc");
  14592. await import(
  14593. /*webpackIgnore: true*/
  14594. /*@vite-ignore*/
  14595. PDFWorker.workerSrc);
  14596. } catch (ex) {
  14597. console.error("_parseHashParams:", ex);
  14598. }
  14599. }
  14600. if (params.has("textlayer")) {
  14601. switch (params.get("textlayer")) {
  14602. case "off":
  14603. AppOptions.set("textLayerMode", TextLayerMode.DISABLE);
  14604. break;
  14605. case "visible":
  14606. case "shadow":
  14607. case "hover":
  14608. viewerContainer.classList.add(`textLayer-${params.get("textlayer")}`);
  14609. try {
  14610. await loadPDFBug();
  14611. this._PDFBug.loadCSS();
  14612. } catch (ex) {
  14613. console.error("_parseHashParams:", ex);
  14614. }
  14615. break;
  14616. }
  14617. }
  14618. if (params.has("pdfbug")) {
  14619. AppOptions.setAll({
  14620. pdfBug: true,
  14621. fontExtraProperties: true
  14622. });
  14623. const enabled = params.get("pdfbug").split(",");
  14624. try {
  14625. await loadPDFBug();
  14626. this._PDFBug.init(mainContainer, enabled);
  14627. } catch (ex) {
  14628. console.error("_parseHashParams:", ex);
  14629. }
  14630. }
  14631. if (params.has("locale")) {
  14632. AppOptions.set("localeProperties", {
  14633. lang: params.get("locale")
  14634. });
  14635. }
  14636. const opts = {
  14637. disableAutoFetch: x => x === "true",
  14638. disableFontFace: x => x === "true",
  14639. disableHistory: x => x === "true",
  14640. disableRange: x => x === "true",
  14641. disableStream: x => x === "true",
  14642. verbosity: x => x | 0
  14643. };
  14644. for (const name in opts) {
  14645. const check = opts[name],
  14646. key = name.toLowerCase();
  14647. if (params.has(key)) {
  14648. AppOptions.set(name, check(params.get(key)));
  14649. }
  14650. }
  14651. },
  14652. async _initializeViewerComponents() {
  14653. const {
  14654. appConfig,
  14655. externalServices,
  14656. l10n,
  14657. mlManager
  14658. } = this;
  14659. const abortSignal = this._globalAbortController.signal;
  14660. const eventBus = new EventBus();
  14661. this.eventBus = AppOptions.eventBus = eventBus;
  14662. mlManager?.setEventBus(eventBus, abortSignal);
  14663. const overlayManager = this.overlayManager = new OverlayManager();
  14664. const renderingQueue = this.pdfRenderingQueue = new PDFRenderingQueue();
  14665. renderingQueue.onIdle = this._cleanup.bind(this);
  14666. const linkService = this.pdfLinkService = new PDFLinkService({
  14667. eventBus,
  14668. externalLinkTarget: AppOptions.get("externalLinkTarget"),
  14669. externalLinkRel: AppOptions.get("externalLinkRel"),
  14670. ignoreDestinationZoom: AppOptions.get("ignoreDestinationZoom")
  14671. });
  14672. const downloadManager = this.downloadManager = new DownloadManager();
  14673. const findController = this.findController = new PDFFindController({
  14674. linkService,
  14675. eventBus,
  14676. updateMatchesCountOnProgress: true
  14677. });
  14678. const pdfScriptingManager = this.pdfScriptingManager = new PDFScriptingManager({
  14679. eventBus,
  14680. externalServices,
  14681. docProperties: this._scriptingDocProperties.bind(this)
  14682. });
  14683. const container = appConfig.mainContainer,
  14684. viewer = appConfig.viewerContainer;
  14685. const annotationEditorMode = AppOptions.get("annotationEditorMode");
  14686. const pageColors = AppOptions.get("forcePageColors") || window.matchMedia("(forced-colors: active)").matches ? {
  14687. background: AppOptions.get("pageColorsBackground"),
  14688. foreground: AppOptions.get("pageColorsForeground")
  14689. } : null;
  14690. let altTextManager;
  14691. if (AppOptions.get("enableUpdatedAddImage")) {
  14692. altTextManager = appConfig.newAltTextDialog ? new NewAltTextManager(appConfig.newAltTextDialog, overlayManager, eventBus) : null;
  14693. } else {
  14694. altTextManager = appConfig.altTextDialog ? new AltTextManager(appConfig.altTextDialog, container, overlayManager, eventBus) : null;
  14695. }
  14696. if (appConfig.editorUndoBar) {
  14697. this.editorUndoBar = new EditorUndoBar(appConfig.editorUndoBar, eventBus);
  14698. }
  14699. const signatureManager = AppOptions.get("enableSignatureEditor") && appConfig.addSignatureDialog ? new SignatureManager(appConfig.addSignatureDialog, appConfig.editSignatureDialog, appConfig.annotationEditorParams?.editorSignatureAddSignature || null, overlayManager, l10n, externalServices.createSignatureStorage(eventBus, abortSignal), eventBus) : null;
  14700. const enableHWA = AppOptions.get("enableHWA"),
  14701. maxCanvasPixels = AppOptions.get("maxCanvasPixels"),
  14702. maxCanvasDim = AppOptions.get("maxCanvasDim");
  14703. const pdfViewer = this.pdfViewer = new PDFViewer({
  14704. container,
  14705. viewer,
  14706. eventBus,
  14707. renderingQueue,
  14708. linkService,
  14709. downloadManager,
  14710. altTextManager,
  14711. signatureManager,
  14712. editorUndoBar: this.editorUndoBar,
  14713. findController,
  14714. scriptingManager: AppOptions.get("enableScripting") && pdfScriptingManager,
  14715. l10n,
  14716. textLayerMode: AppOptions.get("textLayerMode"),
  14717. annotationMode: AppOptions.get("annotationMode"),
  14718. annotationEditorMode,
  14719. annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
  14720. enableHighlightFloatingButton: AppOptions.get("enableHighlightFloatingButton"),
  14721. enableUpdatedAddImage: AppOptions.get("enableUpdatedAddImage"),
  14722. enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage"),
  14723. imageResourcesPath: AppOptions.get("imageResourcesPath"),
  14724. enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
  14725. maxCanvasPixels,
  14726. maxCanvasDim,
  14727. enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
  14728. enablePermissions: AppOptions.get("enablePermissions"),
  14729. pageColors,
  14730. mlManager,
  14731. abortSignal,
  14732. enableHWA,
  14733. supportsPinchToZoom: this.supportsPinchToZoom,
  14734. enableAutoLinking: AppOptions.get("enableAutoLinking")
  14735. });
  14736. renderingQueue.setViewer(pdfViewer);
  14737. linkService.setViewer(pdfViewer);
  14738. pdfScriptingManager.setViewer(pdfViewer);
  14739. if (appConfig.sidebar?.thumbnailView) {
  14740. this.pdfThumbnailViewer = new PDFThumbnailViewer({
  14741. container: appConfig.sidebar.thumbnailView,
  14742. eventBus,
  14743. renderingQueue,
  14744. linkService,
  14745. maxCanvasPixels,
  14746. maxCanvasDim,
  14747. pageColors,
  14748. abortSignal,
  14749. enableHWA
  14750. });
  14751. renderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
  14752. }
  14753. if (!this.isViewerEmbedded && !AppOptions.get("disableHistory")) {
  14754. this.pdfHistory = new PDFHistory({
  14755. linkService,
  14756. eventBus
  14757. });
  14758. linkService.setHistory(this.pdfHistory);
  14759. }
  14760. if (!this.supportsIntegratedFind && appConfig.findBar) {
  14761. this.findBar = new PDFFindBar(appConfig.findBar, appConfig.principalContainer, eventBus);
  14762. }
  14763. if (appConfig.annotationEditorParams) {
  14764. if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
  14765. const editorSignatureButton = appConfig.toolbar?.editorSignatureButton;
  14766. if (editorSignatureButton && AppOptions.get("enableSignatureEditor")) {
  14767. editorSignatureButton.parentElement.hidden = false;
  14768. }
  14769. this.annotationEditorParams = new AnnotationEditorParams(appConfig.annotationEditorParams, eventBus);
  14770. } else {
  14771. for (const id of ["editorModeButtons", "editorModeSeparator"]) {
  14772. document.getElementById(id)?.classList.add("hidden");
  14773. }
  14774. }
  14775. }
  14776. if (mlManager && appConfig.secondaryToolbar?.imageAltTextSettingsButton) {
  14777. this.imageAltTextSettings = new ImageAltTextSettings(appConfig.altTextSettingsDialog, overlayManager, eventBus, mlManager);
  14778. }
  14779. if (appConfig.documentProperties) {
  14780. this.pdfDocumentProperties = new PDFDocumentProperties(appConfig.documentProperties, overlayManager, eventBus, l10n, () => this._docFilename);
  14781. }
  14782. if (appConfig.secondaryToolbar?.cursorHandToolButton) {
  14783. this.pdfCursorTools = new PDFCursorTools({
  14784. container,
  14785. eventBus,
  14786. cursorToolOnLoad: AppOptions.get("cursorToolOnLoad")
  14787. });
  14788. }
  14789. if (appConfig.toolbar) {
  14790. this.toolbar = new Toolbar(appConfig.toolbar, eventBus, AppOptions.get("toolbarDensity"));
  14791. }
  14792. if (appConfig.secondaryToolbar) {
  14793. if (AppOptions.get("enableAltText")) {
  14794. appConfig.secondaryToolbar.imageAltTextSettingsButton?.classList.remove("hidden");
  14795. appConfig.secondaryToolbar.imageAltTextSettingsSeparator?.classList.remove("hidden");
  14796. }
  14797. this.secondaryToolbar = new SecondaryToolbar(appConfig.secondaryToolbar, eventBus);
  14798. }
  14799. if (this.supportsFullscreen && appConfig.secondaryToolbar?.presentationModeButton) {
  14800. this.pdfPresentationMode = new PDFPresentationMode({
  14801. container,
  14802. pdfViewer,
  14803. eventBus
  14804. });
  14805. }
  14806. if (appConfig.passwordOverlay) {
  14807. this.passwordPrompt = new PasswordPrompt(appConfig.passwordOverlay, overlayManager, this.isViewerEmbedded);
  14808. }
  14809. if (appConfig.sidebar?.outlineView) {
  14810. this.pdfOutlineViewer = new PDFOutlineViewer({
  14811. container: appConfig.sidebar.outlineView,
  14812. eventBus,
  14813. l10n,
  14814. linkService,
  14815. downloadManager
  14816. });
  14817. }
  14818. if (appConfig.sidebar?.attachmentsView) {
  14819. this.pdfAttachmentViewer = new PDFAttachmentViewer({
  14820. container: appConfig.sidebar.attachmentsView,
  14821. eventBus,
  14822. l10n,
  14823. downloadManager
  14824. });
  14825. }
  14826. if (appConfig.sidebar?.layersView) {
  14827. this.pdfLayerViewer = new PDFLayerViewer({
  14828. container: appConfig.sidebar.layersView,
  14829. eventBus,
  14830. l10n
  14831. });
  14832. }
  14833. if (appConfig.sidebar) {
  14834. this.pdfSidebar = new PDFSidebar({
  14835. elements: appConfig.sidebar,
  14836. eventBus,
  14837. l10n
  14838. });
  14839. this.pdfSidebar.onToggled = this.forceRendering.bind(this);
  14840. this.pdfSidebar.onUpdateThumbnails = () => {
  14841. for (const pageView of pdfViewer.getCachedPageViews()) {
  14842. if (pageView.renderingState === RenderingStates.FINISHED) {
  14843. this.pdfThumbnailViewer.getThumbnail(pageView.id - 1)?.setImage(pageView);
  14844. }
  14845. }
  14846. this.pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
  14847. };
  14848. }
  14849. },
  14850. async run(config) {
  14851. await this.initialize(config);
  14852. const {
  14853. appConfig,
  14854. eventBus
  14855. } = this;
  14856. let file;
  14857. const queryString = document.location.search.substring(1);
  14858. const params = parseQueryString(queryString);
  14859. file = params.get("file") ?? AppOptions.get("defaultUrl");
  14860. validateFileURL(file);
  14861. const fileInput = this._openFileInput = document.createElement("input");
  14862. fileInput.id = "fileInput";
  14863. fileInput.hidden = true;
  14864. fileInput.type = "file";
  14865. fileInput.value = null;
  14866. document.body.append(fileInput);
  14867. fileInput.addEventListener("change", function (evt) {
  14868. const {
  14869. files
  14870. } = evt.target;
  14871. if (!files || files.length === 0) {
  14872. return;
  14873. }
  14874. eventBus.dispatch("fileinputchange", {
  14875. source: this,
  14876. fileInput: evt.target
  14877. });
  14878. });
  14879. appConfig.mainContainer.addEventListener("dragover", function (evt) {
  14880. for (const item of evt.dataTransfer.items) {
  14881. if (item.type === "application/pdf") {
  14882. evt.dataTransfer.dropEffect = evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move";
  14883. stopEvent(evt);
  14884. return;
  14885. }
  14886. }
  14887. });
  14888. appConfig.mainContainer.addEventListener("drop", function (evt) {
  14889. if (evt.dataTransfer.files?.[0].type !== "application/pdf") {
  14890. return;
  14891. }
  14892. stopEvent(evt);
  14893. eventBus.dispatch("fileinputchange", {
  14894. source: this,
  14895. fileInput: evt.dataTransfer
  14896. });
  14897. });
  14898. if (!AppOptions.get("supportsDocumentFonts")) {
  14899. AppOptions.set("disableFontFace", true);
  14900. this.l10n.get("pdfjs-web-fonts-disabled").then(msg => {
  14901. console.warn(msg);
  14902. });
  14903. }
  14904. if (!this.supportsPrinting) {
  14905. appConfig.toolbar?.print?.classList.add("hidden");
  14906. appConfig.secondaryToolbar?.printButton.classList.add("hidden");
  14907. }
  14908. if (!this.supportsFullscreen) {
  14909. appConfig.secondaryToolbar?.presentationModeButton.classList.add("hidden");
  14910. }
  14911. if (this.supportsIntegratedFind) {
  14912. appConfig.findBar?.toggleButton?.classList.add("hidden");
  14913. }
  14914. if (file) {
  14915. this.open({
  14916. url: file
  14917. });
  14918. } else {
  14919. this._hideViewBookmark();
  14920. }
  14921. },
  14922. get externalServices() {
  14923. return shadow(this, "externalServices", new ExternalServices());
  14924. },
  14925. get initialized() {
  14926. return this._initializedCapability.settled;
  14927. },
  14928. get initializedPromise() {
  14929. return this._initializedCapability.promise;
  14930. },
  14931. updateZoom(steps, scaleFactor, origin) {
  14932. if (this.pdfViewer.isInPresentationMode) {
  14933. return;
  14934. }
  14935. this.pdfViewer.updateScale({
  14936. drawingDelay: AppOptions.get("defaultZoomDelay"),
  14937. steps,
  14938. scaleFactor,
  14939. origin
  14940. });
  14941. },
  14942. zoomIn() {
  14943. this.updateZoom(1);
  14944. },
  14945. zoomOut() {
  14946. this.updateZoom(-1);
  14947. },
  14948. zoomReset() {
  14949. if (this.pdfViewer.isInPresentationMode) {
  14950. return;
  14951. }
  14952. this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
  14953. },
  14954. touchPinchCallback(origin, prevDistance, distance) {
  14955. if (this.supportsPinchToZoom) {
  14956. const newScaleFactor = this._accumulateFactor(this.pdfViewer.currentScale, distance / prevDistance, "_touchUnusedFactor");
  14957. this.updateZoom(null, newScaleFactor, origin);
  14958. } else {
  14959. const PIXELS_PER_LINE_SCALE = 30;
  14960. const ticks = this._accumulateTicks((distance - prevDistance) / PIXELS_PER_LINE_SCALE, "_touchUnusedTicks");
  14961. this.updateZoom(ticks, null, origin);
  14962. }
  14963. },
  14964. touchPinchEndCallback() {
  14965. this._touchUnusedTicks = 0;
  14966. this._touchUnusedFactor = 1;
  14967. },
  14968. get pagesCount() {
  14969. return this.pdfDocument ? this.pdfDocument.numPages : 0;
  14970. },
  14971. get page() {
  14972. return this.pdfViewer.currentPageNumber;
  14973. },
  14974. set page(val) {
  14975. this.pdfViewer.currentPageNumber = val;
  14976. },
  14977. get supportsPrinting() {
  14978. return PDFPrintServiceFactory.supportsPrinting;
  14979. },
  14980. get supportsFullscreen() {
  14981. return shadow(this, "supportsFullscreen", document.fullscreenEnabled);
  14982. },
  14983. get supportsPinchToZoom() {
  14984. return shadow(this, "supportsPinchToZoom", AppOptions.get("supportsPinchToZoom"));
  14985. },
  14986. get supportsIntegratedFind() {
  14987. return shadow(this, "supportsIntegratedFind", AppOptions.get("supportsIntegratedFind"));
  14988. },
  14989. get loadingBar() {
  14990. const barElement = document.getElementById("loadingBar");
  14991. const bar = barElement ? new ProgressBar(barElement) : null;
  14992. return shadow(this, "loadingBar", bar);
  14993. },
  14994. get supportsMouseWheelZoomCtrlKey() {
  14995. return shadow(this, "supportsMouseWheelZoomCtrlKey", AppOptions.get("supportsMouseWheelZoomCtrlKey"));
  14996. },
  14997. get supportsMouseWheelZoomMetaKey() {
  14998. return shadow(this, "supportsMouseWheelZoomMetaKey", AppOptions.get("supportsMouseWheelZoomMetaKey"));
  14999. },
  15000. get supportsCaretBrowsingMode() {
  15001. return AppOptions.get("supportsCaretBrowsingMode");
  15002. },
  15003. moveCaret(isUp, select) {
  15004. this._caretBrowsing ||= new CaretBrowsingMode(this._globalAbortController.signal, this.appConfig.mainContainer, this.appConfig.viewerContainer, this.appConfig.toolbar?.container);
  15005. this._caretBrowsing.moveCaret(isUp, select);
  15006. },
  15007. setTitleUsingUrl(url = "", downloadUrl = null) {
  15008. this.url = url;
  15009. this.baseUrl = url.split("#", 1)[0];
  15010. if (downloadUrl) {
  15011. this._downloadUrl = downloadUrl === url ? this.baseUrl : downloadUrl.split("#", 1)[0];
  15012. }
  15013. if (isDataScheme(url)) {
  15014. this._hideViewBookmark();
  15015. }
  15016. let title = pdfjs_getPdfFilenameFromUrl(url, "");
  15017. if (!title) {
  15018. try {
  15019. title = decodeURIComponent(getFilenameFromUrl(url));
  15020. } catch {}
  15021. }
  15022. this.setTitle(title || url);
  15023. },
  15024. setTitle(title = this._title) {
  15025. this._title = title;
  15026. if (this.isViewerEmbedded) {
  15027. return;
  15028. }
  15029. const editorIndicator = this._hasAnnotationEditors && !this.pdfRenderingQueue.printing;
  15030. document.title = `${editorIndicator ? "* " : ""}${title}`;
  15031. },
  15032. get _docFilename() {
  15033. return this._contentDispositionFilename || pdfjs_getPdfFilenameFromUrl(this.url);
  15034. },
  15035. _hideViewBookmark() {
  15036. const {
  15037. secondaryToolbar
  15038. } = this.appConfig;
  15039. secondaryToolbar?.viewBookmarkButton.classList.add("hidden");
  15040. if (secondaryToolbar?.presentationModeButton.classList.contains("hidden")) {
  15041. document.getElementById("viewBookmarkSeparator")?.classList.add("hidden");
  15042. }
  15043. },
  15044. async close() {
  15045. this._unblockDocumentLoadEvent();
  15046. this._hideViewBookmark();
  15047. if (!this.pdfLoadingTask) {
  15048. return;
  15049. }
  15050. if (this.pdfDocument?.annotationStorage.size > 0 && this._annotationStorageModified) {
  15051. try {
  15052. await this.save();
  15053. } catch {}
  15054. }
  15055. const promises = [];
  15056. promises.push(this.pdfLoadingTask.destroy());
  15057. this.pdfLoadingTask = null;
  15058. if (this.pdfDocument) {
  15059. this.pdfDocument = null;
  15060. this.pdfThumbnailViewer?.setDocument(null);
  15061. this.pdfViewer.setDocument(null);
  15062. this.pdfLinkService.setDocument(null);
  15063. this.pdfDocumentProperties?.setDocument(null);
  15064. }
  15065. this.pdfLinkService.externalLinkEnabled = true;
  15066. this.store = null;
  15067. this.isInitialViewSet = false;
  15068. this.url = "";
  15069. this.baseUrl = "";
  15070. this._downloadUrl = "";
  15071. this.documentInfo = null;
  15072. this.metadata = null;
  15073. this._contentDispositionFilename = null;
  15074. this._contentLength = null;
  15075. this._saveInProgress = false;
  15076. this._hasAnnotationEditors = false;
  15077. promises.push(this.pdfScriptingManager.destroyPromise, this.passwordPrompt.close());
  15078. this.setTitle();
  15079. this.pdfSidebar?.reset();
  15080. this.pdfOutlineViewer?.reset();
  15081. this.pdfAttachmentViewer?.reset();
  15082. this.pdfLayerViewer?.reset();
  15083. this.pdfHistory?.reset();
  15084. this.findBar?.reset();
  15085. this.toolbar?.reset();
  15086. this.secondaryToolbar?.reset();
  15087. this._PDFBug?.cleanup();
  15088. await Promise.all(promises);
  15089. },
  15090. async open(args) {
  15091. if (this.pdfLoadingTask) {
  15092. await this.close();
  15093. }
  15094. const workerParams = AppOptions.getAll(OptionKind.WORKER);
  15095. Object.assign(GlobalWorkerOptions, workerParams);
  15096. if (args.url) {
  15097. this.setTitleUsingUrl(args.originalUrl || args.url, args.url);
  15098. }
  15099. const apiParams = AppOptions.getAll(OptionKind.API);
  15100. const loadingTask = getDocument({
  15101. ...apiParams,
  15102. ...args
  15103. });
  15104. this.pdfLoadingTask = loadingTask;
  15105. loadingTask.onPassword = (updateCallback, reason) => {
  15106. if (this.isViewerEmbedded) {
  15107. this._unblockDocumentLoadEvent();
  15108. }
  15109. this.pdfLinkService.externalLinkEnabled = false;
  15110. this.passwordPrompt.setUpdateCallback(updateCallback, reason);
  15111. this.passwordPrompt.open();
  15112. };
  15113. loadingTask.onProgress = ({
  15114. loaded,
  15115. total
  15116. }) => {
  15117. this.progress(loaded / total);
  15118. };
  15119. return loadingTask.promise.then(pdfDocument => {
  15120. this.load(pdfDocument);
  15121. }, reason => {
  15122. if (loadingTask !== this.pdfLoadingTask) {
  15123. return undefined;
  15124. }
  15125. let key = "pdfjs-loading-error";
  15126. if (reason instanceof InvalidPDFException) {
  15127. key = "pdfjs-invalid-file-error";
  15128. } else if (reason instanceof ResponseException) {
  15129. key = reason.missing ? "pdfjs-missing-file-error" : "pdfjs-unexpected-response-error";
  15130. }
  15131. return this._documentError(key, {
  15132. message: reason.message
  15133. }).then(() => {
  15134. throw reason;
  15135. });
  15136. });
  15137. },
  15138. async download() {
  15139. let data;
  15140. try {
  15141. data = await (this.pdfDocument ? this.pdfDocument.getData() : this.pdfLoadingTask.getData());
  15142. } catch {}
  15143. this.downloadManager.download(data, this._downloadUrl, this._docFilename);
  15144. },
  15145. async save() {
  15146. if (this._saveInProgress) {
  15147. return;
  15148. }
  15149. this._saveInProgress = true;
  15150. await this.pdfScriptingManager.dispatchWillSave();
  15151. try {
  15152. const data = await this.pdfDocument.saveDocument();
  15153. this.downloadManager.download(data, this._downloadUrl, this._docFilename);
  15154. } catch (reason) {
  15155. console.error(`Error when saving the document:`, reason);
  15156. await this.download();
  15157. } finally {
  15158. await this.pdfScriptingManager.dispatchDidSave();
  15159. this._saveInProgress = false;
  15160. }
  15161. if (this._hasAnnotationEditors) {
  15162. this.externalServices.reportTelemetry({
  15163. type: "editing",
  15164. data: {
  15165. type: "save",
  15166. stats: this.pdfDocument?.annotationStorage.editorStats
  15167. }
  15168. });
  15169. }
  15170. },
  15171. async downloadOrSave() {
  15172. const {
  15173. classList
  15174. } = this.appConfig.appContainer;
  15175. classList.add("wait");
  15176. await (this.pdfDocument?.annotationStorage.size > 0 ? this.save() : this.download());
  15177. classList.remove("wait");
  15178. },
  15179. async _documentError(key, moreInfo = null) {
  15180. this._unblockDocumentLoadEvent();
  15181. const message = await this._otherError(key || "pdfjs-loading-error", moreInfo);
  15182. this.eventBus.dispatch("documenterror", {
  15183. source: this,
  15184. message,
  15185. reason: moreInfo?.message ?? null
  15186. });
  15187. },
  15188. async _otherError(key, moreInfo = null) {
  15189. const message = await this.l10n.get(key);
  15190. const moreInfoText = [`PDF.js v${version || "?"} (build: ${build || "?"})`];
  15191. if (moreInfo) {
  15192. moreInfoText.push(`Message: ${moreInfo.message}`);
  15193. if (moreInfo.stack) {
  15194. moreInfoText.push(`Stack: ${moreInfo.stack}`);
  15195. } else {
  15196. if (moreInfo.filename) {
  15197. moreInfoText.push(`File: ${moreInfo.filename}`);
  15198. }
  15199. if (moreInfo.lineNumber) {
  15200. moreInfoText.push(`Line: ${moreInfo.lineNumber}`);
  15201. }
  15202. }
  15203. }
  15204. console.error(`${message}\n\n${moreInfoText.join("\n")}`);
  15205. return message;
  15206. },
  15207. progress(level) {
  15208. const percent = Math.round(level * 100);
  15209. if (!this.loadingBar || percent <= this.loadingBar.percent) {
  15210. return;
  15211. }
  15212. this.loadingBar.percent = percent;
  15213. if (this.pdfDocument?.loadingParams.disableAutoFetch ?? AppOptions.get("disableAutoFetch")) {
  15214. this.loadingBar.setDisableAutoFetch();
  15215. }
  15216. },
  15217. load(pdfDocument) {
  15218. this.pdfDocument = pdfDocument;
  15219. pdfDocument.getDownloadInfo().then(({
  15220. length
  15221. }) => {
  15222. this._contentLength = length;
  15223. this.loadingBar?.hide();
  15224. firstPagePromise.then(() => {
  15225. this.eventBus.dispatch("documentloaded", {
  15226. source: this
  15227. });
  15228. });
  15229. });
  15230. const pageLayoutPromise = pdfDocument.getPageLayout().catch(() => {});
  15231. const pageModePromise = pdfDocument.getPageMode().catch(() => {});
  15232. const openActionPromise = pdfDocument.getOpenAction().catch(() => {});
  15233. this.toolbar?.setPagesCount(pdfDocument.numPages, false);
  15234. this.secondaryToolbar?.setPagesCount(pdfDocument.numPages);
  15235. this.pdfLinkService.setDocument(pdfDocument);
  15236. this.pdfDocumentProperties?.setDocument(pdfDocument);
  15237. const pdfViewer = this.pdfViewer;
  15238. pdfViewer.setDocument(pdfDocument);
  15239. const {
  15240. firstPagePromise,
  15241. onePageRendered,
  15242. pagesPromise
  15243. } = pdfViewer;
  15244. this.pdfThumbnailViewer?.setDocument(pdfDocument);
  15245. const storedPromise = (this.store = new ViewHistory(pdfDocument.fingerprints[0])).getMultiple({
  15246. page: null,
  15247. zoom: DEFAULT_SCALE_VALUE,
  15248. scrollLeft: "0",
  15249. scrollTop: "0",
  15250. rotation: null,
  15251. sidebarView: SidebarView.UNKNOWN,
  15252. scrollMode: ScrollMode.UNKNOWN,
  15253. spreadMode: SpreadMode.UNKNOWN
  15254. }).catch(() => {});
  15255. firstPagePromise.then(pdfPage => {
  15256. this.loadingBar?.setWidth(this.appConfig.viewerContainer);
  15257. this._initializeAnnotationStorageCallbacks(pdfDocument);
  15258. Promise.all([animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => {
  15259. const viewOnLoad = AppOptions.get("viewOnLoad");
  15260. this._initializePdfHistory({
  15261. fingerprint: pdfDocument.fingerprints[0],
  15262. viewOnLoad,
  15263. initialDest: openAction?.dest
  15264. });
  15265. const initialBookmark = this.initialBookmark;
  15266. const zoom = AppOptions.get("defaultZoomValue");
  15267. let hash = zoom ? `zoom=${zoom}` : null;
  15268. let rotation = null;
  15269. let sidebarView = AppOptions.get("sidebarViewOnLoad");
  15270. let scrollMode = AppOptions.get("scrollModeOnLoad");
  15271. let spreadMode = AppOptions.get("spreadModeOnLoad");
  15272. if (stored?.page && viewOnLoad !== ViewOnLoad.INITIAL) {
  15273. hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`;
  15274. rotation = parseInt(stored.rotation, 10);
  15275. if (sidebarView === SidebarView.UNKNOWN) {
  15276. sidebarView = stored.sidebarView | 0;
  15277. }
  15278. if (scrollMode === ScrollMode.UNKNOWN) {
  15279. scrollMode = stored.scrollMode | 0;
  15280. }
  15281. if (spreadMode === SpreadMode.UNKNOWN) {
  15282. spreadMode = stored.spreadMode | 0;
  15283. }
  15284. }
  15285. if (pageMode && sidebarView === SidebarView.UNKNOWN) {
  15286. sidebarView = apiPageModeToSidebarView(pageMode);
  15287. }
  15288. if (pageLayout && scrollMode === ScrollMode.UNKNOWN && spreadMode === SpreadMode.UNKNOWN) {
  15289. const modes = apiPageLayoutToViewerModes(pageLayout);
  15290. spreadMode = modes.spreadMode;
  15291. }
  15292. this.setInitialView(hash, {
  15293. rotation,
  15294. sidebarView,
  15295. scrollMode,
  15296. spreadMode
  15297. });
  15298. this.eventBus.dispatch("documentinit", {
  15299. source: this
  15300. });
  15301. if (!this.isViewerEmbedded) {
  15302. pdfViewer.focus();
  15303. }
  15304. await Promise.race([pagesPromise, new Promise(resolve => {
  15305. setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT);
  15306. })]);
  15307. if (!initialBookmark && !hash) {
  15308. return;
  15309. }
  15310. if (pdfViewer.hasEqualPageSizes) {
  15311. return;
  15312. }
  15313. this.initialBookmark = initialBookmark;
  15314. pdfViewer.currentScaleValue = pdfViewer.currentScaleValue;
  15315. this.setInitialView(hash);
  15316. }).catch(() => {
  15317. this.setInitialView();
  15318. }).then(function () {
  15319. pdfViewer.update();
  15320. });
  15321. });
  15322. pagesPromise.then(() => {
  15323. this._unblockDocumentLoadEvent();
  15324. this._initializeAutoPrint(pdfDocument, openActionPromise);
  15325. }, reason => {
  15326. this._documentError("pdfjs-loading-error", {
  15327. message: reason.message
  15328. });
  15329. });
  15330. onePageRendered.then(data => {
  15331. this.externalServices.reportTelemetry({
  15332. type: "pageInfo",
  15333. timestamp: data.timestamp
  15334. });
  15335. if (this.pdfOutlineViewer) {
  15336. pdfDocument.getOutline().then(outline => {
  15337. if (pdfDocument !== this.pdfDocument) {
  15338. return;
  15339. }
  15340. this.pdfOutlineViewer.render({
  15341. outline,
  15342. pdfDocument
  15343. });
  15344. });
  15345. }
  15346. if (this.pdfAttachmentViewer) {
  15347. pdfDocument.getAttachments().then(attachments => {
  15348. if (pdfDocument !== this.pdfDocument) {
  15349. return;
  15350. }
  15351. this.pdfAttachmentViewer.render({
  15352. attachments
  15353. });
  15354. });
  15355. }
  15356. if (this.pdfLayerViewer) {
  15357. pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => {
  15358. if (pdfDocument !== this.pdfDocument) {
  15359. return;
  15360. }
  15361. this.pdfLayerViewer.render({
  15362. optionalContentConfig,
  15363. pdfDocument
  15364. });
  15365. });
  15366. }
  15367. });
  15368. this._initializePageLabels(pdfDocument);
  15369. this._initializeMetadata(pdfDocument);
  15370. },
  15371. async _scriptingDocProperties(pdfDocument) {
  15372. if (!this.documentInfo) {
  15373. await new Promise(resolve => {
  15374. this.eventBus._on("metadataloaded", resolve, {
  15375. once: true
  15376. });
  15377. });
  15378. if (pdfDocument !== this.pdfDocument) {
  15379. return null;
  15380. }
  15381. }
  15382. if (!this._contentLength) {
  15383. await new Promise(resolve => {
  15384. this.eventBus._on("documentloaded", resolve, {
  15385. once: true
  15386. });
  15387. });
  15388. if (pdfDocument !== this.pdfDocument) {
  15389. return null;
  15390. }
  15391. }
  15392. return {
  15393. ...this.documentInfo,
  15394. baseURL: this.baseUrl,
  15395. filesize: this._contentLength,
  15396. filename: this._docFilename,
  15397. metadata: this.metadata?.getRaw(),
  15398. authors: this.metadata?.get("dc:creator"),
  15399. numPages: this.pagesCount,
  15400. URL: this.url
  15401. };
  15402. },
  15403. async _initializeAutoPrint(pdfDocument, openActionPromise) {
  15404. const [openAction, jsActions] = await Promise.all([openActionPromise, this.pdfViewer.enableScripting ? null : pdfDocument.getJSActions()]);
  15405. if (pdfDocument !== this.pdfDocument) {
  15406. return;
  15407. }
  15408. let triggerAutoPrint = openAction?.action === "Print";
  15409. if (jsActions) {
  15410. console.warn("Warning: JavaScript support is not enabled");
  15411. for (const name in jsActions) {
  15412. if (triggerAutoPrint) {
  15413. break;
  15414. }
  15415. switch (name) {
  15416. case "WillClose":
  15417. case "WillSave":
  15418. case "DidSave":
  15419. case "WillPrint":
  15420. case "DidPrint":
  15421. continue;
  15422. }
  15423. triggerAutoPrint = jsActions[name].some(js => AutoPrintRegExp.test(js));
  15424. }
  15425. }
  15426. if (triggerAutoPrint) {
  15427. this.triggerPrinting();
  15428. }
  15429. },
  15430. async _initializeMetadata(pdfDocument) {
  15431. const {
  15432. info,
  15433. metadata,
  15434. contentDispositionFilename,
  15435. contentLength
  15436. } = await pdfDocument.getMetadata();
  15437. if (pdfDocument !== this.pdfDocument) {
  15438. return;
  15439. }
  15440. this.documentInfo = info;
  15441. this.metadata = metadata;
  15442. this._contentDispositionFilename ??= contentDispositionFilename;
  15443. this._contentLength ??= contentLength;
  15444. console.log(`PDF ${pdfDocument.fingerprints[0]} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${version || "?"} [${build || "?"}])`);
  15445. let pdfTitle = info.Title;
  15446. const metadataTitle = metadata?.get("dc:title");
  15447. if (metadataTitle) {
  15448. if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) {
  15449. pdfTitle = metadataTitle;
  15450. }
  15451. }
  15452. if (pdfTitle) {
  15453. this.setTitle(`${pdfTitle} - ${this._contentDispositionFilename || this._title}`);
  15454. } else if (this._contentDispositionFilename) {
  15455. this.setTitle(this._contentDispositionFilename);
  15456. }
  15457. if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) {
  15458. if (pdfDocument.loadingParams.enableXfa) {
  15459. console.warn("Warning: XFA Foreground documents are not supported");
  15460. } else {
  15461. console.warn("Warning: XFA support is not enabled");
  15462. }
  15463. } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderForms) {
  15464. console.warn("Warning: Interactive form support is not enabled");
  15465. }
  15466. if (info.IsSignaturesPresent) {
  15467. console.warn("Warning: Digital signatures validation is not supported");
  15468. }
  15469. this.eventBus.dispatch("metadataloaded", {
  15470. source: this
  15471. });
  15472. },
  15473. async _initializePageLabels(pdfDocument) {
  15474. const labels = await pdfDocument.getPageLabels();
  15475. if (pdfDocument !== this.pdfDocument) {
  15476. return;
  15477. }
  15478. if (!labels || AppOptions.get("disablePageLabels")) {
  15479. return;
  15480. }
  15481. const numLabels = labels.length;
  15482. let standardLabels = 0,
  15483. emptyLabels = 0;
  15484. for (let i = 0; i < numLabels; i++) {
  15485. const label = labels[i];
  15486. if (label === (i + 1).toString()) {
  15487. standardLabels++;
  15488. } else if (label === "") {
  15489. emptyLabels++;
  15490. } else {
  15491. break;
  15492. }
  15493. }
  15494. if (standardLabels >= numLabels || emptyLabels >= numLabels) {
  15495. return;
  15496. }
  15497. const {
  15498. pdfViewer,
  15499. pdfThumbnailViewer,
  15500. toolbar
  15501. } = this;
  15502. pdfViewer.setPageLabels(labels);
  15503. pdfThumbnailViewer?.setPageLabels(labels);
  15504. toolbar?.setPagesCount(numLabels, true);
  15505. toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
  15506. },
  15507. _initializePdfHistory({
  15508. fingerprint,
  15509. viewOnLoad,
  15510. initialDest = null
  15511. }) {
  15512. if (!this.pdfHistory) {
  15513. return;
  15514. }
  15515. this.pdfHistory.initialize({
  15516. fingerprint,
  15517. resetHistory: viewOnLoad === ViewOnLoad.INITIAL,
  15518. updateUrl: AppOptions.get("historyUpdateUrl")
  15519. });
  15520. if (this.pdfHistory.initialBookmark) {
  15521. this.initialBookmark = this.pdfHistory.initialBookmark;
  15522. this.initialRotation = this.pdfHistory.initialRotation;
  15523. }
  15524. if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) {
  15525. this.initialBookmark = JSON.stringify(initialDest);
  15526. this.pdfHistory.push({
  15527. explicitDest: initialDest,
  15528. pageNumber: null
  15529. });
  15530. }
  15531. },
  15532. _initializeAnnotationStorageCallbacks(pdfDocument) {
  15533. if (pdfDocument !== this.pdfDocument) {
  15534. return;
  15535. }
  15536. const {
  15537. annotationStorage
  15538. } = pdfDocument;
  15539. annotationStorage.onSetModified = () => {
  15540. window.addEventListener("beforeunload", beforeUnload);
  15541. this._annotationStorageModified = true;
  15542. };
  15543. annotationStorage.onResetModified = () => {
  15544. window.removeEventListener("beforeunload", beforeUnload);
  15545. delete this._annotationStorageModified;
  15546. };
  15547. annotationStorage.onAnnotationEditor = typeStr => {
  15548. this._hasAnnotationEditors = !!typeStr;
  15549. this.setTitle();
  15550. };
  15551. },
  15552. setInitialView(storedHash, {
  15553. rotation,
  15554. sidebarView,
  15555. scrollMode,
  15556. spreadMode
  15557. } = {}) {
  15558. const setRotation = angle => {
  15559. if (isValidRotation(angle)) {
  15560. this.pdfViewer.pagesRotation = angle;
  15561. }
  15562. };
  15563. const setViewerModes = (scroll, spread) => {
  15564. if (isValidScrollMode(scroll)) {
  15565. this.pdfViewer.scrollMode = scroll;
  15566. }
  15567. if (isValidSpreadMode(spread)) {
  15568. this.pdfViewer.spreadMode = spread;
  15569. }
  15570. };
  15571. this.isInitialViewSet = true;
  15572. this.pdfSidebar?.setInitialView(sidebarView);
  15573. setViewerModes(scrollMode, spreadMode);
  15574. if (this.initialBookmark) {
  15575. setRotation(this.initialRotation);
  15576. delete this.initialRotation;
  15577. this.pdfLinkService.setHash(this.initialBookmark);
  15578. this.initialBookmark = null;
  15579. } else if (storedHash) {
  15580. setRotation(rotation);
  15581. this.pdfLinkService.setHash(storedHash);
  15582. }
  15583. this.toolbar?.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel);
  15584. this.secondaryToolbar?.setPageNumber(this.pdfViewer.currentPageNumber);
  15585. if (!this.pdfViewer.currentScaleValue) {
  15586. this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
  15587. }
  15588. },
  15589. _cleanup() {
  15590. if (!this.pdfDocument) {
  15591. return;
  15592. }
  15593. this.pdfViewer.cleanup();
  15594. this.pdfThumbnailViewer?.cleanup();
  15595. this.pdfDocument.cleanup(AppOptions.get("fontExtraProperties"));
  15596. },
  15597. forceRendering() {
  15598. this.pdfRenderingQueue.printing = !!this.printService;
  15599. this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar?.visibleView === SidebarView.THUMBS;
  15600. this.pdfRenderingQueue.renderHighestPriority();
  15601. },
  15602. beforePrint() {
  15603. this._printAnnotationStoragePromise = this.pdfScriptingManager.dispatchWillPrint().catch(() => {}).then(() => this.pdfDocument?.annotationStorage.print);
  15604. if (this.printService) {
  15605. return;
  15606. }
  15607. if (!this.supportsPrinting) {
  15608. this._otherError("pdfjs-printing-not-supported");
  15609. return;
  15610. }
  15611. if (!this.pdfViewer.pageViewsReady) {
  15612. this.l10n.get("pdfjs-printing-not-ready").then(msg => {
  15613. window.alert(msg);
  15614. });
  15615. return;
  15616. }
  15617. this.printService = PDFPrintServiceFactory.createPrintService({
  15618. pdfDocument: this.pdfDocument,
  15619. pagesOverview: this.pdfViewer.getPagesOverview(),
  15620. printContainer: this.appConfig.printContainer,
  15621. printResolution: AppOptions.get("printResolution"),
  15622. printAnnotationStoragePromise: this._printAnnotationStoragePromise
  15623. });
  15624. this.forceRendering();
  15625. this.setTitle();
  15626. this.printService.layout();
  15627. if (this._hasAnnotationEditors) {
  15628. this.externalServices.reportTelemetry({
  15629. type: "editing",
  15630. data: {
  15631. type: "print",
  15632. stats: this.pdfDocument?.annotationStorage.editorStats
  15633. }
  15634. });
  15635. }
  15636. },
  15637. afterPrint() {
  15638. if (this._printAnnotationStoragePromise) {
  15639. this._printAnnotationStoragePromise.then(() => {
  15640. this.pdfScriptingManager.dispatchDidPrint();
  15641. });
  15642. this._printAnnotationStoragePromise = null;
  15643. }
  15644. if (this.printService) {
  15645. this.printService.destroy();
  15646. this.printService = null;
  15647. this.pdfDocument?.annotationStorage.resetModified();
  15648. }
  15649. this.forceRendering();
  15650. this.setTitle();
  15651. },
  15652. rotatePages(delta) {
  15653. this.pdfViewer.pagesRotation += delta;
  15654. },
  15655. requestPresentationMode() {
  15656. this.pdfPresentationMode?.request();
  15657. },
  15658. triggerPrinting() {
  15659. if (this.supportsPrinting) {
  15660. window.print();
  15661. }
  15662. },
  15663. bindEvents() {
  15664. if (this._eventBusAbortController) {
  15665. return;
  15666. }
  15667. const ac = this._eventBusAbortController = new AbortController();
  15668. const opts = {
  15669. signal: ac.signal
  15670. };
  15671. const {
  15672. eventBus,
  15673. externalServices,
  15674. pdfDocumentProperties,
  15675. pdfViewer,
  15676. preferences
  15677. } = this;
  15678. eventBus._on("resize", onResize.bind(this), opts);
  15679. eventBus._on("hashchange", onHashchange.bind(this), opts);
  15680. eventBus._on("beforeprint", this.beforePrint.bind(this), opts);
  15681. eventBus._on("afterprint", this.afterPrint.bind(this), opts);
  15682. eventBus._on("pagerender", onPageRender.bind(this), opts);
  15683. eventBus._on("pagerendered", onPageRendered.bind(this), opts);
  15684. eventBus._on("updateviewarea", onUpdateViewarea.bind(this), opts);
  15685. eventBus._on("pagechanging", onPageChanging.bind(this), opts);
  15686. eventBus._on("scalechanging", onScaleChanging.bind(this), opts);
  15687. eventBus._on("rotationchanging", onRotationChanging.bind(this), opts);
  15688. eventBus._on("sidebarviewchanged", onSidebarViewChanged.bind(this), opts);
  15689. eventBus._on("pagemode", onPageMode.bind(this), opts);
  15690. eventBus._on("namedaction", onNamedAction.bind(this), opts);
  15691. eventBus._on("presentationmodechanged", evt => pdfViewer.presentationModeState = evt.state, opts);
  15692. eventBus._on("presentationmode", this.requestPresentationMode.bind(this), opts);
  15693. eventBus._on("switchannotationeditormode", evt => pdfViewer.annotationEditorMode = evt, opts);
  15694. eventBus._on("print", this.triggerPrinting.bind(this), opts);
  15695. eventBus._on("download", this.downloadOrSave.bind(this), opts);
  15696. eventBus._on("firstpage", () => this.page = 1, opts);
  15697. eventBus._on("lastpage", () => this.page = this.pagesCount, opts);
  15698. eventBus._on("nextpage", () => pdfViewer.nextPage(), opts);
  15699. eventBus._on("previouspage", () => pdfViewer.previousPage(), opts);
  15700. eventBus._on("zoomin", this.zoomIn.bind(this), opts);
  15701. eventBus._on("zoomout", this.zoomOut.bind(this), opts);
  15702. eventBus._on("zoomreset", this.zoomReset.bind(this), opts);
  15703. eventBus._on("pagenumberchanged", onPageNumberChanged.bind(this), opts);
  15704. eventBus._on("scalechanged", evt => pdfViewer.currentScaleValue = evt.value, opts);
  15705. eventBus._on("rotatecw", this.rotatePages.bind(this, 90), opts);
  15706. eventBus._on("rotateccw", this.rotatePages.bind(this, -90), opts);
  15707. eventBus._on("optionalcontentconfig", evt => pdfViewer.optionalContentConfigPromise = evt.promise, opts);
  15708. eventBus._on("switchscrollmode", evt => pdfViewer.scrollMode = evt.mode, opts);
  15709. eventBus._on("scrollmodechanged", onViewerModesChanged.bind(this, "scrollMode"), opts);
  15710. eventBus._on("switchspreadmode", evt => pdfViewer.spreadMode = evt.mode, opts);
  15711. eventBus._on("spreadmodechanged", onViewerModesChanged.bind(this, "spreadMode"), opts);
  15712. eventBus._on("imagealttextsettings", onImageAltTextSettings.bind(this), opts);
  15713. eventBus._on("documentproperties", () => pdfDocumentProperties?.open(), opts);
  15714. eventBus._on("findfromurlhash", onFindFromUrlHash.bind(this), opts);
  15715. eventBus._on("updatefindmatchescount", onUpdateFindMatchesCount.bind(this), opts);
  15716. eventBus._on("updatefindcontrolstate", onUpdateFindControlState.bind(this), opts);
  15717. eventBus._on("fileinputchange", onFileInputChange.bind(this), opts);
  15718. eventBus._on("openfile", onOpenFile.bind(this), opts);
  15719. },
  15720. bindWindowEvents() {
  15721. if (this._windowAbortController) {
  15722. return;
  15723. }
  15724. this._windowAbortController = new AbortController();
  15725. const {
  15726. eventBus,
  15727. appConfig: {
  15728. mainContainer
  15729. },
  15730. pdfViewer,
  15731. _windowAbortController: {
  15732. signal
  15733. }
  15734. } = this;
  15735. this._touchManager = new TouchManager({
  15736. container: window,
  15737. isPinchingDisabled: () => pdfViewer.isInPresentationMode,
  15738. isPinchingStopped: () => this.overlayManager?.active,
  15739. onPinching: this.touchPinchCallback.bind(this),
  15740. onPinchEnd: this.touchPinchEndCallback.bind(this),
  15741. signal
  15742. });
  15743. function addWindowResolutionChange(evt = null) {
  15744. if (evt) {
  15745. pdfViewer.refresh();
  15746. }
  15747. const mediaQueryList = window.matchMedia(`(resolution: ${OutputScale.pixelRatio}dppx)`);
  15748. mediaQueryList.addEventListener("change", addWindowResolutionChange, {
  15749. once: true,
  15750. signal
  15751. });
  15752. }
  15753. addWindowResolutionChange();
  15754. window.addEventListener("wheel", onWheel.bind(this), {
  15755. passive: false,
  15756. signal
  15757. });
  15758. window.addEventListener("click", onClick.bind(this), {
  15759. signal
  15760. });
  15761. window.addEventListener("keydown", onKeyDown.bind(this), {
  15762. signal
  15763. });
  15764. window.addEventListener("keyup", onKeyUp.bind(this), {
  15765. signal
  15766. });
  15767. window.addEventListener("resize", () => eventBus.dispatch("resize", {
  15768. source: window
  15769. }), {
  15770. signal
  15771. });
  15772. window.addEventListener("hashchange", () => {
  15773. eventBus.dispatch("hashchange", {
  15774. source: window,
  15775. hash: document.location.hash.substring(1)
  15776. });
  15777. }, {
  15778. signal
  15779. });
  15780. window.addEventListener("beforeprint", () => eventBus.dispatch("beforeprint", {
  15781. source: window
  15782. }), {
  15783. signal
  15784. });
  15785. window.addEventListener("afterprint", () => eventBus.dispatch("afterprint", {
  15786. source: window
  15787. }), {
  15788. signal
  15789. });
  15790. window.addEventListener("updatefromsandbox", evt => {
  15791. eventBus.dispatch("updatefromsandbox", {
  15792. source: window,
  15793. detail: evt.detail
  15794. });
  15795. }, {
  15796. signal
  15797. });
  15798. if (!("onscrollend" in document.documentElement)) {
  15799. return;
  15800. }
  15801. ({
  15802. scrollTop: this._lastScrollTop,
  15803. scrollLeft: this._lastScrollLeft
  15804. } = mainContainer);
  15805. const scrollend = () => {
  15806. ({
  15807. scrollTop: this._lastScrollTop,
  15808. scrollLeft: this._lastScrollLeft
  15809. } = mainContainer);
  15810. this._isScrolling = false;
  15811. mainContainer.addEventListener("scroll", scroll, {
  15812. passive: true,
  15813. signal
  15814. });
  15815. mainContainer.removeEventListener("scrollend", scrollend);
  15816. mainContainer.removeEventListener("blur", scrollend);
  15817. };
  15818. const scroll = () => {
  15819. if (this._isCtrlKeyDown) {
  15820. return;
  15821. }
  15822. if (this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) {
  15823. return;
  15824. }
  15825. mainContainer.removeEventListener("scroll", scroll);
  15826. this._isScrolling = true;
  15827. mainContainer.addEventListener("scrollend", scrollend, {
  15828. signal
  15829. });
  15830. mainContainer.addEventListener("blur", scrollend, {
  15831. signal
  15832. });
  15833. };
  15834. mainContainer.addEventListener("scroll", scroll, {
  15835. passive: true,
  15836. signal
  15837. });
  15838. },
  15839. unbindEvents() {
  15840. this._eventBusAbortController?.abort();
  15841. this._eventBusAbortController = null;
  15842. },
  15843. unbindWindowEvents() {
  15844. this._windowAbortController?.abort();
  15845. this._windowAbortController = null;
  15846. this._touchManager = null;
  15847. },
  15848. async testingClose() {
  15849. this.unbindEvents();
  15850. this.unbindWindowEvents();
  15851. this._globalAbortController?.abort();
  15852. this._globalAbortController = null;
  15853. this.findBar?.close();
  15854. await Promise.all([this.l10n?.destroy(), this.close()]);
  15855. },
  15856. _accumulateTicks(ticks, prop) {
  15857. if (this[prop] > 0 && ticks < 0 || this[prop] < 0 && ticks > 0) {
  15858. this[prop] = 0;
  15859. }
  15860. this[prop] += ticks;
  15861. const wholeTicks = Math.trunc(this[prop]);
  15862. this[prop] -= wholeTicks;
  15863. return wholeTicks;
  15864. },
  15865. _accumulateFactor(previousScale, factor, prop) {
  15866. if (factor === 1) {
  15867. return 1;
  15868. }
  15869. if (this[prop] > 1 && factor < 1 || this[prop] < 1 && factor > 1) {
  15870. this[prop] = 1;
  15871. }
  15872. const newFactor = Math.floor(previousScale * factor * this[prop] * 100) / (100 * previousScale);
  15873. this[prop] = factor / newFactor;
  15874. return newFactor;
  15875. },
  15876. _unblockDocumentLoadEvent() {
  15877. document.blockUnblockOnload?.(false);
  15878. this._unblockDocumentLoadEvent = () => {};
  15879. },
  15880. get scriptingReady() {
  15881. return this.pdfScriptingManager.ready;
  15882. }
  15883. };
  15884. initCom(PDFViewerApplication);
  15885. {
  15886. PDFPrintServiceFactory.initGlobals(PDFViewerApplication);
  15887. }
  15888. {
  15889. const HOSTED_VIEWER_ORIGINS = new Set(["null", "http://mozilla.github.io", "https://mozilla.github.io"]);
  15890. var validateFileURL = function (file) {
  15891. if (!file) {
  15892. return;
  15893. }
  15894. const viewerOrigin = URL.parse(window.location)?.origin || "null";
  15895. if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) {
  15896. return;
  15897. }
  15898. // const fileOrigin = URL.parse(file, window.location)?.origin;
  15899. // if (fileOrigin === viewerOrigin) {
  15900. // return;
  15901. // }
  15902. // const ex = new Error("file origin does not match viewer's");
  15903. // PDFViewerApplication._documentError("pdfjs-loading-error", {
  15904. // message: ex.message
  15905. // });
  15906. // throw ex;
  15907. };
  15908. var onFileInputChange = function (evt) {
  15909. if (this.pdfViewer?.isInPresentationMode) {
  15910. return;
  15911. }
  15912. const file = evt.fileInput.files[0];
  15913. this.open({
  15914. url: URL.createObjectURL(file),
  15915. originalUrl: file.name
  15916. });
  15917. };
  15918. var onOpenFile = function (evt) {
  15919. this._openFileInput?.click();
  15920. };
  15921. }
  15922. function onPageRender({
  15923. pageNumber
  15924. }) {
  15925. if (pageNumber === this.page) {
  15926. this.toolbar?.updateLoadingIndicatorState(true);
  15927. }
  15928. }
  15929. function onPageRendered({
  15930. pageNumber,
  15931. isDetailView,
  15932. error
  15933. }) {
  15934. if (pageNumber === this.page) {
  15935. this.toolbar?.updateLoadingIndicatorState(false);
  15936. }
  15937. if (!isDetailView && this.pdfSidebar?.visibleView === SidebarView.THUMBS) {
  15938. const pageView = this.pdfViewer.getPageView(pageNumber - 1);
  15939. const thumbnailView = this.pdfThumbnailViewer?.getThumbnail(pageNumber - 1);
  15940. if (pageView) {
  15941. thumbnailView?.setImage(pageView);
  15942. }
  15943. }
  15944. if (error) {
  15945. this._otherError("pdfjs-rendering-error", error);
  15946. }
  15947. }
  15948. function onPageMode({
  15949. mode
  15950. }) {
  15951. let view;
  15952. switch (mode) {
  15953. case "thumbs":
  15954. view = SidebarView.THUMBS;
  15955. break;
  15956. case "bookmarks":
  15957. case "outline":
  15958. view = SidebarView.OUTLINE;
  15959. break;
  15960. case "attachments":
  15961. view = SidebarView.ATTACHMENTS;
  15962. break;
  15963. case "layers":
  15964. view = SidebarView.LAYERS;
  15965. break;
  15966. case "none":
  15967. view = SidebarView.NONE;
  15968. break;
  15969. default:
  15970. console.error('Invalid "pagemode" hash parameter: ' + mode);
  15971. return;
  15972. }
  15973. this.pdfSidebar?.switchView(view, true);
  15974. }
  15975. function onNamedAction(evt) {
  15976. switch (evt.action) {
  15977. case "GoToPage":
  15978. this.appConfig.toolbar?.pageNumber.select();
  15979. break;
  15980. case "Find":
  15981. if (!this.supportsIntegratedFind) {
  15982. this.findBar?.toggle();
  15983. }
  15984. break;
  15985. case "Print":
  15986. this.triggerPrinting();
  15987. break;
  15988. case "SaveAs":
  15989. this.downloadOrSave();
  15990. break;
  15991. }
  15992. }
  15993. function onSidebarViewChanged({
  15994. view
  15995. }) {
  15996. this.pdfRenderingQueue.isThumbnailViewEnabled = view === SidebarView.THUMBS;
  15997. if (this.isInitialViewSet) {
  15998. this.store?.set("sidebarView", view).catch(() => {});
  15999. }
  16000. }
  16001. function onUpdateViewarea({
  16002. location
  16003. }) {
  16004. if (this.isInitialViewSet) {
  16005. this.store?.setMultiple({
  16006. page: location.pageNumber,
  16007. zoom: location.scale,
  16008. scrollLeft: location.left,
  16009. scrollTop: location.top,
  16010. rotation: location.rotation
  16011. }).catch(() => {});
  16012. }
  16013. if (this.appConfig.secondaryToolbar) {
  16014. this.appConfig.secondaryToolbar.viewBookmarkButton.href = this.pdfLinkService.getAnchorUrl(location.pdfOpenParams);
  16015. }
  16016. }
  16017. function onViewerModesChanged(name, evt) {
  16018. if (this.isInitialViewSet && !this.pdfViewer.isInPresentationMode) {
  16019. this.store?.set(name, evt.mode).catch(() => {});
  16020. }
  16021. }
  16022. function onResize() {
  16023. const {
  16024. pdfDocument,
  16025. pdfViewer,
  16026. pdfRenderingQueue
  16027. } = this;
  16028. if (pdfRenderingQueue.printing && window.matchMedia("print").matches) {
  16029. return;
  16030. }
  16031. if (!pdfDocument) {
  16032. return;
  16033. }
  16034. const currentScaleValue = pdfViewer.currentScaleValue;
  16035. if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") {
  16036. pdfViewer.currentScaleValue = currentScaleValue;
  16037. }
  16038. pdfViewer.update();
  16039. }
  16040. function onHashchange(evt) {
  16041. const hash = evt.hash;
  16042. if (!hash) {
  16043. return;
  16044. }
  16045. if (!this.isInitialViewSet) {
  16046. this.initialBookmark = hash;
  16047. } else if (!this.pdfHistory?.popStateInProgress) {
  16048. this.pdfLinkService.setHash(hash);
  16049. }
  16050. }
  16051. function onPageNumberChanged(evt) {
  16052. const {
  16053. pdfViewer
  16054. } = this;
  16055. if (evt.value !== "") {
  16056. this.pdfLinkService.goToPage(evt.value);
  16057. }
  16058. if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) {
  16059. this.toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
  16060. }
  16061. }
  16062. function onImageAltTextSettings() {
  16063. this.imageAltTextSettings?.open({
  16064. enableGuessAltText: AppOptions.get("enableGuessAltText"),
  16065. enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage")
  16066. });
  16067. }
  16068. function onFindFromUrlHash(evt) {
  16069. this.eventBus.dispatch("find", {
  16070. source: evt.source,
  16071. type: "",
  16072. query: evt.query,
  16073. caseSensitive: false,
  16074. entireWord: false,
  16075. highlightAll: true,
  16076. findPrevious: false,
  16077. matchDiacritics: true
  16078. });
  16079. }
  16080. function onUpdateFindMatchesCount({
  16081. matchesCount
  16082. }) {
  16083. if (this.supportsIntegratedFind) {
  16084. this.externalServices.updateFindMatchesCount(matchesCount);
  16085. } else {
  16086. this.findBar?.updateResultsCount(matchesCount);
  16087. }
  16088. }
  16089. function onUpdateFindControlState({
  16090. state,
  16091. previous,
  16092. entireWord,
  16093. matchesCount,
  16094. rawQuery
  16095. }) {
  16096. if (this.supportsIntegratedFind) {
  16097. this.externalServices.updateFindControlState({
  16098. result: state,
  16099. findPrevious: previous,
  16100. entireWord,
  16101. matchesCount,
  16102. rawQuery
  16103. });
  16104. } else {
  16105. this.findBar?.updateUIState(state, previous, matchesCount);
  16106. }
  16107. }
  16108. function onScaleChanging(evt) {
  16109. this.toolbar?.setPageScale(evt.presetValue, evt.scale);
  16110. this.pdfViewer.update();
  16111. }
  16112. function onRotationChanging(evt) {
  16113. if (this.pdfThumbnailViewer) {
  16114. this.pdfThumbnailViewer.pagesRotation = evt.pagesRotation;
  16115. }
  16116. this.forceRendering();
  16117. this.pdfViewer.currentPageNumber = evt.pageNumber;
  16118. }
  16119. function onPageChanging({
  16120. pageNumber,
  16121. pageLabel
  16122. }) {
  16123. this.toolbar?.setPageNumber(pageNumber, pageLabel);
  16124. this.secondaryToolbar?.setPageNumber(pageNumber);
  16125. if (this.pdfSidebar?.visibleView === SidebarView.THUMBS) {
  16126. this.pdfThumbnailViewer?.scrollThumbnailIntoView(pageNumber);
  16127. }
  16128. const currentPage = this.pdfViewer.getPageView(pageNumber - 1);
  16129. this.toolbar?.updateLoadingIndicatorState(currentPage?.renderingState === RenderingStates.RUNNING);
  16130. }
  16131. function onWheel(evt) {
  16132. const {
  16133. pdfViewer,
  16134. supportsMouseWheelZoomCtrlKey,
  16135. supportsMouseWheelZoomMetaKey,
  16136. supportsPinchToZoom
  16137. } = this;
  16138. if (pdfViewer.isInPresentationMode) {
  16139. return;
  16140. }
  16141. const deltaMode = evt.deltaMode;
  16142. let scaleFactor = Math.exp(-evt.deltaY / 100);
  16143. const isBuiltInMac = false;
  16144. const isPinchToZoom = evt.ctrlKey && !this._isCtrlKeyDown && deltaMode === WheelEvent.DOM_DELTA_PIXEL && evt.deltaX === 0 && (Math.abs(scaleFactor - 1) < 0.05 || isBuiltInMac) && evt.deltaZ === 0;
  16145. const origin = [evt.clientX, evt.clientY];
  16146. if (isPinchToZoom || evt.ctrlKey && supportsMouseWheelZoomCtrlKey || evt.metaKey && supportsMouseWheelZoomMetaKey) {
  16147. evt.preventDefault();
  16148. if (this._isScrolling || document.visibilityState === "hidden" || this.overlayManager.active) {
  16149. return;
  16150. }
  16151. if (isPinchToZoom && supportsPinchToZoom) {
  16152. scaleFactor = this._accumulateFactor(pdfViewer.currentScale, scaleFactor, "_wheelUnusedFactor");
  16153. this.updateZoom(null, scaleFactor, origin);
  16154. } else {
  16155. const delta = normalizeWheelEventDirection(evt);
  16156. let ticks = 0;
  16157. if (deltaMode === WheelEvent.DOM_DELTA_LINE || deltaMode === WheelEvent.DOM_DELTA_PAGE) {
  16158. ticks = Math.abs(delta) >= 1 ? Math.sign(delta) : this._accumulateTicks(delta, "_wheelUnusedTicks");
  16159. } else {
  16160. const PIXELS_PER_LINE_SCALE = 30;
  16161. ticks = this._accumulateTicks(delta / PIXELS_PER_LINE_SCALE, "_wheelUnusedTicks");
  16162. }
  16163. this.updateZoom(ticks, null, origin);
  16164. }
  16165. }
  16166. }
  16167. function closeSecondaryToolbar({
  16168. target
  16169. }) {
  16170. if (!this.secondaryToolbar?.isOpen) {
  16171. return;
  16172. }
  16173. const {
  16174. toolbar,
  16175. secondaryToolbar
  16176. } = this.appConfig;
  16177. if (this.pdfViewer.containsElement(target) || toolbar?.container.contains(target) && !secondaryToolbar?.toolbar.contains(target) && !secondaryToolbar?.toggleButton.contains(target)) {
  16178. this.secondaryToolbar.close();
  16179. }
  16180. }
  16181. function closeEditorUndoBar(evt) {
  16182. if (!this.editorUndoBar?.isOpen) {
  16183. return;
  16184. }
  16185. if (this.appConfig.secondaryToolbar?.toolbar.contains(evt.target)) {
  16186. this.editorUndoBar.hide();
  16187. }
  16188. }
  16189. function onClick(evt) {
  16190. closeSecondaryToolbar.call(this, evt);
  16191. closeEditorUndoBar.call(this, evt);
  16192. }
  16193. function onKeyUp(evt) {
  16194. if (evt.key === "Control") {
  16195. this._isCtrlKeyDown = false;
  16196. }
  16197. }
  16198. function onKeyDown(evt) {
  16199. this._isCtrlKeyDown = evt.key === "Control";
  16200. if (this.editorUndoBar?.isOpen && evt.keyCode !== 9 && evt.keyCode !== 16 && !((evt.keyCode === 13 || evt.keyCode === 32) && getActiveOrFocusedElement() === this.appConfig.editorUndoBar.undoButton)) {
  16201. this.editorUndoBar.hide();
  16202. }
  16203. if (this.overlayManager.active) {
  16204. return;
  16205. }
  16206. const {
  16207. eventBus,
  16208. pdfViewer
  16209. } = this;
  16210. const isViewerInPresentationMode = pdfViewer.isInPresentationMode;
  16211. let handled = false,
  16212. ensureViewerFocused = false;
  16213. const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0);
  16214. if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
  16215. switch (evt.keyCode) {
  16216. case 70:
  16217. if (!this.supportsIntegratedFind && !evt.shiftKey) {
  16218. this.findBar?.open();
  16219. handled = true;
  16220. }
  16221. break;
  16222. case 71:
  16223. if (!this.supportsIntegratedFind) {
  16224. const {
  16225. state
  16226. } = this.findController;
  16227. if (state) {
  16228. const newState = {
  16229. source: window,
  16230. type: "again",
  16231. findPrevious: cmd === 5 || cmd === 12
  16232. };
  16233. eventBus.dispatch("find", {
  16234. ...state,
  16235. ...newState
  16236. });
  16237. }
  16238. handled = true;
  16239. }
  16240. break;
  16241. case 61:
  16242. case 107:
  16243. case 187:
  16244. case 171:
  16245. this.zoomIn();
  16246. handled = true;
  16247. break;
  16248. case 173:
  16249. case 109:
  16250. case 189:
  16251. this.zoomOut();
  16252. handled = true;
  16253. break;
  16254. case 48:
  16255. case 96:
  16256. if (!isViewerInPresentationMode) {
  16257. setTimeout(() => {
  16258. this.zoomReset();
  16259. });
  16260. handled = false;
  16261. }
  16262. break;
  16263. case 38:
  16264. if (isViewerInPresentationMode || this.page > 1) {
  16265. this.page = 1;
  16266. handled = true;
  16267. ensureViewerFocused = true;
  16268. }
  16269. break;
  16270. case 40:
  16271. if (isViewerInPresentationMode || this.page < this.pagesCount) {
  16272. this.page = this.pagesCount;
  16273. handled = true;
  16274. ensureViewerFocused = true;
  16275. }
  16276. break;
  16277. }
  16278. }
  16279. if (cmd === 1 || cmd === 8) {
  16280. switch (evt.keyCode) {
  16281. case 83:
  16282. eventBus.dispatch("download", {
  16283. source: window
  16284. });
  16285. handled = true;
  16286. break;
  16287. case 79:
  16288. {
  16289. eventBus.dispatch("openfile", {
  16290. source: window
  16291. });
  16292. handled = true;
  16293. }
  16294. break;
  16295. }
  16296. }
  16297. if (cmd === 3 || cmd === 10) {
  16298. switch (evt.keyCode) {
  16299. case 80:
  16300. this.requestPresentationMode();
  16301. handled = true;
  16302. this.externalServices.reportTelemetry({
  16303. type: "buttons",
  16304. data: {
  16305. id: "presentationModeKeyboard"
  16306. }
  16307. });
  16308. break;
  16309. case 71:
  16310. if (this.appConfig.toolbar) {
  16311. this.appConfig.toolbar.pageNumber.select();
  16312. handled = true;
  16313. }
  16314. break;
  16315. }
  16316. }
  16317. if (handled) {
  16318. if (ensureViewerFocused && !isViewerInPresentationMode) {
  16319. pdfViewer.focus();
  16320. }
  16321. evt.preventDefault();
  16322. return;
  16323. }
  16324. const curElement = getActiveOrFocusedElement();
  16325. const curElementTagName = curElement?.tagName.toUpperCase();
  16326. if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElementTagName === "BUTTON" && (evt.keyCode === 13 || evt.keyCode === 32) || curElement?.isContentEditable) {
  16327. if (evt.keyCode !== 27) {
  16328. return;
  16329. }
  16330. }
  16331. if (cmd === 0) {
  16332. let turnPage = 0,
  16333. turnOnlyIfPageFit = false;
  16334. switch (evt.keyCode) {
  16335. case 38:
  16336. if (this.supportsCaretBrowsingMode) {
  16337. this.moveCaret(true, false);
  16338. handled = true;
  16339. break;
  16340. }
  16341. case 33:
  16342. if (pdfViewer.isVerticalScrollbarEnabled) {
  16343. turnOnlyIfPageFit = true;
  16344. }
  16345. turnPage = -1;
  16346. break;
  16347. case 8:
  16348. if (!isViewerInPresentationMode) {
  16349. turnOnlyIfPageFit = true;
  16350. }
  16351. turnPage = -1;
  16352. break;
  16353. case 37:
  16354. if (this.supportsCaretBrowsingMode) {
  16355. return;
  16356. }
  16357. if (pdfViewer.isHorizontalScrollbarEnabled) {
  16358. turnOnlyIfPageFit = true;
  16359. }
  16360. case 75:
  16361. case 80:
  16362. turnPage = -1;
  16363. break;
  16364. case 27:
  16365. if (this.secondaryToolbar?.isOpen) {
  16366. this.secondaryToolbar.close();
  16367. handled = true;
  16368. }
  16369. if (!this.supportsIntegratedFind && this.findBar?.opened) {
  16370. this.findBar.close();
  16371. handled = true;
  16372. }
  16373. break;
  16374. case 40:
  16375. if (this.supportsCaretBrowsingMode) {
  16376. this.moveCaret(false, false);
  16377. handled = true;
  16378. break;
  16379. }
  16380. case 34:
  16381. if (pdfViewer.isVerticalScrollbarEnabled) {
  16382. turnOnlyIfPageFit = true;
  16383. }
  16384. turnPage = 1;
  16385. break;
  16386. case 13:
  16387. case 32:
  16388. if (!isViewerInPresentationMode) {
  16389. turnOnlyIfPageFit = true;
  16390. }
  16391. turnPage = 1;
  16392. break;
  16393. case 39:
  16394. if (this.supportsCaretBrowsingMode) {
  16395. return;
  16396. }
  16397. if (pdfViewer.isHorizontalScrollbarEnabled) {
  16398. turnOnlyIfPageFit = true;
  16399. }
  16400. case 74:
  16401. case 78:
  16402. turnPage = 1;
  16403. break;
  16404. case 36:
  16405. if (isViewerInPresentationMode || this.page > 1) {
  16406. this.page = 1;
  16407. handled = true;
  16408. ensureViewerFocused = true;
  16409. }
  16410. break;
  16411. case 35:
  16412. if (isViewerInPresentationMode || this.page < this.pagesCount) {
  16413. this.page = this.pagesCount;
  16414. handled = true;
  16415. ensureViewerFocused = true;
  16416. }
  16417. break;
  16418. case 83:
  16419. this.pdfCursorTools?.switchTool(CursorTool.SELECT);
  16420. break;
  16421. case 72:
  16422. this.pdfCursorTools?.switchTool(CursorTool.HAND);
  16423. break;
  16424. case 82:
  16425. this.rotatePages(90);
  16426. break;
  16427. case 115:
  16428. this.pdfSidebar?.toggle();
  16429. break;
  16430. }
  16431. if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) {
  16432. if (turnPage > 0) {
  16433. pdfViewer.nextPage();
  16434. } else {
  16435. pdfViewer.previousPage();
  16436. }
  16437. handled = true;
  16438. }
  16439. }
  16440. if (cmd === 4) {
  16441. switch (evt.keyCode) {
  16442. case 13:
  16443. case 32:
  16444. if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") {
  16445. break;
  16446. }
  16447. pdfViewer.previousPage();
  16448. handled = true;
  16449. break;
  16450. case 38:
  16451. this.moveCaret(true, true);
  16452. handled = true;
  16453. break;
  16454. case 40:
  16455. this.moveCaret(false, true);
  16456. handled = true;
  16457. break;
  16458. case 82:
  16459. this.rotatePages(-90);
  16460. break;
  16461. }
  16462. }
  16463. if (!handled && !isViewerInPresentationMode) {
  16464. if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") {
  16465. ensureViewerFocused = true;
  16466. }
  16467. }
  16468. if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) {
  16469. pdfViewer.focus();
  16470. }
  16471. if (handled) {
  16472. evt.preventDefault();
  16473. }
  16474. }
  16475. function beforeUnload(evt) {
  16476. evt.preventDefault();
  16477. evt.returnValue = "";
  16478. return false;
  16479. }
  16480. ;// ./web/viewer.js
  16481. const pdfjsVersion = "5.1.91";
  16482. const pdfjsBuild = "45cbe8bb0";
  16483. const AppConstants = {
  16484. LinkTarget: LinkTarget,
  16485. RenderingStates: RenderingStates,
  16486. ScrollMode: ScrollMode,
  16487. SpreadMode: SpreadMode
  16488. };
  16489. window.PDFViewerApplication = PDFViewerApplication;
  16490. window.PDFViewerApplicationConstants = AppConstants;
  16491. window.PDFViewerApplicationOptions = AppOptions;
  16492. function getViewerConfiguration() {
  16493. return {
  16494. appContainer: document.body,
  16495. principalContainer: document.getElementById("mainContainer"),
  16496. mainContainer: document.getElementById("viewerContainer"),
  16497. viewerContainer: document.getElementById("viewer"),
  16498. toolbar: {
  16499. container: document.getElementById("toolbarContainer"),
  16500. numPages: document.getElementById("numPages"),
  16501. pageNumber: document.getElementById("pageNumber"),
  16502. scaleSelect: document.getElementById("scaleSelect"),
  16503. customScaleOption: document.getElementById("customScaleOption"),
  16504. previous: document.getElementById("previous"),
  16505. next: document.getElementById("next"),
  16506. zoomIn: document.getElementById("zoomInButton"),
  16507. zoomOut: document.getElementById("zoomOutButton"),
  16508. print: document.getElementById("printButton"),
  16509. editorFreeTextButton: document.getElementById("editorFreeTextButton"),
  16510. editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"),
  16511. editorHighlightButton: document.getElementById("editorHighlightButton"),
  16512. editorHighlightParamsToolbar: document.getElementById("editorHighlightParamsToolbar"),
  16513. editorHighlightColorPicker: document.getElementById("editorHighlightColorPicker"),
  16514. editorInkButton: document.getElementById("editorInkButton"),
  16515. editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
  16516. editorStampButton: document.getElementById("editorStampButton"),
  16517. editorStampParamsToolbar: document.getElementById("editorStampParamsToolbar"),
  16518. editorSignatureButton: document.getElementById("editorSignatureButton"),
  16519. editorSignatureParamsToolbar: document.getElementById("editorSignatureParamsToolbar"),
  16520. download: document.getElementById("downloadButton")
  16521. },
  16522. secondaryToolbar: {
  16523. toolbar: document.getElementById("secondaryToolbar"),
  16524. toggleButton: document.getElementById("secondaryToolbarToggleButton"),
  16525. presentationModeButton: document.getElementById("presentationMode"),
  16526. openFileButton: document.getElementById("secondaryOpenFile"),
  16527. printButton: document.getElementById("secondaryPrint"),
  16528. downloadButton: document.getElementById("secondaryDownload"),
  16529. viewBookmarkButton: document.getElementById("viewBookmark"),
  16530. firstPageButton: document.getElementById("firstPage"),
  16531. lastPageButton: document.getElementById("lastPage"),
  16532. pageRotateCwButton: document.getElementById("pageRotateCw"),
  16533. pageRotateCcwButton: document.getElementById("pageRotateCcw"),
  16534. cursorSelectToolButton: document.getElementById("cursorSelectTool"),
  16535. cursorHandToolButton: document.getElementById("cursorHandTool"),
  16536. scrollPageButton: document.getElementById("scrollPage"),
  16537. scrollVerticalButton: document.getElementById("scrollVertical"),
  16538. scrollHorizontalButton: document.getElementById("scrollHorizontal"),
  16539. scrollWrappedButton: document.getElementById("scrollWrapped"),
  16540. spreadNoneButton: document.getElementById("spreadNone"),
  16541. spreadOddButton: document.getElementById("spreadOdd"),
  16542. spreadEvenButton: document.getElementById("spreadEven"),
  16543. imageAltTextSettingsButton: document.getElementById("imageAltTextSettings"),
  16544. imageAltTextSettingsSeparator: document.getElementById("imageAltTextSettingsSeparator"),
  16545. documentPropertiesButton: document.getElementById("documentProperties")
  16546. },
  16547. sidebar: {
  16548. outerContainer: document.getElementById("outerContainer"),
  16549. sidebarContainer: document.getElementById("sidebarContainer"),
  16550. toggleButton: document.getElementById("sidebarToggleButton"),
  16551. resizer: document.getElementById("sidebarResizer"),
  16552. thumbnailButton: document.getElementById("viewThumbnail"),
  16553. outlineButton: document.getElementById("viewOutline"),
  16554. attachmentsButton: document.getElementById("viewAttachments"),
  16555. layersButton: document.getElementById("viewLayers"),
  16556. thumbnailView: document.getElementById("thumbnailView"),
  16557. outlineView: document.getElementById("outlineView"),
  16558. attachmentsView: document.getElementById("attachmentsView"),
  16559. layersView: document.getElementById("layersView"),
  16560. currentOutlineItemButton: document.getElementById("currentOutlineItem")
  16561. },
  16562. findBar: {
  16563. bar: document.getElementById("findbar"),
  16564. toggleButton: document.getElementById("viewFindButton"),
  16565. findField: document.getElementById("findInput"),
  16566. highlightAllCheckbox: document.getElementById("findHighlightAll"),
  16567. caseSensitiveCheckbox: document.getElementById("findMatchCase"),
  16568. matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"),
  16569. entireWordCheckbox: document.getElementById("findEntireWord"),
  16570. findMsg: document.getElementById("findMsg"),
  16571. findResultsCount: document.getElementById("findResultsCount"),
  16572. findPreviousButton: document.getElementById("findPreviousButton"),
  16573. findNextButton: document.getElementById("findNextButton")
  16574. },
  16575. passwordOverlay: {
  16576. dialog: document.getElementById("passwordDialog"),
  16577. label: document.getElementById("passwordText"),
  16578. input: document.getElementById("password"),
  16579. submitButton: document.getElementById("passwordSubmit"),
  16580. cancelButton: document.getElementById("passwordCancel")
  16581. },
  16582. documentProperties: {
  16583. dialog: document.getElementById("documentPropertiesDialog"),
  16584. closeButton: document.getElementById("documentPropertiesClose"),
  16585. fields: {
  16586. fileName: document.getElementById("fileNameField"),
  16587. fileSize: document.getElementById("fileSizeField"),
  16588. title: document.getElementById("titleField"),
  16589. author: document.getElementById("authorField"),
  16590. subject: document.getElementById("subjectField"),
  16591. keywords: document.getElementById("keywordsField"),
  16592. creationDate: document.getElementById("creationDateField"),
  16593. modificationDate: document.getElementById("modificationDateField"),
  16594. creator: document.getElementById("creatorField"),
  16595. producer: document.getElementById("producerField"),
  16596. version: document.getElementById("versionField"),
  16597. pageCount: document.getElementById("pageCountField"),
  16598. pageSize: document.getElementById("pageSizeField"),
  16599. linearized: document.getElementById("linearizedField")
  16600. }
  16601. },
  16602. altTextDialog: {
  16603. dialog: document.getElementById("altTextDialog"),
  16604. optionDescription: document.getElementById("descriptionButton"),
  16605. optionDecorative: document.getElementById("decorativeButton"),
  16606. textarea: document.getElementById("descriptionTextarea"),
  16607. cancelButton: document.getElementById("altTextCancel"),
  16608. saveButton: document.getElementById("altTextSave")
  16609. },
  16610. newAltTextDialog: {
  16611. dialog: document.getElementById("newAltTextDialog"),
  16612. title: document.getElementById("newAltTextTitle"),
  16613. descriptionContainer: document.getElementById("newAltTextDescriptionContainer"),
  16614. textarea: document.getElementById("newAltTextDescriptionTextarea"),
  16615. disclaimer: document.getElementById("newAltTextDisclaimer"),
  16616. learnMore: document.getElementById("newAltTextLearnMore"),
  16617. imagePreview: document.getElementById("newAltTextImagePreview"),
  16618. createAutomatically: document.getElementById("newAltTextCreateAutomatically"),
  16619. createAutomaticallyButton: document.getElementById("newAltTextCreateAutomaticallyButton"),
  16620. downloadModel: document.getElementById("newAltTextDownloadModel"),
  16621. downloadModelDescription: document.getElementById("newAltTextDownloadModelDescription"),
  16622. error: document.getElementById("newAltTextError"),
  16623. errorCloseButton: document.getElementById("newAltTextCloseButton"),
  16624. cancelButton: document.getElementById("newAltTextCancel"),
  16625. notNowButton: document.getElementById("newAltTextNotNow"),
  16626. saveButton: document.getElementById("newAltTextSave")
  16627. },
  16628. altTextSettingsDialog: {
  16629. dialog: document.getElementById("altTextSettingsDialog"),
  16630. createModelButton: document.getElementById("createModelButton"),
  16631. aiModelSettings: document.getElementById("aiModelSettings"),
  16632. learnMore: document.getElementById("altTextSettingsLearnMore"),
  16633. deleteModelButton: document.getElementById("deleteModelButton"),
  16634. downloadModelButton: document.getElementById("downloadModelButton"),
  16635. showAltTextDialogButton: document.getElementById("showAltTextDialogButton"),
  16636. altTextSettingsCloseButton: document.getElementById("altTextSettingsCloseButton"),
  16637. closeButton: document.getElementById("altTextSettingsCloseButton")
  16638. },
  16639. addSignatureDialog: {
  16640. dialog: document.getElementById("addSignatureDialog"),
  16641. panels: document.getElementById("addSignatureActionContainer"),
  16642. typeButton: document.getElementById("addSignatureTypeButton"),
  16643. typeInput: document.getElementById("addSignatureTypeInput"),
  16644. drawButton: document.getElementById("addSignatureDrawButton"),
  16645. drawSVG: document.getElementById("addSignatureDraw"),
  16646. drawPlaceholder: document.getElementById("addSignatureDrawPlaceholder"),
  16647. drawThickness: document.getElementById("addSignatureDrawThickness"),
  16648. imageButton: document.getElementById("addSignatureImageButton"),
  16649. imageSVG: document.getElementById("addSignatureImage"),
  16650. imagePlaceholder: document.getElementById("addSignatureImagePlaceholder"),
  16651. imagePicker: document.getElementById("addSignatureFilePicker"),
  16652. imagePickerLink: document.getElementById("addSignatureImageBrowse"),
  16653. description: document.getElementById("addSignatureDescription"),
  16654. clearButton: document.getElementById("clearSignatureButton"),
  16655. saveContainer: document.getElementById("addSignatureSaveContainer"),
  16656. saveCheckbox: document.getElementById("addSignatureSaveCheckbox"),
  16657. errorBar: document.getElementById("addSignatureError"),
  16658. errorCloseButton: document.getElementById("addSignatureErrorCloseButton"),
  16659. cancelButton: document.getElementById("addSignatureCancelButton"),
  16660. addButton: document.getElementById("addSignatureAddButton")
  16661. },
  16662. editSignatureDialog: {
  16663. dialog: document.getElementById("editSignatureDescriptionDialog"),
  16664. description: document.getElementById("editSignatureDescription"),
  16665. editSignatureView: document.getElementById("editSignatureView"),
  16666. cancelButton: document.getElementById("editSignatureCancelButton"),
  16667. updateButton: document.getElementById("editSignatureUpdateButton")
  16668. },
  16669. annotationEditorParams: {
  16670. editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
  16671. editorFreeTextColor: document.getElementById("editorFreeTextColor"),
  16672. editorInkColor: document.getElementById("editorInkColor"),
  16673. editorInkThickness: document.getElementById("editorInkThickness"),
  16674. editorInkOpacity: document.getElementById("editorInkOpacity"),
  16675. editorStampAddImage: document.getElementById("editorStampAddImage"),
  16676. editorSignatureAddSignature: document.getElementById("editorSignatureAddSignature"),
  16677. editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness"),
  16678. editorHighlightShowAll: document.getElementById("editorHighlightShowAll")
  16679. },
  16680. printContainer: document.getElementById("printContainer"),
  16681. editorUndoBar: {
  16682. container: document.getElementById("editorUndoBar"),
  16683. message: document.getElementById("editorUndoBarMessage"),
  16684. undoButton: document.getElementById("editorUndoBarUndoButton"),
  16685. closeButton: document.getElementById("editorUndoBarCloseButton")
  16686. }
  16687. };
  16688. }
  16689. function webViewerLoad() {
  16690. const config = getViewerConfiguration();
  16691. const event = new CustomEvent("webviewerloaded", {
  16692. bubbles: true,
  16693. cancelable: true,
  16694. detail: {
  16695. source: window
  16696. }
  16697. });
  16698. try {
  16699. parent.document.dispatchEvent(event);
  16700. } catch (ex) {
  16701. console.error("webviewerloaded:", ex);
  16702. document.dispatchEvent(event);
  16703. }
  16704. PDFViewerApplication.run(config);
  16705. }
  16706. document.blockUnblockOnload?.(true);
  16707. if (document.readyState === "interactive" || document.readyState === "complete") {
  16708. webViewerLoad();
  16709. } else {
  16710. document.addEventListener("DOMContentLoaded", webViewerLoad, true);
  16711. }
  16712. var __webpack_exports__PDFViewerApplication = __webpack_exports__.PDFViewerApplication;
  16713. var __webpack_exports__PDFViewerApplicationConstants = __webpack_exports__.PDFViewerApplicationConstants;
  16714. var __webpack_exports__PDFViewerApplicationOptions = __webpack_exports__.PDFViewerApplicationOptions;
  16715. export { __webpack_exports__PDFViewerApplication as PDFViewerApplication, __webpack_exports__PDFViewerApplicationConstants as PDFViewerApplicationConstants, __webpack_exports__PDFViewerApplicationOptions as PDFViewerApplicationOptions };
  16716. //# sourceMappingURL=viewer.mjs.map