diff --git a/262895555_441278487364856_7316686619361518172_n.590a78f4.webp b/262895555_441278487364856_7316686619361518172_n.590a78f4.webp new file mode 100644 index 0000000..3024fc4 Binary files /dev/null and b/262895555_441278487364856_7316686619361518172_n.590a78f4.webp differ diff --git a/269938369_454534669372571_1947093545422259915_n.cf211a6e.webp b/269938369_454534669372571_1947093545422259915_n.cf211a6e.webp new file mode 100644 index 0000000..a4c0189 Binary files /dev/null and b/269938369_454534669372571_1947093545422259915_n.cf211a6e.webp differ diff --git a/269956173_454533756039329_4072914612737619889_n.ba07d08a.webp b/269956173_454533756039329_4072914612737619889_n.ba07d08a.webp new file mode 100644 index 0000000..3bcaa69 Binary files /dev/null and b/269956173_454533756039329_4072914612737619889_n.ba07d08a.webp differ diff --git a/273689848_485971852895519_4908781330946524575_n.49537a91.webp b/273689848_485971852895519_4908781330946524575_n.49537a91.webp new file mode 100644 index 0000000..0c5b2f6 Binary files /dev/null and b/273689848_485971852895519_4908781330946524575_n.49537a91.webp differ diff --git a/316935277_679619776864058_6564455032934480513_n.858257f8.webp b/316935277_679619776864058_6564455032934480513_n.858257f8.webp new file mode 100644 index 0000000..7cae6f7 Binary files /dev/null and b/316935277_679619776864058_6564455032934480513_n.858257f8.webp differ diff --git a/426686592_938590920966941_399216056587584926_n.cbede989.webp b/426686592_938590920966941_399216056587584926_n.cbede989.webp new file mode 100644 index 0000000..7a53806 Binary files /dev/null and b/426686592_938590920966941_399216056587584926_n.cbede989.webp differ diff --git a/431086734_941741980651835_8944467793448600810_n.b72dac28.webp b/431086734_941741980651835_8944467793448600810_n.b72dac28.webp new file mode 100644 index 0000000..f45c7c8 Binary files /dev/null and b/431086734_941741980651835_8944467793448600810_n.b72dac28.webp differ diff --git a/The_Rolling_Stones_-_Goats_Head_Soup.ccc5cfca.webp b/The_Rolling_Stones_-_Goats_Head_Soup.ccc5cfca.webp new file mode 100644 index 0000000..eea4da3 Binary files /dev/null and b/The_Rolling_Stones_-_Goats_Head_Soup.ccc5cfca.webp differ diff --git a/blog.html b/blog.html new file mode 100644 index 0000000..acb9daf --- /dev/null +++ b/blog.html @@ -0,0 +1 @@ +Blog - Sopa de cabra

Últimes notícies

Triple Disc de Platí

Triple Disc de Platí per les 130.000 còpies venudes del Ben Endins, que el certifica com el disc de pop rock en català més venut de la història!

Continua llegint

Que et vagi bé

A Ànima, cada senzill anirà acompanyat d'un Podcast a youtube i a Spotify Poadcasters! Ja teniu disponible el primer capítol.

Continua llegint
\ No newline at end of file diff --git a/entry.html b/entry.html new file mode 100644 index 0000000..72904b7 --- /dev/null +++ b/entry.html @@ -0,0 +1 @@ +Triple Disc de Platí
triple disc de platí

Triple Disc de Platí

Els Sopa de Cabra amb el triple disc de platí per les 130.000 còpies venudes del disc "Ben Endins".

Els gironins Sopa de Cabra han rebut aquest divendres el triple disc de platí per les 130.000 còpies físiques venudes del disc Ben endins’ que el certifica com el disc de pop rock en català més venut. Sopa de Cabra rebia el reconeixement en el marc del programa És nadal al món de RAC1, i de mans de Salvador Escribà, director de Salseta Discos. El passat 10 de maig, dia en què se celebraven 30 anys de la publicació del Ben endins, Sopa de Cabra va començar a anunciar els actes que formarien part d'aquest aniversari com una llarga gira que s'allargarà fins al novembre de l'any vinent. De fet, Sopa de Cabra va anunciar un gran final de festa d'aquest aniversari al Palau Sant Jordi el 26 de novembre de 2022.

En el marc d'aquesta celebració, el grup va publicar dues noves versions col·lectives dels seus clàssics Si et quedes amb mi amb Santi Balmes, Suu, Alguer Miquel, Judit Neddermann, Joan Dausà i Beth, i El boig de la ciutat amb Álvaro Soler, Alfred García i Ramon Mirabet. Sopa de Cabra va publicar també el 3 de desembre una edició especial i limitada en format de triple vinil i doble cedé que incloïa sis noves cançons enregistrades al mític concert de Zeleste, que va entrar directe al #46 de la Llista dels discos més venuts de l'estat espanyol.

Sopa de Cabra va anunciar un gran final de festa d'aquest aniversari al Palau Sant Jordi el 26 de novembre de 2022. Els gironins tornaran al Palau Sant Jordi onze anys després de la seva darrera actuació en aquest espai. Després del concert, el grup farà una aturada indefinida per tal de poder preparar noves cançons.

El disc Ben endins va ser enregistrat en directe a la Sala Zeleste, actualment Sala Razzmatazz, de Barcelona el 21 i 22 de febrer del 1991 i va ser publicat el 10 de maig del mateix any. A part de les cançons enregistrades en directe, aquest treball també incloïa 5 cançons inèdites d'estudi. En total, un doble LP de 19 cançons amb temes tan emblemàtics com Si et quedes amb mi, El boig de la ciutat, L'Empordà o Mai trobaràs.

Text: www.elpuntavui.cat

Sopa de Cabra Concert a Zeleste 21/02/1991

Llista de cançons

  1. «Tot queda igual», 2:58
  2. «Bloquejats», 4:51
  3. «Mai trobaràs», 3:32
  4. «El boig de la ciutat», 3:34
  5. «Cardíaco y acabado», 2:52
  6. «Si et quedes amb mi», 3:04
  7. «No tinguis pressa», 2:54
  8. «L'Estació de França», 3:10
  9. «El sexo (que me hace feliz)», 2:43
  10. «L'Empordà», 3:14
  11. «Quan et mous», 4:43
  12. «Ninyin's Mine», 2:50
  13. «Guerra», 4:37
  14. «Rock'n'Roll», 5:44
  15. «Sota una estrella», 3:08
  16. «No vull canviar de pell», 3:30
  17. «El so de la llum», 2:55
  18. «Fes la teva sort», 3:43
  19. «Podré tornar enrere», 5:02
\ No newline at end of file diff --git a/favicon-32x32.da17ac0b.png b/favicon-32x32.da17ac0b.png new file mode 100644 index 0000000..7ca1115 Binary files /dev/null and b/favicon-32x32.da17ac0b.png differ diff --git a/frontpage.c29f5254.webp b/frontpage.c29f5254.webp new file mode 100644 index 0000000..07e2dac Binary files /dev/null and b/frontpage.c29f5254.webp differ diff --git a/header.4b2d7a69.webp b/header.4b2d7a69.webp new file mode 100644 index 0000000..941eb0a Binary files /dev/null and b/header.4b2d7a69.webp differ diff --git a/img/gallery/12492024_219944455011344_336612228290827569_o.webp b/img/gallery/12492024_219944455011344_336612228290827569_o.webp new file mode 100644 index 0000000..993e51f Binary files /dev/null and b/img/gallery/12492024_219944455011344_336612228290827569_o.webp differ diff --git a/img/gallery/19667904_1253259684782475_8630511483122508075_o.webp b/img/gallery/19667904_1253259684782475_8630511483122508075_o.webp new file mode 100644 index 0000000..6819c04 Binary files /dev/null and b/img/gallery/19667904_1253259684782475_8630511483122508075_o.webp differ diff --git a/img/gallery/20863395_10213138061427446_2473429440185152936_o.webp b/img/gallery/20863395_10213138061427446_2473429440185152936_o.webp new file mode 100644 index 0000000..ea2d284 Binary files /dev/null and b/img/gallery/20863395_10213138061427446_2473429440185152936_o.webp differ diff --git a/img/gallery/20863499_10213138061067437_6524767662291126342_o.webp b/img/gallery/20863499_10213138061067437_6524767662291126342_o.webp new file mode 100644 index 0000000..8cac56b Binary files /dev/null and b/img/gallery/20863499_10213138061067437_6524767662291126342_o.webp differ diff --git a/img/gallery/20863606_10213138062427471_3964677280364398077_o.webp b/img/gallery/20863606_10213138062427471_3964677280364398077_o.webp new file mode 100644 index 0000000..4b6d3fa Binary files /dev/null and b/img/gallery/20863606_10213138062427471_3964677280364398077_o.webp differ diff --git a/img/gallery/20900575_10213138058907383_6383143293281590355_o.webp b/img/gallery/20900575_10213138058907383_6383143293281590355_o.webp new file mode 100644 index 0000000..81952c5 Binary files /dev/null and b/img/gallery/20900575_10213138058907383_6383143293281590355_o.webp differ diff --git a/img/gallery/20900836_10213138062747479_684569587259653747_o.webp b/img/gallery/20900836_10213138062747479_684569587259653747_o.webp new file mode 100644 index 0000000..72fdfff Binary files /dev/null and b/img/gallery/20900836_10213138062747479_684569587259653747_o.webp differ diff --git a/img/gallery/20900859_10213138057787355_8404973558510904910_o.webp b/img/gallery/20900859_10213138057787355_8404973558510904910_o.webp new file mode 100644 index 0000000..13528dc Binary files /dev/null and b/img/gallery/20900859_10213138057787355_8404973558510904910_o.webp differ diff --git a/img/gallery/20933876_10213138058827381_6194223440581518600_o.webp b/img/gallery/20933876_10213138058827381_6194223440581518600_o.webp new file mode 100644 index 0000000..f02dc9b Binary files /dev/null and b/img/gallery/20933876_10213138058827381_6194223440581518600_o.webp differ diff --git a/img/gallery/20934699_10213138062147464_8812593825107092398_o.webp b/img/gallery/20934699_10213138062147464_8812593825107092398_o.webp new file mode 100644 index 0000000..e7524d2 Binary files /dev/null and b/img/gallery/20934699_10213138062147464_8812593825107092398_o.webp differ diff --git a/img/gallery/20988225_10213138059467397_7909237604708182708_o.webp b/img/gallery/20988225_10213138059467397_7909237604708182708_o.webp new file mode 100644 index 0000000..20712c5 Binary files /dev/null and b/img/gallery/20988225_10213138059467397_7909237604708182708_o.webp differ diff --git a/img/gallery/20988944_10213138063187490_2487594279134998654_o.webp b/img/gallery/20988944_10213138063187490_2487594279134998654_o.webp new file mode 100644 index 0000000..e9cf00d Binary files /dev/null and b/img/gallery/20988944_10213138063187490_2487594279134998654_o.webp differ diff --git a/img/gallery/237482270_10226493791399343_6120046567788670868_n.webp b/img/gallery/237482270_10226493791399343_6120046567788670868_n.webp new file mode 100644 index 0000000..4899512 Binary files /dev/null and b/img/gallery/237482270_10226493791399343_6120046567788670868_n.webp differ diff --git a/index.710f3afd.css b/index.710f3afd.css new file mode 100644 index 0000000..fbd203f --- /dev/null +++ b/index.710f3afd.css @@ -0,0 +1,2 @@ +:root{--primary-color:#ffc94a;--secondary-color:#c08b5c;--ternary-color:#795458;--quaternary-color:#453f78;--accent-color:#c08b5c;--light-color:#fafbfd;--bg-color:antiquewhite}*{box-sizing:border-box;margin:0;padding:0}body{color:var(--ternary-color);font-family:Fira Sans,sans-serif;font-weight:300;line-height:1.5}h1,h2{margin-bottom:10px;font-weight:700}p{margin-bottom:1rem;font-size:1.1rem}a{color:var(--quaternary-color);border-bottom:1px dotted #453f78;border-bottom:1px dotted var(--quaternary-color);text-decoration:none}a:hover{color:var(--primary-color);border-bottom:1px solid #ffc94a;border-bottom:1px solid var(--primary-color)}h1{letter-spacing:-1px;text-align:center;font-size:2.5rem;font-weight:700}@media (min-width:576px){h1{font-size:3rem;font-weight:900}}h2{text-align:center;margin-bottom:1.5rem;font-size:2rem;font-weight:700}@media (min-width:576px){h2{font-size:2.5rem;font-weight:900}}h3{border-bottom:1px solid #ffc94a;border-bottom:1px solid var(--primary-color);margin-bottom:1rem;font-size:1.75rem}ol,ul{margin-bottom:1rem;margin-left:1.5rem}@media (min-width:576px){:is(ol,ul){margin-left:3rem}}:is(ol,ul) li{margin-bottom:.5rem;font-size:1.1rem}ul{list-style-type:square}main{min-height:calc(100vh - 310px);padding-top:50px;padding-bottom:50px}.paper{background-color:#faebd7;background-color:var(--bg-color)}.container{width:100%;margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}header{background:url(header.4b2d7a69.webp) 50%/cover no-repeat;height:180px;padding:15px}header a.logo{color:#fff;font-family:Protest Revolution,sans-serif;font-size:2.5rem;font-style:normal;font-weight:400}@media (min-width:576px){header a.logo{font-size:3rem}}header a.logo:hover{color:var(--primary-color)}header .container{color:#fff;text-align:center;background:#453f78cc;max-width:500px;padding:10px}header .logo{border:0;margin-bottom:5px;display:block}header .logo img{width:auto;height:80px}header nav{text-align:center;text-transform:uppercase}header nav ul{margin:0;padding-left:0}header nav ul li{margin-right:1rem;padding-bottom:.2rem;font-weight:500;display:inline-block}header nav ul li a{color:inherit;border:none}header nav ul li a:hover{color:var(--accent-color);border:none}header nav ul li:last-child{margin-right:0}header nav li.active{color:var(--accent-color);border-bottom:2px solid #c08b5c;border-bottom:2px solid var(--accent-color);text-shadow:0 0 8px #000c}header nav li.active a:hover{color:inherit}footer{background-color:#453f78;background-color:var(--quaternary-color);color:#fff;height:130px;padding:30px 15px;font-size:.8rem}footer p{font-size:inherit;margin-bottom:.5rem}footer a{color:var(--accent-color);border:none}footer a:hover{color:var(--primary-color);border:none}footer ul{margin-bottom:5px;margin-left:0;list-style-type:none}footer ul li{padding-right:1rem;display:inline-block}footer ul li:last-child{padding-right:0}.intro{width:90%;margin-left:auto;margin-right:auto;font-size:1.1rem}@media (min-width:768px){.intro{width:75%;margin:3rem auto;font-size:1.5rem}}.video{margin:20px 0}@media (min-width:768px){.video{margin:40px 0}}.video-container{width:100%;height:0;padding-bottom:56.25%;position:relative}.video-container-43{width:100%;height:0;padding-bottom:75%;position:relative}.video-box{width:100%;height:100%;position:absolute;top:0;left:0}.video-desc{font-size:.9rem}.clearfix{overflow:auto}body.home{color:var(--primary-color);text-align:center;background-image:url(frontpage.c29f5254.webp);background-position:50%;background-repeat:no-repeat;background-size:cover}body.home header{background:0 0}body.home main{padding-top:calc(100vh - 850px)}body.home main p{font-size:1.1rem}@media (min-width:1200px){body.home main p{font-size:2.3rem}}body.home h1{text-shadow:0 2px 2px #0009;font-family:Protest Revolution,sans-serif;font-size:6rem;font-style:normal;font-weight:400;line-height:1}@media (min-width:576px){body.home h1{font-size:8rem}}@media (min-width:768px){body.home h1{font-size:10rem}}@media (min-width:1200px){body.home h1{font-size:12rem}}body.home a{color:inherit;border:none}body.home nav ul{margin-left:0;padding-top:1rem;padding-left:0}body.home nav ul li{font-size:1.3rem}body.home .home-logo{width:500px;height:auto;margin-bottom:30px}body.home footer{text-align:center;background-color:#0000;font-weight:500}body.home footer .copyright a,body.home footer a:hover{color:var(--accent-color)}.table-fluid{width:100%;margin-top:30px;margin-bottom:30px;overflow-x:auto}table{border-spacing:0;border-collapse:collapse;width:100%}caption{border-top:1px solid #ffc94a;border-top:1px solid var(--primary-color);padding:15px;font-size:1.3rem;font-weight:700}td,th{vertical-align:bottom;text-align:left;padding:.5rem;font-size:1.1rem}td{color:var(--secondary-color)}th[scope=col]:first-of-type{text-align:left}th[scope=col]{font-size:1rem;font-weight:400}th[scope=row]{text-align:left;font-size:1.4rem;font-weight:700}thead tr{border-top:1px solid #ffc94a;border-top:1px solid var(--primary-color);border-bottom:1px solid #ffc94a;border-bottom:1px solid var(--primary-color)}tbody tr:nth-child(odd){background-color:#453f78;background-color:var(--quaternary-color)}tbody tr:nth-child(odd) a{color:var(--secondary-color);border-bottom:1px dotted #c08b5c;border-bottom:1px dotted var(--secondary-color)}tbody tr:nth-child(odd) a:hover{color:var(--primary-color);border-bottom:1px solid #ffc94a;border-bottom:1px solid var(--primary-color)}tfoot{border-bottom:1px solid #ffc94a;border-bottom:1px solid var(--primary-color)}tfoot td{text-align:left;font-size:.8rem}.aims-img{border:1px solid #453f78;border:solid 1px var(--quaternary-color);float:right;text-align:center;width:152px;margin-left:12px;font-size:small}@media (min-width:768px){.aims-img{width:252px}}.aims-img img{width:150px;height:150px}@media (min-width:768px){.aims-img img{width:250px;height:250px}}.grid-blog article{background:#fafbfd;background:var(--light-color);border:1px solid #ffc94a;border:1px solid var(--primary-color);margin-bottom:3rem}.grid-blog article h1,.grid-blog article h2{text-align:start}@media (min-width:768px){.grid-blog{grid-template-columns:repeat(2,1fr);gap:3rem;display:grid}.grid-blog article{margin-bottom:0}}@media (min-width:1200px){.grid-blog{grid-template-columns:repeat(4,1fr);gap:3rem;display:grid}.grid-blog article:first-child{grid-column:1/span 2}}.card-content{padding:15px}.card-content h2{margin-top:0;margin-bottom:.5rem;font-size:1.75rem;font-weight:700;line-height:1.2}:is(.card-content h2,.card-content h4) a{color:var(--ternary-color);border-bottom:none}:is(.card-content h2,.card-content h4) a:hover{color:var(--accent-color)}.meta-data{color:var(--secondary-color);margin-bottom:2px;font-size:.9rem}.card-image{position:relative}.card-image a{background-color:#453f78;background-color:var(--quaternary-color);color:var(--light-color);border-bottom:none;padding:.5rem;font-size:.8rem;position:absolute;top:8px;left:8px}.card-image a:hover{background:#c08b5c;background:var(--accent-color)}.img-fluid{object-fit:cover;width:100%;height:auto;display:block}.blog-navigation{justify-content:center;gap:1rem;margin-top:4rem;list-style-type:none;display:flex}.blog-navigation li a{border:1px solid #ffc94a;border:1px solid var(--primary-color);background-color:#fafbfd;background-color:var(--light-color);padding:.5rem;text-decoration:none;display:inline-block}.blog-navigation li a:hover,.blog-navigation li a.current{background-color:#c08b5c;background-color:var(--accent-color);border:1px solid #c08b5c;border:1px solid var(--accent-color);color:var(--light-color)}a.more{margin-top:0;display:inline-block}a.more:after{content:">";padding-left:.5rem}ul.breadcrumb{margin-top:1rem;margin-bottom:2rem;margin-left:0;font-size:.8rem;list-style:none}ul.breadcrumb li{display:inline-block}ul.breadcrumb li a{border-bottom:none}ul.breadcrumb li a:hover{color:var(--accent-color)}ul.breadcrumb li+li{padding-left:.25rem}ul.breadcrumb li+li:before{content:">";padding-right:.25rem}ul.breadcrumb li.active{font-weight:700}.grid-blog-post h1,.grid-blog-post h2{text-align:start}@media (min-width:1200px){.grid-blog-post{grid-template-columns:65% auto;gap:4rem;display:grid}}.blog-post{background-color:#fafbfd;background-color:var(--light-color);border:1px solid #ffc94a;border:solid 1px var(--primary-color);padding:1rem}.blog-post header{background-color:#faebd7;background-image:none;background-color:var(--bg-color);height:fit-content;padding:.7rem}.blog-post header a{border-bottom:none}.blog-post header a:hover{color:var(--accent-color)}.blog-post h1{margin-bottom:1rem;font-size:2.6rem;line-height:1.2}.blog-post h2{margin-top:1rem;margin-bottom:1rem;font-size:2rem}.blog-post .intro{margin-top:1.5rem;margin-bottom:1.5rem}@media (min-width:768px){.blog-post .intro{margin-top:3rem;margin-bottom:3rem}}.blog-post blockquote{border-left:3px solid #c08b5c;border-left:3px solid var(--accent-color);margin-bottom:1rem;padding-left:2rem}@media (min-width:1200px){.blog-post blockquote{margin-left:3rem;padding-left:2rem}.blog-post blockquote p{font-size:1.6rem}}.last-posts{grid-template-columns:1fr;column-gap:20px;display:grid}@media (min-width:768px){.last-posts{grid-template-columns:1fr 1fr}}@media (min-width:1200px){.last-posts{grid-template-columns:1fr}}.last-posts article{background-color:#fafbfd;background-color:var(--light-color);border:1px solid #ffc94a;border:solid 1px var(--primary-color);margin-bottom:2rem}@media (min-width:1200px){.last-posts article{margin-top:0;display:block}}.last-posts article .card-content{padding:10px}aside section:first-of-type{margin-top:3rem}@media (min-width:1200px){aside section:first-of-type{margin-top:0}}aside section:last-of-type a{background-color:#fafbfd;background-color:var(--light-color);border:1px solid #ffc94a;border:solid 1px var(--primary-color);margin-bottom:.5rem;margin-right:.5rem;padding:.25rem;text-decoration:none;display:inline-block}aside section:last-of-type a:hover{background-color:#c08b5c;background-color:var(--accent-color);border:1px solid #c08b5c;border:1px solid var(--accent-color);color:var(--light-color)}aside section:last-of-type ul{margin-left:0;font-size:.8rem;list-style-type:none}@media (min-width:1200px){aside section:last-of-type ul{display:block}}aside section:last-of-type ul li{display:inline-block} +/*# sourceMappingURL=index.710f3afd.css.map */ diff --git a/index.710f3afd.css.map b/index.710f3afd.css.map new file mode 100644 index 0000000..d9e1c08 --- /dev/null +++ b/index.710f3afd.css.map @@ -0,0 +1 @@ +{"mappings":"ACAA,gLAUA,2CAMA,iGAQA,yCAMA,sCAKA,uIAQA,gHAOA,0EAME,yBAA2B,mCAM7B,yEAME,yBAA2B,qCAM7B,qHAOA,4CAKE,yBAA2B,6BAI3B,mDAMF,0BAIA,yEAMA,iEAKA,8FAOE,yBAA2B,4BAI3B,yBAA2B,4BAI3B,yBAA2B,4BAI3B,0BAA4B,6BAK9B,2GAME,sHAOE,yBAA2B,8BAK7B,+CAKA,iGAQA,sDAKE,wCAYF,sDAIE,sCAIE,6FAME,6CAKA,+DAOF,2CAKF,qJAOE,2CAWN,mIAQE,+CAKA,+CAMA,sDAMA,+DAKE,qDAKA,wCAMJ,qEAME,yBAA2B,oDAO7B,qBAGE,yBAA2B,sBAO7B,6EASA,6EAOA,iEAQA,4BAIA,wBAIA,gMASE,gCAIA,+CAGE,kCAGE,0BAA4B,mCAMhC,kJAQE,yBAA2B,6BAI3B,yBAA2B,8BAI3B,0BAA4B,8BAK9B,sCAME,+DAKE,qCAMJ,gEAMA,0EAKE,iFAYJ,2EAOA,2DAMA,6HAQA,2EAQA,gCAKA,4CAIA,6CAKA,+DAOE,6JASA,0FAIE,wIAOA,wIASJ,mFAIE,yCAMF,uJASE,yBAA2B,uBAI3B,uCAIE,yBAA2B,wCAQ7B,sJAOE,6DAMF,yBAA2B,qEAKzB,oCAKF,0BAA4B,qEAK1B,qDAMJ,2BAGE,oGAUE,uFASA,yEAOJ,0EAOA,8BAGE,6LAaA,sEAMF,iEAOA,mGAQI,0MAUA,+MAYJ,yCAKA,4CAKA,+FAOE,sCAGE,sCAIA,mDAMF,wCAIA,4DAKA,wCAMA,uDAKA,0BAA4B,sEAO9B,oJAOE,mIAOE,uCAIA,oDAMF,kEAMA,gEAMA,yDAIE,yBAA2B,sDAM7B,mIAME,0BAA4B,yDAME,0CAOlC,mEAKE,yBAA2B,2CAI3B,0BAA4B,uCAI5B,mKAOE,0BAA4B,gDAK5B,+CAOF,4CAGE,0BAA4B,0CAM5B,yPAYA,wLASA,iFAKE,0BAA4B,6CAI5B","sources":["index.710f3afd.css","src/css/style.css"],"sourcesContent":[":root {\n --primary-color: #ffc94a;\n --secondary-color: #c08b5c;\n --ternary-color: #795458;\n --quaternary-color: #453f78;\n --accent-color: #c08b5c;\n --light-color: #fafbfd;\n --bg-color: antiquewhite;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n color: var(--ternary-color);\n font-family: Fira Sans, sans-serif;\n font-weight: 300;\n line-height: 1.5;\n}\n\nh1, h2 {\n margin-bottom: 10px;\n font-weight: 700;\n}\n\np {\n margin-bottom: 1rem;\n font-size: 1.1rem;\n}\n\na {\n color: var(--quaternary-color);\n border-bottom: 1px dotted #453f78;\n border-bottom: 1px dotted var(--quaternary-color);\n text-decoration: none;\n}\n\na:hover {\n color: var(--primary-color);\n border-bottom: 1px solid #ffc94a;\n border-bottom: 1px solid var(--primary-color);\n}\n\nh1 {\n letter-spacing: -1px;\n text-align: center;\n font-size: 2.5rem;\n font-weight: 700;\n}\n\n@media (width >= 576px) {\n h1 {\n font-size: 3rem;\n font-weight: 900;\n }\n}\n\nh2 {\n text-align: center;\n margin-bottom: 1.5rem;\n font-size: 2rem;\n font-weight: 700;\n}\n\n@media (width >= 576px) {\n h2 {\n font-size: 2.5rem;\n font-weight: 900;\n }\n}\n\nh3 {\n border-bottom: 1px solid #ffc94a;\n border-bottom: 1px solid var(--primary-color);\n margin-bottom: 1rem;\n font-size: 1.75rem;\n}\n\nol, ul {\n margin-bottom: 1rem;\n margin-left: 1.5rem;\n}\n\n@media (width >= 576px) {\n :is(ol, ul) {\n margin-left: 3rem;\n }\n}\n\n:is(ol, ul) li {\n margin-bottom: .5rem;\n font-size: 1.1rem;\n}\n\nul {\n list-style-type: square;\n}\n\nmain {\n min-height: calc(100vh - 310px);\n padding-top: 50px;\n padding-bottom: 50px;\n}\n\n.paper {\n background-color: #faebd7;\n background-color: var(--bg-color);\n}\n\n.container {\n width: 100%;\n margin-left: auto;\n margin-right: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n\n@media (width >= 576px) {\n .container {\n max-width: 540px;\n }\n}\n\n@media (width >= 768px) {\n .container {\n max-width: 720px;\n }\n}\n\n@media (width >= 992px) {\n .container {\n max-width: 960px;\n }\n}\n\n@media (width >= 1200px) {\n .container {\n max-width: 1140px;\n }\n}\n\nheader {\n background: url(\"header.4b2d7a69.webp\") 50% / cover no-repeat;\n height: 180px;\n padding: 15px;\n}\n\nheader a.logo {\n color: #fff;\n font-family: Protest Revolution, sans-serif;\n font-size: 2.5rem;\n font-style: normal;\n font-weight: 400;\n}\n\n@media (width >= 576px) {\n header a.logo {\n font-size: 3rem;\n }\n}\n\nheader a.logo:hover {\n color: var(--primary-color);\n}\n\nheader .container {\n color: #fff;\n text-align: center;\n background: #453f78cc;\n max-width: 500px;\n padding: 10px;\n}\n\nheader .logo {\n border: 0;\n margin-bottom: 5px;\n display: block;\n}\n\nheader .logo img {\n width: auto;\n height: 80px;\n}\n\nheader nav {\n text-align: center;\n text-transform: uppercase;\n}\n\nheader nav ul {\n margin: 0;\n padding-left: 0;\n}\n\nheader nav ul li {\n margin-right: 1rem;\n padding-bottom: .2rem;\n font-weight: 500;\n display: inline-block;\n}\n\nheader nav ul li a {\n color: inherit;\n border: none;\n}\n\nheader nav ul li a:hover {\n color: var(--accent-color);\n border: none;\n}\n\nheader nav ul li:last-child {\n margin-right: 0;\n}\n\nheader nav li.active {\n color: var(--accent-color);\n border-bottom: 2px solid #c08b5c;\n border-bottom: 2px solid var(--accent-color);\n text-shadow: 0 0 8px #000c;\n}\n\nheader nav li.active a:hover {\n color: inherit;\n}\n\nfooter {\n background-color: #453f78;\n background-color: var(--quaternary-color);\n color: #fff;\n height: 130px;\n padding: 30px 15px;\n font-size: .8rem;\n}\n\nfooter p {\n font-size: inherit;\n margin-bottom: .5rem;\n}\n\nfooter a {\n color: var(--accent-color);\n border: none;\n}\n\nfooter a:hover {\n color: var(--primary-color);\n border: none;\n}\n\nfooter ul {\n margin-bottom: 5px;\n margin-left: 0;\n list-style-type: none;\n}\n\nfooter ul li {\n padding-right: 1rem;\n display: inline-block;\n}\n\nfooter ul li:last-child {\n padding-right: 0;\n}\n\n.intro {\n width: 90%;\n margin-left: auto;\n margin-right: auto;\n font-size: 1.1rem;\n}\n\n@media (width >= 768px) {\n .intro {\n width: 75%;\n margin: 3rem auto;\n font-size: 1.5rem;\n }\n}\n\n.video {\n margin: 20px 0;\n}\n\n@media (width >= 768px) {\n .video {\n margin: 40px 0;\n }\n}\n\n.video-container {\n width: 100%;\n height: 0;\n padding-bottom: 56.25%;\n position: relative;\n}\n\n.video-container-43 {\n width: 100%;\n height: 0;\n padding-bottom: 75%;\n position: relative;\n}\n\n.video-box {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.video-desc {\n font-size: .9rem;\n}\n\n.clearfix {\n overflow: auto;\n}\n\nbody.home {\n color: var(--primary-color);\n text-align: center;\n background-image: url(\"frontpage.c29f5254.webp\");\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\nbody.home header {\n background: none;\n}\n\nbody.home main {\n padding-top: calc(100vh - 850px);\n}\n\nbody.home main p {\n font-size: 1.1rem;\n}\n\n@media (width >= 1200px) {\n body.home main p {\n font-size: 2.3rem;\n }\n}\n\nbody.home h1 {\n text-shadow: 0 2px 2px #0009;\n font-family: Protest Revolution, sans-serif;\n font-size: 6rem;\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n}\n\n@media (width >= 576px) {\n body.home h1 {\n font-size: 8rem;\n }\n}\n\n@media (width >= 768px) {\n body.home h1 {\n font-size: 10rem;\n }\n}\n\n@media (width >= 1200px) {\n body.home h1 {\n font-size: 12rem;\n }\n}\n\nbody.home a {\n color: inherit;\n border: none;\n}\n\nbody.home nav ul {\n margin-left: 0;\n padding-top: 1rem;\n padding-left: 0;\n}\n\nbody.home nav ul li {\n font-size: 1.3rem;\n}\n\nbody.home .home-logo {\n width: 500px;\n height: auto;\n margin-bottom: 30px;\n}\n\nbody.home footer {\n text-align: center;\n background-color: #0000;\n font-weight: 500;\n}\n\nbody.home footer .copyright a, body.home footer a:hover {\n color: var(--accent-color);\n}\n\n.table-fluid {\n width: 100%;\n margin-top: 30px;\n margin-bottom: 30px;\n overflow-x: auto;\n}\n\ntable {\n border-spacing: 0;\n border-collapse: collapse;\n width: 100%;\n}\n\ncaption {\n border-top: 1px solid #ffc94a;\n border-top: 1px solid var(--primary-color);\n padding: 15px;\n font-size: 1.3rem;\n font-weight: 700;\n}\n\ntd, th {\n vertical-align: bottom;\n text-align: left;\n padding: .5rem;\n font-size: 1.1rem;\n}\n\ntd {\n color: var(--secondary-color);\n}\n\nth[scope=\"col\"]:first-of-type {\n text-align: left;\n}\n\nth[scope=\"col\"] {\n font-size: 1rem;\n font-weight: normal;\n}\n\nth[scope=\"row\"] {\n text-align: left;\n font-size: 1.4rem;\n font-weight: bold;\n}\n\nthead tr {\n border-top: 1px solid #ffc94a;\n border-top: 1px solid var(--primary-color);\n border-bottom: 1px solid #ffc94a;\n border-bottom: 1px solid var(--primary-color);\n}\n\ntbody tr:nth-child(odd) {\n background-color: #453f78;\n background-color: var(--quaternary-color);\n}\n\ntbody tr:nth-child(odd) a {\n color: var(--secondary-color);\n border-bottom: 1px dotted #c08b5c;\n border-bottom: 1px dotted var(--secondary-color);\n}\n\ntbody tr:nth-child(odd) a:hover {\n color: var(--primary-color);\n border-bottom: 1px solid #ffc94a;\n border-bottom: 1px solid var(--primary-color);\n}\n\ntfoot {\n border-bottom: 1px solid #ffc94a;\n border-bottom: 1px solid var(--primary-color);\n}\n\ntfoot td {\n text-align: left;\n font-size: .8rem;\n}\n\n.aims-img {\n border: 1px solid #453f78;\n border: solid 1px var(--quaternary-color);\n float: right;\n text-align: center;\n width: 152px;\n margin-left: 12px;\n font-size: small;\n}\n\n@media (width >= 768px) {\n .aims-img {\n width: 252px;\n }\n}\n\n.aims-img img {\n width: 150px;\n height: 150px;\n}\n\n@media (width >= 768px) {\n .aims-img img {\n width: 250px;\n height: 250px;\n }\n}\n\n.grid-blog article {\n background: #fafbfd;\n background: var(--light-color);\n border: 1px solid #ffc94a;\n border: 1px solid var(--primary-color);\n margin-bottom: 3rem;\n}\n\n.grid-blog article h1, .grid-blog article h2 {\n text-align: start;\n}\n\n@media (width >= 768px) {\n .grid-blog {\n grid-template-columns: repeat(2, 1fr);\n gap: 3rem;\n display: grid;\n }\n\n .grid-blog article {\n margin-bottom: 0;\n }\n}\n\n@media (width >= 1200px) {\n .grid-blog {\n grid-template-columns: repeat(4, 1fr);\n gap: 3rem;\n display: grid;\n }\n\n .grid-blog article:first-child {\n grid-column: 1 / span 2;\n }\n}\n\n.card-content {\n padding: 15px;\n}\n\n.card-content h2 {\n margin-top: 0;\n margin-bottom: .5rem;\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.2;\n}\n\n:is(.card-content h2, .card-content h4) a {\n color: var(--ternary-color);\n border-bottom: none;\n}\n\n:is(.card-content h2, .card-content h4) a:hover {\n color: var(--accent-color);\n}\n\n.meta-data {\n color: var(--secondary-color);\n margin-bottom: 2px;\n font-size: .9rem;\n}\n\n.card-image {\n position: relative;\n}\n\n.card-image a {\n background-color: #453f78;\n background-color: var(--quaternary-color);\n color: var(--light-color);\n border-bottom: none;\n padding: .5rem;\n font-size: .8rem;\n position: absolute;\n top: 8px;\n left: 8px;\n}\n\n.card-image a:hover {\n background: #c08b5c;\n background: var(--accent-color);\n}\n\n.img-fluid {\n object-fit: cover;\n width: 100%;\n height: auto;\n display: block;\n}\n\n.blog-navigation {\n justify-content: center;\n gap: 1rem;\n margin-top: 4rem;\n list-style-type: none;\n display: flex;\n}\n\n.blog-navigation li a {\n border: 1px solid #ffc94a;\n border: 1px solid var(--primary-color);\n background-color: #fafbfd;\n background-color: var(--light-color);\n padding: .5rem;\n text-decoration: none;\n display: inline-block;\n}\n\n.blog-navigation li a:hover, .blog-navigation li a.current {\n background-color: #c08b5c;\n background-color: var(--accent-color);\n border: 1px solid #c08b5c;\n border: 1px solid var(--accent-color);\n color: var(--light-color);\n}\n\na.more {\n margin-top: 0;\n display: inline-block;\n}\n\na.more:after {\n content: \">\";\n padding-left: .5rem;\n}\n\nul.breadcrumb {\n margin-top: 1rem;\n margin-bottom: 2rem;\n margin-left: 0;\n font-size: .8rem;\n list-style: none;\n}\n\nul.breadcrumb li {\n display: inline-block;\n}\n\nul.breadcrumb li a {\n border-bottom: none;\n}\n\nul.breadcrumb li a:hover {\n color: var(--accent-color);\n}\n\nul.breadcrumb li + li {\n padding-left: .25rem;\n}\n\nul.breadcrumb li + li:before {\n content: \">\";\n padding-right: .25rem;\n}\n\nul.breadcrumb li.active {\n font-weight: 700;\n}\n\n.grid-blog-post h1, .grid-blog-post h2 {\n text-align: start;\n}\n\n@media (width >= 1200px) {\n .grid-blog-post {\n grid-template-columns: 65% auto;\n gap: 4rem;\n display: grid;\n }\n}\n\n.blog-post {\n background-color: #fafbfd;\n background-color: var(--light-color);\n border: 1px solid #ffc94a;\n border: solid 1px var(--primary-color);\n padding: 1rem;\n}\n\n.blog-post header {\n background-color: #faebd7;\n background-image: none;\n background-color: var(--bg-color);\n height: fit-content;\n padding: .7rem;\n}\n\n.blog-post header a {\n border-bottom: none;\n}\n\n.blog-post header a:hover {\n color: var(--accent-color);\n}\n\n.blog-post h1 {\n margin-bottom: 1rem;\n font-size: 2.6rem;\n line-height: 1.2;\n}\n\n.blog-post h2 {\n margin-top: 1rem;\n margin-bottom: 1rem;\n font-size: 2rem;\n}\n\n.blog-post .intro {\n margin-top: 1.5rem;\n margin-bottom: 1.5rem;\n}\n\n@media (width >= 768px) {\n .blog-post .intro {\n margin-top: 3rem;\n margin-bottom: 3rem;\n }\n}\n\n.blog-post blockquote {\n border-left: 3px solid #c08b5c;\n border-left: 3px solid var(--accent-color);\n margin-bottom: 1rem;\n padding-left: 2rem;\n}\n\n@media (width >= 1200px) {\n .blog-post blockquote {\n margin-left: 3rem;\n padding-left: 2rem;\n }\n\n .blog-post blockquote p {\n font-size: 1.6rem;\n }\n}\n\n.last-posts {\n grid-template-columns: 1fr;\n column-gap: 20px;\n display: grid;\n}\n\n@media (width >= 768px) {\n .last-posts {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n@media (width >= 1200px) {\n .last-posts {\n grid-template-columns: 1fr;\n }\n}\n\n.last-posts article {\n background-color: #fafbfd;\n background-color: var(--light-color);\n border: 1px solid #ffc94a;\n border: solid 1px var(--primary-color);\n margin-bottom: 2rem;\n}\n\n@media (width >= 1200px) {\n .last-posts article {\n margin-top: 0;\n display: block;\n }\n}\n\n.last-posts article .card-content {\n padding: 10px;\n}\n\naside section:first-of-type {\n margin-top: 3rem;\n}\n\n@media (width >= 1200px) {\n aside section:first-of-type {\n margin-top: 0;\n }\n}\n\naside section:last-of-type a {\n background-color: #fafbfd;\n background-color: var(--light-color);\n border: 1px solid #ffc94a;\n border: solid 1px var(--primary-color);\n margin-bottom: .5rem;\n margin-right: .5rem;\n padding: .25rem;\n text-decoration: none;\n display: inline-block;\n}\n\naside section:last-of-type a:hover {\n background-color: #c08b5c;\n background-color: var(--accent-color);\n border: 1px solid #c08b5c;\n border: 1px solid var(--accent-color);\n color: var(--light-color);\n}\n\naside section:last-of-type ul {\n margin-left: 0;\n font-size: .8rem;\n list-style-type: none;\n}\n\n@media (width >= 1200px) {\n aside section:last-of-type ul {\n display: block;\n }\n}\n\naside section:last-of-type ul li {\n display: inline-block;\n}\n/*# sourceMappingURL=index.710f3afd.css.map */\n","@import './base.css';\n@import './frontpage.css';\n@import './start.css';\n@import './blog.css';\n@import './entry.css';\n"],"names":[],"version":3,"file":"index.710f3afd.css.map"} \ No newline at end of file diff --git a/index.7df0f162.js b/index.7df0f162.js new file mode 100644 index 0000000..f87a4a8 --- /dev/null +++ b/index.7df0f162.js @@ -0,0 +1,2 @@ +var o={};o=(o=0)=>new Promise(e=>setTimeout(e,o)),async function(){var e;console.log("Going!"),await ((e=o)&&e.__esModule?e.default:e)(200),console.log("Ending!")}(); +//# sourceMappingURL=index.7df0f162.js.map diff --git a/index.7df0f162.js.map b/index.7df0f162.js.map new file mode 100644 index 0000000..a403c96 --- /dev/null +++ b/index.7df0f162.js.map @@ -0,0 +1 @@ +{"mappings":"A,I,E,C,EEEA,EAFa,CAAC,EAAS,CAAC,GAAK,IAAI,QAAQ,AAAA,GAAW,WAAW,EAAS,IDSxE,AANA,qB,EACE,QAAQ,GAAG,CAAC,UACZ,MAAM,AAAA,CAAA,A,C,EAAA,I,E,U,C,E,O,C,CAAA,EAAK,KACX,QAAQ,GAAG,CAAC,UACd","sources":["","src/js/index.js","node_modules/waait/index.js"],"sourcesContent":["\nfunction $parcel$interopDefault(a) {\n return a && a.__esModule ? a.default : a;\n}\n// index.js\nvar $108cc35f84e0fa19$exports = {};\nconst $108cc35f84e0fa19$var$wait = (amount = 0)=>new Promise((resolve)=>setTimeout(resolve, amount));\n$108cc35f84e0fa19$exports = $108cc35f84e0fa19$var$wait;\n\n\nasync function $1e7d327333d6316b$var$go() {\n console.log('Going!');\n await (0, (/*@__PURE__*/$parcel$interopDefault($108cc35f84e0fa19$exports)))(200);\n console.log('Ending!');\n}\n$1e7d327333d6316b$var$go();\n\n\n//# sourceMappingURL=index.7df0f162.js.map\n","// index.js\nimport wait from 'waait';\n\nasync function go() {\n console.log('Going!');\n await wait(200);\n console.log('Ending!');\n}\n\ngo();\n","const wait = (amount = 0) => new Promise(resolve => setTimeout(resolve, amount));\n\nmodule.exports = wait;\n"],"names":["$108cc35f84e0fa19$exports","amount","Promise","resolve","setTimeout","$1e7d327333d6316b$var$go","a","console","log","__esModule","default"],"version":3,"file":"index.7df0f162.js.map"} \ No newline at end of file diff --git a/index.c1245c29.js b/index.c1245c29.js new file mode 100644 index 0000000..498863e --- /dev/null +++ b/index.c1245c29.js @@ -0,0 +1,2 @@ +var o;o={},o=(o=0)=>new Promise(e=>setTimeout(e,o)),async function(){var e;console.log("Going!"),await ((e=o)&&e.__esModule?e.default:e)(200),console.log("Ending!")}(); +//# sourceMappingURL=index.c1245c29.js.map diff --git a/index.c1245c29.js.map b/index.c1245c29.js.map new file mode 100644 index 0000000..bf83250 --- /dev/null +++ b/index.c1245c29.js.map @@ -0,0 +1 @@ +{"mappings":"A,I,E,E,C,EEEA,EAFa,CAAC,EAAS,CAAC,GAAK,IAAI,QAAQ,AAAA,GAAW,WAAW,EAAS,IDSxE,AANA,qB,EACE,QAAQ,GAAG,CAAC,UACZ,MAAM,AAAA,CAAA,A,C,EAAA,I,E,U,C,E,O,C,CAAA,EAAK,KACX,QAAQ,GAAG,CAAC,UACd","sources":["","src/js/index.js","node_modules/waait/index.js"],"sourcesContent":["(function () {\n\nfunction $parcel$interopDefault(a) {\n return a && a.__esModule ? a.default : a;\n}\n// index.js\nvar $149be58dad956dbb$exports = {};\nconst $149be58dad956dbb$var$wait = (amount = 0)=>new Promise((resolve)=>setTimeout(resolve, amount));\n$149be58dad956dbb$exports = $149be58dad956dbb$var$wait;\n\n\nasync function $dfb6d0416c4d943a$var$go() {\n console.log('Going!');\n await (0, (/*@__PURE__*/$parcel$interopDefault($149be58dad956dbb$exports)))(200);\n console.log('Ending!');\n}\n$dfb6d0416c4d943a$var$go();\n\n})();\n//# sourceMappingURL=index.c1245c29.js.map\n","// index.js\nimport wait from 'waait';\n\nasync function go() {\n console.log('Going!');\n await wait(200);\n console.log('Ending!');\n}\n\ngo();\n","const wait = (amount = 0) => new Promise(resolve => setTimeout(resolve, amount));\n\nmodule.exports = wait;\n"],"names":["$149be58dad956dbb$exports","amount","Promise","resolve","setTimeout","$dfb6d0416c4d943a$var$go","a","console","log","__esModule","default"],"version":3,"file":"index.c1245c29.js.map"} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..8b97df9 --- /dev/null +++ b/index.html @@ -0,0 +1 @@ +Sopa de cabra

Sopa de cabra

\ No newline at end of file diff --git a/links.html b/links.html new file mode 100644 index 0000000..ccf7437 --- /dev/null +++ b/links.html @@ -0,0 +1 @@ +Enllaços - Sopa de cabra

Recursos utilitzats

En els següents enllaços trobareu informació quant als recursos que s'han utilitzat en aquest lloc web:

\ No newline at end of file diff --git a/photoswipe.esm.2e2aa850.js b/photoswipe.esm.2e2aa850.js new file mode 100644 index 0000000..7aa8f43 --- /dev/null +++ b/photoswipe.esm.2e2aa850.js @@ -0,0 +1,5 @@ +(0,("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{}).parcelRequire94c2.register)("gG83T",function(t,i){/*! + * PhotoSwipe 5.4.4 - https://photoswipe.com + * (c) 2024 Dmytro Semenov + */function e(t,i,e){let s=document.createElement(i);return t&&(s.className=t),e&&e.appendChild(s),s}function s(t,i){return t.x=i.x,t.y=i.y,void 0!==i.id&&(t.id=i.id),t}function n(t){t.x=Math.round(t.x),t.y=Math.round(t.y)}function o(t,i){let e=Math.abs(t.x-i.x),s=Math.abs(t.y-i.y);return Math.sqrt(e*e+s*s)}function a(t,i){return t.x===i.x&&t.y===i.y}function r(t,i,e){return Math.min(Math.max(t,i),e)}function h(t,i,e){let s=`translate3d(${t}px,${i||0}px,0)`;return void 0!==e&&(s+=` scale3d(${e},${e},1)`),s}function l(t,i,e,s){t.style.transform=h(i,e,s)}function p(t,i,e,s){t.style.transition=i?`${i} ${e}ms ${s||"cubic-bezier(.4,0,.22,1)"}`:"none"}function d(t,i,e){t.style.width="number"==typeof i?`${i}px`:i,t.style.height="number"==typeof e?`${e}px`:e}Object.defineProperty(t.exports,"__esModule",{value:!0,configurable:!0}),Object.defineProperty(t.exports,"default",{get:function(){return te},set:void 0,enumerable:!0,configurable:!0});let c={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function m(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}let u=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{u=!0}}))}catch(t){}class v{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach(t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)}),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;let a=n?"removeEventListener":"addEventListener";i.split(" ").forEach(i=>{if(i){o||(n?this._pool=this._pool.filter(s=>s.type!==i||s.listener!==e||s.target!==t):this._pool.push({target:t,type:i,listener:e,passive:s}));let r=!!u&&{passive:s||!1};t[a](i,e,r)}})}}function _(t,i){if(t.getViewportSizeFn){let e=t.getViewportSizeFn(t,i);if(e)return e}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function g(t,i,e,s,n){let o=0;if(i.paddingFn)o=i.paddingFn(e,s,n)[t];else if(i.padding)o=i.padding[t];else{let e="padding"+t[0].toUpperCase()+t.slice(1);i[e]&&(o=i[e])}return Number(o)||0}function y(t,i,e,s){return{x:i.x-g("left",t,i,e,s)-g("right",t,i,e,s),y:i.y-g("top",t,i,e,s)-g("bottom",t,i,e,s)}}class f{constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){let{pswp:i}=this.slide,e=this.slide["x"===t?"width":"height"]*this.currZoomLevel,s=g("x"===t?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),n=this.slide.panAreaSize[t];this.center[t]=Math.round((n-e)/2)+s,this.max[t]=e>n?Math.round(n-e)+s:this.center[t],this.min[t]=e>n?s:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return r(i,this.max[t],this.min[t])}}class w{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){let s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;let n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,no?n:o),this.vFill=Math.min(1,o),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){let i=this.options[t+"ZoomLevel"];if(i)return"function"==typeof i?i(this):"fill"===i?this.fill:"fit"===i?this.fit:Number(i)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,3*this.fit),this.elementSize&&t*this.elementSize.x>4e3&&(t=4e3/this.elementSize.x)),t}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,4*this.fit)}}class x{constructor(t,i,s){this.data=t,this.index=i,this.pswp=s,this.isActive=i===s.currIndex,this.currentResolution=0,this.panAreaSize={x:0,y:0},this.pan={x:0,y:0},this.isFirstSlide=this.isActive&&!s.opener.isOpen,this.zoomLevels=new w(s.options,t,i,s),this.pswp.dispatch("gettingData",{slide:this,data:this.data,index:i}),this.content=this.pswp.contentLoader.getContentBySlide(this),this.container=e("pswp__zoom-wrap","div"),this.holderElement=null,this.currZoomLevel=1,this.width=this.content.width,this.height=this.content.height,this.heavyAppended=!1,this.bounds=new f(this),this.prevDisplayedWidth=-1,this.prevDisplayedHeight=-1,this.pswp.dispatch("slideInit",{slide:this})}setIsActive(t){t&&!this.isActive?this.activate():!t&&this.isActive&&this.deactivate()}append(t){this.holderElement=t,this.container.style.transformOrigin="0 0",this.data&&(this.calculateSize(),this.load(),this.updateContentSize(),this.appendHeavy(),this.holderElement.appendChild(this.container),this.zoomAndPanToInitial(),this.pswp.dispatch("firstZoomPan",{slide:this}),this.applyCurrentZoomPan(),this.pswp.dispatch("afterSetContent",{slide:this}),this.isActive&&this.activate())}load(){this.content.load(!1),this.pswp.dispatch("slideLoad",{slide:this})}appendHeavy(){let{pswp:t}=this;this.heavyAppended||!t.opener.isOpen||t.mainScroll.isShifted()||(this.isActive,0)||this.pswp.dispatch("appendHeavy",{slide:this}).defaultPrevented||(this.heavyAppended=!0,this.content.append(),this.pswp.dispatch("appendHeavyContent",{slide:this}))}activate(){this.isActive=!0,this.appendHeavy(),this.content.activate(),this.pswp.dispatch("slideActivate",{slide:this})}deactivate(){this.isActive=!1,this.content.deactivate(),this.currZoomLevel!==this.zoomLevels.initial&&this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize(),this.pswp.dispatch("slideDeactivate",{slide:this})}destroy(){this.content.hasSlide=!1,this.content.remove(),this.container.remove(),this.pswp.dispatch("slideDestroy",{slide:this})}resize(){this.currZoomLevel!==this.zoomLevels.initial&&this.isActive?(this.calculateSize(),this.bounds.update(this.currZoomLevel),this.panTo(this.pan.x,this.pan.y)):(this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize())}updateContentSize(t){let i=this.currentResolution||this.zoomLevels.initial;if(!i)return;let e=Math.round(this.width*i)||this.pswp.viewportSize.x,s=Math.round(this.height*i)||this.pswp.viewportSize.y;(this.sizeChanged(e,s)||t)&&this.content.setDisplayedSize(e,s)}sizeChanged(t,i){return(t!==this.prevDisplayedWidth||i!==this.prevDisplayedHeight)&&(this.prevDisplayedWidth=t,this.prevDisplayedHeight=i,!0)}getPlaceholderElement(){var t;return null===(t=this.content.placeholder)||void 0===t?void 0:t.element}zoomTo(t,i,e,s){let{pswp:o}=this;if(!this.isZoomable()||o.mainScroll.isShifted())return;o.dispatch("beforeZoomTo",{destZoomLevel:t,centerPoint:i,transitionDuration:e}),o.animations.stopAllPan();let a=this.currZoomLevel;s||(t=r(t,this.zoomLevels.min,this.zoomLevels.max)),this.setZoomLevel(t),this.pan.x=this.calculateZoomToPanOffset("x",i,a),this.pan.y=this.calculateZoomToPanOffset("y",i,a),n(this.pan);let h=()=>{this._setResolution(t),this.applyCurrentZoomPan()};e?o.animations.startTransition({isPan:!0,name:"zoomTo",target:this.container,transform:this.getCurrentTransform(),onComplete:h,duration:e,easing:o.options.easing}):h()}toggleZoom(t){this.zoomTo(this.currZoomLevel===this.zoomLevels.initial?this.zoomLevels.secondary:this.zoomLevels.initial,t,this.pswp.options.zoomAnimationDuration)}setZoomLevel(t){this.currZoomLevel=t,this.bounds.update(this.currZoomLevel)}calculateZoomToPanOffset(t,i,e){if(0==this.bounds.max[t]-this.bounds.min[t])return this.bounds.center[t];i||(i=this.pswp.getViewportCenterPoint()),e||(e=this.zoomLevels.initial);let s=this.currZoomLevel/e;return this.bounds.correctPan(t,(this.pan[t]-i[t])*s+i[t])}panTo(t,i){this.pan.x=this.bounds.correctPan("x",t),this.pan.y=this.bounds.correctPan("y",i),this.applyCurrentZoomPan()}isPannable(){return!!this.width&&this.currZoomLevel>this.zoomLevels.fit}isZoomable(){return!!this.width&&this.content.isZoomable()}applyCurrentZoomPan(){this._applyZoomTransform(this.pan.x,this.pan.y,this.currZoomLevel),this===this.pswp.currSlide&&this.pswp.dispatch("zoomPanUpdate",{slide:this})}zoomAndPanToInitial(){this.currZoomLevel=this.zoomLevels.initial,this.bounds.update(this.currZoomLevel),s(this.pan,this.bounds.center),this.pswp.dispatch("initialZoomPan",{slide:this})}_applyZoomTransform(t,i,e){e/=this.currentResolution||this.zoomLevels.initial,l(this.container,t,i,e)}calculateSize(){let{pswp:t}=this;s(this.panAreaSize,y(t.options,t.viewportSize,this.data,this.index)),this.zoomLevels.update(this.width,this.height,this.panAreaSize),t.dispatch("calcSlideSize",{slide:this})}getCurrentTransform(){let t=this.currZoomLevel/(this.currentResolution||this.zoomLevels.initial);return h(this.pan.x,this.pan.y,t)}_setResolution(t){t!==this.currentResolution&&(this.currentResolution=t,this.updateContentSize(),this.pswp.dispatch("resolutionChanged"))}}class P{constructor(t){this.gestures=t,this.pswp=t.pswp,this.startPan={x:0,y:0}}start(){this.pswp.currSlide&&s(this.startPan,this.pswp.currSlide.pan),this.pswp.animations.stopAll()}change(){let{p1:t,prevP1:i,dragAxis:e}=this.gestures,{currSlide:s}=this.pswp;if("y"===e&&this.pswp.options.closeOnVerticalDrag&&s&&s.currZoomLevel<=s.zoomLevels.fit&&!this.gestures.isMultitouch){let e=s.pan.y+(t.y-i.y);if(!this.pswp.dispatch("verticalDrag",{panY:e}).defaultPrevented){this._setPanWithFriction("y",e,.6);let t=1-Math.abs(this._getVerticalDragRatio(s.pan.y));this.pswp.applyBgOpacity(t),s.applyCurrentZoomPan()}}else!this._panOrMoveMainScroll("x")&&(this._panOrMoveMainScroll("y"),s&&(n(s.pan),s.applyCurrentZoomPan()))}end(){let{velocity:t}=this.gestures,{mainScroll:i,currSlide:e}=this.pswp,s=0;if(this.pswp.animations.stopAll(),i.isShifted()){let e=(i.x-i.getCurrSlideX())/this.pswp.viewportSize.x;t.x<-.5&&e<0||t.x<.1&&e<-.5?(s=1,t.x=Math.min(t.x,0)):(t.x>.5&&e>0||t.x>-.1&&e>.5)&&(s=-1,t.x=Math.max(t.x,0)),i.moveIndexBy(s,!0,t.x)}e&&e.currZoomLevel>e.zoomLevels.max||this.gestures.isMultitouch?this.gestures.zoomLevels.correctZoomPan(!0):(this._finishPanGestureForAxis("x"),this._finishPanGestureForAxis("y"))}_finishPanGestureForAxis(t){let{velocity:i}=this.gestures,{currSlide:e}=this.pswp;if(!e)return;let{pan:s,bounds:n}=e,o=s[t],a=this.pswp.bgOpacity<1&&"y"===t,h=o+.995*i[t]/(1-.995);if(a){let t=this._getVerticalDragRatio(o),i=this._getVerticalDragRatio(h);if(t<0&&i<-.4||t>0&&i>.4){this.pswp.close();return}}let l=n.correctPan(t,h);if(o===l)return;let p=l===h?1:.82,d=this.pswp.bgOpacity,c=l-o;this.pswp.animations.startSpring({name:"panGesture"+t,isPan:!0,start:o,end:l,velocity:i[t],dampingRatio:p,onUpdate:i=>{if(a&&this.pswp.bgOpacity<1){let t=1-(l-i)/c;this.pswp.applyBgOpacity(r(d+(1-d)*t,0,1))}s[t]=Math.floor(i),e.applyCurrentZoomPan()}})}_panOrMoveMainScroll(t){let{p1:i,dragAxis:e,prevP1:s,isMultitouch:n}=this.gestures,{currSlide:o,mainScroll:a}=this.pswp,r=i[t]-s[t],h=a.x+r;if(!r||!o)return!1;if("x"===t&&!o.isPannable()&&!n)return a.moveTo(h,!0),!0;let{bounds:l}=o,p=o.pan[t]+r;if(this.pswp.options.allowPanToNext&&"x"===e&&"x"===t&&!n){let i=a.getCurrSlideX(),e=a.x-i,s=r>0;if(p>l.min[t]&&s){if(l.min[t]<=this.startPan[t])return a.moveTo(h,!0),!0;this._setPanWithFriction(t,p)}else if(p0)return a.moveTo(Math.max(h,i),!0),!0;if(e<0)return a.moveTo(Math.min(h,i),!0),!0}else this._setPanWithFriction(t,p)}else"y"===t&&(a.isShifted()||l.min.y===l.max.y)||this._setPanWithFriction(t,p);return!1}_getVerticalDragRatio(t){var i,e;return(t-(null!==(i=null===(e=this.pswp.currSlide)||void 0===e?void 0:e.bounds.center.y)&&void 0!==i?i:0))/(this.pswp.viewportSize.y/3)}_setPanWithFriction(t,i,e){let{currSlide:s}=this.pswp;if(!s)return;let{pan:n,bounds:o}=s;if(o.correctPan(t,i)!==i||e){let s=Math.round(i-n[t]);n[t]+=s*(e||.35)}else n[t]=i}}function S(t,i,e){return t.x=(i.x+e.x)/2,t.y=(i.y+e.y)/2,t}class b{constructor(t){this.gestures=t,this._startPan={x:0,y:0},this._startZoomPoint={x:0,y:0},this._zoomPoint={x:0,y:0},this._wasOverFitZoomLevel=!1,this._startZoomLevel=1}start(){let{currSlide:t}=this.gestures.pswp;t&&(this._startZoomLevel=t.currZoomLevel,s(this._startPan,t.pan)),this.gestures.pswp.animations.stopAllPan(),this._wasOverFitZoomLevel=!1}change(){let{p1:t,startP1:i,p2:e,startP2:s,pswp:n}=this.gestures,{currSlide:a}=n;if(!a)return;let r=a.zoomLevels.min,h=a.zoomLevels.max;if(!a.isZoomable()||n.mainScroll.isShifted())return;S(this._startZoomPoint,i,s),S(this._zoomPoint,t,e);let l=1/o(i,s)*o(t,e)*this._startZoomLevel;if(l>a.zoomLevels.initial+a.zoomLevels.initial/15&&(this._wasOverFitZoomLevel=!0),lh&&(l=h+(l-h)*.05);a.pan.x=this._calculatePanForZoomLevel("x",l),a.pan.y=this._calculatePanForZoomLevel("y",l),a.setZoomLevel(l),a.applyCurrentZoomPan()}end(){let{pswp:t}=this.gestures,{currSlide:i}=t;(!i||i.currZoomLeveln.zoomLevels.max?i=n.zoomLevels.max:(h=!1,i=o);let l=e.bgOpacity,p=e.bgOpacity<1,d=s({x:0,y:0},n.pan),c=s({x:0,y:0},d);t&&(this._zoomPoint.x=0,this._zoomPoint.y=0,this._startZoomPoint.x=0,this._startZoomPoint.y=0,this._startZoomLevel=o,s(this._startPan,d)),h&&(c={x:this._calculatePanForZoomLevel("x",i),y:this._calculatePanForZoomLevel("y",i)}),n.setZoomLevel(i),c={x:n.bounds.correctPan("x",c.x),y:n.bounds.correctPan("y",c.y)},n.setZoomLevel(o);let m=!a(c,d);if(!m&&!h&&!p){n._setResolution(i),n.applyCurrentZoomPan();return}e.animations.stopAllPan(),e.animations.startSpring({isPan:!0,start:0,end:1e3,velocity:0,dampingRatio:1,naturalFrequency:40,onUpdate:t=>{if(t/=1e3,m||h){if(m&&(n.pan.x=d.x+(c.x-d.x)*t,n.pan.y=d.y+(c.y-d.y)*t),h){let e=o+(i-o)*t;n.setZoomLevel(e)}n.applyCurrentZoomPan()}p&&e.bgOpacity<1&&e.applyBgOpacity(r(l+(1-l)*t,0,1))},onComplete:()=>{n._setResolution(i),n.applyCurrentZoomPan()}})}}function L(t){return!!t.target.closest(".pswp__container")}class z{constructor(t){this.gestures=t}click(t,i){let e=i.target.classList,s=e.contains("pswp__img"),n=e.contains("pswp__item")||e.contains("pswp__zoom-wrap");s?this._doClickOrTapAction("imageClick",t,i):n&&this._doClickOrTapAction("bgClick",t,i)}tap(t,i){L(i)&&this._doClickOrTapAction("tap",t,i)}doubleTap(t,i){L(i)&&this._doClickOrTapAction("doubleTap",t,i)}_doClickOrTapAction(t,i,e){var s;let{pswp:n}=this.gestures,{currSlide:o}=n,a=t+"Action",r=n.options[a];if(!n.dispatch(a,{point:i,originalEvent:e}).defaultPrevented){if("function"==typeof r){r.call(n,i,e);return}switch(r){case"close":case"next":n[r]();break;case"zoom":null==o||o.toggleZoom(i);break;case"zoom-or-close":null!=o&&o.isZoomable()&&o.zoomLevels.secondary!==o.zoomLevels.initial?o.toggleZoom(i):n.options.clickToCloseNonZoomable&&n.close();break;case"toggle-controls":null===(s=this.gestures.pswp.element)||void 0===s||s.classList.toggle("pswp--ui-visible")}}}}class I{constructor(t){this.pswp=t,this.dragAxis=null,this.p1={x:0,y:0},this.p2={x:0,y:0},this.prevP1={x:0,y:0},this.prevP2={x:0,y:0},this.startP1={x:0,y:0},this.startP2={x:0,y:0},this.velocity={x:0,y:0},this._lastStartP1={x:0,y:0},this._intervalP1={x:0,y:0},this._numActivePoints=0,this._ongoingPointers=[],this._touchEventEnabled="ontouchstart"in window,this._pointerEventEnabled=!!window.PointerEvent,this.supportsTouch=this._touchEventEnabled||this._pointerEventEnabled&&navigator.maxTouchPoints>1,this._numActivePoints=0,this._intervalTime=0,this._velocityCalculated=!1,this.isMultitouch=!1,this.isDragging=!1,this.isZooming=!1,this.raf=null,this._tapTimer=null,this.supportsTouch||(t.options.allowPanToNext=!1),this.drag=new P(this),this.zoomLevels=new b(this),this.tapHandler=new z(this),t.on("bindEvents",()=>{t.events.add(t.scrollWrap,"click",this._onClick.bind(this)),this._pointerEventEnabled?this._bindEvents("pointer","down","up","cancel"):this._touchEventEnabled?(this._bindEvents("touch","start","end","cancel"),t.scrollWrap&&(t.scrollWrap.ontouchmove=()=>{},t.scrollWrap.ontouchend=()=>{})):this._bindEvents("mouse","down","up")})}_bindEvents(t,i,e,s){let{pswp:n}=this,{events:o}=n,a=s?t+s:"";o.add(n.scrollWrap,t+i,this.onPointerDown.bind(this)),o.add(window,t+"move",this.onPointerMove.bind(this)),o.add(window,t+e,this.onPointerUp.bind(this)),a&&o.add(n.scrollWrap,a,this.onPointerUp.bind(this))}onPointerDown(t){let i="mousedown"===t.type||"mouse"===t.pointerType;if(i&&t.button>0)return;let{pswp:e}=this;if(!e.opener.isOpen){t.preventDefault();return}e.dispatch("pointerDown",{originalEvent:t}).defaultPrevented||(i&&(e.mouseDetected(),this._preventPointerEventBehaviour(t,"down")),e.animations.stopAll(),this._updatePoints(t,"down"),1===this._numActivePoints&&(this.dragAxis=null,s(this.startP1,this.p1)),this._numActivePoints>1?(this._clearTapTimer(),this.isMultitouch=!0):this.isMultitouch=!1)}onPointerMove(t){this._preventPointerEventBehaviour(t,"move"),this._numActivePoints&&(this._updatePoints(t,"move"),this.pswp.dispatch("pointerMove",{originalEvent:t}).defaultPrevented||(1!==this._numActivePoints||this.isDragging?this._numActivePoints>1&&!this.isZooming&&(this._finishDrag(),this.isZooming=!0,this._updateStartPoints(),this.zoomLevels.start(),this._rafStopLoop(),this._rafRenderLoop()):(this.dragAxis||this._calculateDragDirection(),this.dragAxis&&!this.isDragging&&(this.isZooming&&(this.isZooming=!1,this.zoomLevels.end()),this.isDragging=!0,this._clearTapTimer(),this._updateStartPoints(),this._intervalTime=Date.now(),this._velocityCalculated=!1,s(this._intervalP1,this.p1),this.velocity.x=0,this.velocity.y=0,this.drag.start(),this._rafStopLoop(),this._rafRenderLoop()))))}_finishDrag(){this.isDragging&&(this.isDragging=!1,this._velocityCalculated||this._updateVelocity(!0),this.drag.end(),this.dragAxis=null)}onPointerUp(t){this._numActivePoints&&(this._updatePoints(t,"up"),!this.pswp.dispatch("pointerUp",{originalEvent:t}).defaultPrevented&&(0!==this._numActivePoints||(this._rafStopLoop(),this.isDragging?this._finishDrag():this.isZooming||this.isMultitouch||this._finishTap(t)),this._numActivePoints<2&&this.isZooming&&(this.isZooming=!1,this.zoomLevels.end(),1===this._numActivePoints&&(this.dragAxis=null,this._updateStartPoints()))))}_rafRenderLoop(){(this.isDragging||this.isZooming)&&(this._updateVelocity(),this.isDragging?a(this.p1,this.prevP1)||this.drag.change():a(this.p1,this.prevP1)&&a(this.p2,this.prevP2)||this.zoomLevels.change(),this._updatePrevPoints(),this.raf=requestAnimationFrame(this._rafRenderLoop.bind(this)))}_updateVelocity(t){let i=Date.now(),e=i-this._intervalTime;(!(e<50)||t)&&(this.velocity.x=this._getVelocity("x",e),this.velocity.y=this._getVelocity("y",e),this._intervalTime=i,s(this._intervalP1,this.p1),this._velocityCalculated=!0)}_finishTap(t){let{mainScroll:i}=this.pswp;if(i.isShifted()){i.moveIndexBy(0,!0);return}if(t.type.indexOf("cancel")>0)return;if("mouseup"===t.type||"mouse"===t.pointerType){this.tapHandler.click(this.startP1,t);return}let e=this.pswp.options.doubleTapAction?300:0;this._tapTimer?(this._clearTapTimer(),25>o(this._lastStartP1,this.startP1)&&this.tapHandler.doubleTap(this.startP1,t)):(s(this._lastStartP1,this.startP1),this._tapTimer=setTimeout(()=>{this.tapHandler.tap(this.startP1,t),this._clearTapTimer()},e))}_clearTapTimer(){this._tapTimer&&(clearTimeout(this._tapTimer),this._tapTimer=null)}_getVelocity(t,i){let e=this.p1[t]-this._intervalP1[t];return Math.abs(e)>1&&i>5?e/i:0}_rafStopLoop(){this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}_preventPointerEventBehaviour(t,i){this.pswp.applyFilters("preventPointerEvent",!0,t,i)&&t.preventDefault()}_updatePoints(t,i){if(this._pointerEventEnabled){let e=this._ongoingPointers.findIndex(i=>i.id===t.pointerId);"up"===i&&e>-1?this._ongoingPointers.splice(e,1):"down"===i&&-1===e?this._ongoingPointers.push(this._convertEventPosToPoint(t,{x:0,y:0})):e>-1&&this._convertEventPosToPoint(t,this._ongoingPointers[e]),this._numActivePoints=this._ongoingPointers.length,this._numActivePoints>0&&s(this.p1,this._ongoingPointers[0]),this._numActivePoints>1&&s(this.p2,this._ongoingPointers[1])}else this._numActivePoints=0,t.type.indexOf("touch")>-1?t.touches&&t.touches.length>0&&(this._convertEventPosToPoint(t.touches[0],this.p1),this._numActivePoints++,t.touches.length>1&&(this._convertEventPosToPoint(t.touches[1],this.p2),this._numActivePoints++)):(this._convertEventPosToPoint(t,this.p1),"up"===i?this._numActivePoints=0:this._numActivePoints++)}_updatePrevPoints(){s(this.prevP1,this.p1),s(this.prevP2,this.p2)}_updateStartPoints(){s(this.startP1,this.p1),s(this.startP2,this.p2),this._updatePrevPoints()}_calculateDragDirection(){if(this.pswp.mainScroll.isShifted())this.dragAxis="x";else{let t=Math.abs(this.p1.x-this.startP1.x)-Math.abs(this.p1.y-this.startP1.y);if(0!==t){let i=t>0?"x":"y";Math.abs(this.p1[i]-this.startP1[i])>=10&&(this.dragAxis=i)}}}_convertEventPosToPoint(t,i){return i.x=t.pageX-this.pswp.offset.x,i.y=t.pageY-this.pswp.offset.y,"pointerId"in t?i.id=t.pointerId:void 0!==t.identifier&&(i.id=t.identifier),i}_onClick(t){this.pswp.mainScroll.isShifted()&&(t.preventDefault(),t.stopPropagation())}}class A{constructor(t){this.pswp=t,this.x=0,this.slideWidth=0,this._currPositionIndex=0,this._prevPositionIndex=0,this._containerShiftIndex=-1,this.itemHolders=[]}resize(t){let{pswp:i}=this,e=Math.round(i.viewportSize.x+i.viewportSize.x*i.options.spacing),s=e!==this.slideWidth;s&&(this.slideWidth=e,this.moveTo(this.getCurrSlideX())),this.itemHolders.forEach((i,e)=>{s&&l(i.el,(e+this._containerShiftIndex)*this.slideWidth),t&&i.slide&&i.slide.resize()})}resetPosition(){this._currPositionIndex=0,this._prevPositionIndex=0,this.slideWidth=0,this._containerShiftIndex=-1}appendHolders(){this.itemHolders=[];for(let t=0;t<3;t++){let i=e("pswp__item","div",this.pswp.container);i.setAttribute("role","group"),i.setAttribute("aria-roledescription","slide"),i.setAttribute("aria-hidden","true"),i.style.display=1===t?"block":"none",this.itemHolders.push({el:i})}}canBeSwiped(){return this.pswp.getNumItems()>1}moveIndexBy(t,i,e){let{pswp:s}=this,n=s.potentialIndex+t,o=s.getNumItems();if(s.canLoop()){n=s.getLoopedIndex(n);let i=(t+o)%o;t=i<=o/2?i:i-o}else n<0?n=0:n>=o&&(n=o-1),t=n-s.potentialIndex;s.potentialIndex=n,this._currPositionIndex-=t,s.animations.stopMainScroll();let a=this.getCurrSlideX();if(i){s.animations.startSpring({isMainScroll:!0,start:this.x,end:a,velocity:e||0,naturalFrequency:30,dampingRatio:1,onUpdate:t=>{this.moveTo(t)},onComplete:()=>{this.updateCurrItem(),s.appendHeavy()}});let t=s.potentialIndex-s.currIndex;if(s.canLoop()){let i=(t+o)%o;t=i<=o/2?i:i-o}Math.abs(t)>1&&this.updateCurrItem()}else this.moveTo(a),this.updateCurrItem();return!!t}getCurrSlideX(){return this.slideWidth*this._currPositionIndex}isShifted(){return this.x!==this.getCurrSlideX()}updateCurrItem(){var t;let i;let{pswp:e}=this,s=this._prevPositionIndex-this._currPositionIndex;if(!s)return;this._prevPositionIndex=this._currPositionIndex,e.currIndex=e.potentialIndex;let n=Math.abs(s);n>=3&&(this._containerShiftIndex+=s+(s>0?-3:3),n=3,this.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.destroy(),t.slide=void 0}));for(let t=0;t0?(i=this.itemHolders.shift())&&(this.itemHolders[2]=i,this._containerShiftIndex++,l(i.el,(this._containerShiftIndex+2)*this.slideWidth),e.setContent(i,e.currIndex-n+t+2)):(i=this.itemHolders.pop())&&(this.itemHolders.unshift(i),this._containerShiftIndex--,l(i.el,this._containerShiftIndex*this.slideWidth),e.setContent(i,e.currIndex+n-t-2));Math.abs(this._containerShiftIndex)>50&&!this.isShifted()&&(this.resetPosition(),this.resize()),e.animations.stopAllPan(),this.itemHolders.forEach((t,i)=>{t.slide&&t.slide.setIsActive(1===i)}),e.currSlide=null===(t=this.itemHolders[1])||void 0===t?void 0:t.slide,e.contentLoader.updateLazy(s),e.currSlide&&e.currSlide.applyCurrentZoomPan(),e.dispatch("change")}moveTo(t,i){if(!this.pswp.canLoop()&&i){let i=(this.slideWidth*this._currPositionIndex-t)/this.slideWidth;i+=this.pswp.currIndex;let e=Math.round(t-this.x);(i<0&&e>0||i>=this.pswp.getNumItems()-1&&e<0)&&(t=this.x+.35*e)}this.x=t,this.pswp.container&&l(this.pswp.container,t),this.pswp.dispatch("moveMainScroll",{x:t,dragging:null!=i&&i})}}let C={Escape:27,z:90,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Tab:9},T=(t,i)=>i?t:C[t];class Z{constructor(t){this.pswp=t,this._wasFocused=!1,t.on("bindEvents",()=>{t.options.trapFocus&&(t.options.initialPointerPos||this._focusRoot(),t.events.add(document,"focusin",this._onFocusIn.bind(this))),t.events.add(document,"keydown",this._onKeyDown.bind(this))});let i=document.activeElement;t.on("destroy",()=>{t.options.returnFocus&&i&&this._wasFocused&&i.focus()})}_focusRoot(){!this._wasFocused&&this.pswp.element&&(this.pswp.element.focus(),this._wasFocused=!0)}_onKeyDown(t){let i,e;let{pswp:s}=this;if(s.dispatch("keydown",{originalEvent:t}).defaultPrevented||"button"in t&&1===t.button||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey)return;let n=!1,o="key"in t;switch(o?t.key:t.keyCode){case T("Escape",o):s.options.escKey&&(i="close");break;case T("z",o):i="toggleZoom";break;case T("ArrowLeft",o):e="x";break;case T("ArrowUp",o):e="y";break;case T("ArrowRight",o):e="x",n=!0;break;case T("ArrowDown",o):n=!0,e="y";break;case T("Tab",o):this._focusRoot()}if(e){t.preventDefault();let{currSlide:o}=s;s.options.arrowKeys&&"x"===e&&s.getNumItems()>1?i=n?"next":"prev":o&&o.currZoomLevel>o.zoomLevels.fit&&(o.pan[e]+=n?-80:80,o.panTo(o.pan.x,o.pan.y))}i&&(t.preventDefault(),s[i]())}_onFocusIn(t){let{template:i}=this.pswp;i&&document!==t.target&&i!==t.target&&!i.contains(t.target)&&i.focus()}}class O{constructor(t){var i;this.props=t;let{target:e,onComplete:s,transform:n,onFinish:o=()=>{},duration:a=333,easing:r="cubic-bezier(.4,0,.22,1)"}=t;this.onFinish=o;let h=n?"transform":"opacity",l=null!==(i=t[h])&&void 0!==i?i:"";this._target=e,this._onComplete=s,this._finished=!1,this._onTransitionEnd=this._onTransitionEnd.bind(this),this._helperTimeout=setTimeout(()=>{p(e,h,a,r),this._helperTimeout=setTimeout(()=>{e.addEventListener("transitionend",this._onTransitionEnd,!1),e.addEventListener("transitioncancel",this._onTransitionEnd,!1),this._helperTimeout=setTimeout(()=>{this._finalizeAnimation()},a+500),e.style[h]=l},30)},0)}_onTransitionEnd(t){t.target===this._target&&this._finalizeAnimation()}_finalizeAnimation(){!this._finished&&(this._finished=!0,this.onFinish(),this._onComplete&&this._onComplete())}destroy(){this._helperTimeout&&clearTimeout(this._helperTimeout),p(this._target),this._target.removeEventListener("transitionend",this._onTransitionEnd,!1),this._target.removeEventListener("transitioncancel",this._onTransitionEnd,!1),this._finished||this._finalizeAnimation()}}class D{constructor(t,i,e){this.velocity=1e3*t,this._dampingRatio=i||.75,this._naturalFrequency=e||12,this._dampedFrequency=this._naturalFrequency,this._dampingRatio<1&&(this._dampedFrequency*=Math.sqrt(1-this._dampingRatio*this._dampingRatio))}easeFrame(t,i){let e,s=0;i/=1e3;let n=Math.E**(-this._dampingRatio*this._naturalFrequency*i);if(1===this._dampingRatio)e=this.velocity+this._naturalFrequency*t,s=(t+e*i)*n,this.velocity=-(s*this._naturalFrequency)+e*n;else if(this._dampingRatio<1){e=1/this._dampedFrequency*(this._dampingRatio*this._naturalFrequency*t+this.velocity);let o=Math.cos(this._dampedFrequency*i),a=Math.sin(this._dampedFrequency*i);s=n*(t*o+e*a),this.velocity=-(s*this._naturalFrequency)*this._dampingRatio+n*(-this._dampedFrequency*t*a+this._dampedFrequency*e*o)}return s}}class E{constructor(t){this.props=t,this._raf=0;let{start:i,end:e,velocity:s,onUpdate:n,onComplete:o,onFinish:a=()=>{},dampingRatio:r,naturalFrequency:h}=t;this.onFinish=a;let l=new D(s,r,h),p=Date.now(),d=i-e,c=()=>{this._raf&&(1>Math.abs(d=l.easeFrame(d,Date.now()-p))&&50>Math.abs(l.velocity)?(n(e),o&&o(),this.onFinish()):(p=Date.now(),n(d+e),this._raf=requestAnimationFrame(c)))};this._raf=requestAnimationFrame(c)}destroy(){this._raf>=0&&cancelAnimationFrame(this._raf),this._raf=0}}class M{constructor(){this.activeAnimations=[]}startSpring(t){this._start(t,!0)}startTransition(t){this._start(t)}_start(t,i){let e=i?new E(t):new O(t);return this.activeAnimations.push(e),e.onFinish=()=>this.stop(e),e}stop(t){t.destroy();let i=this.activeAnimations.indexOf(t);i>-1&&this.activeAnimations.splice(i,1)}stopAll(){this.activeAnimations.forEach(t=>{t.destroy()}),this.activeAnimations=[]}stopAllPan(){this.activeAnimations=this.activeAnimations.filter(t=>!t.props.isPan||(t.destroy(),!1))}stopMainScroll(){this.activeAnimations=this.activeAnimations.filter(t=>!t.props.isMainScroll||(t.destroy(),!1))}isPanRunning(){return this.activeAnimations.some(t=>t.props.isPan)}}class F{constructor(t){this.pswp=t,t.events.add(t.element,"wheel",this._onWheel.bind(this))}_onWheel(t){t.preventDefault();let{currSlide:i}=this.pswp,{deltaX:e,deltaY:s}=t;if(i&&!this.pswp.dispatch("wheel",{originalEvent:t}).defaultPrevented){if(t.ctrlKey||this.pswp.options.wheelToZoom){if(i.isZoomable()){let e=-s;1===t.deltaMode?e*=.05:e*=t.deltaMode?1:.002,e=2**e;let n=i.currZoomLevel*e;i.zoomTo(n,{x:t.clientX,y:t.clientY})}}else i.isPannable()&&(1===t.deltaMode&&(e*=18,s*=18),i.panTo(i.pan.x-e,i.pan.y-s))}}}class R{constructor(t,i){var s;let n=i.name||i.className,o=i.html;if(!1===t.options[n])return;"string"==typeof t.options[n+"SVG"]&&(o=t.options[n+"SVG"]),t.dispatch("uiElementCreate",{data:i});let a="";i.isButton?(a+="pswp__button ",a+=i.className||`pswp__button--${i.name}`):a+=i.className||`pswp__${i.name}`;let r=i.isButton?i.tagName||"button":i.tagName||"div",h=e(a,r=r.toLowerCase());if(i.isButton){"button"===r&&(h.type="button");let{title:e}=i,{ariaLabel:s}=i;"string"==typeof t.options[n+"Title"]&&(e=t.options[n+"Title"]),e&&(h.title=e);let o=s||e;o&&h.setAttribute("aria-label",o)}h.innerHTML=function(t){if("string"==typeof t)return t;if(!t||!t.isCustomSVG)return"";let i='"}(o),i.onInit&&i.onInit(h,t),i.onClick&&(h.onclick=e=>{"string"==typeof i.onClick?t[i.onClick]():"function"==typeof i.onClick&&i.onClick(e,h,t)});let l=i.appendTo||"bar",p=t.element;"bar"===l?(t.topBar||(t.topBar=e("pswp__top-bar pswp__hide-on-close","div",t.scrollWrap)),p=t.topBar):(h.classList.add("pswp__hide-on-close"),"wrapper"===l&&(p=t.scrollWrap)),null===(s=p)||void 0===s||s.appendChild(t.applyFilters("uiElement",h,i))}}function B(t,i,e){t.classList.add("pswp__button--arrow"),t.setAttribute("aria-controls","pswp__items"),i.on("change",()=>{i.options.loop||(e?t.disabled=!(i.currIndex0))})}let H={name:"arrowPrev",className:"pswp__button--arrow--prev",title:"Previous",order:10,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"prev",onInit:B},k={name:"arrowNext",className:"pswp__button--arrow--next",title:"Next",order:11,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"next",onInit:(t,i)=>{B(t,i,!0)}},N={name:"close",title:"Close",order:20,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-close"},onClick:"close"},W={name:"zoom",title:"Zoom",order:10,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-zoom"},onClick:"toggleZoom"},V={name:"preloader",appendTo:"bar",order:7,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-loading"},onInit:(t,i)=>{let e;let s=null,n=(i,e)=>{t.classList.toggle("pswp__preloader--"+i,e)},o=t=>{e!==t&&(e=t,n("active",t))},a=()=>{var t;if(!(null!==(t=i.currSlide)&&void 0!==t&&t.content.isLoading())){o(!1),s&&(clearTimeout(s),s=null);return}s||(s=setTimeout(()=>{var t;o(!!(null===(t=i.currSlide)||void 0===t?void 0:t.content.isLoading())),s=null},i.options.preloaderDelay))};i.on("change",a),i.on("loadComplete",t=>{i.currSlide===t.slide&&a()}),i.ui&&(i.ui.updatePreloaderVisibility=a)}},q={name:"counter",order:5,onInit:(t,i)=>{i.on("change",()=>{t.innerText=i.currIndex+1+i.options.indexIndicatorSep+i.getNumItems()})}};function U(t,i){t.classList.toggle("pswp--zoomed-in",i)}class G{constructor(t){this.pswp=t,this.isRegistered=!1,this.uiElementsData=[],this.items=[],this.updatePreloaderVisibility=()=>{},this._lastUpdatedZoomLevel=void 0}init(){let{pswp:t}=this;this.isRegistered=!1,this.uiElementsData=[N,H,k,W,V,q],t.dispatch("uiRegister"),this.uiElementsData.sort((t,i)=>(t.order||0)-(i.order||0)),this.items=[],this.isRegistered=!0,this.uiElementsData.forEach(t=>{this.registerElement(t)}),t.on("change",()=>{var i;null===(i=t.element)||void 0===i||i.classList.toggle("pswp--one-slide",1===t.getNumItems())}),t.on("zoomPanUpdate",()=>this._onZoomPanUpdate())}registerElement(t){this.isRegistered?this.items.push(new R(this.pswp,t)):this.uiElementsData.push(t)}_onZoomPanUpdate(){let{template:t,currSlide:i,options:e}=this.pswp;if(this.pswp.opener.isClosing||!t||!i)return;let{currZoomLevel:s}=i;if(this.pswp.opener.isOpen||(s=i.zoomLevels.initial),s!==this._lastUpdatedZoomLevel){if(this._lastUpdatedZoomLevel=s,.01>Math.abs(i.zoomLevels.initial-i.zoomLevels.secondary)||!i.isZoomable()){U(t,!1),t.classList.remove("pswp--zoom-allowed");return}t.classList.add("pswp--zoom-allowed"),U(t,(s===i.zoomLevels.initial?i.zoomLevels.secondary:i.zoomLevels.initial)<=s),("zoom"===e.imageClickAction||"zoom-or-close"===e.imageClickAction)&&t.classList.add("pswp--click-to-zoom")}}}class K{constructor(t,i){this.type=t,this.defaultPrevented=!1,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class ${constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,i,e=100){var s,n,o;this._filters[t]||(this._filters[t]=[]),null===(s=this._filters[t])||void 0===s||s.push({fn:i,priority:e}),null===(n=this._filters[t])||void 0===n||n.sort((t,i)=>t.priority-i.priority),null===(o=this.pswp)||void 0===o||o.addFilter(t,i,e)}removeFilter(t,i){this._filters[t]&&(this._filters[t]=this._filters[t].filter(t=>t.fn!==i)),this.pswp&&this.pswp.removeFilter(t,i)}applyFilters(t,...i){var e;return null===(e=this._filters[t])||void 0===e||e.forEach(t=>{i[0]=t.fn.apply(this,i)}),i[0]}on(t,i){var e,s;this._listeners[t]||(this._listeners[t]=[]),null===(e=this._listeners[t])||void 0===e||e.push(i),null===(s=this.pswp)||void 0===s||s.on(t,i)}off(t,i){var e;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(t=>i!==t)),null===(e=this.pswp)||void 0===e||e.off(t,i)}dispatch(t,i){var e;if(this.pswp)return this.pswp.dispatch(t,i);let s=new K(t,i);return null===(e=this._listeners[t])||void 0===e||e.forEach(t=>{t.call(this,s)}),s}}class X{constructor(t,i){if(this.element=e("pswp__img pswp__img--placeholder",t?"img":"div",i),t){let i=this.element;i.decoding="async",i.alt="",i.src=t,i.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,i){this.element&&("IMG"===this.element.tagName?(d(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=h(0,0,t/250)):d(this.element,t,i))}destroy(){var t;null!==(t=this.element)&&void 0!==t&&t.parentNode&&this.element.remove(),this.element=null}}class Y{constructor(t,i,e){this.instance=i,this.data=t,this.index=e,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=c.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,i){if(this.slide&&this.usePlaceholder()){if(this.placeholder){let t=this.placeholder.element;t&&!t.parentElement&&this.slide.container.prepend(t)}else{let t=this.instance.applyFilters("placeholderSrc",!!this.data.msrc&&!!this.slide.isFirstSlide&&this.data.msrc,this);this.placeholder=new X(t,this.slide.container)}}(!this.element||i)&&!this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented&&(this.isImageContent()?(this.element=e("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=e("pswp__content","div"),this.element.innerHTML=this.data.html||""),i&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){var i,e;if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;let s=this.element;this.updateSrcsetSizes(),this.data.srcset&&(s.srcset=this.data.srcset),s.src=null!==(i=this.data.src)&&void 0!==i?i:"",s.alt=null!==(e=this.data.alt)&&void 0!==e?e:"",this.state=c.LOADING,s.complete?this.onLoaded():(s.onload=()=>{this.onLoaded()},s.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=c.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===c.LOADED||this.state===c.ERROR)&&this.removePlaceholder())}onError(){this.state=c.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===c.LOADING,this)}isError(){return this.state===c.ERROR}isImageContent(){return"image"===this.type}setDisplayedSize(t,i){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,i),!this.instance.dispatch("contentResize",{content:this,width:t,height:i}).defaultPrevented&&(d(this.element,t,i),this.isImageContent()&&!this.isError()))){let e=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=i,e?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:i,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==c.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;let t=this.element,i=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||i>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=i+"px",t.dataset.largestUsedSize=String(i))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){if(this.slide){var t,i;let s=e("pswp__error-msg","div");s.innerText=null!==(t=null===(i=this.instance.options)||void 0===i?void 0:i.errorMsg)&&void 0!==t?t:"",s=this.instance.applyFilters("contentErrorElement",s,this),this.element=e("pswp__content pswp__error-msg-container","div"),this.element.appendChild(s),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===c.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;let t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||m())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){!this.instance.dispatch("contentActivate",{content:this}).defaultPrevented&&this.slide&&(this.isImageContent()&&this.isDecoding&&!m()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===c.LOADED||this.state===c.ERROR)&&this.removePlaceholder()))}}function j(t,i,e){let s;let n=i.createContentFromData(t,e),{options:o}=i;if(o){let a;s=new w(o,t,-1),a=i.pswp?i.pswp.viewportSize:_(o,i);let r=y(o,a,t,e);s.update(n.width,n.height,r)}return n.lazyLoad(),s&&n.setDisplayedSize(Math.ceil(n.width*s.initial),Math.ceil(n.height*s.initial)),n}class J{constructor(t){this.pswp=t,this.limit=Math.max(t.options.preload[0]+t.options.preload[1]+1,5),this._cachedItems=[]}updateLazy(t){let i;let{pswp:e}=this;if(e.dispatch("lazyLoad").defaultPrevented)return;let{preload:s}=e.options,n=void 0===t||t>=0;for(i=0;i<=s[1];i++)this.loadSlideByIndex(e.currIndex+(n?i:-i));for(i=1;i<=s[0];i++)this.loadSlideByIndex(e.currIndex+(n?-i:i))}loadSlideByIndex(t){let i=this.pswp.getLoopedIndex(t),e=this.getContentByIndex(i);!e&&(e=function(t,i){let e=i.getItemData(t);if(!i.dispatch("lazyLoadSlide",{index:t,itemData:e}).defaultPrevented)return j(e,i,t)}(i,this.pswp))&&this.addToCache(e)}getContentBySlide(t){let i=this.getContentByIndex(t.index);return i||(i=this.pswp.createContentFromData(t.data,t.index),this.addToCache(i)),i.setSlide(t),i}addToCache(t){if(this.removeByIndex(t.index),this._cachedItems.push(t),this._cachedItems.length>this.limit){let t=this._cachedItems.findIndex(t=>!t.isAttached&&!t.hasSlide);-1!==t&&this._cachedItems.splice(t,1)[0].destroy()}}removeByIndex(t){let i=this._cachedItems.findIndex(i=>i.index===t);-1!==i&&this._cachedItems.splice(i,1)}getContentByIndex(t){return this._cachedItems.find(i=>i.index===t)}destroy(){this._cachedItems.forEach(t=>t.destroy()),this._cachedItems=[]}}class Q extends ${getNumItems(){var t;let i=0,e=null===(t=this.options)||void 0===t?void 0:t.dataSource;e&&"length"in e?i=e.length:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),e.items&&(i=e.items.length));let s=this.dispatch("numItems",{dataSource:e,numItems:i});return this.applyFilters("numItems",s.numItems,e)}createContentFromData(t,i){return new Y(t,this,i)}getItemData(t){var i;let e=null===(i=this.options)||void 0===i?void 0:i.dataSource,s={};Array.isArray(e)?s=e[t]:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),s=e.items[t]);let n=s;n instanceof Element&&(n=this._domElementToItemData(n));let o=this.dispatch("itemData",{itemData:n||{},index:t});return this.applyFilters("itemData",o.itemData,t)}_getGalleryDOMElements(t){var i,e;return null!==(i=this.options)&&void 0!==i&&i.children||null!==(e=this.options)&&void 0!==e&&e.childSelector?function(t,i,e=document){let s=[];if(t instanceof Element)s=[t];else if(t instanceof NodeList||Array.isArray(t))s=Array.from(t);else{let n="string"==typeof t?t:i;n&&(s=Array.from(e.querySelectorAll(n)))}return s}(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){let i={element:t},e="A"===t.tagName?t:t.querySelector("a");if(e){i.src=e.dataset.pswpSrc||e.href,e.dataset.pswpSrcset&&(i.srcset=e.dataset.pswpSrcset),i.width=e.dataset.pswpWidth?parseInt(e.dataset.pswpWidth,10):0,i.height=e.dataset.pswpHeight?parseInt(e.dataset.pswpHeight,10):0,i.w=i.width,i.h=i.height,e.dataset.pswpType&&(i.type=e.dataset.pswpType);let n=t.querySelector("img");if(n){var s;i.msrc=n.currentSrc||n.src,i.alt=null!==(s=n.getAttribute("alt"))&&void 0!==s?s:""}(e.dataset.pswpCropped||e.dataset.cropped)&&(i.thumbCropped=!0)}return this.applyFilters("domItemData",i,t,e)}lazyLoadData(t,i){return j(t,this,i)}}class tt{constructor(t){this.pswp=t,this.isClosed=!0,this.isOpen=!1,this.isClosing=!1,this.isOpening=!1,this._duration=void 0,this._useAnimation=!1,this._croppedZoom=!1,this._animateRootOpacity=!1,this._animateBgOpacity=!1,this._placeholder=void 0,this._opacityElement=void 0,this._cropContainer1=void 0,this._cropContainer2=void 0,this._thumbBounds=void 0,this._prepareOpen=this._prepareOpen.bind(this),t.on("firstZoomPan",this._prepareOpen)}open(){this._prepareOpen(),this._start()}close(){if(this.isClosed||this.isClosing||this.isOpening)return;let t=this.pswp.currSlide;this.isOpen=!1,this.isOpening=!1,this.isClosing=!0,this._duration=this.pswp.options.hideAnimationDuration,t&&t.currZoomLevel*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps(),setTimeout(()=>{this._start()},this._croppedZoom?30:0)}_prepareOpen(){if(this.pswp.off("firstZoomPan",this._prepareOpen),!this.isOpening){let t=this.pswp.currSlide;this.isOpening=!0,this.isClosing=!1,this._duration=this.pswp.options.showAnimationDuration,t&&t.zoomLevels.initial*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps()}}_applyStartProps(){var t,i;let{pswp:e}=this,s=this.pswp.currSlide,{options:n}=e;if("fade"===n.showHideAnimationType?(n.showHideOpacity=!0,this._thumbBounds=void 0):"none"===n.showHideAnimationType?(n.showHideOpacity=!1,this._duration=0,this._thumbBounds=void 0):this.isOpening&&e._initialThumbBounds?this._thumbBounds=e._initialThumbBounds:this._thumbBounds=this.pswp.getThumbBounds(),this._placeholder=null==s?void 0:s.getPlaceholderElement(),e.animations.stopAll(),this._useAnimation=!!(this._duration&&this._duration>50),this._animateZoom=!!this._thumbBounds&&(null==s?void 0:s.content.usePlaceholder())&&(!this.isClosing||!e.mainScroll.isShifted()),this._animateZoom?this._animateRootOpacity=null!==(t=n.showHideOpacity)&&void 0!==t&&t:(this._animateRootOpacity=!0,this.isOpening&&s&&(s.zoomAndPanToInitial(),s.applyCurrentZoomPan())),this._animateBgOpacity=!this._animateRootOpacity&&this.pswp.options.bgOpacity>.003,this._opacityElement=this._animateRootOpacity?e.element:e.bg,!this._useAnimation){this._duration=0,this._animateZoom=!1,this._animateBgOpacity=!1,this._animateRootOpacity=!0,this.isOpening&&(e.element&&(e.element.style.opacity=String(.003)),e.applyBgOpacity(1));return}this._animateZoom&&this._thumbBounds&&this._thumbBounds.innerRect?(this._croppedZoom=!0,this._cropContainer1=this.pswp.container,this._cropContainer2=null===(i=this.pswp.currSlide)||void 0===i?void 0:i.holderElement,e.container&&(e.container.style.overflow="hidden",e.container.style.width=e.viewportSize.x+"px")):this._croppedZoom=!1,this.isOpening?(this._animateRootOpacity?(e.element&&(e.element.style.opacity=String(.003)),e.applyBgOpacity(1)):(this._animateBgOpacity&&e.bg&&(e.bg.style.opacity=String(.003)),e.element&&(e.element.style.opacity="1")),this._animateZoom&&(this._setClosedStateZoomPan(),this._placeholder&&(this._placeholder.style.willChange="transform",this._placeholder.style.opacity=String(.003)))):this.isClosing&&(e.mainScroll.itemHolders[0]&&(e.mainScroll.itemHolders[0].el.style.display="none"),e.mainScroll.itemHolders[2]&&(e.mainScroll.itemHolders[2].el.style.display="none"),this._croppedZoom&&0!==e.mainScroll.x&&(e.mainScroll.resetPosition(),e.mainScroll.resize()))}_start(){this.isOpening&&this._useAnimation&&this._placeholder&&"IMG"===this._placeholder.tagName?new Promise(t=>{var i;let e=!1,s=!0;("decode"in(i=this._placeholder)?i.decode().catch(()=>{}):i.complete?Promise.resolve(i):new Promise((t,e)=>{i.onload=()=>t(i),i.onerror=e})).finally(()=>{e=!0,s||t(!0)}),setTimeout(()=>{s=!1,e&&t(!0)},50),setTimeout(t,250)}).finally(()=>this._initiate()):this._initiate()}_initiate(){var t,i;null===(t=this.pswp.element)||void 0===t||t.style.setProperty("--pswp-transition-duration",this._duration+"ms"),this.pswp.dispatch(this.isOpening?"openingAnimationStart":"closingAnimationStart"),this.pswp.dispatch("initialZoom"+(this.isOpening?"In":"Out")),null===(i=this.pswp.element)||void 0===i||i.classList.toggle("pswp--ui-visible",this.isOpening),this.isOpening?(this._placeholder&&(this._placeholder.style.opacity="1"),this._animateToOpenState()):this.isClosing&&this._animateToClosedState(),this._useAnimation||this._onAnimationComplete()}_onAnimationComplete(){let{pswp:t}=this;if(this.isOpen=this.isOpening,this.isClosed=this.isClosing,this.isOpening=!1,this.isClosing=!1,t.dispatch(this.isOpen?"openingAnimationEnd":"closingAnimationEnd"),t.dispatch("initialZoom"+(this.isOpen?"InEnd":"OutEnd")),this.isClosed)t.destroy();else if(this.isOpen){var i;this._animateZoom&&t.container&&(t.container.style.overflow="visible",t.container.style.width="100%"),null===(i=t.currSlide)||void 0===i||i.applyCurrentZoomPan()}}_animateToOpenState(){let{pswp:t}=this;this._animateZoom&&(this._croppedZoom&&this._cropContainer1&&this._cropContainer2&&(this._animateTo(this._cropContainer1,"transform","translate3d(0,0,0)"),this._animateTo(this._cropContainer2,"transform","none")),t.currSlide&&(t.currSlide.zoomAndPanToInitial(),this._animateTo(t.currSlide.container,"transform",t.currSlide.getCurrentTransform()))),this._animateBgOpacity&&t.bg&&this._animateTo(t.bg,"opacity",String(t.options.bgOpacity)),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","1")}_animateToClosedState(){let{pswp:t}=this;this._animateZoom&&this._setClosedStateZoomPan(!0),this._animateBgOpacity&&t.bgOpacity>.01&&t.bg&&this._animateTo(t.bg,"opacity","0"),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","0")}_setClosedStateZoomPan(t){if(!this._thumbBounds)return;let{pswp:i}=this,{innerRect:e}=this._thumbBounds,{currSlide:n,viewportSize:o}=i;if(this._croppedZoom&&e&&this._cropContainer1&&this._cropContainer2){let i=-o.x+(this._thumbBounds.x-e.x)+e.w,s=-o.y+(this._thumbBounds.y-e.y)+e.h,n=o.x-e.w,a=o.y-e.h;t?(this._animateTo(this._cropContainer1,"transform",h(i,s)),this._animateTo(this._cropContainer2,"transform",h(n,a))):(l(this._cropContainer1,i,s),l(this._cropContainer2,n,a))}n&&(s(n.pan,e||this._thumbBounds),n.currZoomLevel=this._thumbBounds.w/n.width,t?this._animateTo(n.container,"transform",n.getCurrentTransform()):n.applyCurrentZoomPan())}_animateTo(t,i,e){if(!this._duration){t.style[i]=e;return}let{animations:s}=this.pswp,n={duration:this._duration,easing:this.pswp.options.easing,onComplete:()=>{s.activeAnimations.length||this._onAnimationComplete()},target:t};n[i]=e,s.startTransition(n)}}let ti={allowPanToNext:!0,spacing:.1,loop:!0,pinchToClose:!0,closeOnVerticalDrag:!0,hideAnimationDuration:333,showAnimationDuration:333,zoomAnimationDuration:333,escKey:!0,arrowKeys:!0,trapFocus:!0,returnFocus:!0,maxWidthToAnimate:4e3,clickToCloseNonZoomable:!0,imageClickAction:"zoom-or-close",bgClickAction:"close",tapAction:"toggle-controls",doubleTapAction:"zoom",indexIndicatorSep:" / ",preloaderDelay:2e3,bgOpacity:.8,index:0,errorMsg:"The image cannot be loaded",preload:[1,2],easing:"cubic-bezier(.4,0,.22,1)"};class te extends Q{constructor(t){super(),this.options=this._prepareOptions(t||{}),this.offset={x:0,y:0},this._prevViewportSize={x:0,y:0},this.viewportSize={x:0,y:0},this.bgOpacity=1,this.currIndex=0,this.potentialIndex=0,this.isOpen=!1,this.isDestroying=!1,this.hasMouse=!1,this._initialItemData={},this._initialThumbBounds=void 0,this.topBar=void 0,this.element=void 0,this.template=void 0,this.container=void 0,this.scrollWrap=void 0,this.currSlide=void 0,this.events=new v,this.animations=new M,this.mainScroll=new A(this),this.gestures=new I(this),this.opener=new tt(this),this.keyboard=new Z(this),this.contentLoader=new J(this)}init(){if(this.isOpen||this.isDestroying)return!1;this.isOpen=!0,this.dispatch("init"),this.dispatch("beforeOpen"),this._createMainStructure();let t="pswp--open";return this.gestures.supportsTouch&&(t+=" pswp--touch"),this.options.mainClass&&(t+=" "+this.options.mainClass),this.element&&(this.element.className+=" "+t),this.currIndex=this.options.index||0,this.potentialIndex=this.currIndex,this.dispatch("firstUpdate"),this.scrollWheel=new F(this),(Number.isNaN(this.currIndex)||this.currIndex<0||this.currIndex>=this.getNumItems())&&(this.currIndex=0),this.gestures.supportsTouch||this.mouseDetected(),this.updateSize(),this.offset.y=window.pageYOffset,this._initialItemData=this.getItemData(this.currIndex),this.dispatch("gettingData",{index:this.currIndex,data:this._initialItemData,slide:void 0}),this._initialThumbBounds=this.getThumbBounds(),this.dispatch("initialLayout"),this.on("openingAnimationEnd",()=>{let{itemHolders:t}=this.mainScroll;t[0]&&(t[0].el.style.display="block",this.setContent(t[0],this.currIndex-1)),t[2]&&(t[2].el.style.display="block",this.setContent(t[2],this.currIndex+1)),this.appendHeavy(),this.contentLoader.updateLazy(),this.events.add(window,"resize",this._handlePageResize.bind(this)),this.events.add(window,"scroll",this._updatePageScrollOffset.bind(this)),this.dispatch("bindEvents")}),this.mainScroll.itemHolders[1]&&this.setContent(this.mainScroll.itemHolders[1],this.currIndex),this.dispatch("change"),this.opener.open(),this.dispatch("afterInit"),!0}getLoopedIndex(t){let i=this.getNumItems();return this.options.loop&&(t>i-1&&(t-=i),t<0&&(t+=i)),r(t,0,i-1)}appendHeavy(){this.mainScroll.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.appendHeavy()})}goTo(t){this.mainScroll.moveIndexBy(this.getLoopedIndex(t)-this.potentialIndex)}next(){this.goTo(this.potentialIndex+1)}prev(){this.goTo(this.potentialIndex-1)}zoomTo(...t){var i;null===(i=this.currSlide)||void 0===i||i.zoomTo(...t)}toggleZoom(){var t;null===(t=this.currSlide)||void 0===t||t.toggleZoom()}close(){this.opener.isOpen&&!this.isDestroying&&(this.isDestroying=!0,this.dispatch("close"),this.events.removeAll(),this.opener.close())}destroy(){var t;if(!this.isDestroying){this.options.showHideAnimationType="none",this.close();return}this.dispatch("destroy"),this._listeners={},this.scrollWrap&&(this.scrollWrap.ontouchmove=null,this.scrollWrap.ontouchend=null),null===(t=this.element)||void 0===t||t.remove(),this.mainScroll.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.destroy()}),this.contentLoader.destroy(),this.events.removeAll()}refreshSlideContent(t){this.contentLoader.removeByIndex(t),this.mainScroll.itemHolders.forEach((i,e)=>{var s,n,o;let a=(null!==(s=null===(n=this.currSlide)||void 0===n?void 0:n.index)&&void 0!==s?s:0)-1+e;this.canLoop()&&(a=this.getLoopedIndex(a)),a===t&&(this.setContent(i,t,!0),1===e&&(this.currSlide=i.slide,null===(o=i.slide)||void 0===o||o.setIsActive(!0)))}),this.dispatch("change")}setContent(t,i,e){if(this.canLoop()&&(i=this.getLoopedIndex(i)),t.slide){if(t.slide.index===i&&!e)return;t.slide.destroy(),t.slide=void 0}if(!this.canLoop()&&(i<0||i>=this.getNumItems()))return;let s=this.getItemData(i);t.slide=new x(s,i,this),i===this.currIndex&&(this.currSlide=t.slide),t.slide.append(t.el)}getViewportCenterPoint(){return{x:this.viewportSize.x/2,y:this.viewportSize.y/2}}updateSize(t){if(this.isDestroying)return;let i=_(this.options,this);!t&&a(i,this._prevViewportSize)||(s(this._prevViewportSize,i),this.dispatch("beforeResize"),s(this.viewportSize,this._prevViewportSize),this._updatePageScrollOffset(),this.dispatch("viewportSize"),this.mainScroll.resize(this.opener.isOpen),!this.hasMouse&&window.matchMedia("(any-hover: hover)").matches&&this.mouseDetected(),this.dispatch("resize"))}applyBgOpacity(t){this.bgOpacity=Math.max(t,0),this.bg&&(this.bg.style.opacity=String(this.bgOpacity*this.options.bgOpacity))}mouseDetected(){if(!this.hasMouse){var t;this.hasMouse=!0,null===(t=this.element)||void 0===t||t.classList.add("pswp--has_mouse")}}_handlePageResize(){this.updateSize(),/iPhone|iPad|iPod/i.test(window.navigator.userAgent)&&setTimeout(()=>{this.updateSize()},500)}_updatePageScrollOffset(){this.setScrollOffset(0,window.pageYOffset)}setScrollOffset(t,i){this.offset.x=t,this.offset.y=i,this.dispatch("updateScrollOffset")}_createMainStructure(){this.element=e("pswp","div"),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.template=this.element,this.bg=e("pswp__bg","div",this.element),this.scrollWrap=e("pswp__scroll-wrap","section",this.element),this.container=e("pswp__container","div",this.scrollWrap),this.scrollWrap.setAttribute("aria-roledescription","carousel"),this.container.setAttribute("aria-live","off"),this.container.setAttribute("id","pswp__items"),this.mainScroll.appendHolders(),this.ui=new G(this),this.ui.init(),(this.options.appendToEl||document.body).appendChild(this.element)}getThumbBounds(){return function(t,i,e){let s,n;let o=e.dispatch("thumbBounds",{index:t,itemData:i,instance:e});if(o.thumbBounds)return o.thumbBounds;let{element:a}=i;if(a&&!1!==e.options.thumbSelector){let t=e.options.thumbSelector||"img";n=a.matches(t)?a:a.querySelector(t)}return(n=e.applyFilters("thumbEl",n,i,t))&&(s=i.thumbCropped?function(t,i,e){let s=t.getBoundingClientRect(),n=s.width/i,o=s.height/e,a=n>o?n:o,r=(s.width-i*a)/2,h=(s.height-e*a)/2,l={x:s.left+r,y:s.top+h,w:i*a};return l.innerRect={w:s.width,h:s.height,x:r,y:h},l}(n,i.width||i.w||0,i.height||i.h||0):function(t){let i=t.getBoundingClientRect();return{x:i.left,y:i.top,w:i.width}}(n)),e.applyFilters("thumbBounds",s,i,t)}(this.currIndex,this.currSlide?this.currSlide.data:this._initialItemData,this)}canLoop(){return this.options.loop&&this.getNumItems()>2}_prepareOptions(t){return window.matchMedia("(prefers-reduced-motion), (update: slow)").matches&&(t.showHideAnimationType="none",t.zoomAnimationDuration=0),{...ti,...t}}}}); +//# sourceMappingURL=photoswipe.esm.2e2aa850.js.map diff --git a/photoswipe.esm.2e2aa850.js.map b/photoswipe.esm.2e2aa850.js.map new file mode 100644 index 0000000..25ad386 --- /dev/null +++ b/photoswipe.esm.2e2aa850.js.map @@ -0,0 +1 @@ +{"mappings":"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","sources":["","node_modules/photoswipe/dist/photoswipe.esm.js","src/js/util/util.js","src/js/util/dom-events.js","src/js/util/viewport-size.js","src/js/slide/pan-bounds.js","src/js/slide/zoom-level.js","src/js/slide/slide.js","src/js/gestures/drag-handler.js","src/js/gestures/zoom-handler.js","src/js/gestures/tap-handler.js","src/js/gestures/gestures.js","src/js/main-scroll.js","src/js/keyboard.js","src/js/util/css-animation.js","src/js/util/spring-easer.js","src/js/util/spring-animation.js","src/js/util/animations.js","src/js/scroll-wheel.js","src/js/ui/ui-element.js","src/js/ui/button-arrow.js","src/js/ui/button-close.js","src/js/ui/button-zoom.js","src/js/ui/loading-indicator.js","src/js/ui/counter-indicator.js","src/js/ui/ui.js","src/js/slide/get-thumb-bounds.js","src/js/core/eventable.js","src/js/slide/placeholder.js","src/js/slide/content.js","src/js/slide/loader.js","src/js/core/base.js","src/js/opener.js","src/js/photoswipe.js"],"sourcesContent":["(function () {\n\nfunction $parcel$defineInteropFlag(a) {\n Object.defineProperty(a, '__esModule', {value: true, configurable: true});\n}\n\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n var parcelRequire = $parcel$global[\"parcelRequire94c2\"];\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"gG83T\", function(module, exports) {\n\n$parcel$defineInteropFlag(module.exports);\n\n$parcel$export(module.exports, \"default\", function () { return $c246d27966689419$export$2e2bcd8739ae039; });\n/*!\n * PhotoSwipe 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */ /** @typedef {import('../photoswipe.js').Point} Point */ /**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */ function $c246d27966689419$var$createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) el.className = className;\n if (appendToEl) appendToEl.appendChild(el);\n return el;\n}\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */ function $c246d27966689419$var$equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n if (p2.id !== undefined) p1.id = p2.id;\n return p1;\n}\n/**\r\n * @param {Point} p\r\n */ function $c246d27966689419$var$roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */ function $c246d27966689419$var$getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt(x * x + y * y);\n}\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */ function $c246d27966689419$var$pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */ function $c246d27966689419$var$clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */ function $c246d27966689419$var$toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n if (scale !== undefined) propValue += ` scale3d(${scale},${scale},1)`;\n return propValue;\n}\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */ function $c246d27966689419$var$setTransform(el, x, y, scale) {\n el.style.transform = $c246d27966689419$var$toTransformString(x, y, scale);\n}\nconst $c246d27966689419$var$defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */ function $c246d27966689419$var$setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop ? `${prop} ${duration}ms ${ease || $c246d27966689419$var$defaultCSSEasing}` : 'none';\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */ function $c246d27966689419$var$setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/**\r\n * @param {HTMLElement} el\r\n */ function $c246d27966689419$var$removeTransitionStyle(el) {\n $c246d27966689419$var$setTransitionStyle(el);\n}\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */ function $c246d27966689419$var$decodeImage(img) {\n if ('decode' in img) return img.decode().catch(()=>{});\n if (img.complete) return Promise.resolve(img);\n return new Promise((resolve, reject)=>{\n img.onload = ()=>resolve(img);\n img.onerror = reject;\n });\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ /** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ const $c246d27966689419$var$LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */ function $c246d27966689419$var$specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */ function $c246d27966689419$var$getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */ let elements = [];\n if (option instanceof Element) elements = [\n option\n ];\n else if (option instanceof NodeList || Array.isArray(option)) elements = Array.from(option);\n else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) elements = Array.from(parent.querySelectorAll(selector));\n }\n return elements;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */ function $c246d27966689419$var$isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n// Detect passive event listener support\nlet $c246d27966689419$var$supportsPassive = false;\n/* eslint-disable */ try {\n /* @ts-ignore */ window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\n get: ()=>{\n $c246d27966689419$var$supportsPassive = true;\n }\n }));\n} catch (e) {}\n/* eslint-enable */ /**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */ class $c246d27966689419$var$DOMEvents {\n constructor(){\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */ this._pool = [];\n }\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */ add(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive);\n }\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */ remove(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive, true);\n }\n /**\r\n * Removes all bound events\r\n */ removeAll() {\n this._pool.forEach((poolItem)=>{\n this._toggleListener(poolItem.target, poolItem.type, poolItem.listener, poolItem.passive, true, true);\n });\n this._pool = [];\n }\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */ _toggleListener(target, type, listener, passive, unbind, skipPool) {\n if (!target) return;\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\n const types = type.split(' ');\n types.forEach((eType)=>{\n if (eType) {\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\n // so developer doesn't need to do this manually\n if (!skipPool) {\n if (unbind) // Remove from the events pool\n this._pool = this._pool.filter((poolItem)=>{\n return poolItem.type !== eType || poolItem.listener !== listener || poolItem.target !== target;\n });\n else // Add to the events pool\n this._pool.push({\n target: target,\n type: eType,\n listener: listener,\n passive: passive\n });\n } // most PhotoSwipe events call preventDefault,\n // and we do not need browser to scroll the page\n const eventOptions = $c246d27966689419$var$supportsPassive ? {\n passive: passive || false\n } : false;\n target[methodName](eType, listener, eventOptions);\n }\n });\n }\n}\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */ function $c246d27966689419$var$getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) return newViewportSize;\n }\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */ function $c246d27966689419$var$parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n if (options.paddingFn) paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n else if (options.padding) paddingValue = options.padding[prop];\n else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n if (options[legacyPropName]) // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */ function $c246d27966689419$var$getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - $c246d27966689419$var$parsePaddingOption('left', options, viewportSize, itemData, index) - $c246d27966689419$var$parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - $c246d27966689419$var$parsePaddingOption('top', options, viewportSize, itemData, index) - $c246d27966689419$var$parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {Record} Point */ /** @typedef {'x' | 'y'} Axis */ /**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */ class $c246d27966689419$var$PanBounds {\n /**\r\n * @param {Slide} slide\r\n */ constructor(slide){\n this.slide = slide;\n this.currZoomLevel = 1;\n this.center = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n this.max = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n this.min = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n }\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */ update(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n if (!this.slide.width) this.reset();\n else {\n this._updateAxis('x');\n this._updateAxis('y');\n this.slide.pswp.dispatch('calcBounds', {\n slide: this.slide\n });\n }\n }\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */ _updateAxis(axis) {\n const { pswp: pswp } = this.slide;\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\n const paddingProp = axis === 'x' ? 'left' : 'top';\n const padding = $c246d27966689419$var$parsePaddingOption(paddingProp, pswp.options, pswp.viewportSize, this.slide.data, this.slide.index);\n const panAreaSize = this.slide.panAreaSize[axis]; // Default position of element.\n // By default, it is center of viewport:\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding; // maximum pan position\n this.max[axis] = elSize > panAreaSize ? Math.round(panAreaSize - elSize) + padding : this.center[axis]; // minimum pan position\n this.min[axis] = elSize > panAreaSize ? padding : this.center[axis];\n }\n reset() {\n this.center.x = 0;\n this.center.y = 0;\n this.max.x = 0;\n this.max.y = 0;\n this.min.x = 0;\n this.min.y = 0;\n }\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */ correctPan(axis, panOffset) {\n // checkPanBounds\n return $c246d27966689419$var$clamp(panOffset, this.max[axis], this.min[axis]);\n }\n}\nconst $c246d27966689419$var$MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ /**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */ class $c246d27966689419$var$ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */ constructor(options, itemData, index, pswp){\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */ this.panAreaSize = null;\n /** @type { Point | null } */ this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */ update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */ const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n if (this.pswp) this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */ _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n if (!optionValue) return;\n if (typeof optionValue === 'function') return optionValue(this);\n if (optionValue === 'fill') return this.fill;\n if (optionValue === 'fit') return this.fit;\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n if (currZoomLevel) return currZoomLevel;\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n if (this.elementSize && currZoomLevel * this.elementSize.x > $c246d27966689419$var$MAX_IMAGE_WIDTH) currZoomLevel = $c246d27966689419$var$MAX_IMAGE_WIDTH / this.elementSize.x;\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n * Renders and allows to control a single slide\r\n */ class $c246d27966689419$var$Slide {\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(data, index, pswp){\n this.data = data;\n this.index = index;\n this.pswp = pswp;\n this.isActive = index === pswp.currIndex;\n this.currentResolution = 0;\n /** @type {Point} */ this.panAreaSize = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.pan = {\n x: 0,\n y: 0\n };\n this.isFirstSlide = this.isActive && !pswp.opener.isOpen;\n this.zoomLevels = new $c246d27966689419$var$ZoomLevel(pswp.options, data, index, pswp);\n this.pswp.dispatch('gettingData', {\n slide: this,\n data: this.data,\n index: index\n });\n this.content = this.pswp.contentLoader.getContentBySlide(this);\n this.container = $c246d27966689419$var$createElement('pswp__zoom-wrap', 'div');\n /** @type {HTMLElement | null} */ this.holderElement = null;\n this.currZoomLevel = 1;\n /** @type {number} */ this.width = this.content.width;\n /** @type {number} */ this.height = this.content.height;\n this.heavyAppended = false;\n this.bounds = new $c246d27966689419$var$PanBounds(this);\n this.prevDisplayedWidth = -1;\n this.prevDisplayedHeight = -1;\n this.pswp.dispatch('slideInit', {\n slide: this\n });\n }\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */ setIsActive(isActive) {\n if (isActive && !this.isActive) // slide just became active\n this.activate();\n else if (!isActive && this.isActive) // slide just became non-active\n this.deactivate();\n }\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */ append(holderElement) {\n this.holderElement = holderElement;\n this.container.style.transformOrigin = '0 0'; // Slide appended to DOM\n if (!this.data) return;\n this.calculateSize();\n this.load();\n this.updateContentSize();\n this.appendHeavy();\n this.holderElement.appendChild(this.container);\n this.zoomAndPanToInitial();\n this.pswp.dispatch('firstZoomPan', {\n slide: this\n });\n this.applyCurrentZoomPan();\n this.pswp.dispatch('afterSetContent', {\n slide: this\n });\n if (this.isActive) this.activate();\n }\n load() {\n this.content.load(false);\n this.pswp.dispatch('slideLoad', {\n slide: this\n });\n }\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */ appendHeavy() {\n const { pswp: pswp } = this;\n const appendHeavyNearby = true; // todo\n // Avoid appending heavy elements during animations\n if (this.heavyAppended || !pswp.opener.isOpen || pswp.mainScroll.isShifted() || !this.isActive && !appendHeavyNearby) return;\n if (this.pswp.dispatch('appendHeavy', {\n slide: this\n }).defaultPrevented) return;\n this.heavyAppended = true;\n this.content.append();\n this.pswp.dispatch('appendHeavyContent', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */ activate() {\n this.isActive = true;\n this.appendHeavy();\n this.content.activate();\n this.pswp.dispatch('slideActivate', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */ deactivate() {\n this.isActive = false;\n this.content.deactivate();\n if (this.currZoomLevel !== this.zoomLevels.initial) // allow filtering\n this.calculateSize();\n // reset zoom level\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n this.pswp.dispatch('slideDeactivate', {\n slide: this\n });\n }\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */ destroy() {\n this.content.hasSlide = false;\n this.content.remove();\n this.container.remove();\n this.pswp.dispatch('slideDestroy', {\n slide: this\n });\n }\n resize() {\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\n // Keep initial zoom level if it was before the resize,\n // as well as when this slide is not active\n // Reset position and scale to original state\n this.calculateSize();\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n } else {\n // readjust pan position if it's beyond the bounds\n this.calculateSize();\n this.bounds.update(this.currZoomLevel);\n this.panTo(this.pan.x, this.pan.y);\n }\n }\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */ updateContentSize(force) {\n // Use initial zoom level\n // if resolution is not defined (user didn't zoom yet)\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\n if (!scaleMultiplier) return;\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\n if (!this.sizeChanged(width, height) && !force) return;\n this.content.setDisplayedSize(width, height);\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ sizeChanged(width, height) {\n if (width !== this.prevDisplayedWidth || height !== this.prevDisplayedHeight) {\n this.prevDisplayedWidth = width;\n this.prevDisplayedHeight = height;\n return true;\n }\n return false;\n }\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */ getPlaceholderElement() {\n var _this$content$placeho;\n return (_this$content$placeho = this.content.placeholder) === null || _this$content$placeho === void 0 ? void 0 : _this$content$placeho.element;\n }\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */ zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\n const { pswp: pswp } = this;\n if (!this.isZoomable() || pswp.mainScroll.isShifted()) return;\n pswp.dispatch('beforeZoomTo', {\n destZoomLevel: destZoomLevel,\n centerPoint: centerPoint,\n transitionDuration: transitionDuration\n }); // stop all pan and zoom transitions\n pswp.animations.stopAllPan(); // if (!centerPoint) {\n // centerPoint = pswp.getViewportCenterPoint();\n // }\n const prevZoomLevel = this.currZoomLevel;\n if (!ignoreBounds) destZoomLevel = $c246d27966689419$var$clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\n // if (transitionDuration === undefined) {\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\n // }\n this.setZoomLevel(destZoomLevel);\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\n $c246d27966689419$var$roundPoint(this.pan);\n const finishTransition = ()=>{\n this._setResolution(destZoomLevel);\n this.applyCurrentZoomPan();\n };\n if (!transitionDuration) finishTransition();\n else pswp.animations.startTransition({\n isPan: true,\n name: 'zoomTo',\n target: this.container,\n transform: this.getCurrentTransform(),\n onComplete: finishTransition,\n duration: transitionDuration,\n easing: pswp.options.easing\n });\n }\n /**\r\n * @param {Point} [centerPoint]\r\n */ toggleZoom(centerPoint) {\n this.zoomTo(this.currZoomLevel === this.zoomLevels.initial ? this.zoomLevels.secondary : this.zoomLevels.initial, centerPoint, this.pswp.options.zoomAnimationDuration);\n }\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */ setZoomLevel(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n this.bounds.update(this.currZoomLevel);\n }\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */ calculateZoomToPanOffset(axis, point, prevZoomLevel) {\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\n if (totalPanDistance === 0) return this.bounds.center[axis];\n if (!point) point = this.pswp.getViewportCenterPoint();\n if (!prevZoomLevel) prevZoomLevel = this.zoomLevels.initial;\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\n return this.bounds.correctPan(axis, (this.pan[axis] - point[axis]) * zoomFactor + point[axis]);\n }\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */ panTo(panX, panY) {\n this.pan.x = this.bounds.correctPan('x', panX);\n this.pan.y = this.bounds.correctPan('y', panY);\n this.applyCurrentZoomPan();\n }\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */ isPannable() {\n return Boolean(this.width) && this.currZoomLevel > this.zoomLevels.fit;\n }\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */ isZoomable() {\n return Boolean(this.width) && this.content.isZoomable();\n }\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */ applyCurrentZoomPan() {\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\n if (this === this.pswp.currSlide) this.pswp.dispatch('zoomPanUpdate', {\n slide: this\n });\n }\n zoomAndPanToInitial() {\n this.currZoomLevel = this.zoomLevels.initial; // pan according to the zoom level\n this.bounds.update(this.currZoomLevel);\n $c246d27966689419$var$equalizePoints(this.pan, this.bounds.center);\n this.pswp.dispatch('initialZoomPan', {\n slide: this\n });\n }\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */ _applyZoomTransform(x, y, zoom) {\n zoom /= this.currentResolution || this.zoomLevels.initial;\n $c246d27966689419$var$setTransform(this.container, x, y, zoom);\n }\n calculateSize() {\n const { pswp: pswp } = this;\n $c246d27966689419$var$equalizePoints(this.panAreaSize, $c246d27966689419$var$getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index));\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\n pswp.dispatch('calcSlideSize', {\n slide: this\n });\n }\n /** @returns {string} */ getCurrentTransform() {\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\n return $c246d27966689419$var$toTransformString(this.pan.x, this.pan.y, scale);\n }\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */ _setResolution(newResolution) {\n if (newResolution === this.currentResolution) return;\n this.currentResolution = newResolution;\n this.updateContentSize();\n this.pswp.dispatch('resolutionChanged');\n }\n}\n/** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('./gestures.js').default} Gestures */ const $c246d27966689419$var$PAN_END_FRICTION = 0.35;\nconst $c246d27966689419$var$VERTICAL_DRAG_FRICTION = 0.6; // 1 corresponds to the third of viewport height\nconst $c246d27966689419$var$MIN_RATIO_TO_CLOSE = 0.4; // Minimum speed required to navigate\n// to next or previous slide\nconst $c246d27966689419$var$MIN_NEXT_SLIDE_SPEED = 0.5;\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */ function $c246d27966689419$var$project(initialVelocity, decelerationRate) {\n return initialVelocity * decelerationRate / (1 - decelerationRate);\n}\n/**\r\n * Handles single pointer dragging\r\n */ class $c246d27966689419$var$DragHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n this.pswp = gestures.pswp;\n /** @type {Point} */ this.startPan = {\n x: 0,\n y: 0\n };\n }\n start() {\n if (this.pswp.currSlide) $c246d27966689419$var$equalizePoints(this.startPan, this.pswp.currSlide.pan);\n this.pswp.animations.stopAll();\n }\n change() {\n const { p1: p1, prevP1: prevP1, dragAxis: dragAxis } = this.gestures;\n const { currSlide: currSlide } = this.pswp;\n if (dragAxis === 'y' && this.pswp.options.closeOnVerticalDrag && currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit && !this.gestures.isMultitouch) {\n // Handle vertical drag to close\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\n if (!this.pswp.dispatch('verticalDrag', {\n panY: panY\n }).defaultPrevented) {\n this._setPanWithFriction('y', panY, $c246d27966689419$var$VERTICAL_DRAG_FRICTION);\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\n this.pswp.applyBgOpacity(bgOpacity);\n currSlide.applyCurrentZoomPan();\n }\n } else {\n const mainScrollChanged = this._panOrMoveMainScroll('x');\n if (!mainScrollChanged) {\n this._panOrMoveMainScroll('y');\n if (currSlide) {\n $c246d27966689419$var$roundPoint(currSlide.pan);\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n }\n end() {\n const { velocity: velocity } = this.gestures;\n const { mainScroll: mainScroll, currSlide: currSlide } = this.pswp;\n let indexDiff = 0;\n this.pswp.animations.stopAll(); // Handle main scroll if it's shifted\n if (mainScroll.isShifted()) {\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX(); // Ratio between 0 and 1:\n // 0 - slide is not visible at all,\n // 0.5 - half of the slide is visible\n // 1 - slide is fully visible\n const currentSlideVisibilityRatio = mainScrollShiftDiff / this.pswp.viewportSize.x; // Go next slide.\n //\n // - if velocity and its direction is matched,\n // and we see at least tiny part of the next slide\n //\n // - or if we see less than 50% of the current slide\n // and velocity is close to 0\n //\n if (velocity.x < -$c246d27966689419$var$MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0 || velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5) {\n // Go to next slide\n indexDiff = 1;\n velocity.x = Math.min(velocity.x, 0);\n } else if (velocity.x > $c246d27966689419$var$MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0 || velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5) {\n // Go to prev slide\n indexDiff = -1;\n velocity.x = Math.max(velocity.x, 0);\n }\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\n } // Restore zoom level\n if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max || this.gestures.isMultitouch) this.gestures.zoomLevels.correctZoomPan(true);\n else {\n // we run two animations instead of one,\n // as each axis has own pan boundaries and thus different spring function\n // (correctZoomPan does not have this functionality,\n // it animates all properties with single timing function)\n this._finishPanGestureForAxis('x');\n this._finishPanGestureForAxis('y');\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */ _finishPanGestureForAxis(axis) {\n const { velocity: velocity } = this.gestures;\n const { currSlide: currSlide } = this.pswp;\n if (!currSlide) return;\n const { pan: pan, bounds: bounds } = currSlide;\n const panPos = pan[axis];\n const restoreBgOpacity = this.pswp.bgOpacity < 1 && axis === 'y'; // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\n // Increasing this number will reduce travel distance\n const decelerationRate = 0.995; // 0.99\n // Pan position if there is no bounds\n const projectedPosition = panPos + $c246d27966689419$var$project(velocity[axis], decelerationRate);\n if (restoreBgOpacity) {\n const vDragRatio = this._getVerticalDragRatio(panPos);\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition); // If we are above and moving upwards,\n // or if we are below and moving downwards\n if (vDragRatio < 0 && projectedVDragRatio < -$c246d27966689419$var$MIN_RATIO_TO_CLOSE || vDragRatio > 0 && projectedVDragRatio > $c246d27966689419$var$MIN_RATIO_TO_CLOSE) {\n this.pswp.close();\n return;\n }\n } // Pan position with corrected bounds\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition); // Exit if pan position should not be changed\n // or if speed it too low\n if (panPos === correctedPanPosition) return;\n // Overshoot if the final position is out of pan bounds\n const dampingRatio = correctedPanPosition === projectedPosition ? 1 : 0.82;\n const initialBgOpacity = this.pswp.bgOpacity;\n const totalPanDist = correctedPanPosition - panPos;\n this.pswp.animations.startSpring({\n name: 'panGesture' + axis,\n isPan: true,\n start: panPos,\n end: correctedPanPosition,\n velocity: velocity[axis],\n dampingRatio: dampingRatio,\n onUpdate: (pos)=>{\n // Animate opacity of background relative to Y pan position of an image\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\n // 0 - start of animation, 1 - end of animation\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist; // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n this.pswp.applyBgOpacity($c246d27966689419$var$clamp(initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio, 0, 1));\n }\n pan[axis] = Math.floor(pos);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */ _panOrMoveMainScroll(axis) {\n const { p1: p1, dragAxis: dragAxis, prevP1: prevP1, isMultitouch: isMultitouch } = this.gestures;\n const { currSlide: currSlide, mainScroll: mainScroll } = this.pswp;\n const delta = p1[axis] - prevP1[axis];\n const newMainScrollX = mainScroll.x + delta;\n if (!delta || !currSlide) return false;\n // Always move main scroll if image can not be panned\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\n mainScroll.moveTo(newMainScrollX, true);\n return true; // changed main scroll\n }\n const { bounds: bounds } = currSlide;\n const newPan = currSlide.pan[axis] + delta;\n if (this.pswp.options.allowPanToNext && dragAxis === 'x' && axis === 'x' && !isMultitouch) {\n const currSlideMainScrollX = mainScroll.getCurrSlideX(); // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\n const isLeftToRight = delta > 0;\n const isRightToLeft = !isLeftToRight;\n if (newPan > bounds.min[axis] && isLeftToRight) {\n // Panning from left to right, beyond the left edge\n // Wether the image was at minimum pan position (or less)\n // when this drag gesture started.\n // Minimum pan position refers to the left edge of the image.\n const wasAtMinPanPosition = bounds.min[axis] <= this.startPan[axis];\n if (wasAtMinPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\n // Paning from right to left, beyond the right edge\n // Maximum pan position refers to the right edge of the image.\n const wasAtMaxPanPosition = this.startPan[axis] <= bounds.max[axis];\n if (wasAtMaxPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n } else // If main scroll is shifted\n if (mainScrollShiftDiff !== 0) {\n // If main scroll is shifted right\n if (mainScrollShiftDiff > 0) {\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\n return true;\n } else if (mainScrollShiftDiff < 0) {\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\n return true;\n }\n } else // We are within pan bounds, so just pan\n this._setPanWithFriction(axis, newPan);\n } else {\n if (axis === 'y') // Do not pan vertically if main scroll is shifted o\n {\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) this._setPanWithFriction(axis, newPan);\n } else this._setPanWithFriction(axis, newPan);\n }\n return false;\n }\n // If we move below the ratio is positive\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */ _getVerticalDragRatio(panY) {\n var _this$pswp$currSlide$, _this$pswp$currSlide;\n return (panY - ((_this$pswp$currSlide$ = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.bounds.center.y) !== null && _this$pswp$currSlide$ !== void 0 ? _this$pswp$currSlide$ : 0)) / (this.pswp.viewportSize.y / 3);\n }\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */ _setPanWithFriction(axis, potentialPan, customFriction) {\n const { currSlide: currSlide } = this.pswp;\n if (!currSlide) return;\n const { pan: pan, bounds: bounds } = currSlide;\n const correctedPan = bounds.correctPan(axis, potentialPan); // If we are out of pan bounds\n if (correctedPan !== potentialPan || customFriction) {\n const delta = Math.round(potentialPan - pan[axis]);\n pan[axis] += delta * (customFriction || $c246d27966689419$var$PAN_END_FRICTION);\n } else pan[axis] = potentialPan;\n }\n}\n/** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('./gestures.js').default} Gestures */ const $c246d27966689419$var$UPPER_ZOOM_FRICTION = 0.05;\nconst $c246d27966689419$var$LOWER_ZOOM_FRICTION = 0.15;\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */ function $c246d27966689419$var$getZoomPointsCenter(p, p1, p2) {\n p.x = (p1.x + p2.x) / 2;\n p.y = (p1.y + p2.y) / 2;\n return p;\n}\nclass $c246d27966689419$var$ZoomHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._startPan = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._startZoomPoint = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._zoomPoint = {\n x: 0,\n y: 0\n };\n /** @private */ this._wasOverFitZoomLevel = false;\n /** @private */ this._startZoomLevel = 1;\n }\n start() {\n const { currSlide: currSlide } = this.gestures.pswp;\n if (currSlide) {\n this._startZoomLevel = currSlide.currZoomLevel;\n $c246d27966689419$var$equalizePoints(this._startPan, currSlide.pan);\n }\n this.gestures.pswp.animations.stopAllPan();\n this._wasOverFitZoomLevel = false;\n }\n change() {\n const { p1: p1, startP1: startP1, p2: p2, startP2: startP2, pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if (!currSlide) return;\n const minZoomLevel = currSlide.zoomLevels.min;\n const maxZoomLevel = currSlide.zoomLevels.max;\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) return;\n $c246d27966689419$var$getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\n $c246d27966689419$var$getZoomPointsCenter(this._zoomPoint, p1, p2);\n let currZoomLevel = 1 / $c246d27966689419$var$getDistanceBetween(startP1, startP2) * $c246d27966689419$var$getDistanceBetween(p1, p2) * this._startZoomLevel; // slightly over the zoom.fit\n if (currZoomLevel > currSlide.zoomLevels.initial + currSlide.zoomLevels.initial / 15) this._wasOverFitZoomLevel = true;\n if (currZoomLevel < minZoomLevel) {\n if (pswp.options.pinchToClose && !this._wasOverFitZoomLevel && this._startZoomLevel <= currSlide.zoomLevels.initial) {\n // fade out background if zooming out\n const bgOpacity = 1 - (minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2);\n if (!pswp.dispatch('pinchClose', {\n bgOpacity: bgOpacity\n }).defaultPrevented) pswp.applyBgOpacity(bgOpacity);\n } else // Apply the friction if zoom level is below the min\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * $c246d27966689419$var$LOWER_ZOOM_FRICTION;\n } else if (currZoomLevel > maxZoomLevel) // Apply the friction if zoom level is above the max\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * $c246d27966689419$var$UPPER_ZOOM_FRICTION;\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\n currSlide.setZoomLevel(currZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n end() {\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial) && !this._wasOverFitZoomLevel && pswp.options.pinchToClose) pswp.close();\n else this.correctZoomPan();\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */ _calculatePanForZoomLevel(axis, currZoomLevel) {\n const zoomFactor = currZoomLevel / this._startZoomLevel;\n return this._zoomPoint[axis] - (this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor;\n }\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */ correctZoomPan(ignoreGesture) {\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if (!(currSlide !== null && currSlide !== void 0 && currSlide.isZoomable())) return;\n if (this._zoomPoint.x === 0) ignoreGesture = true;\n const prevZoomLevel = currSlide.currZoomLevel;\n /** @type {number} */ let destinationZoomLevel;\n let currZoomLevelNeedsChange = true;\n if (prevZoomLevel < currSlide.zoomLevels.initial) destinationZoomLevel = currSlide.zoomLevels.initial; // zoom to min\n else if (prevZoomLevel > currSlide.zoomLevels.max) destinationZoomLevel = currSlide.zoomLevels.max; // zoom to max\n else {\n currZoomLevelNeedsChange = false;\n destinationZoomLevel = prevZoomLevel;\n }\n const initialBgOpacity = pswp.bgOpacity;\n const restoreBgOpacity = pswp.bgOpacity < 1;\n const initialPan = $c246d27966689419$var$equalizePoints({\n x: 0,\n y: 0\n }, currSlide.pan);\n let destinationPan = $c246d27966689419$var$equalizePoints({\n x: 0,\n y: 0\n }, initialPan);\n if (ignoreGesture) {\n this._zoomPoint.x = 0;\n this._zoomPoint.y = 0;\n this._startZoomPoint.x = 0;\n this._startZoomPoint.y = 0;\n this._startZoomLevel = prevZoomLevel;\n $c246d27966689419$var$equalizePoints(this._startPan, initialPan);\n }\n if (currZoomLevelNeedsChange) destinationPan = {\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\n };\n // set zoom level, so pan bounds are updated according to it\n currSlide.setZoomLevel(destinationZoomLevel);\n destinationPan = {\n x: currSlide.bounds.correctPan('x', destinationPan.x),\n y: currSlide.bounds.correctPan('y', destinationPan.y)\n }; // return zoom level and its bounds to initial\n currSlide.setZoomLevel(prevZoomLevel);\n const panNeedsChange = !$c246d27966689419$var$pointsEqual(destinationPan, initialPan);\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\n // update resolution after gesture\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan(); // nothing to animate\n return;\n }\n pswp.animations.stopAllPan();\n pswp.animations.startSpring({\n isPan: true,\n start: 0,\n end: 1000,\n velocity: 0,\n dampingRatio: 1,\n naturalFrequency: 40,\n onUpdate: (now)=>{\n now /= 1000; // 0 - start, 1 - end\n if (panNeedsChange || currZoomLevelNeedsChange) {\n if (panNeedsChange) {\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\n }\n if (currZoomLevelNeedsChange) {\n const newZoomLevel = prevZoomLevel + (destinationZoomLevel - prevZoomLevel) * now;\n currSlide.setZoomLevel(newZoomLevel);\n }\n currSlide.applyCurrentZoomPan();\n } // Restore background opacity\n if (restoreBgOpacity && pswp.bgOpacity < 1) // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n pswp.applyBgOpacity($c246d27966689419$var$clamp(initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1));\n },\n onComplete: ()=>{\n // update resolution after transition ends\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n}\n/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */ /** @typedef {import('./gestures.js').default} Gestures */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */ /**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */ function $c246d27966689419$var$didTapOnMainContent(event) {\n return !!/** @type {HTMLElement} */ event.target.closest('.pswp__container');\n}\n/**\r\n * Tap, double-tap handler.\r\n */ class $c246d27966689419$var$TapHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ click(point, originalEvent) {\n const targetClassList = /** @type {HTMLElement} */ originalEvent.target.classList;\n const isImageClick = targetClassList.contains('pswp__img');\n const isBackgroundClick = targetClassList.contains('pswp__item') || targetClassList.contains('pswp__zoom-wrap');\n if (isImageClick) this._doClickOrTapAction('imageClick', point, originalEvent);\n else if (isBackgroundClick) this._doClickOrTapAction('bgClick', point, originalEvent);\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ tap(point, originalEvent) {\n if ($c246d27966689419$var$didTapOnMainContent(originalEvent)) this._doClickOrTapAction('tap', point, originalEvent);\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ doubleTap(point, originalEvent) {\n if ($c246d27966689419$var$didTapOnMainContent(originalEvent)) this._doClickOrTapAction('doubleTap', point, originalEvent);\n }\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ _doClickOrTapAction(actionName, point, originalEvent) {\n var _this$gestures$pswp$e;\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n const actionFullName = /** @type {AddPostfix} */ actionName + 'Action';\n const optionValue = pswp.options[actionFullName];\n if (pswp.dispatch(actionFullName, {\n point: point,\n originalEvent: originalEvent\n }).defaultPrevented) return;\n if (typeof optionValue === 'function') {\n optionValue.call(pswp, point, originalEvent);\n return;\n }\n switch(optionValue){\n case 'close':\n case 'next':\n pswp[optionValue]();\n break;\n case 'zoom':\n currSlide === null || currSlide === void 0 || currSlide.toggleZoom(point);\n break;\n case 'zoom-or-close':\n // by default click zooms current image,\n // if it can not be zoomed - gallery will be closed\n if (currSlide !== null && currSlide !== void 0 && currSlide.isZoomable() && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) currSlide.toggleZoom(point);\n else if (pswp.options.clickToCloseNonZoomable) pswp.close();\n break;\n case 'toggle-controls':\n (_this$gestures$pswp$e = this.gestures.pswp.element) === null || _this$gestures$pswp$e === void 0 || _this$gestures$pswp$e.classList.toggle('pswp--ui-visible'); // if (_controlsVisible) {\n break;\n }\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').Point} Point */ // How far should user should drag\n// until we can determine that the gesture is swipe and its direction\nconst $c246d27966689419$var$AXIS_SWIPE_HYSTERISIS = 10; //const PAN_END_FRICTION = 0.35;\nconst $c246d27966689419$var$DOUBLE_TAP_DELAY = 300; // ms\nconst $c246d27966689419$var$MIN_TAP_DISTANCE = 25; // px\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */ class $c246d27966689419$var$Gestures {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n /** @type {'x' | 'y' | null} */ this.dragAxis = null; // point objects are defined once and reused\n // PhotoSwipe keeps track only of two pointers, others are ignored\n /** @type {Point} */ this.p1 = {\n x: 0,\n y: 0\n }; // the first pressed pointer\n /** @type {Point} */ this.p2 = {\n x: 0,\n y: 0\n }; // the second pressed pointer\n /** @type {Point} */ this.prevP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.prevP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.startP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.startP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.velocity = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */ this._lastStartP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */ this._intervalP1 = {\n x: 0,\n y: 0\n };\n /** @private */ this._numActivePoints = 0;\n /** @type {Point[]}\r\n * @private\r\n */ this._ongoingPointers = [];\n /** @private */ this._touchEventEnabled = 'ontouchstart' in window;\n /** @private */ this._pointerEventEnabled = !!window.PointerEvent;\n this.supportsTouch = this._touchEventEnabled || this._pointerEventEnabled && navigator.maxTouchPoints > 1;\n /** @private */ this._numActivePoints = 0;\n /** @private */ this._intervalTime = 0;\n /** @private */ this._velocityCalculated = false;\n this.isMultitouch = false;\n this.isDragging = false;\n this.isZooming = false;\n /** @type {number | null} */ this.raf = null;\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */ this._tapTimer = null;\n if (!this.supportsTouch) // disable pan to next slide for non-touch devices\n pswp.options.allowPanToNext = false;\n this.drag = new $c246d27966689419$var$DragHandler(this);\n this.zoomLevels = new $c246d27966689419$var$ZoomHandler(this);\n this.tapHandler = new $c246d27966689419$var$TapHandler(this);\n pswp.on('bindEvents', ()=>{\n pswp.events.add(pswp.scrollWrap, 'click', /** @type EventListener */ this._onClick.bind(this));\n if (this._pointerEventEnabled) this._bindEvents('pointer', 'down', 'up', 'cancel');\n else if (this._touchEventEnabled) {\n this._bindEvents('touch', 'start', 'end', 'cancel'); // In previous versions we also bound mouse event here,\n // in case device supports both touch and mouse events,\n // but newer versions of browsers now support PointerEvent.\n // on iOS10 if you bind touchmove/end after touchstart,\n // and you don't preventDefault touchstart (which PhotoSwipe does),\n // preventDefault will have no effect on touchmove and touchend.\n // Unless you bind it previously.\n if (pswp.scrollWrap) {\n pswp.scrollWrap.ontouchmove = ()=>{};\n pswp.scrollWrap.ontouchend = ()=>{};\n }\n } else this._bindEvents('mouse', 'down', 'up');\n });\n }\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */ _bindEvents(pref, down, up, cancel) {\n const { pswp: pswp } = this;\n const { events: events } = pswp;\n const cancelEvent = cancel ? pref + cancel : '';\n events.add(pswp.scrollWrap, pref + down, /** @type EventListener */ this.onPointerDown.bind(this));\n events.add(window, pref + 'move', /** @type EventListener */ this.onPointerMove.bind(this));\n events.add(window, pref + up, /** @type EventListener */ this.onPointerUp.bind(this));\n if (cancelEvent) events.add(pswp.scrollWrap, cancelEvent, /** @type EventListener */ this.onPointerUp.bind(this));\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerDown(e) {\n // We do not call preventDefault for touch events\n // to allow browser to show native dialog on longpress\n // (the one that allows to save image or open it in new tab).\n //\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse'; // Allow dragging only via left mouse button.\n // http://www.quirksmode.org/js/events_properties.html\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\n if (isMousePointer && e.button > 0) return;\n const { pswp: pswp } = this; // if PhotoSwipe is opening or closing\n if (!pswp.opener.isOpen) {\n e.preventDefault();\n return;\n }\n if (pswp.dispatch('pointerDown', {\n originalEvent: e\n }).defaultPrevented) return;\n if (isMousePointer) {\n pswp.mouseDetected(); // preventDefault mouse event to prevent\n // browser image drag feature\n this._preventPointerEventBehaviour(e, 'down');\n }\n pswp.animations.stopAll();\n this._updatePoints(e, 'down');\n if (this._numActivePoints === 1) {\n this.dragAxis = null; // we need to store initial point to determine the main axis,\n // drag is activated only after the axis is determined\n $c246d27966689419$var$equalizePoints(this.startP1, this.p1);\n }\n if (this._numActivePoints > 1) {\n // Tap or double tap should not trigger if more than one pointer\n this._clearTapTimer();\n this.isMultitouch = true;\n } else this.isMultitouch = false;\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerMove(e) {\n this._preventPointerEventBehaviour(e, 'move');\n if (!this._numActivePoints) return;\n this._updatePoints(e, 'move');\n if (this.pswp.dispatch('pointerMove', {\n originalEvent: e\n }).defaultPrevented) return;\n if (this._numActivePoints === 1 && !this.isDragging) {\n if (!this.dragAxis) this._calculateDragDirection();\n // Drag axis was detected, emit drag.start\n if (this.dragAxis && !this.isDragging) {\n if (this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n }\n this.isDragging = true;\n this._clearTapTimer(); // Tap can not trigger after drag\n // Adjust starting point\n this._updateStartPoints();\n this._intervalTime = Date.now(); //this._startTime = this._intervalTime;\n this._velocityCalculated = false;\n $c246d27966689419$var$equalizePoints(this._intervalP1, this.p1);\n this.velocity.x = 0;\n this.velocity.y = 0;\n this.drag.start();\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n } else if (this._numActivePoints > 1 && !this.isZooming) {\n this._finishDrag();\n this.isZooming = true; // Adjust starting points\n this._updateStartPoints();\n this.zoomLevels.start();\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n }\n /**\r\n * @private\r\n */ _finishDrag() {\n if (this.isDragging) {\n this.isDragging = false; // Try to calculate velocity,\n // if it wasn't calculated yet in drag.change\n if (!this._velocityCalculated) this._updateVelocity(true);\n this.drag.end();\n this.dragAxis = null;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerUp(e) {\n if (!this._numActivePoints) return;\n this._updatePoints(e, 'up');\n if (this.pswp.dispatch('pointerUp', {\n originalEvent: e\n }).defaultPrevented) return;\n if (this._numActivePoints === 0) {\n this._rafStopLoop();\n if (this.isDragging) this._finishDrag();\n else if (!this.isZooming && !this.isMultitouch) //this.zoomLevels.correctZoomPan();\n this._finishTap(e);\n }\n if (this._numActivePoints < 2 && this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n if (this._numActivePoints === 1) {\n // Since we have 1 point left, we need to reinitiate drag\n this.dragAxis = null;\n this._updateStartPoints();\n }\n }\n }\n /**\r\n * @private\r\n */ _rafRenderLoop() {\n if (this.isDragging || this.isZooming) {\n this._updateVelocity();\n if (this.isDragging) // make sure that pointer moved since the last update\n {\n if (!$c246d27966689419$var$pointsEqual(this.p1, this.prevP1)) this.drag.change();\n } else if (!$c246d27966689419$var$pointsEqual(this.p1, this.prevP1) || !$c246d27966689419$var$pointsEqual(this.p2, this.prevP2)) this.zoomLevels.change();\n this._updatePrevPoints();\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\n }\n }\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */ _updateVelocity(force) {\n const time = Date.now();\n const duration = time - this._intervalTime;\n if (duration < 50 && !force) return;\n this.velocity.x = this._getVelocity('x', duration);\n this.velocity.y = this._getVelocity('y', duration);\n this._intervalTime = time;\n $c246d27966689419$var$equalizePoints(this._intervalP1, this.p1);\n this._velocityCalculated = true;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */ _finishTap(e) {\n const { mainScroll: mainScroll } = this.pswp; // Do not trigger tap events if main scroll is shifted\n if (mainScroll.isShifted()) {\n // restore main scroll position\n // (usually happens if stopped in the middle of animation)\n mainScroll.moveIndexBy(0, true);\n return;\n } // Do not trigger tap for touchcancel or pointercancel\n if (e.type.indexOf('cancel') > 0) return;\n // Trigger click instead of tap for mouse events\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\n this.tapHandler.click(this.startP1, e);\n return;\n } // Disable delay if there is no doubleTapAction\n const tapDelay = this.pswp.options.doubleTapAction ? $c246d27966689419$var$DOUBLE_TAP_DELAY : 0; // If tapTimer is defined - we tapped recently,\n // check if the current tap is close to the previous one,\n // if yes - trigger double tap\n if (this._tapTimer) {\n this._clearTapTimer(); // Check if two taps were more or less on the same place\n if ($c246d27966689419$var$getDistanceBetween(this._lastStartP1, this.startP1) < $c246d27966689419$var$MIN_TAP_DISTANCE) this.tapHandler.doubleTap(this.startP1, e);\n } else {\n $c246d27966689419$var$equalizePoints(this._lastStartP1, this.startP1);\n this._tapTimer = setTimeout(()=>{\n this.tapHandler.tap(this.startP1, e);\n this._clearTapTimer();\n }, tapDelay);\n }\n }\n /**\r\n * @private\r\n */ _clearTapTimer() {\n if (this._tapTimer) {\n clearTimeout(this._tapTimer);\n this._tapTimer = null;\n }\n }\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */ _getVelocity(axis, duration) {\n // displacement is like distance, but can be negative.\n const displacement = this.p1[axis] - this._intervalP1[axis];\n if (Math.abs(displacement) > 1 && duration > 5) return displacement / duration;\n return 0;\n }\n /**\r\n * @private\r\n */ _rafStopLoop() {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = null;\n }\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */ _preventPointerEventBehaviour(e, pointerType) {\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\n if (preventPointerEvent) e.preventDefault();\n }\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */ _updatePoints(e, pointerType) {\n if (this._pointerEventEnabled) {\n const pointerEvent = /** @type {PointerEvent} */ e; // Try to find the current pointer in ongoing pointers by its ID\n const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer)=>{\n return ongoingPointer.id === pointerEvent.pointerId;\n });\n if (pointerType === 'up' && pointerIndex > -1) // release the pointer - remove it from ongoing\n this._ongoingPointers.splice(pointerIndex, 1);\n else if (pointerType === 'down' && pointerIndex === -1) // add new pointer\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, {\n x: 0,\n y: 0\n }));\n else if (pointerIndex > -1) // update existing pointer\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\n this._numActivePoints = this._ongoingPointers.length; // update points that PhotoSwipe uses\n // to calculate position and scale\n if (this._numActivePoints > 0) $c246d27966689419$var$equalizePoints(this.p1, this._ongoingPointers[0]);\n if (this._numActivePoints > 1) $c246d27966689419$var$equalizePoints(this.p2, this._ongoingPointers[1]);\n } else {\n const touchEvent = /** @type {TouchEvent} */ e;\n this._numActivePoints = 0;\n if (touchEvent.type.indexOf('touch') > -1) // Touch Event\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\n {\n if (touchEvent.touches && touchEvent.touches.length > 0) {\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\n this._numActivePoints++;\n if (touchEvent.touches.length > 1) {\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\n this._numActivePoints++;\n }\n }\n } else {\n // Mouse Event\n this._convertEventPosToPoint(/** @type {PointerEvent} */ e, this.p1);\n if (pointerType === 'up') // clear all points on mouseup\n this._numActivePoints = 0;\n else this._numActivePoints++;\n }\n }\n }\n /** update points that were used during previous rAF tick\r\n * @private\r\n */ _updatePrevPoints() {\n $c246d27966689419$var$equalizePoints(this.prevP1, this.p1);\n $c246d27966689419$var$equalizePoints(this.prevP2, this.p2);\n }\n /** update points at the start of gesture\r\n * @private\r\n */ _updateStartPoints() {\n $c246d27966689419$var$equalizePoints(this.startP1, this.p1);\n $c246d27966689419$var$equalizePoints(this.startP2, this.p2);\n this._updatePrevPoints();\n }\n /** @private */ _calculateDragDirection() {\n if (this.pswp.mainScroll.isShifted()) // if main scroll position is shifted – direction is always horizontal\n this.dragAxis = 'x';\n else {\n // calculate delta of the last touchmove tick\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\n if (diff !== 0) {\n // check if pointer was shifted horizontally or vertically\n const axisToCheck = diff > 0 ? 'x' : 'y';\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= $c246d27966689419$var$AXIS_SWIPE_HYSTERISIS) this.dragAxis = axisToCheck;\n }\n }\n }\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */ _convertEventPosToPoint(e, p) {\n p.x = e.pageX - this.pswp.offset.x;\n p.y = e.pageY - this.pswp.offset.y;\n if ('pointerId' in e) p.id = e.pointerId;\n else if (e.identifier !== undefined) p.id = e.identifier;\n return p;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */ _onClick(e) {\n // Do not allow click event to pass through after drag\n if (this.pswp.mainScroll.isShifted()) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./slide/slide.js').default} Slide */ /** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */ const $c246d27966689419$var$MAIN_SCROLL_END_FRICTION = 0.35; // const MIN_SWIPE_TRANSITION_DURATION = 250;\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */ class $c246d27966689419$var$MainScroll {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.x = 0;\n this.slideWidth = 0;\n /** @private */ this._currPositionIndex = 0;\n /** @private */ this._prevPositionIndex = 0;\n /** @private */ this._containerShiftIndex = -1;\n /** @type {ItemHolder[]} */ this.itemHolders = [];\n }\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */ resize(resizeSlides) {\n const { pswp: pswp } = this;\n const newSlideWidth = Math.round(pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing); // Mobile browsers might trigger a resize event during a gesture.\n // (due to toolbar appearing or hiding).\n // Avoid re-adjusting main scroll position if width wasn't changed\n const slideWidthChanged = newSlideWidth !== this.slideWidth;\n if (slideWidthChanged) {\n this.slideWidth = newSlideWidth;\n this.moveTo(this.getCurrSlideX());\n }\n this.itemHolders.forEach((itemHolder, index)=>{\n if (slideWidthChanged) $c246d27966689419$var$setTransform(itemHolder.el, (index + this._containerShiftIndex) * this.slideWidth);\n if (resizeSlides && itemHolder.slide) itemHolder.slide.resize();\n });\n }\n /**\r\n * Reset X position of the main scroller to zero\r\n */ resetPosition() {\n // Position on the main scroller (offset)\n // it is independent from slide index\n this._currPositionIndex = 0;\n this._prevPositionIndex = 0; // This will force recalculation of size on next resize()\n this.slideWidth = 0; // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\n this._containerShiftIndex = -1;\n }\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */ appendHolders() {\n this.itemHolders = []; // append our three slide holders -\n // previous, current, and next\n for(let i = 0; i < 3; i++){\n const el = $c246d27966689419$var$createElement('pswp__item', 'div', this.pswp.container);\n el.setAttribute('role', 'group');\n el.setAttribute('aria-roledescription', 'slide');\n el.setAttribute('aria-hidden', 'true'); // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\n el.style.display = i === 1 ? 'block' : 'none';\n this.itemHolders.push({\n el: el //index: -1\n });\n }\n }\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */ canBeSwiped() {\n return this.pswp.getNumItems() > 1;\n }\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */ moveIndexBy(diff, animate, velocityX) {\n const { pswp: pswp } = this;\n let newIndex = pswp.potentialIndex + diff;\n const numSlides = pswp.getNumItems();\n if (pswp.canLoop()) {\n newIndex = pswp.getLoopedIndex(newIndex);\n const distance = (diff + numSlides) % numSlides;\n if (distance <= numSlides / 2) // go forward\n diff = distance;\n else // go backwards\n diff = distance - numSlides;\n } else {\n if (newIndex < 0) newIndex = 0;\n else if (newIndex >= numSlides) newIndex = numSlides - 1;\n diff = newIndex - pswp.potentialIndex;\n }\n pswp.potentialIndex = newIndex;\n this._currPositionIndex -= diff;\n pswp.animations.stopMainScroll();\n const destinationX = this.getCurrSlideX();\n if (!animate) {\n this.moveTo(destinationX);\n this.updateCurrItem();\n } else {\n pswp.animations.startSpring({\n isMainScroll: true,\n start: this.x,\n end: destinationX,\n velocity: velocityX || 0,\n naturalFrequency: 30,\n dampingRatio: 1,\n //0.7,\n onUpdate: (x)=>{\n this.moveTo(x);\n },\n onComplete: ()=>{\n this.updateCurrItem();\n pswp.appendHeavy();\n }\n });\n let currDiff = pswp.potentialIndex - pswp.currIndex;\n if (pswp.canLoop()) {\n const currDistance = (currDiff + numSlides) % numSlides;\n if (currDistance <= numSlides / 2) // go forward\n currDiff = currDistance;\n else // go backwards\n currDiff = currDistance - numSlides;\n } // Force-append new slides during transition\n // if difference between slides is more than 1\n if (Math.abs(currDiff) > 1) this.updateCurrItem();\n }\n return Boolean(diff);\n }\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */ getCurrSlideX() {\n return this.slideWidth * this._currPositionIndex;\n }\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */ isShifted() {\n return this.x !== this.getCurrSlideX();\n }\n /**\r\n * Update slides X positions and set their content\r\n */ updateCurrItem() {\n var _this$itemHolders$;\n const { pswp: pswp } = this;\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\n if (!positionDifference) return;\n this._prevPositionIndex = this._currPositionIndex;\n pswp.currIndex = pswp.potentialIndex;\n let diffAbs = Math.abs(positionDifference);\n /** @type {ItemHolder | undefined} */ let tempHolder;\n if (diffAbs >= 3) {\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\n diffAbs = 3; // If slides are changed by 3 screens or more - clean up previous slides\n this.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide;\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.destroy();\n itemHolder.slide = undefined;\n });\n }\n for(let i = 0; i < diffAbs; i++)if (positionDifference > 0) {\n tempHolder = this.itemHolders.shift();\n if (tempHolder) {\n this.itemHolders[2] = tempHolder; // move first to last\n this._containerShiftIndex++;\n $c246d27966689419$var$setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex - diffAbs + i + 2);\n }\n } else {\n tempHolder = this.itemHolders.pop();\n if (tempHolder) {\n this.itemHolders.unshift(tempHolder); // move last to first\n this._containerShiftIndex--;\n $c246d27966689419$var$setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex + diffAbs - i - 2);\n }\n }\n // Reset transfrom every 50ish navigations in one direction.\n //\n // Otherwise transform will keep growing indefinitely,\n // which might cause issues as browsers have a maximum transform limit.\n // I wasn't able to reach it, but just to be safe.\n // This should not cause noticable lag.\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\n this.resetPosition();\n this.resize();\n } // Pan transition might be running (and consntantly updating pan position)\n pswp.animations.stopAllPan();\n this.itemHolders.forEach((itemHolder, i)=>{\n if (itemHolder.slide) // Slide in the 2nd holder is always active\n itemHolder.slide.setIsActive(i === 1);\n });\n pswp.currSlide = (_this$itemHolders$ = this.itemHolders[1]) === null || _this$itemHolders$ === void 0 ? void 0 : _this$itemHolders$.slide;\n pswp.contentLoader.updateLazy(positionDifference);\n if (pswp.currSlide) pswp.currSlide.applyCurrentZoomPan();\n pswp.dispatch('change');\n }\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */ moveTo(x, dragging) {\n if (!this.pswp.canLoop() && dragging) {\n // Apply friction\n let newSlideIndexOffset = (this.slideWidth * this._currPositionIndex - x) / this.slideWidth;\n newSlideIndexOffset += this.pswp.currIndex;\n const delta = Math.round(x - this.x);\n if (newSlideIndexOffset < 0 && delta > 0 || newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0) x = this.x + delta * $c246d27966689419$var$MAIN_SCROLL_END_FRICTION;\n }\n this.x = x;\n if (this.pswp.container) $c246d27966689419$var$setTransform(this.pswp.container, x);\n this.pswp.dispatch('moveMainScroll', {\n x: x,\n dragging: dragging !== null && dragging !== void 0 ? dragging : false\n });\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */ const $c246d27966689419$var$KeyboardKeyCodesMap = {\n Escape: 27,\n z: 90,\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n Tab: 9\n};\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */ const $c246d27966689419$var$getKeyboardEventKey = (key, isKeySupported)=>{\n return isKeySupported ? key : $c246d27966689419$var$KeyboardKeyCodesMap[key];\n};\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */ class $c246d27966689419$var$Keyboard {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n /** @private */ this._wasFocused = false;\n pswp.on('bindEvents', ()=>{\n if (pswp.options.trapFocus) {\n // Dialog was likely opened by keyboard if initial point is not defined\n if (!pswp.options.initialPointerPos) // focus causes layout,\n // which causes lag during the animation,\n // that's why we delay it until the opener transition ends\n this._focusRoot();\n pswp.events.add(document, 'focusin', /** @type EventListener */ this._onFocusIn.bind(this));\n }\n pswp.events.add(document, 'keydown', /** @type EventListener */ this._onKeyDown.bind(this));\n });\n const lastActiveElement = /** @type {HTMLElement} */ document.activeElement;\n pswp.on('destroy', ()=>{\n if (pswp.options.returnFocus && lastActiveElement && this._wasFocused) lastActiveElement.focus();\n });\n }\n /** @private */ _focusRoot() {\n if (!this._wasFocused && this.pswp.element) {\n this.pswp.element.focus();\n this._wasFocused = true;\n }\n }\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */ _onKeyDown(e) {\n const { pswp: pswp } = this;\n if (pswp.dispatch('keydown', {\n originalEvent: e\n }).defaultPrevented) return;\n if ($c246d27966689419$var$specialKeyUsed(e)) // don't do anything if special key pressed\n // to prevent from overriding default browser actions\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\n return;\n /** @type {Methods | undefined} */ let keydownAction;\n /** @type {'x' | 'y' | undefined} */ let axis;\n let isForward = false;\n const isKeySupported = 'key' in e;\n switch(isKeySupported ? e.key : e.keyCode){\n case $c246d27966689419$var$getKeyboardEventKey('Escape', isKeySupported):\n if (pswp.options.escKey) keydownAction = 'close';\n break;\n case $c246d27966689419$var$getKeyboardEventKey('z', isKeySupported):\n keydownAction = 'toggleZoom';\n break;\n case $c246d27966689419$var$getKeyboardEventKey('ArrowLeft', isKeySupported):\n axis = 'x';\n break;\n case $c246d27966689419$var$getKeyboardEventKey('ArrowUp', isKeySupported):\n axis = 'y';\n break;\n case $c246d27966689419$var$getKeyboardEventKey('ArrowRight', isKeySupported):\n axis = 'x';\n isForward = true;\n break;\n case $c246d27966689419$var$getKeyboardEventKey('ArrowDown', isKeySupported):\n isForward = true;\n axis = 'y';\n break;\n case $c246d27966689419$var$getKeyboardEventKey('Tab', isKeySupported):\n this._focusRoot();\n break;\n } // if left/right/top/bottom key\n if (axis) {\n // prevent page scroll\n e.preventDefault();\n const { currSlide: currSlide } = pswp;\n if (pswp.options.arrowKeys && axis === 'x' && pswp.getNumItems() > 1) keydownAction = isForward ? 'next' : 'prev';\n else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\n // up/down arrow keys pan the image vertically\n // left/right arrow keys pan horizontally.\n // Unless there is only one image,\n // or arrowKeys option is disabled\n currSlide.pan[axis] += isForward ? -80 : 80;\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\n }\n }\n if (keydownAction) {\n e.preventDefault(); // @ts-ignore\n pswp[keydownAction]();\n }\n }\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */ _onFocusIn(e) {\n const { template: template } = this.pswp;\n if (template && document !== e.target && template !== e.target && !template.contains(/** @type {Node} */ e.target)) // focus root element\n template.focus();\n }\n}\nconst $c246d27966689419$var$DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ /** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */ /** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */ /**\r\n * Runs CSS transition.\r\n */ class $c246d27966689419$var$CSSAnimation {\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */ constructor(props){\n var _props$prop;\n this.props = props;\n const { target: target, onComplete: onComplete, transform: transform, onFinish: onFinish = ()=>{}, duration: duration = 333, easing: easing = $c246d27966689419$var$DEFAULT_EASING } = props;\n this.onFinish = onFinish; // support only transform and opacity\n const prop = transform ? 'transform' : 'opacity';\n const propValue = (_props$prop = props[prop]) !== null && _props$prop !== void 0 ? _props$prop : '';\n /** @private */ this._target = target;\n /** @private */ this._onComplete = onComplete;\n /** @private */ this._finished = false;\n /** @private */ this._onTransitionEnd = this._onTransitionEnd.bind(this); // Using timeout hack to make sure that animation\n // starts even if the animated property was changed recently,\n // otherwise transitionend might not fire or transition won't start.\n // https://drafts.csswg.org/css-transitions/#starting\n //\n // ¯\\_(ツ)_/¯\n /** @private */ this._helperTimeout = setTimeout(()=>{\n $c246d27966689419$var$setTransitionStyle(target, prop, duration, easing);\n this._helperTimeout = setTimeout(()=>{\n target.addEventListener('transitionend', this._onTransitionEnd, false);\n target.addEventListener('transitioncancel', this._onTransitionEnd, false); // Safari occasionally does not emit transitionend event\n // if element property was modified during the transition,\n // which may be caused by resize or third party component,\n // using timeout as a safety fallback\n this._helperTimeout = setTimeout(()=>{\n this._finalizeAnimation();\n }, duration + 500);\n target.style[prop] = propValue;\n }, 30); // Do not reduce this number\n }, 0);\n }\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */ _onTransitionEnd(e) {\n if (e.target === this._target) this._finalizeAnimation();\n }\n /**\r\n * @private\r\n */ _finalizeAnimation() {\n if (!this._finished) {\n this._finished = true;\n this.onFinish();\n if (this._onComplete) this._onComplete();\n }\n }\n destroy() {\n if (this._helperTimeout) clearTimeout(this._helperTimeout);\n $c246d27966689419$var$removeTransitionStyle(this._target);\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\n if (!this._finished) this._finalizeAnimation();\n }\n}\nconst $c246d27966689419$var$DEFAULT_NATURAL_FREQUENCY = 12;\nconst $c246d27966689419$var$DEFAULT_DAMPING_RATIO = 0.75;\n/**\r\n * Spring easing helper\r\n */ class $c246d27966689419$var$SpringEaser {\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */ constructor(initialVelocity, dampingRatio, naturalFrequency){\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\n // https://en.wikipedia.org/wiki/Damping_ratio\n this._dampingRatio = dampingRatio || $c246d27966689419$var$DEFAULT_DAMPING_RATIO; // https://en.wikipedia.org/wiki/Natural_frequency\n this._naturalFrequency = naturalFrequency || $c246d27966689419$var$DEFAULT_NATURAL_FREQUENCY;\n this._dampedFrequency = this._naturalFrequency;\n if (this._dampingRatio < 1) this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\n }\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */ easeFrame(deltaPosition, deltaTime) {\n // Inspired by Apple Webkit and Android spring function implementation\n // https://en.wikipedia.org/wiki/Oscillation\n // https://en.wikipedia.org/wiki/Damping_ratio\n // we ignore mass (assume that it's 1kg)\n let displacement = 0;\n let coeff;\n deltaTime /= 1000;\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\n if (this._dampingRatio === 1) {\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\n this.velocity = displacement * -this._naturalFrequency + coeff * naturalDumpingPow;\n } else if (this._dampingRatio < 1) {\n coeff = 1 / this._dampedFrequency * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\n displacement = naturalDumpingPow * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\n this.velocity = displacement * -this._naturalFrequency * this._dampingRatio + naturalDumpingPow * (-this._dampedFrequency * deltaPosition * dumpedFSin + this._dampedFrequency * coeff * dumpedFCos);\n } // Overdamped (>1) damping ratio is not supported\n return displacement;\n }\n}\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ /**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */ /** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */ class $c246d27966689419$var$SpringAnimation {\n /**\r\n * @param {SpringAnimationProps} props\r\n */ constructor(props){\n this.props = props;\n this._raf = 0;\n const { start: start, end: end, velocity: velocity, onUpdate: onUpdate, onComplete: onComplete, onFinish: onFinish = ()=>{}, dampingRatio: dampingRatio, naturalFrequency: naturalFrequency } = props;\n this.onFinish = onFinish;\n const easer = new $c246d27966689419$var$SpringEaser(velocity, dampingRatio, naturalFrequency);\n let prevTime = Date.now();\n let deltaPosition = start - end;\n const animationLoop = ()=>{\n if (this._raf) {\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime); // Stop the animation if velocity is low and position is close to end\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\n // Finalize the animation\n onUpdate(end);\n if (onComplete) onComplete();\n this.onFinish();\n } else {\n prevTime = Date.now();\n onUpdate(deltaPosition + end);\n this._raf = requestAnimationFrame(animationLoop);\n }\n }\n };\n this._raf = requestAnimationFrame(animationLoop);\n }\n destroy() {\n if (this._raf >= 0) cancelAnimationFrame(this._raf);\n this._raf = 0;\n }\n}\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */ /** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */ /** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */ /** @typedef {SpringAnimation | CSSAnimation} Animation */ /** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */ /**\r\n * Manages animations\r\n */ class $c246d27966689419$var$Animations {\n constructor(){\n /** @type {Animation[]} */ this.activeAnimations = [];\n }\n /**\r\n * @param {SpringAnimationProps} props\r\n */ startSpring(props) {\n this._start(props, true);\n }\n /**\r\n * @param {CssAnimationProps} props\r\n */ startTransition(props) {\n this._start(props);\n }\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */ _start(props, isSpring) {\n const animation = isSpring ? new $c246d27966689419$var$SpringAnimation(/** @type SpringAnimationProps */ props) : new $c246d27966689419$var$CSSAnimation(/** @type CssAnimationProps */ props);\n this.activeAnimations.push(animation);\n animation.onFinish = ()=>this.stop(animation);\n return animation;\n }\n /**\r\n * @param {Animation} animation\r\n */ stop(animation) {\n animation.destroy();\n const index = this.activeAnimations.indexOf(animation);\n if (index > -1) this.activeAnimations.splice(index, 1);\n }\n stopAll() {\n // _stopAllAnimations\n this.activeAnimations.forEach((animation)=>{\n animation.destroy();\n });\n this.activeAnimations = [];\n }\n /**\r\n * Stop all pan or zoom transitions\r\n */ stopAllPan() {\n this.activeAnimations = this.activeAnimations.filter((animation)=>{\n if (animation.props.isPan) {\n animation.destroy();\n return false;\n }\n return true;\n });\n }\n stopMainScroll() {\n this.activeAnimations = this.activeAnimations.filter((animation)=>{\n if (animation.props.isMainScroll) {\n animation.destroy();\n return false;\n }\n return true;\n });\n }\n /**\r\n * Returns true if main scroll transition is running\r\n */ // isMainScrollRunning() {\n // return this.activeAnimations.some((animation) => {\n // return animation.props.isMainScroll;\n // });\n // }\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */ isPanRunning() {\n return this.activeAnimations.some((animation)=>{\n return animation.props.isPan;\n });\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */ class $c246d27966689419$var$ScrollWheel {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n pswp.events.add(pswp.element, 'wheel', /** @type EventListener */ this._onWheel.bind(this));\n }\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */ _onWheel(e) {\n e.preventDefault();\n const { currSlide: currSlide } = this.pswp;\n let { deltaX: deltaX, deltaY: deltaY } = e;\n if (!currSlide) return;\n if (this.pswp.dispatch('wheel', {\n originalEvent: e\n }).defaultPrevented) return;\n if (e.ctrlKey || this.pswp.options.wheelToZoom) // zoom\n {\n if (currSlide.isZoomable()) {\n let zoomFactor = -deltaY;\n if (e.deltaMode === 1) zoomFactor *= 0.05;\n else zoomFactor *= e.deltaMode ? 1 : 0.002;\n zoomFactor = 2 ** zoomFactor;\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\n currSlide.zoomTo(destZoomLevel, {\n x: e.clientX,\n y: e.clientY\n });\n }\n } else // pan\n if (currSlide.isPannable()) {\n if (e.deltaMode === 1) {\n // 18 - average line height\n deltaX *= 18;\n deltaY *= 18;\n }\n currSlide.panTo(currSlide.pan.x - deltaX, currSlide.pan.y - deltaY);\n }\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */ /**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */ /**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */ /** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */ /** @typedef {string | UIElementMarkupProps} UIElementMarkup */ /**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */ function $c246d27966689419$var$addElementHTML(htmlData) {\n if (typeof htmlData === 'string') // Allow developers to provide full svg,\n // For example:\n // \n // \n // \n // \n // Can also be any HTML string.\n return htmlData;\n if (!htmlData || !htmlData.isCustomSVG) return '';\n const svgData = htmlData;\n let out = ''; // replace all %d with size\n out = out.split('%d').join(/** @type {string} */ svgData.size || 32); // Icons may contain outline/shadow,\n // to make it we \"clone\" base icon shape and add border to it.\n // Icon itself and border are styled via CSS.\n //\n // Property shadowID defines ID of element that should be cloned.\n if (svgData.outlineID) out += '';\n out += svgData.inner;\n out += '';\n return out;\n}\nclass $c246d27966689419$var$UIElement {\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */ constructor(pswp, data){\n var _container;\n const name = data.name || data.className;\n let elementHTML = data.html; // @ts-expect-error lookup only by `data.name` maybe?\n if (pswp.options[name] === false) // exit if element is disabled from options\n return;\n // Allow to override SVG icons from options\n // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'SVG'] === 'string') // arrowPrevSVG\n // arrowNextSVG\n // closeSVG\n // zoomSVG\n // @ts-expect-error lookup only by `data.name` maybe?\n elementHTML = pswp.options[name + 'SVG'];\n pswp.dispatch('uiElementCreate', {\n data: data\n });\n let className = '';\n if (data.isButton) {\n className += 'pswp__button ';\n className += data.className || `pswp__button--${data.name}`;\n } else className += data.className || `pswp__${data.name}`;\n let tagName = data.isButton ? data.tagName || 'button' : data.tagName || 'div';\n tagName = /** @type {keyof HTMLElementTagNameMap} */ tagName.toLowerCase();\n /** @type {HTMLElement} */ const element = $c246d27966689419$var$createElement(className, tagName);\n if (data.isButton) {\n if (tagName === 'button') /** @type {HTMLButtonElement} */ element.type = 'button';\n let { title: title } = data;\n const { ariaLabel: ariaLabel } = data; // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'Title'] === 'string') // @ts-expect-error lookup only by `data.name` maybe?\n title = pswp.options[name + 'Title'];\n if (title) element.title = title;\n const ariaText = ariaLabel || title;\n if (ariaText) element.setAttribute('aria-label', ariaText);\n }\n element.innerHTML = $c246d27966689419$var$addElementHTML(elementHTML);\n if (data.onInit) data.onInit(element, pswp);\n if (data.onClick) element.onclick = (e)=>{\n if (typeof data.onClick === 'string') // @ts-ignore\n pswp[data.onClick]();\n else if (typeof data.onClick === 'function') data.onClick(e, element, pswp);\n };\n // Top bar is default position\n const appendTo = data.appendTo || 'bar';\n /** @type {HTMLElement | undefined} root element by default */ let container = pswp.element;\n if (appendTo === 'bar') {\n if (!pswp.topBar) pswp.topBar = $c246d27966689419$var$createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\n container = pswp.topBar;\n } else {\n // element outside of top bar gets a secondary class\n // that makes element fade out on close\n element.classList.add('pswp__hide-on-close');\n if (appendTo === 'wrapper') container = pswp.scrollWrap;\n }\n (_container = container) === null || _container === void 0 || _container.appendChild(pswp.applyFilters('uiElement', element, data));\n }\n}\n/*\r\n Backward and forward arrow buttons\r\n */ /** @typedef {import('./ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */ function $c246d27966689419$var$initArrowButton(element, pswp, isNextButton) {\n element.classList.add('pswp__button--arrow'); // TODO: this should point to a unique id for this instance\n element.setAttribute('aria-controls', 'pswp__items');\n pswp.on('change', ()=>{\n if (!pswp.options.loop) {\n if (isNextButton) /** @type {HTMLButtonElement} */ element.disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\n else /** @type {HTMLButtonElement} */ element.disabled = !(pswp.currIndex > 0);\n }\n });\n}\n/** @type {UIElementData} */ const $c246d27966689419$var$arrowPrev = {\n name: 'arrowPrev',\n className: 'pswp__button--arrow--prev',\n title: 'Previous',\n order: 10,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'prev',\n onInit: $c246d27966689419$var$initArrowButton\n};\n/** @type {UIElementData} */ const $c246d27966689419$var$arrowNext = {\n name: 'arrowNext',\n className: 'pswp__button--arrow--next',\n title: 'Next',\n order: 11,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'next',\n onInit: (el, pswp)=>{\n $c246d27966689419$var$initArrowButton(el, pswp, true);\n }\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $c246d27966689419$var$closeButton = {\n name: 'close',\n title: 'Close',\n order: 20,\n isButton: true,\n html: {\n isCustomSVG: true,\n inner: '',\n outlineID: 'pswp__icn-close'\n },\n onClick: 'close'\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $c246d27966689419$var$zoomButton = {\n name: 'zoom',\n title: 'Zoom',\n order: 10,\n isButton: true,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-zoom'\n },\n onClick: 'toggleZoom'\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $c246d27966689419$var$loadingIndicator = {\n name: 'preloader',\n appendTo: 'bar',\n order: 7,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-loading'\n },\n onInit: (indicatorElement, pswp)=>{\n /** @type {boolean | undefined} */ let isVisible;\n /** @type {NodeJS.Timeout | null} */ let delayTimeout = null;\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */ const toggleIndicatorClass = (className, add)=>{\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\n };\n /**\r\n * @param {boolean} visible\r\n */ const setIndicatorVisibility = (visible)=>{\n if (isVisible !== visible) {\n isVisible = visible;\n toggleIndicatorClass('active', visible);\n }\n };\n const updatePreloaderVisibility = ()=>{\n var _pswp$currSlide;\n if (!((_pswp$currSlide = pswp.currSlide) !== null && _pswp$currSlide !== void 0 && _pswp$currSlide.content.isLoading())) {\n setIndicatorVisibility(false);\n if (delayTimeout) {\n clearTimeout(delayTimeout);\n delayTimeout = null;\n }\n return;\n }\n if (!delayTimeout) // display loading indicator with delay\n delayTimeout = setTimeout(()=>{\n var _pswp$currSlide2;\n setIndicatorVisibility(Boolean((_pswp$currSlide2 = pswp.currSlide) === null || _pswp$currSlide2 === void 0 ? void 0 : _pswp$currSlide2.content.isLoading()));\n delayTimeout = null;\n }, pswp.options.preloaderDelay);\n };\n pswp.on('change', updatePreloaderVisibility);\n pswp.on('loadComplete', (e)=>{\n if (pswp.currSlide === e.slide) updatePreloaderVisibility();\n }); // expose the method\n if (pswp.ui) pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\n }\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $c246d27966689419$var$counterIndicator = {\n name: 'counter',\n order: 5,\n onInit: (counterElement, pswp)=>{\n pswp.on('change', ()=>{\n counterElement.innerText = pswp.currIndex + 1 + pswp.options.indexIndicatorSep + pswp.getNumItems();\n });\n }\n};\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./ui-element.js').UIElementData} UIElementData */ /**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */ function $c246d27966689419$var$setZoomedIn(el, isZoomedIn) {\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\n}\nclass $c246d27966689419$var$UI {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.isRegistered = false;\n /** @type {UIElementData[]} */ this.uiElementsData = [];\n /** @type {(UIElement | UIElementData)[]} */ this.items = [];\n /** @type {() => void} */ this.updatePreloaderVisibility = ()=>{};\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */ this._lastUpdatedZoomLevel = undefined;\n }\n init() {\n const { pswp: pswp } = this;\n this.isRegistered = false;\n this.uiElementsData = [\n $c246d27966689419$var$closeButton,\n $c246d27966689419$var$arrowPrev,\n $c246d27966689419$var$arrowNext,\n $c246d27966689419$var$zoomButton,\n $c246d27966689419$var$loadingIndicator,\n $c246d27966689419$var$counterIndicator\n ];\n pswp.dispatch('uiRegister'); // sort by order\n this.uiElementsData.sort((a, b)=>{\n // default order is 0\n return (a.order || 0) - (b.order || 0);\n });\n this.items = [];\n this.isRegistered = true;\n this.uiElementsData.forEach((uiElementData)=>{\n this.registerElement(uiElementData);\n });\n pswp.on('change', ()=>{\n var _pswp$element;\n (_pswp$element = pswp.element) === null || _pswp$element === void 0 || _pswp$element.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\n });\n pswp.on('zoomPanUpdate', ()=>this._onZoomPanUpdate());\n }\n /**\r\n * @param {UIElementData} elementData\r\n */ registerElement(elementData) {\n if (this.isRegistered) this.items.push(new $c246d27966689419$var$UIElement(this.pswp, elementData));\n else this.uiElementsData.push(elementData);\n }\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */ _onZoomPanUpdate() {\n const { template: template, currSlide: currSlide, options: options } = this.pswp;\n if (this.pswp.opener.isClosing || !template || !currSlide) return;\n let { currZoomLevel: currZoomLevel } = currSlide; // if not open yet - check against initial zoom level\n if (!this.pswp.opener.isOpen) currZoomLevel = currSlide.zoomLevels.initial;\n if (currZoomLevel === this._lastUpdatedZoomLevel) return;\n this._lastUpdatedZoomLevel = currZoomLevel;\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary; // Initial and secondary zoom levels are almost equal\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\n // disable zoom\n $c246d27966689419$var$setZoomedIn(template, false);\n template.classList.remove('pswp--zoom-allowed');\n return;\n }\n template.classList.add('pswp--zoom-allowed');\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\n $c246d27966689419$var$setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\n if (options.imageClickAction === 'zoom' || options.imageClickAction === 'zoom-or-close') template.classList.add('pswp--click-to-zoom');\n }\n}\n/** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */ /**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */ function $c246d27966689419$var$getBoundsByElement(el) {\n const thumbAreaRect = el.getBoundingClientRect();\n return {\n x: thumbAreaRect.left,\n y: thumbAreaRect.top,\n w: thumbAreaRect.width\n };\n}\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */ function $c246d27966689419$var$getCroppedBoundsByElement(el, imageWidth, imageHeight) {\n const thumbAreaRect = el.getBoundingClientRect(); // fill image into the area\n // (do they same as object-fit:cover does to retrieve coordinates)\n const hRatio = thumbAreaRect.width / imageWidth;\n const vRatio = thumbAreaRect.height / imageHeight;\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */ const bounds = {\n x: thumbAreaRect.left + offsetX,\n y: thumbAreaRect.top + offsetY,\n w: imageWidth * fillZoomLevel\n }; // Coordinates of inner crop area\n // relative to the image\n bounds.innerRect = {\n w: thumbAreaRect.width,\n h: thumbAreaRect.height,\n x: offsetX,\n y: offsetY\n };\n return bounds;\n}\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */ function $c246d27966689419$var$getThumbBounds(index, itemData, instance) {\n // legacy event, before filters were introduced\n const event = instance.dispatch('thumbBounds', {\n index: index,\n itemData: itemData,\n instance: instance\n }); // @ts-expect-error\n if (event.thumbBounds) // @ts-expect-error\n return event.thumbBounds;\n const { element: element } = itemData;\n /** @type {Bounds | undefined} */ let thumbBounds;\n /** @type {HTMLElement | null | undefined} */ let thumbnail;\n if (element && instance.options.thumbSelector !== false) {\n const thumbSelector = instance.options.thumbSelector || 'img';\n thumbnail = element.matches(thumbSelector) ? element : /** @type {HTMLElement | null} */ element.querySelector(thumbSelector);\n }\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\n if (thumbnail) {\n if (!itemData.thumbCropped) thumbBounds = $c246d27966689419$var$getBoundsByElement(thumbnail);\n else thumbBounds = $c246d27966689419$var$getCroppedBoundsByElement(thumbnail, itemData.width || itemData.w || 0, itemData.height || itemData.h || 0);\n }\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\n}\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../slide/content.js').default} ContentDefault */ /** @typedef {import('../slide/slide.js').default} Slide */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ /** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ /**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */ /** @typedef {{ x?: number; y?: number }} Point */ /**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */ /**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */ /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */ /**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */ class $c246d27966689419$var$PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */ constructor(type, details){\n this.type = type;\n this.defaultPrevented = false;\n if (details) Object.assign(this, details);\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */ class $c246d27966689419$var$Eventable {\n constructor(){\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */ this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */ this._filters = {};\n /** @type {PhotoSwipe | undefined} */ this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */ this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */ addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n if (!this._filters[name]) this._filters[name] = [];\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn: fn,\n priority: priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2)=>f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */ removeFilter(name, fn) {\n if (this._filters[name]) // @ts-expect-error\n this._filters[name] = this._filters[name].filter((filter)=>filter.fn !== fn);\n if (this.pswp) this.pswp.removeFilter(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */ applyFilters(name, ...args) {\n var _this$_filters$name3;\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach((filter)=>{\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n if (!this._listeners[name]) this._listeners[name] = [];\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ off(name, fn) {\n var _this$pswp3;\n if (this._listeners[name]) // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter((listener)=>fn !== listener);\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */ dispatch(name, details) {\n var _this$_listeners$name2;\n if (this.pswp) return this.pswp.dispatch(name, details);\n const event = /** @type {AugmentedEvent} */ new $c246d27966689419$var$PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach((listener)=>{\n listener.call(this, event);\n });\n return event;\n }\n}\nclass $c246d27966689419$var$Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */ constructor(imageSrc, container){\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */ this.element = $c246d27966689419$var$createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n $c246d27966689419$var$setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = $c246d27966689419$var$toTransformString(0, 0, width / 250);\n } else $c246d27966689419$var$setWidthHeight(this.element, width, height);\n }\n destroy() {\n var _this$element;\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) this.element.remove();\n this.element = null;\n }\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../util/util.js').LoadState} LoadState */ class $c246d27966689419$var$Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */ constructor(itemData, instance, index){\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {Placeholder | undefined} */ this.placeholder = undefined;\n /** @type {Slide | undefined} */ this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */ this.state = $c246d27966689419$var$LOAD_STATE.IDLE;\n if (this.data.type) this.type = this.data.type;\n else if (this.data.src) this.type = 'image';\n else this.type = 'html';\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) // With delay, as image might be loaded, but not rendered\n setTimeout(()=>{\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */ load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new $c246d27966689419$var$Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) this.slide.container.prepend(placeholderEl);\n }\n }\n if (this.element && !reload) return;\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n if (this.isImageContent()) {\n this.element = $c246d27966689419$var$createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) this.loadImage(isLazy);\n } else {\n this.element = $c246d27966689419$var$createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n if (reload && this.slide) this.slide.updateContentSize(true);\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */ loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n const imageElement = /** @type HTMLImageElement */ this.element;\n this.updateSrcsetSizes();\n if (this.data.srcset) imageElement.srcset = this.data.srcset;\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = $c246d27966689419$var$LOAD_STATE.LOADING;\n if (imageElement.complete) this.onLoaded();\n else {\n imageElement.onload = ()=>{\n this.onLoaded();\n };\n imageElement.onerror = ()=>{\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */ setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */ onLoaded() {\n this.state = $c246d27966689419$var$LOAD_STATE.LOADED;\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n if (this.state === $c246d27966689419$var$LOAD_STATE.LOADED || this.state === $c246d27966689419$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n }\n /**\r\n * Content load error handler\r\n */ onError() {\n this.state = $c246d27966689419$var$LOAD_STATE.ERROR;\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */ isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === $c246d27966689419$var$LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */ isError() {\n return this.state === $c246d27966689419$var$LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */ isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.placeholder) this.placeholder.setDisplayedSize(width, height);\n if (this.instance.dispatch('contentResize', {\n content: this,\n width: width,\n height: height\n }).defaultPrevented) return;\n $c246d27966689419$var$setWidthHeight(this.element, width, height);\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n if (isInitialSizeUpdate) this.loadImage(false);\n else this.updateSrcsetSizes();\n if (this.slide) this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width: width,\n height: height,\n content: this\n });\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */ isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== $c246d27966689419$var$LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */ updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) return;\n const image = /** @type HTMLImageElement */ this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */ usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */ lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) return;\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */ keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */ destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) return;\n this.remove();\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */ displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n let errorMsgEl = $c246d27966689419$var$createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl = /** @type {HTMLDivElement} */ this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = $c246d27966689419$var$createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */ append() {\n if (this.isAttached || !this.element) return;\n this.isAttached = true;\n if (this.state === $c246d27966689419$var$LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) return;\n const supportsDecode = 'decode' in this.element;\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || $c246d27966689419$var$isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */ this.element.decode().catch(()=>{}).finally(()=>{\n this.isDecoding = false;\n this.appendImage();\n });\n } else this.appendImage();\n } else if (this.slide && !this.element.parentNode) this.slide.container.appendChild(this.element);\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */ activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) return;\n if (this.isImageContent() && this.isDecoding && !$c246d27966689419$var$isSafari()) // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n else if (this.isError()) this.load(false, true); // try to reload\n if (this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n /**\r\n * Deactivate the content\r\n */ deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n if (this.slide && this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * Remove the content from DOM\r\n */ remove() {\n this.isAttached = false;\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) return;\n if (this.element && this.element.parentNode) this.element.remove();\n if (this.placeholder && this.placeholder.element) this.placeholder.element.remove();\n }\n /**\r\n * Append the image content to slide container\r\n */ appendImage() {\n if (!this.isAttached) return;\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) return;\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) this.slide.container.appendChild(this.element);\n if (this.state === $c246d27966689419$var$LOAD_STATE.LOADED || this.state === $c246d27966689419$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n}\n/** @typedef {import('./content.js').default} Content */ /** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ const $c246d27966689419$var$MIN_SLIDES_TO_CACHE = 5;\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ function $c246d27966689419$var$lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */ let zoomLevel;\n const { options: options } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new $c246d27966689419$var$ZoomLevel(options, itemData, -1);\n let viewportSize;\n if (instance.pswp) viewportSize = instance.pswp.viewportSize;\n else viewportSize = $c246d27966689419$var$getViewportSize(options, instance);\n const panAreaSize = $c246d27966689419$var$getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n content.lazyLoad();\n if (zoomLevel) content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */ function $c246d27966689419$var$lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n if (instance.dispatch('lazyLoadSlide', {\n index: index,\n itemData: itemData\n }).defaultPrevented) return;\n return $c246d27966689419$var$lazyLoadData(itemData, instance, index);\n}\nclass $c246d27966689419$var$ContentLoader {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp; // Total amount of cached images\n this.limit = Math.max(pswp.options.preload[0] + pswp.options.preload[1] + 1, $c246d27966689419$var$MIN_SLIDES_TO_CACHE);\n /** @type {Content[]} */ this._cachedItems = [];\n }\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */ updateLazy(diff) {\n const { pswp: pswp } = this;\n if (pswp.dispatch('lazyLoad').defaultPrevented) return;\n const { preload: preload } = pswp.options;\n const isForward = diff === undefined ? true : diff >= 0;\n let i; // preload[1] - num items to preload in forward direction\n for(i = 0; i <= preload[1]; i++)this.loadSlideByIndex(pswp.currIndex + (isForward ? i : -i));\n // preload[0] - num items to preload in backward direction\n for(i = 1; i <= preload[0]; i++)this.loadSlideByIndex(pswp.currIndex + (isForward ? -i : i));\n }\n /**\r\n * @param {number} initialIndex\r\n */ loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex); // try to get cached content\n let content = this.getContentByIndex(index);\n if (!content) {\n // no cached content, so try to load from scratch:\n content = $c246d27966689419$var$lazyLoadSlide(index, this.pswp); // if content can be loaded, add it to cache:\n if (content) this.addToCache(content);\n }\n }\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */ getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n } // assign slide to content\n content.setSlide(slide);\n return content;\n }\n /**\r\n * @param {Content} content\r\n */ addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n this._cachedItems.push(content);\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex((item)=>{\n return !item.isAttached && !item.hasSlide;\n });\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n removedItem.destroy();\n }\n }\n }\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */ removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex((item)=>item.index === index);\n if (indexToRemove !== -1) this._cachedItems.splice(indexToRemove, 1);\n }\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */ getContentByIndex(index) {\n return this._cachedItems.find((content)=>content.index === index);\n }\n destroy() {\n this._cachedItems.forEach((content)=>content.destroy());\n this._cachedItems = [];\n }\n}\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */ /** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */ /**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */ class $c246d27966689419$var$PhotoSwipeBase extends $c246d27966689419$var$Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */ getNumItems() {\n var _this$options;\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n if (dataSource && 'length' in dataSource) // may be an array or just object with length property\n numItems = dataSource.length;\n else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n if (dataSource.items) numItems = dataSource.items.length;\n } // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource: dataSource,\n numItems: numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */ createContentFromData(slideData, index) {\n return new $c246d27966689419$var$Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */ getItemData(index) {\n var _this$options2;\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */ let dataSourceItem = {};\n if (Array.isArray(dataSource)) // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n dataSourceItem = dataSource.items[index];\n }\n let itemData = dataSourceItem;\n if (itemData instanceof Element) itemData = this._domElementToItemData(itemData);\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index: index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */ _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) return $c246d27966689419$var$getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n return [\n galleryElement\n ];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */ _domElementToItemData(element) {\n /** @type {SlideData} */ const itemData = {\n element: element\n };\n const linkEl = /** @type {HTMLAnchorElement} */ element.tagName === 'A' ? element : element.querySelector('a');\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n if (linkEl.dataset.pswpSrcset) itemData.srcset = linkEl.dataset.pswpSrcset;\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n if (linkEl.dataset.pswpType) itemData.type = linkEl.dataset.pswpType;\n const thumbnailEl = element.querySelector('img');\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) itemData.thumbCropped = true;\n }\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ lazyLoadData(itemData, index) {\n return $c246d27966689419$var$lazyLoadData(itemData, this, index);\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */ /** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */ // some browsers do not paint\n// elements which opacity is set to 0,\n// since we need to pre-render elements for the animation -\n// we set it to the minimum amount\nconst $c246d27966689419$var$MIN_OPACITY = 0.003;\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */ class $c246d27966689419$var$Opener {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.isClosed = true;\n this.isOpen = false;\n this.isClosing = false;\n this.isOpening = false;\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */ this._duration = undefined;\n /** @private */ this._useAnimation = false;\n /** @private */ this._croppedZoom = false;\n /** @private */ this._animateRootOpacity = false;\n /** @private */ this._animateBgOpacity = false;\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */ this._placeholder = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */ this._opacityElement = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */ this._cropContainer1 = undefined;\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */ this._cropContainer2 = undefined;\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */ this._thumbBounds = undefined;\n this._prepareOpen = this._prepareOpen.bind(this); // Override initial zoom and pan position\n pswp.on('firstZoomPan', this._prepareOpen);\n }\n open() {\n this._prepareOpen();\n this._start();\n }\n close() {\n if (this.isClosed || this.isClosing || this.isOpening) // if we close during opening animation\n // for now do nothing,\n // browsers aren't good at changing the direction of the CSS transition\n return;\n const slide = this.pswp.currSlide;\n this.isOpen = false;\n this.isOpening = false;\n this.isClosing = true;\n this._duration = this.pswp.options.hideAnimationDuration;\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) this._duration = 0;\n this._applyStartProps();\n setTimeout(()=>{\n this._start();\n }, this._croppedZoom ? 30 : 0);\n }\n /** @private */ _prepareOpen() {\n this.pswp.off('firstZoomPan', this._prepareOpen);\n if (!this.isOpening) {\n const slide = this.pswp.currSlide;\n this.isOpening = true;\n this.isClosing = false;\n this._duration = this.pswp.options.showAnimationDuration;\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) this._duration = 0;\n this._applyStartProps();\n }\n }\n /** @private */ _applyStartProps() {\n const { pswp: pswp } = this;\n const slide = this.pswp.currSlide;\n const { options: options } = pswp;\n if (options.showHideAnimationType === 'fade') {\n options.showHideOpacity = true;\n this._thumbBounds = undefined;\n } else if (options.showHideAnimationType === 'none') {\n options.showHideOpacity = false;\n this._duration = 0;\n this._thumbBounds = undefined;\n } else if (this.isOpening && pswp._initialThumbBounds) // Use initial bounds if defined\n this._thumbBounds = pswp._initialThumbBounds;\n else this._thumbBounds = this.pswp.getThumbBounds();\n this._placeholder = slide === null || slide === void 0 ? void 0 : slide.getPlaceholderElement();\n pswp.animations.stopAll(); // Discard animations when duration is less than 50ms\n this._useAnimation = Boolean(this._duration && this._duration > 50);\n this._animateZoom = Boolean(this._thumbBounds) && (slide === null || slide === void 0 ? void 0 : slide.content.usePlaceholder()) && (!this.isClosing || !pswp.mainScroll.isShifted());\n if (!this._animateZoom) {\n this._animateRootOpacity = true;\n if (this.isOpening && slide) {\n slide.zoomAndPanToInitial();\n slide.applyCurrentZoomPan();\n }\n } else {\n var _options$showHideOpac;\n this._animateRootOpacity = (_options$showHideOpac = options.showHideOpacity) !== null && _options$showHideOpac !== void 0 ? _options$showHideOpac : false;\n }\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > $c246d27966689419$var$MIN_OPACITY;\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\n if (!this._useAnimation) {\n this._duration = 0;\n this._animateZoom = false;\n this._animateBgOpacity = false;\n this._animateRootOpacity = true;\n if (this.isOpening) {\n if (pswp.element) pswp.element.style.opacity = String($c246d27966689419$var$MIN_OPACITY);\n pswp.applyBgOpacity(1);\n }\n return;\n }\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\n var _this$pswp$currSlide;\n // Properties are used when animation from cropped thumbnail\n this._croppedZoom = true;\n this._cropContainer1 = this.pswp.container;\n this._cropContainer2 = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.holderElement;\n if (pswp.container) {\n pswp.container.style.overflow = 'hidden';\n pswp.container.style.width = pswp.viewportSize.x + 'px';\n }\n } else this._croppedZoom = false;\n if (this.isOpening) {\n // Apply styles before opening transition\n if (this._animateRootOpacity) {\n if (pswp.element) pswp.element.style.opacity = String($c246d27966689419$var$MIN_OPACITY);\n pswp.applyBgOpacity(1);\n } else {\n if (this._animateBgOpacity && pswp.bg) pswp.bg.style.opacity = String($c246d27966689419$var$MIN_OPACITY);\n if (pswp.element) pswp.element.style.opacity = '1';\n }\n if (this._animateZoom) {\n this._setClosedStateZoomPan();\n if (this._placeholder) {\n // tell browser that we plan to animate the placeholder\n this._placeholder.style.willChange = 'transform'; // hide placeholder to allow hiding of\n // elements that overlap it (such as icons over the thumbnail)\n this._placeholder.style.opacity = String($c246d27966689419$var$MIN_OPACITY);\n }\n }\n } else if (this.isClosing) {\n // hide nearby slides to make sure that\n // they are not painted during the transition\n if (pswp.mainScroll.itemHolders[0]) pswp.mainScroll.itemHolders[0].el.style.display = 'none';\n if (pswp.mainScroll.itemHolders[2]) pswp.mainScroll.itemHolders[2].el.style.display = 'none';\n if (this._croppedZoom) {\n if (pswp.mainScroll.x !== 0) {\n // shift the main scroller to zero position\n pswp.mainScroll.resetPosition();\n pswp.mainScroll.resize();\n }\n }\n }\n }\n /** @private */ _start() {\n if (this.isOpening && this._useAnimation && this._placeholder && this._placeholder.tagName === 'IMG') // To ensure smooth animation\n // we wait till the current slide image placeholder is decoded,\n // but no longer than 250ms,\n // and no shorter than 50ms\n // (just using requestanimationframe is not enough in Firefox,\n // for some reason)\n new Promise((resolve)=>{\n let decoded = false;\n let isDelaying = true;\n $c246d27966689419$var$decodeImage(/** @type {HTMLImageElement} */ this._placeholder).finally(()=>{\n decoded = true;\n if (!isDelaying) resolve(true);\n });\n setTimeout(()=>{\n isDelaying = false;\n if (decoded) resolve(true);\n }, 50);\n setTimeout(resolve, 250);\n }).finally(()=>this._initiate());\n else this._initiate();\n }\n /** @private */ _initiate() {\n var _this$pswp$element, _this$pswp$element2;\n (_this$pswp$element = this.pswp.element) === null || _this$pswp$element === void 0 || _this$pswp$element.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\n this.pswp.dispatch(this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'); // legacy event\n this.pswp.dispatch(/** @type {'initialZoomIn' | 'initialZoomOut'} */ 'initialZoom' + (this.isOpening ? 'In' : 'Out'));\n (_this$pswp$element2 = this.pswp.element) === null || _this$pswp$element2 === void 0 || _this$pswp$element2.classList.toggle('pswp--ui-visible', this.isOpening);\n if (this.isOpening) {\n if (this._placeholder) // unhide the placeholder\n this._placeholder.style.opacity = '1';\n this._animateToOpenState();\n } else if (this.isClosing) this._animateToClosedState();\n if (!this._useAnimation) this._onAnimationComplete();\n }\n /** @private */ _onAnimationComplete() {\n const { pswp: pswp } = this;\n this.isOpen = this.isOpening;\n this.isClosed = this.isClosing;\n this.isOpening = false;\n this.isClosing = false;\n pswp.dispatch(this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'); // legacy event\n pswp.dispatch(/** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */ 'initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'));\n if (this.isClosed) pswp.destroy();\n else if (this.isOpen) {\n var _pswp$currSlide;\n if (this._animateZoom && pswp.container) {\n pswp.container.style.overflow = 'visible';\n pswp.container.style.width = '100%';\n }\n (_pswp$currSlide = pswp.currSlide) === null || _pswp$currSlide === void 0 || _pswp$currSlide.applyCurrentZoomPan();\n }\n }\n /** @private */ _animateToOpenState() {\n const { pswp: pswp } = this;\n if (this._animateZoom) {\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\n this._animateTo(this._cropContainer2, 'transform', 'none');\n }\n if (pswp.currSlide) {\n pswp.currSlide.zoomAndPanToInitial();\n this._animateTo(pswp.currSlide.container, 'transform', pswp.currSlide.getCurrentTransform());\n }\n }\n if (this._animateBgOpacity && pswp.bg) this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\n if (this._animateRootOpacity && pswp.element) this._animateTo(pswp.element, 'opacity', '1');\n }\n /** @private */ _animateToClosedState() {\n const { pswp: pswp } = this;\n if (this._animateZoom) this._setClosedStateZoomPan(true);\n // do not animate opacity if it's already at 0\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) this._animateTo(pswp.bg, 'opacity', '0');\n if (this._animateRootOpacity && pswp.element) this._animateTo(pswp.element, 'opacity', '0');\n }\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */ _setClosedStateZoomPan(animate) {\n if (!this._thumbBounds) return;\n const { pswp: pswp } = this;\n const { innerRect: innerRect } = this._thumbBounds;\n const { currSlide: currSlide, viewportSize: viewportSize } = pswp;\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\n const containerTwoPanX = viewportSize.x - innerRect.w;\n const containerTwoPanY = viewportSize.y - innerRect.h;\n if (animate) {\n this._animateTo(this._cropContainer1, 'transform', $c246d27966689419$var$toTransformString(containerOnePanX, containerOnePanY));\n this._animateTo(this._cropContainer2, 'transform', $c246d27966689419$var$toTransformString(containerTwoPanX, containerTwoPanY));\n } else {\n $c246d27966689419$var$setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\n $c246d27966689419$var$setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\n }\n }\n if (currSlide) {\n $c246d27966689419$var$equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\n if (animate) this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\n else currSlide.applyCurrentZoomPan();\n }\n }\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */ _animateTo(target, prop, propValue) {\n if (!this._duration) {\n target.style[prop] = propValue;\n return;\n }\n const { animations: animations } = this.pswp;\n /** @type {AnimationProps} */ const animProps = {\n duration: this._duration,\n easing: this.pswp.options.easing,\n onComplete: ()=>{\n if (!animations.activeAnimations.length) this._onAnimationComplete();\n },\n target: target\n };\n animProps[prop] = propValue;\n animations.startTransition(animProps);\n }\n}\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */ /** @typedef {import('./slide/slide.js').SlideData} SlideData */ /** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */ /** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */ /** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ /** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ /** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */ /** @typedef {{ x: number; y: number; id?: string | number }} Point */ /** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */ /** @typedef {SlideData[]} DataSourceArray */ /** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */ /** @typedef {DataSourceArray | DataSourceObject} DataSource */ /** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */ /** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */ /** @typedef {Type | { default: Type }} PhotoSwipeModule */ /** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */ /**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */ /** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */ /**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */ /** @type {PreparedPhotoSwipeOptions} */ const $c246d27966689419$var$defaultOptions = {\n allowPanToNext: true,\n spacing: 0.1,\n loop: true,\n pinchToClose: true,\n closeOnVerticalDrag: true,\n hideAnimationDuration: 333,\n showAnimationDuration: 333,\n zoomAnimationDuration: 333,\n escKey: true,\n arrowKeys: true,\n trapFocus: true,\n returnFocus: true,\n maxWidthToAnimate: 4000,\n clickToCloseNonZoomable: true,\n imageClickAction: 'zoom-or-close',\n bgClickAction: 'close',\n tapAction: 'toggle-controls',\n doubleTapAction: 'zoom',\n indexIndicatorSep: ' / ',\n preloaderDelay: 2000,\n bgOpacity: 0.8,\n index: 0,\n errorMsg: 'The image cannot be loaded',\n preload: [\n 1,\n 2\n ],\n easing: 'cubic-bezier(.4,0,.22,1)'\n};\n/**\r\n * PhotoSwipe Core\r\n */ class $c246d27966689419$export$2e2bcd8739ae039 extends $c246d27966689419$var$PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */ constructor(options){\n super();\n this.options = this._prepareOptions(options || {});\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */ this.offset = {\n x: 0,\n y: 0\n };\n /**\r\n * @type {Point}\r\n * @private\r\n */ this._prevViewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */ this.viewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * background (backdrop) opacity\r\n */ this.bgOpacity = 1;\n this.currIndex = 0;\n this.potentialIndex = 0;\n this.isOpen = false;\n this.isDestroying = false;\n this.hasMouse = false;\n /**\r\n * @private\r\n * @type {SlideData}\r\n */ this._initialItemData = {};\n /** @type {Bounds | undefined} */ this._initialThumbBounds = undefined;\n /** @type {HTMLDivElement | undefined} */ this.topBar = undefined;\n /** @type {HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {HTMLDivElement | undefined} */ this.template = undefined;\n /** @type {HTMLDivElement | undefined} */ this.container = undefined;\n /** @type {HTMLElement | undefined} */ this.scrollWrap = undefined;\n /** @type {Slide | undefined} */ this.currSlide = undefined;\n this.events = new $c246d27966689419$var$DOMEvents();\n this.animations = new $c246d27966689419$var$Animations();\n this.mainScroll = new $c246d27966689419$var$MainScroll(this);\n this.gestures = new $c246d27966689419$var$Gestures(this);\n this.opener = new $c246d27966689419$var$Opener(this);\n this.keyboard = new $c246d27966689419$var$Keyboard(this);\n this.contentLoader = new $c246d27966689419$var$ContentLoader(this);\n }\n /** @returns {boolean} */ init() {\n if (this.isOpen || this.isDestroying) return false;\n this.isOpen = true;\n this.dispatch('init'); // legacy\n this.dispatch('beforeOpen');\n this._createMainStructure(); // add classes to the root element of PhotoSwipe\n let rootClasses = 'pswp--open';\n if (this.gestures.supportsTouch) rootClasses += ' pswp--touch';\n if (this.options.mainClass) rootClasses += ' ' + this.options.mainClass;\n if (this.element) this.element.className += ' ' + rootClasses;\n this.currIndex = this.options.index || 0;\n this.potentialIndex = this.currIndex;\n this.dispatch('firstUpdate'); // starting index can be modified here\n // initialize scroll wheel handler to block the scroll\n this.scrollWheel = new $c246d27966689419$var$ScrollWheel(this); // sanitize index\n if (Number.isNaN(this.currIndex) || this.currIndex < 0 || this.currIndex >= this.getNumItems()) this.currIndex = 0;\n if (!this.gestures.supportsTouch) // enable mouse features if no touch support detected\n this.mouseDetected();\n // causes forced synchronous layout\n this.updateSize();\n this.offset.y = window.pageYOffset;\n this._initialItemData = this.getItemData(this.currIndex);\n this.dispatch('gettingData', {\n index: this.currIndex,\n data: this._initialItemData,\n slide: undefined\n }); // *Layout* - calculate size and position of elements here\n this._initialThumbBounds = this.getThumbBounds();\n this.dispatch('initialLayout');\n this.on('openingAnimationEnd', ()=>{\n const { itemHolders: itemHolders } = this.mainScroll; // Add content to the previous and next slide\n if (itemHolders[0]) {\n itemHolders[0].el.style.display = 'block';\n this.setContent(itemHolders[0], this.currIndex - 1);\n }\n if (itemHolders[2]) {\n itemHolders[2].el.style.display = 'block';\n this.setContent(itemHolders[2], this.currIndex + 1);\n }\n this.appendHeavy();\n this.contentLoader.updateLazy();\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\n this.dispatch('bindEvents');\n }); // set content for center slide (first time)\n if (this.mainScroll.itemHolders[1]) this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\n this.dispatch('change');\n this.opener.open();\n this.dispatch('afterInit');\n return true;\n }\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */ getLoopedIndex(index) {\n const numSlides = this.getNumItems();\n if (this.options.loop) {\n if (index > numSlides - 1) index -= numSlides;\n if (index < 0) index += numSlides;\n }\n return $c246d27966689419$var$clamp(index, 0, numSlides - 1);\n }\n appendHeavy() {\n this.mainScroll.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide;\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.appendHeavy();\n });\n }\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */ goTo(index) {\n this.mainScroll.moveIndexBy(this.getLoopedIndex(index) - this.potentialIndex);\n }\n /**\r\n * Go to the next slide.\r\n */ next() {\n this.goTo(this.potentialIndex + 1);\n }\n /**\r\n * Go to the previous slide.\r\n */ prev() {\n this.goTo(this.potentialIndex - 1);\n }\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */ zoomTo(...args) {\n var _this$currSlide;\n (_this$currSlide = this.currSlide) === null || _this$currSlide === void 0 || _this$currSlide.zoomTo(...args);\n }\n /**\r\n * @see slide/slide.js toggleZoom\r\n */ toggleZoom() {\n var _this$currSlide2;\n (_this$currSlide2 = this.currSlide) === null || _this$currSlide2 === void 0 || _this$currSlide2.toggleZoom();\n }\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */ close() {\n if (!this.opener.isOpen || this.isDestroying) return;\n this.isDestroying = true;\n this.dispatch('close');\n this.events.removeAll();\n this.opener.close();\n }\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */ destroy() {\n var _this$element;\n if (!this.isDestroying) {\n this.options.showHideAnimationType = 'none';\n this.close();\n return;\n }\n this.dispatch('destroy');\n this._listeners = {};\n if (this.scrollWrap) {\n this.scrollWrap.ontouchmove = null;\n this.scrollWrap.ontouchend = null;\n }\n (_this$element = this.element) === null || _this$element === void 0 || _this$element.remove();\n this.mainScroll.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide2;\n (_itemHolder$slide2 = itemHolder.slide) === null || _itemHolder$slide2 === void 0 || _itemHolder$slide2.destroy();\n });\n this.contentLoader.destroy();\n this.events.removeAll();\n }\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */ refreshSlideContent(slideIndex) {\n this.contentLoader.removeByIndex(slideIndex);\n this.mainScroll.itemHolders.forEach((itemHolder, i)=>{\n var _this$currSlide$index, _this$currSlide3;\n let potentialHolderIndex = ((_this$currSlide$index = (_this$currSlide3 = this.currSlide) === null || _this$currSlide3 === void 0 ? void 0 : _this$currSlide3.index) !== null && _this$currSlide$index !== void 0 ? _this$currSlide$index : 0) - 1 + i;\n if (this.canLoop()) potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\n if (potentialHolderIndex === slideIndex) {\n // set the new slide content\n this.setContent(itemHolder, slideIndex, true); // activate the new slide if it's current\n if (i === 1) {\n var _itemHolder$slide3;\n this.currSlide = itemHolder.slide;\n (_itemHolder$slide3 = itemHolder.slide) === null || _itemHolder$slide3 === void 0 || _itemHolder$slide3.setIsActive(true);\n }\n }\n });\n this.dispatch('change');\n }\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */ setContent(holder, index, force) {\n if (this.canLoop()) index = this.getLoopedIndex(index);\n if (holder.slide) {\n if (holder.slide.index === index && !force) // exit if holder already contains this slide\n // this could be common when just three slides are used\n return;\n // destroy previous slide\n holder.slide.destroy();\n holder.slide = undefined;\n } // exit if no loop and index is out of bounds\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) return;\n const itemData = this.getItemData(index);\n holder.slide = new $c246d27966689419$var$Slide(itemData, index, this); // set current slide\n if (index === this.currIndex) this.currSlide = holder.slide;\n holder.slide.append(holder.el);\n }\n /** @returns {Point} */ getViewportCenterPoint() {\n return {\n x: this.viewportSize.x / 2,\n y: this.viewportSize.y / 2\n };\n }\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */ updateSize(force) {\n // let item;\n // let itemIndex;\n if (this.isDestroying) // exit if PhotoSwipe is closed or closing\n // (to avoid errors, as resize event might be delayed)\n return;\n //const newWidth = this.scrollWrap.clientWidth;\n //const newHeight = this.scrollWrap.clientHeight;\n const newViewportSize = $c246d27966689419$var$getViewportSize(this.options, this);\n if (!force && $c246d27966689419$var$pointsEqual(newViewportSize, this._prevViewportSize)) // Exit if dimensions were not changed\n return;\n //this._prevViewportSize.x = newWidth;\n //this._prevViewportSize.y = newHeight;\n $c246d27966689419$var$equalizePoints(this._prevViewportSize, newViewportSize);\n this.dispatch('beforeResize');\n $c246d27966689419$var$equalizePoints(this.viewportSize, this._prevViewportSize);\n this._updatePageScrollOffset();\n this.dispatch('viewportSize'); // Resize slides only after opener animation is finished\n // and don't re-calculate size on inital size update\n this.mainScroll.resize(this.opener.isOpen);\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) this.mouseDetected();\n this.dispatch('resize');\n }\n /**\r\n * @param {number} opacity\r\n */ applyBgOpacity(opacity) {\n this.bgOpacity = Math.max(opacity, 0);\n if (this.bg) this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\n }\n /**\r\n * Whether mouse is detected\r\n */ mouseDetected() {\n if (!this.hasMouse) {\n var _this$element2;\n this.hasMouse = true;\n (_this$element2 = this.element) === null || _this$element2 === void 0 || _this$element2.classList.add('pswp--has_mouse');\n }\n }\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */ _handlePageResize() {\n this.updateSize(); // In iOS webview, if element size depends on document size,\n // it'll be measured incorrectly in resize event\n //\n // https://bugs.webkit.org/show_bug.cgi?id=170595\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) setTimeout(()=>{\n this.updateSize();\n }, 500);\n }\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */ _updatePageScrollOffset() {\n this.setScrollOffset(0, window.pageYOffset);\n }\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */ setScrollOffset(x, y) {\n this.offset.x = x;\n this.offset.y = y;\n this.dispatch('updateScrollOffset');\n }\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */ _createMainStructure() {\n // root DOM element of PhotoSwipe (.pswp)\n this.element = $c246d27966689419$var$createElement('pswp', 'div');\n this.element.setAttribute('tabindex', '-1');\n this.element.setAttribute('role', 'dialog'); // template is legacy prop\n this.template = this.element; // Background is added as a separate element,\n // as animating opacity is faster than animating rgba()\n this.bg = $c246d27966689419$var$createElement('pswp__bg', 'div', this.element);\n this.scrollWrap = $c246d27966689419$var$createElement('pswp__scroll-wrap', 'section', this.element);\n this.container = $c246d27966689419$var$createElement('pswp__container', 'div', this.scrollWrap); // aria pattern: carousel\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\n this.container.setAttribute('aria-live', 'off');\n this.container.setAttribute('id', 'pswp__items');\n this.mainScroll.appendHolders();\n this.ui = new $c246d27966689419$var$UI(this);\n this.ui.init(); // append to DOM\n (this.options.appendToEl || document.body).appendChild(this.element);\n }\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */ getThumbBounds() {\n return $c246d27966689419$var$getThumbBounds(this.currIndex, this.currSlide ? this.currSlide.data : this._initialItemData, this);\n }\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */ canLoop() {\n return this.options.loop && this.getNumItems() > 2;\n }\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */ _prepareOptions(options) {\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\n options.showHideAnimationType = 'none';\n options.zoomAnimationDuration = 0;\n }\n /** @type {PreparedPhotoSwipeOptions} */ return {\n ...$c246d27966689419$var$defaultOptions,\n ...options\n };\n }\n}\n\n});\n\n})();\n//# sourceMappingURL=photoswipe.esm.2e2aa850.js.map\n","/*!\n * PhotoSwipe 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\nfunction createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n\n if (className) {\n el.className = className;\n }\n\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n\n return el;\n}\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\n\nfunction equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n\n if (p2.id !== undefined) {\n p1.id = p2.id;\n }\n\n return p1;\n}\n/**\r\n * @param {Point} p\r\n */\n\nfunction roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\n\nfunction getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt(x * x + y * y);\n}\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\n\nfunction pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\n\nfunction clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\n\nfunction toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\n\nfunction setTransform(el, x, y, scale) {\n el.style.transform = toTransformString(x, y, scale);\n}\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\n\nfunction setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop ? `${prop} ${duration}ms ${ease || defaultCSSEasing}` : 'none';\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\n\nfunction setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/**\r\n * @param {HTMLElement} el\r\n */\n\nfunction removeTransitionStyle(el) {\n setTransitionStyle(el);\n}\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\n\nfunction decodeImage(img) {\n if ('decode' in img) {\n return img.decode().catch(() => {});\n }\n\n if (img.complete) {\n return Promise.resolve(img);\n }\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img);\n\n img.onerror = reject;\n });\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\n\nconst LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\n\nfunction specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\n\nfunction getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\n\nfunction isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n// Detect passive event listener support\nlet supportsPassive = false;\n/* eslint-disable */\n\ntry {\n /* @ts-ignore */\n window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\n get: () => {\n supportsPassive = true;\n }\n }));\n} catch (e) {}\n/* eslint-enable */\n\n/**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */\n\n\nclass DOMEvents {\n constructor() {\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */\n this._pool = [];\n }\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\n\n\n add(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive);\n }\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\n\n\n remove(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive, true);\n }\n /**\r\n * Removes all bound events\r\n */\n\n\n removeAll() {\n this._pool.forEach(poolItem => {\n this._toggleListener(poolItem.target, poolItem.type, poolItem.listener, poolItem.passive, true, true);\n });\n\n this._pool = [];\n }\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */\n\n\n _toggleListener(target, type, listener, passive, unbind, skipPool) {\n if (!target) {\n return;\n }\n\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\n const types = type.split(' ');\n types.forEach(eType => {\n if (eType) {\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\n // so developer doesn't need to do this manually\n if (!skipPool) {\n if (unbind) {\n // Remove from the events pool\n this._pool = this._pool.filter(poolItem => {\n return poolItem.type !== eType || poolItem.listener !== listener || poolItem.target !== target;\n });\n } else {\n // Add to the events pool\n this._pool.push({\n target,\n type: eType,\n listener,\n passive\n });\n }\n } // most PhotoSwipe events call preventDefault,\n // and we do not need browser to scroll the page\n\n\n const eventOptions = supportsPassive ? {\n passive: passive || false\n } : false;\n target[methodName](eType, listener, eventOptions);\n }\n });\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\nfunction getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\n\nfunction parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\n\nfunction getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - parsePaddingOption('left', options, viewportSize, itemData, index) - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - parsePaddingOption('top', options, viewportSize, itemData, index) - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {Record} Point */\n\n/** @typedef {'x' | 'y'} Axis */\n\n/**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */\n\nclass PanBounds {\n /**\r\n * @param {Slide} slide\r\n */\n constructor(slide) {\n this.slide = slide;\n this.currZoomLevel = 1;\n this.center =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n this.max =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n this.min =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n }\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */\n\n\n update(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n\n if (!this.slide.width) {\n this.reset();\n } else {\n this._updateAxis('x');\n\n this._updateAxis('y');\n\n this.slide.pswp.dispatch('calcBounds', {\n slide: this.slide\n });\n }\n }\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */\n\n\n _updateAxis(axis) {\n const {\n pswp\n } = this.slide;\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\n const paddingProp = axis === 'x' ? 'left' : 'top';\n const padding = parsePaddingOption(paddingProp, pswp.options, pswp.viewportSize, this.slide.data, this.slide.index);\n const panAreaSize = this.slide.panAreaSize[axis]; // Default position of element.\n // By default, it is center of viewport:\n\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding; // maximum pan position\n\n this.max[axis] = elSize > panAreaSize ? Math.round(panAreaSize - elSize) + padding : this.center[axis]; // minimum pan position\n\n this.min[axis] = elSize > panAreaSize ? padding : this.center[axis];\n } // _getZeroBounds\n\n\n reset() {\n this.center.x = 0;\n this.center.y = 0;\n this.max.x = 0;\n this.max.y = 0;\n this.min.x = 0;\n this.min.y = 0;\n }\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */\n\n\n correctPan(axis, panOffset) {\n // checkPanBounds\n return clamp(panOffset, this.max[axis], this.min[axis]);\n }\n\n}\n\nconst MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\n\nclass ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n\n this.panAreaSize = null;\n /** @type { Point | null } */\n\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\n\n\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\n\n\n _parseZoomLevelOption(optionPrefix) {\n const optionName =\n /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */\n optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n } // 3x of \"fit\" state, but not larger than original\n\n\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/**\r\n * Renders and allows to control a single slide\r\n */\n\nclass Slide {\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(data, index, pswp) {\n this.data = data;\n this.index = index;\n this.pswp = pswp;\n this.isActive = index === pswp.currIndex;\n this.currentResolution = 0;\n /** @type {Point} */\n\n this.panAreaSize = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.pan = {\n x: 0,\n y: 0\n };\n this.isFirstSlide = this.isActive && !pswp.opener.isOpen;\n this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp);\n this.pswp.dispatch('gettingData', {\n slide: this,\n data: this.data,\n index\n });\n this.content = this.pswp.contentLoader.getContentBySlide(this);\n this.container = createElement('pswp__zoom-wrap', 'div');\n /** @type {HTMLElement | null} */\n\n this.holderElement = null;\n this.currZoomLevel = 1;\n /** @type {number} */\n\n this.width = this.content.width;\n /** @type {number} */\n\n this.height = this.content.height;\n this.heavyAppended = false;\n this.bounds = new PanBounds(this);\n this.prevDisplayedWidth = -1;\n this.prevDisplayedHeight = -1;\n this.pswp.dispatch('slideInit', {\n slide: this\n });\n }\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */\n\n\n setIsActive(isActive) {\n if (isActive && !this.isActive) {\n // slide just became active\n this.activate();\n } else if (!isActive && this.isActive) {\n // slide just became non-active\n this.deactivate();\n }\n }\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */\n\n\n append(holderElement) {\n this.holderElement = holderElement;\n this.container.style.transformOrigin = '0 0'; // Slide appended to DOM\n\n if (!this.data) {\n return;\n }\n\n this.calculateSize();\n this.load();\n this.updateContentSize();\n this.appendHeavy();\n this.holderElement.appendChild(this.container);\n this.zoomAndPanToInitial();\n this.pswp.dispatch('firstZoomPan', {\n slide: this\n });\n this.applyCurrentZoomPan();\n this.pswp.dispatch('afterSetContent', {\n slide: this\n });\n\n if (this.isActive) {\n this.activate();\n }\n }\n\n load() {\n this.content.load(false);\n this.pswp.dispatch('slideLoad', {\n slide: this\n });\n }\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */\n\n\n appendHeavy() {\n const {\n pswp\n } = this;\n const appendHeavyNearby = true; // todo\n // Avoid appending heavy elements during animations\n\n if (this.heavyAppended || !pswp.opener.isOpen || pswp.mainScroll.isShifted() || !this.isActive && !appendHeavyNearby) {\n return;\n }\n\n if (this.pswp.dispatch('appendHeavy', {\n slide: this\n }).defaultPrevented) {\n return;\n }\n\n this.heavyAppended = true;\n this.content.append();\n this.pswp.dispatch('appendHeavyContent', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */\n\n\n activate() {\n this.isActive = true;\n this.appendHeavy();\n this.content.activate();\n this.pswp.dispatch('slideActivate', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */\n\n\n deactivate() {\n this.isActive = false;\n this.content.deactivate();\n\n if (this.currZoomLevel !== this.zoomLevels.initial) {\n // allow filtering\n this.calculateSize();\n } // reset zoom level\n\n\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n this.pswp.dispatch('slideDeactivate', {\n slide: this\n });\n }\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */\n\n\n destroy() {\n this.content.hasSlide = false;\n this.content.remove();\n this.container.remove();\n this.pswp.dispatch('slideDestroy', {\n slide: this\n });\n }\n\n resize() {\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\n // Keep initial zoom level if it was before the resize,\n // as well as when this slide is not active\n // Reset position and scale to original state\n this.calculateSize();\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n } else {\n // readjust pan position if it's beyond the bounds\n this.calculateSize();\n this.bounds.update(this.currZoomLevel);\n this.panTo(this.pan.x, this.pan.y);\n }\n }\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */\n\n\n updateContentSize(force) {\n // Use initial zoom level\n // if resolution is not defined (user didn't zoom yet)\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\n\n if (!scaleMultiplier) {\n return;\n }\n\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\n\n if (!this.sizeChanged(width, height) && !force) {\n return;\n }\n\n this.content.setDisplayedSize(width, height);\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n sizeChanged(width, height) {\n if (width !== this.prevDisplayedWidth || height !== this.prevDisplayedHeight) {\n this.prevDisplayedWidth = width;\n this.prevDisplayedHeight = height;\n return true;\n }\n\n return false;\n }\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */\n\n\n getPlaceholderElement() {\n var _this$content$placeho;\n\n return (_this$content$placeho = this.content.placeholder) === null || _this$content$placeho === void 0 ? void 0 : _this$content$placeho.element;\n }\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */\n\n\n zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\n const {\n pswp\n } = this;\n\n if (!this.isZoomable() || pswp.mainScroll.isShifted()) {\n return;\n }\n\n pswp.dispatch('beforeZoomTo', {\n destZoomLevel,\n centerPoint,\n transitionDuration\n }); // stop all pan and zoom transitions\n\n pswp.animations.stopAllPan(); // if (!centerPoint) {\n // centerPoint = pswp.getViewportCenterPoint();\n // }\n\n const prevZoomLevel = this.currZoomLevel;\n\n if (!ignoreBounds) {\n destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\n } // if (transitionDuration === undefined) {\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\n // }\n\n\n this.setZoomLevel(destZoomLevel);\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\n roundPoint(this.pan);\n\n const finishTransition = () => {\n this._setResolution(destZoomLevel);\n\n this.applyCurrentZoomPan();\n };\n\n if (!transitionDuration) {\n finishTransition();\n } else {\n pswp.animations.startTransition({\n isPan: true,\n name: 'zoomTo',\n target: this.container,\n transform: this.getCurrentTransform(),\n onComplete: finishTransition,\n duration: transitionDuration,\n easing: pswp.options.easing\n });\n }\n }\n /**\r\n * @param {Point} [centerPoint]\r\n */\n\n\n toggleZoom(centerPoint) {\n this.zoomTo(this.currZoomLevel === this.zoomLevels.initial ? this.zoomLevels.secondary : this.zoomLevels.initial, centerPoint, this.pswp.options.zoomAnimationDuration);\n }\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */\n\n\n setZoomLevel(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n this.bounds.update(this.currZoomLevel);\n }\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */\n\n\n calculateZoomToPanOffset(axis, point, prevZoomLevel) {\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\n\n if (totalPanDistance === 0) {\n return this.bounds.center[axis];\n }\n\n if (!point) {\n point = this.pswp.getViewportCenterPoint();\n }\n\n if (!prevZoomLevel) {\n prevZoomLevel = this.zoomLevels.initial;\n }\n\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\n return this.bounds.correctPan(axis, (this.pan[axis] - point[axis]) * zoomFactor + point[axis]);\n }\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */\n\n\n panTo(panX, panY) {\n this.pan.x = this.bounds.correctPan('x', panX);\n this.pan.y = this.bounds.correctPan('y', panY);\n this.applyCurrentZoomPan();\n }\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */\n\n\n isPannable() {\n return Boolean(this.width) && this.currZoomLevel > this.zoomLevels.fit;\n }\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */\n\n\n isZoomable() {\n return Boolean(this.width) && this.content.isZoomable();\n }\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */\n\n\n applyCurrentZoomPan() {\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\n\n if (this === this.pswp.currSlide) {\n this.pswp.dispatch('zoomPanUpdate', {\n slide: this\n });\n }\n }\n\n zoomAndPanToInitial() {\n this.currZoomLevel = this.zoomLevels.initial; // pan according to the zoom level\n\n this.bounds.update(this.currZoomLevel);\n equalizePoints(this.pan, this.bounds.center);\n this.pswp.dispatch('initialZoomPan', {\n slide: this\n });\n }\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */\n\n\n _applyZoomTransform(x, y, zoom) {\n zoom /= this.currentResolution || this.zoomLevels.initial;\n setTransform(this.container, x, y, zoom);\n }\n\n calculateSize() {\n const {\n pswp\n } = this;\n equalizePoints(this.panAreaSize, getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index));\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\n pswp.dispatch('calcSlideSize', {\n slide: this\n });\n }\n /** @returns {string} */\n\n\n getCurrentTransform() {\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\n return toTransformString(this.pan.x, this.pan.y, scale);\n }\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */\n\n\n _setResolution(newResolution) {\n if (newResolution === this.currentResolution) {\n return;\n }\n\n this.currentResolution = newResolution;\n this.updateContentSize();\n this.pswp.dispatch('resolutionChanged');\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst PAN_END_FRICTION = 0.35;\nconst VERTICAL_DRAG_FRICTION = 0.6; // 1 corresponds to the third of viewport height\n\nconst MIN_RATIO_TO_CLOSE = 0.4; // Minimum speed required to navigate\n// to next or previous slide\n\nconst MIN_NEXT_SLIDE_SPEED = 0.5;\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */\n\nfunction project(initialVelocity, decelerationRate) {\n return initialVelocity * decelerationRate / (1 - decelerationRate);\n}\n/**\r\n * Handles single pointer dragging\r\n */\n\n\nclass DragHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n this.pswp = gestures.pswp;\n /** @type {Point} */\n\n this.startPan = {\n x: 0,\n y: 0\n };\n }\n\n start() {\n if (this.pswp.currSlide) {\n equalizePoints(this.startPan, this.pswp.currSlide.pan);\n }\n\n this.pswp.animations.stopAll();\n }\n\n change() {\n const {\n p1,\n prevP1,\n dragAxis\n } = this.gestures;\n const {\n currSlide\n } = this.pswp;\n\n if (dragAxis === 'y' && this.pswp.options.closeOnVerticalDrag && currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit && !this.gestures.isMultitouch) {\n // Handle vertical drag to close\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\n\n if (!this.pswp.dispatch('verticalDrag', {\n panY\n }).defaultPrevented) {\n this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION);\n\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\n this.pswp.applyBgOpacity(bgOpacity);\n currSlide.applyCurrentZoomPan();\n }\n } else {\n const mainScrollChanged = this._panOrMoveMainScroll('x');\n\n if (!mainScrollChanged) {\n this._panOrMoveMainScroll('y');\n\n if (currSlide) {\n roundPoint(currSlide.pan);\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n }\n\n end() {\n const {\n velocity\n } = this.gestures;\n const {\n mainScroll,\n currSlide\n } = this.pswp;\n let indexDiff = 0;\n this.pswp.animations.stopAll(); // Handle main scroll if it's shifted\n\n if (mainScroll.isShifted()) {\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX(); // Ratio between 0 and 1:\n // 0 - slide is not visible at all,\n // 0.5 - half of the slide is visible\n // 1 - slide is fully visible\n\n const currentSlideVisibilityRatio = mainScrollShiftDiff / this.pswp.viewportSize.x; // Go next slide.\n //\n // - if velocity and its direction is matched,\n // and we see at least tiny part of the next slide\n //\n // - or if we see less than 50% of the current slide\n // and velocity is close to 0\n //\n\n if (velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0 || velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5) {\n // Go to next slide\n indexDiff = 1;\n velocity.x = Math.min(velocity.x, 0);\n } else if (velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0 || velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5) {\n // Go to prev slide\n indexDiff = -1;\n velocity.x = Math.max(velocity.x, 0);\n }\n\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\n } // Restore zoom level\n\n\n if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max || this.gestures.isMultitouch) {\n this.gestures.zoomLevels.correctZoomPan(true);\n } else {\n // we run two animations instead of one,\n // as each axis has own pan boundaries and thus different spring function\n // (correctZoomPan does not have this functionality,\n // it animates all properties with single timing function)\n this._finishPanGestureForAxis('x');\n\n this._finishPanGestureForAxis('y');\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */\n\n\n _finishPanGestureForAxis(axis) {\n const {\n velocity\n } = this.gestures;\n const {\n currSlide\n } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const {\n pan,\n bounds\n } = currSlide;\n const panPos = pan[axis];\n const restoreBgOpacity = this.pswp.bgOpacity < 1 && axis === 'y'; // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\n // Increasing this number will reduce travel distance\n\n const decelerationRate = 0.995; // 0.99\n // Pan position if there is no bounds\n\n const projectedPosition = panPos + project(velocity[axis], decelerationRate);\n\n if (restoreBgOpacity) {\n const vDragRatio = this._getVerticalDragRatio(panPos);\n\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition); // If we are above and moving upwards,\n // or if we are below and moving downwards\n\n\n if (vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE || vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE) {\n this.pswp.close();\n return;\n }\n } // Pan position with corrected bounds\n\n\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition); // Exit if pan position should not be changed\n // or if speed it too low\n\n if (panPos === correctedPanPosition) {\n return;\n } // Overshoot if the final position is out of pan bounds\n\n\n const dampingRatio = correctedPanPosition === projectedPosition ? 1 : 0.82;\n const initialBgOpacity = this.pswp.bgOpacity;\n const totalPanDist = correctedPanPosition - panPos;\n this.pswp.animations.startSpring({\n name: 'panGesture' + axis,\n isPan: true,\n start: panPos,\n end: correctedPanPosition,\n velocity: velocity[axis],\n dampingRatio,\n onUpdate: pos => {\n // Animate opacity of background relative to Y pan position of an image\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\n // 0 - start of animation, 1 - end of animation\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist; // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n\n this.pswp.applyBgOpacity(clamp(initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio, 0, 1));\n }\n\n pan[axis] = Math.floor(pos);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */\n\n\n _panOrMoveMainScroll(axis) {\n const {\n p1,\n dragAxis,\n prevP1,\n isMultitouch\n } = this.gestures;\n const {\n currSlide,\n mainScroll\n } = this.pswp;\n const delta = p1[axis] - prevP1[axis];\n const newMainScrollX = mainScroll.x + delta;\n\n if (!delta || !currSlide) {\n return false;\n } // Always move main scroll if image can not be panned\n\n\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\n mainScroll.moveTo(newMainScrollX, true);\n return true; // changed main scroll\n }\n\n const {\n bounds\n } = currSlide;\n const newPan = currSlide.pan[axis] + delta;\n\n if (this.pswp.options.allowPanToNext && dragAxis === 'x' && axis === 'x' && !isMultitouch) {\n const currSlideMainScrollX = mainScroll.getCurrSlideX(); // Position of the main scroll relative to the viewport\n\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\n const isLeftToRight = delta > 0;\n const isRightToLeft = !isLeftToRight;\n\n if (newPan > bounds.min[axis] && isLeftToRight) {\n // Panning from left to right, beyond the left edge\n // Wether the image was at minimum pan position (or less)\n // when this drag gesture started.\n // Minimum pan position refers to the left edge of the image.\n const wasAtMinPanPosition = bounds.min[axis] <= this.startPan[axis];\n\n if (wasAtMinPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n\n }\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\n // Paning from right to left, beyond the right edge\n // Maximum pan position refers to the right edge of the image.\n const wasAtMaxPanPosition = this.startPan[axis] <= bounds.max[axis];\n\n if (wasAtMaxPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n\n }\n } else {\n // If main scroll is shifted\n if (mainScrollShiftDiff !== 0) {\n // If main scroll is shifted right\n if (mainScrollShiftDiff > 0\n /*&& isRightToLeft*/\n ) {\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\n return true;\n } else if (mainScrollShiftDiff < 0\n /*&& isLeftToRight*/\n ) {\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\n return true;\n }\n } else {\n // We are within pan bounds, so just pan\n this._setPanWithFriction(axis, newPan);\n }\n }\n } else {\n if (axis === 'y') {\n // Do not pan vertically if main scroll is shifted o\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) {\n this._setPanWithFriction(axis, newPan);\n }\n } else {\n this._setPanWithFriction(axis, newPan);\n }\n }\n\n return false;\n } // If we move above - the ratio is negative\n // If we move below the ratio is positive\n\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */\n\n\n _getVerticalDragRatio(panY) {\n var _this$pswp$currSlide$, _this$pswp$currSlide;\n\n return (panY - ((_this$pswp$currSlide$ = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.bounds.center.y) !== null && _this$pswp$currSlide$ !== void 0 ? _this$pswp$currSlide$ : 0)) / (this.pswp.viewportSize.y / 3);\n }\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */\n\n\n _setPanWithFriction(axis, potentialPan, customFriction) {\n const {\n currSlide\n } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const {\n pan,\n bounds\n } = currSlide;\n const correctedPan = bounds.correctPan(axis, potentialPan); // If we are out of pan bounds\n\n if (correctedPan !== potentialPan || customFriction) {\n const delta = Math.round(potentialPan - pan[axis]);\n pan[axis] += delta * (customFriction || PAN_END_FRICTION);\n } else {\n pan[axis] = potentialPan;\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst UPPER_ZOOM_FRICTION = 0.05;\nconst LOWER_ZOOM_FRICTION = 0.15;\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\n\nfunction getZoomPointsCenter(p, p1, p2) {\n p.x = (p1.x + p2.x) / 2;\n p.y = (p1.y + p2.y) / 2;\n return p;\n}\n\nclass ZoomHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._startPan = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._startZoomPoint = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._zoomPoint = {\n x: 0,\n y: 0\n };\n /** @private */\n\n this._wasOverFitZoomLevel = false;\n /** @private */\n\n this._startZoomLevel = 1;\n }\n\n start() {\n const {\n currSlide\n } = this.gestures.pswp;\n\n if (currSlide) {\n this._startZoomLevel = currSlide.currZoomLevel;\n equalizePoints(this._startPan, currSlide.pan);\n }\n\n this.gestures.pswp.animations.stopAllPan();\n this._wasOverFitZoomLevel = false;\n }\n\n change() {\n const {\n p1,\n startP1,\n p2,\n startP2,\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if (!currSlide) {\n return;\n }\n\n const minZoomLevel = currSlide.zoomLevels.min;\n const maxZoomLevel = currSlide.zoomLevels.max;\n\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) {\n return;\n }\n\n getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\n getZoomPointsCenter(this._zoomPoint, p1, p2);\n\n let currZoomLevel = 1 / getDistanceBetween(startP1, startP2) * getDistanceBetween(p1, p2) * this._startZoomLevel; // slightly over the zoom.fit\n\n\n if (currZoomLevel > currSlide.zoomLevels.initial + currSlide.zoomLevels.initial / 15) {\n this._wasOverFitZoomLevel = true;\n }\n\n if (currZoomLevel < minZoomLevel) {\n if (pswp.options.pinchToClose && !this._wasOverFitZoomLevel && this._startZoomLevel <= currSlide.zoomLevels.initial) {\n // fade out background if zooming out\n const bgOpacity = 1 - (minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2);\n\n if (!pswp.dispatch('pinchClose', {\n bgOpacity\n }).defaultPrevented) {\n pswp.applyBgOpacity(bgOpacity);\n }\n } else {\n // Apply the friction if zoom level is below the min\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION;\n }\n } else if (currZoomLevel > maxZoomLevel) {\n // Apply the friction if zoom level is above the max\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION;\n }\n\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\n currSlide.setZoomLevel(currZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n\n end() {\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial) && !this._wasOverFitZoomLevel && pswp.options.pinchToClose) {\n pswp.close();\n } else {\n this.correctZoomPan();\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */\n\n\n _calculatePanForZoomLevel(axis, currZoomLevel) {\n const zoomFactor = currZoomLevel / this._startZoomLevel;\n return this._zoomPoint[axis] - (this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor;\n }\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */\n\n\n correctZoomPan(ignoreGesture) {\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if (!(currSlide !== null && currSlide !== void 0 && currSlide.isZoomable())) {\n return;\n }\n\n if (this._zoomPoint.x === 0) {\n ignoreGesture = true;\n }\n\n const prevZoomLevel = currSlide.currZoomLevel;\n /** @type {number} */\n\n let destinationZoomLevel;\n let currZoomLevelNeedsChange = true;\n\n if (prevZoomLevel < currSlide.zoomLevels.initial) {\n destinationZoomLevel = currSlide.zoomLevels.initial; // zoom to min\n } else if (prevZoomLevel > currSlide.zoomLevels.max) {\n destinationZoomLevel = currSlide.zoomLevels.max; // zoom to max\n } else {\n currZoomLevelNeedsChange = false;\n destinationZoomLevel = prevZoomLevel;\n }\n\n const initialBgOpacity = pswp.bgOpacity;\n const restoreBgOpacity = pswp.bgOpacity < 1;\n const initialPan = equalizePoints({\n x: 0,\n y: 0\n }, currSlide.pan);\n let destinationPan = equalizePoints({\n x: 0,\n y: 0\n }, initialPan);\n\n if (ignoreGesture) {\n this._zoomPoint.x = 0;\n this._zoomPoint.y = 0;\n this._startZoomPoint.x = 0;\n this._startZoomPoint.y = 0;\n this._startZoomLevel = prevZoomLevel;\n equalizePoints(this._startPan, initialPan);\n }\n\n if (currZoomLevelNeedsChange) {\n destinationPan = {\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\n };\n } // set zoom level, so pan bounds are updated according to it\n\n\n currSlide.setZoomLevel(destinationZoomLevel);\n destinationPan = {\n x: currSlide.bounds.correctPan('x', destinationPan.x),\n y: currSlide.bounds.correctPan('y', destinationPan.y)\n }; // return zoom level and its bounds to initial\n\n currSlide.setZoomLevel(prevZoomLevel);\n const panNeedsChange = !pointsEqual(destinationPan, initialPan);\n\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\n // update resolution after gesture\n currSlide._setResolution(destinationZoomLevel);\n\n currSlide.applyCurrentZoomPan(); // nothing to animate\n\n return;\n }\n\n pswp.animations.stopAllPan();\n pswp.animations.startSpring({\n isPan: true,\n start: 0,\n end: 1000,\n velocity: 0,\n dampingRatio: 1,\n naturalFrequency: 40,\n onUpdate: now => {\n now /= 1000; // 0 - start, 1 - end\n\n if (panNeedsChange || currZoomLevelNeedsChange) {\n if (panNeedsChange) {\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\n }\n\n if (currZoomLevelNeedsChange) {\n const newZoomLevel = prevZoomLevel + (destinationZoomLevel - prevZoomLevel) * now;\n currSlide.setZoomLevel(newZoomLevel);\n }\n\n currSlide.applyCurrentZoomPan();\n } // Restore background opacity\n\n\n if (restoreBgOpacity && pswp.bgOpacity < 1) {\n // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n pswp.applyBgOpacity(clamp(initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1));\n }\n },\n onComplete: () => {\n // update resolution after transition ends\n currSlide._setResolution(destinationZoomLevel);\n\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n\n}\n\n/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */\n\n/**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */\nfunction didTapOnMainContent(event) {\n return !!\n /** @type {HTMLElement} */\n event.target.closest('.pswp__container');\n}\n/**\r\n * Tap, double-tap handler.\r\n */\n\n\nclass TapHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n click(point, originalEvent) {\n const targetClassList =\n /** @type {HTMLElement} */\n originalEvent.target.classList;\n const isImageClick = targetClassList.contains('pswp__img');\n const isBackgroundClick = targetClassList.contains('pswp__item') || targetClassList.contains('pswp__zoom-wrap');\n\n if (isImageClick) {\n this._doClickOrTapAction('imageClick', point, originalEvent);\n } else if (isBackgroundClick) {\n this._doClickOrTapAction('bgClick', point, originalEvent);\n }\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n tap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('tap', point, originalEvent);\n }\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n doubleTap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('doubleTap', point, originalEvent);\n }\n }\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n _doClickOrTapAction(actionName, point, originalEvent) {\n var _this$gestures$pswp$e;\n\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n const actionFullName =\n /** @type {AddPostfix} */\n actionName + 'Action';\n const optionValue = pswp.options[actionFullName];\n\n if (pswp.dispatch(actionFullName, {\n point,\n originalEvent\n }).defaultPrevented) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n optionValue.call(pswp, point, originalEvent);\n return;\n }\n\n switch (optionValue) {\n case 'close':\n case 'next':\n pswp[optionValue]();\n break;\n\n case 'zoom':\n currSlide === null || currSlide === void 0 || currSlide.toggleZoom(point);\n break;\n\n case 'zoom-or-close':\n // by default click zooms current image,\n // if it can not be zoomed - gallery will be closed\n if (currSlide !== null && currSlide !== void 0 && currSlide.isZoomable() && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) {\n currSlide.toggleZoom(point);\n } else if (pswp.options.clickToCloseNonZoomable) {\n pswp.close();\n }\n\n break;\n\n case 'toggle-controls':\n (_this$gestures$pswp$e = this.gestures.pswp.element) === null || _this$gestures$pswp$e === void 0 || _this$gestures$pswp$e.classList.toggle('pswp--ui-visible'); // if (_controlsVisible) {\n // _ui.hideControls();\n // } else {\n // _ui.showControls();\n // }\n\n break;\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n// How far should user should drag\n// until we can determine that the gesture is swipe and its direction\n\nconst AXIS_SWIPE_HYSTERISIS = 10; //const PAN_END_FRICTION = 0.35;\n\nconst DOUBLE_TAP_DELAY = 300; // ms\n\nconst MIN_TAP_DISTANCE = 25; // px\n\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */\n\nclass Gestures {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n /** @type {'x' | 'y' | null} */\n\n this.dragAxis = null; // point objects are defined once and reused\n // PhotoSwipe keeps track only of two pointers, others are ignored\n\n /** @type {Point} */\n\n this.p1 = {\n x: 0,\n y: 0\n }; // the first pressed pointer\n\n /** @type {Point} */\n\n this.p2 = {\n x: 0,\n y: 0\n }; // the second pressed pointer\n\n /** @type {Point} */\n\n this.prevP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.prevP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.startP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.startP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.velocity = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */\n\n this._lastStartP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */\n\n this._intervalP1 = {\n x: 0,\n y: 0\n };\n /** @private */\n\n this._numActivePoints = 0;\n /** @type {Point[]}\r\n * @private\r\n */\n\n this._ongoingPointers = [];\n /** @private */\n\n this._touchEventEnabled = 'ontouchstart' in window;\n /** @private */\n\n this._pointerEventEnabled = !!window.PointerEvent;\n this.supportsTouch = this._touchEventEnabled || this._pointerEventEnabled && navigator.maxTouchPoints > 1;\n /** @private */\n\n this._numActivePoints = 0;\n /** @private */\n\n this._intervalTime = 0;\n /** @private */\n\n this._velocityCalculated = false;\n this.isMultitouch = false;\n this.isDragging = false;\n this.isZooming = false;\n /** @type {number | null} */\n\n this.raf = null;\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */\n\n this._tapTimer = null;\n\n if (!this.supportsTouch) {\n // disable pan to next slide for non-touch devices\n pswp.options.allowPanToNext = false;\n }\n\n this.drag = new DragHandler(this);\n this.zoomLevels = new ZoomHandler(this);\n this.tapHandler = new TapHandler(this);\n pswp.on('bindEvents', () => {\n pswp.events.add(pswp.scrollWrap, 'click',\n /** @type EventListener */\n this._onClick.bind(this));\n\n if (this._pointerEventEnabled) {\n this._bindEvents('pointer', 'down', 'up', 'cancel');\n } else if (this._touchEventEnabled) {\n this._bindEvents('touch', 'start', 'end', 'cancel'); // In previous versions we also bound mouse event here,\n // in case device supports both touch and mouse events,\n // but newer versions of browsers now support PointerEvent.\n // on iOS10 if you bind touchmove/end after touchstart,\n // and you don't preventDefault touchstart (which PhotoSwipe does),\n // preventDefault will have no effect on touchmove and touchend.\n // Unless you bind it previously.\n\n\n if (pswp.scrollWrap) {\n pswp.scrollWrap.ontouchmove = () => {};\n\n pswp.scrollWrap.ontouchend = () => {};\n }\n } else {\n this._bindEvents('mouse', 'down', 'up');\n }\n });\n }\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */\n\n\n _bindEvents(pref, down, up, cancel) {\n const {\n pswp\n } = this;\n const {\n events\n } = pswp;\n const cancelEvent = cancel ? pref + cancel : '';\n events.add(pswp.scrollWrap, pref + down,\n /** @type EventListener */\n this.onPointerDown.bind(this));\n events.add(window, pref + 'move',\n /** @type EventListener */\n this.onPointerMove.bind(this));\n events.add(window, pref + up,\n /** @type EventListener */\n this.onPointerUp.bind(this));\n\n if (cancelEvent) {\n events.add(pswp.scrollWrap, cancelEvent,\n /** @type EventListener */\n this.onPointerUp.bind(this));\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerDown(e) {\n // We do not call preventDefault for touch events\n // to allow browser to show native dialog on longpress\n // (the one that allows to save image or open it in new tab).\n //\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse'; // Allow dragging only via left mouse button.\n // http://www.quirksmode.org/js/events_properties.html\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\n\n if (isMousePointer && e.button > 0) {\n return;\n }\n\n const {\n pswp\n } = this; // if PhotoSwipe is opening or closing\n\n if (!pswp.opener.isOpen) {\n e.preventDefault();\n return;\n }\n\n if (pswp.dispatch('pointerDown', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (isMousePointer) {\n pswp.mouseDetected(); // preventDefault mouse event to prevent\n // browser image drag feature\n\n this._preventPointerEventBehaviour(e, 'down');\n }\n\n pswp.animations.stopAll();\n\n this._updatePoints(e, 'down');\n\n if (this._numActivePoints === 1) {\n this.dragAxis = null; // we need to store initial point to determine the main axis,\n // drag is activated only after the axis is determined\n\n equalizePoints(this.startP1, this.p1);\n }\n\n if (this._numActivePoints > 1) {\n // Tap or double tap should not trigger if more than one pointer\n this._clearTapTimer();\n\n this.isMultitouch = true;\n } else {\n this.isMultitouch = false;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerMove(e) {\n this._preventPointerEventBehaviour(e, 'move');\n\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'move');\n\n if (this.pswp.dispatch('pointerMove', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 1 && !this.isDragging) {\n if (!this.dragAxis) {\n this._calculateDragDirection();\n } // Drag axis was detected, emit drag.start\n\n\n if (this.dragAxis && !this.isDragging) {\n if (this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n }\n\n this.isDragging = true;\n\n this._clearTapTimer(); // Tap can not trigger after drag\n // Adjust starting point\n\n\n this._updateStartPoints();\n\n this._intervalTime = Date.now(); //this._startTime = this._intervalTime;\n\n this._velocityCalculated = false;\n equalizePoints(this._intervalP1, this.p1);\n this.velocity.x = 0;\n this.velocity.y = 0;\n this.drag.start();\n\n this._rafStopLoop();\n\n this._rafRenderLoop();\n }\n } else if (this._numActivePoints > 1 && !this.isZooming) {\n this._finishDrag();\n\n this.isZooming = true; // Adjust starting points\n\n this._updateStartPoints();\n\n this.zoomLevels.start();\n\n this._rafStopLoop();\n\n this._rafRenderLoop();\n }\n }\n /**\r\n * @private\r\n */\n\n\n _finishDrag() {\n if (this.isDragging) {\n this.isDragging = false; // Try to calculate velocity,\n // if it wasn't calculated yet in drag.change\n\n if (!this._velocityCalculated) {\n this._updateVelocity(true);\n }\n\n this.drag.end();\n this.dragAxis = null;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerUp(e) {\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'up');\n\n if (this.pswp.dispatch('pointerUp', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 0) {\n this._rafStopLoop();\n\n if (this.isDragging) {\n this._finishDrag();\n } else if (!this.isZooming && !this.isMultitouch) {\n //this.zoomLevels.correctZoomPan();\n this._finishTap(e);\n }\n }\n\n if (this._numActivePoints < 2 && this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n\n if (this._numActivePoints === 1) {\n // Since we have 1 point left, we need to reinitiate drag\n this.dragAxis = null;\n\n this._updateStartPoints();\n }\n }\n }\n /**\r\n * @private\r\n */\n\n\n _rafRenderLoop() {\n if (this.isDragging || this.isZooming) {\n this._updateVelocity();\n\n if (this.isDragging) {\n // make sure that pointer moved since the last update\n if (!pointsEqual(this.p1, this.prevP1)) {\n this.drag.change();\n }\n } else\n /* if (this.isZooming) */\n {\n if (!pointsEqual(this.p1, this.prevP1) || !pointsEqual(this.p2, this.prevP2)) {\n this.zoomLevels.change();\n }\n }\n\n this._updatePrevPoints();\n\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\n }\n }\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */\n\n\n _updateVelocity(force) {\n const time = Date.now();\n const duration = time - this._intervalTime;\n\n if (duration < 50 && !force) {\n return;\n }\n\n this.velocity.x = this._getVelocity('x', duration);\n this.velocity.y = this._getVelocity('y', duration);\n this._intervalTime = time;\n equalizePoints(this._intervalP1, this.p1);\n this._velocityCalculated = true;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\n\n\n _finishTap(e) {\n const {\n mainScroll\n } = this.pswp; // Do not trigger tap events if main scroll is shifted\n\n if (mainScroll.isShifted()) {\n // restore main scroll position\n // (usually happens if stopped in the middle of animation)\n mainScroll.moveIndexBy(0, true);\n return;\n } // Do not trigger tap for touchcancel or pointercancel\n\n\n if (e.type.indexOf('cancel') > 0) {\n return;\n } // Trigger click instead of tap for mouse events\n\n\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\n this.tapHandler.click(this.startP1, e);\n return;\n } // Disable delay if there is no doubleTapAction\n\n\n const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0; // If tapTimer is defined - we tapped recently,\n // check if the current tap is close to the previous one,\n // if yes - trigger double tap\n\n if (this._tapTimer) {\n this._clearTapTimer(); // Check if two taps were more or less on the same place\n\n\n if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) {\n this.tapHandler.doubleTap(this.startP1, e);\n }\n } else {\n equalizePoints(this._lastStartP1, this.startP1);\n this._tapTimer = setTimeout(() => {\n this.tapHandler.tap(this.startP1, e);\n\n this._clearTapTimer();\n }, tapDelay);\n }\n }\n /**\r\n * @private\r\n */\n\n\n _clearTapTimer() {\n if (this._tapTimer) {\n clearTimeout(this._tapTimer);\n this._tapTimer = null;\n }\n }\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */\n\n\n _getVelocity(axis, duration) {\n // displacement is like distance, but can be negative.\n const displacement = this.p1[axis] - this._intervalP1[axis];\n\n if (Math.abs(displacement) > 1 && duration > 5) {\n return displacement / duration;\n }\n\n return 0;\n }\n /**\r\n * @private\r\n */\n\n\n _rafStopLoop() {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = null;\n }\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\n\n\n _preventPointerEventBehaviour(e, pointerType) {\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\n\n if (preventPointerEvent) {\n e.preventDefault();\n }\n }\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\n\n\n _updatePoints(e, pointerType) {\n if (this._pointerEventEnabled) {\n const pointerEvent =\n /** @type {PointerEvent} */\n e; // Try to find the current pointer in ongoing pointers by its ID\n\n const pointerIndex = this._ongoingPointers.findIndex(ongoingPointer => {\n return ongoingPointer.id === pointerEvent.pointerId;\n });\n\n if (pointerType === 'up' && pointerIndex > -1) {\n // release the pointer - remove it from ongoing\n this._ongoingPointers.splice(pointerIndex, 1);\n } else if (pointerType === 'down' && pointerIndex === -1) {\n // add new pointer\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, {\n x: 0,\n y: 0\n }));\n } else if (pointerIndex > -1) {\n // update existing pointer\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\n }\n\n this._numActivePoints = this._ongoingPointers.length; // update points that PhotoSwipe uses\n // to calculate position and scale\n\n if (this._numActivePoints > 0) {\n equalizePoints(this.p1, this._ongoingPointers[0]);\n }\n\n if (this._numActivePoints > 1) {\n equalizePoints(this.p2, this._ongoingPointers[1]);\n }\n } else {\n const touchEvent =\n /** @type {TouchEvent} */\n e;\n this._numActivePoints = 0;\n\n if (touchEvent.type.indexOf('touch') > -1) {\n // Touch Event\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\n if (touchEvent.touches && touchEvent.touches.length > 0) {\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\n\n this._numActivePoints++;\n\n if (touchEvent.touches.length > 1) {\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\n\n this._numActivePoints++;\n }\n }\n } else {\n // Mouse Event\n this._convertEventPosToPoint(\n /** @type {PointerEvent} */\n e, this.p1);\n\n if (pointerType === 'up') {\n // clear all points on mouseup\n this._numActivePoints = 0;\n } else {\n this._numActivePoints++;\n }\n }\n }\n }\n /** update points that were used during previous rAF tick\r\n * @private\r\n */\n\n\n _updatePrevPoints() {\n equalizePoints(this.prevP1, this.p1);\n equalizePoints(this.prevP2, this.p2);\n }\n /** update points at the start of gesture\r\n * @private\r\n */\n\n\n _updateStartPoints() {\n equalizePoints(this.startP1, this.p1);\n equalizePoints(this.startP2, this.p2);\n\n this._updatePrevPoints();\n }\n /** @private */\n\n\n _calculateDragDirection() {\n if (this.pswp.mainScroll.isShifted()) {\n // if main scroll position is shifted – direction is always horizontal\n this.dragAxis = 'x';\n } else {\n // calculate delta of the last touchmove tick\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\n\n if (diff !== 0) {\n // check if pointer was shifted horizontally or vertically\n const axisToCheck = diff > 0 ? 'x' : 'y';\n\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) {\n this.dragAxis = axisToCheck;\n }\n }\n }\n }\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */\n\n\n _convertEventPosToPoint(e, p) {\n p.x = e.pageX - this.pswp.offset.x;\n p.y = e.pageY - this.pswp.offset.y;\n\n if ('pointerId' in e) {\n p.id = e.pointerId;\n } else if (e.identifier !== undefined) {\n p.id = e.identifier;\n }\n\n return p;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\n\n\n _onClick(e) {\n // Do not allow click event to pass through after drag\n if (this.pswp.mainScroll.isShifted()) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./slide/slide.js').default} Slide */\n\n/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */\n\nconst MAIN_SCROLL_END_FRICTION = 0.35; // const MIN_SWIPE_TRANSITION_DURATION = 250;\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\n\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */\n\nclass MainScroll {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.x = 0;\n this.slideWidth = 0;\n /** @private */\n\n this._currPositionIndex = 0;\n /** @private */\n\n this._prevPositionIndex = 0;\n /** @private */\n\n this._containerShiftIndex = -1;\n /** @type {ItemHolder[]} */\n\n this.itemHolders = [];\n }\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */\n\n\n resize(resizeSlides) {\n const {\n pswp\n } = this;\n const newSlideWidth = Math.round(pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing); // Mobile browsers might trigger a resize event during a gesture.\n // (due to toolbar appearing or hiding).\n // Avoid re-adjusting main scroll position if width wasn't changed\n\n const slideWidthChanged = newSlideWidth !== this.slideWidth;\n\n if (slideWidthChanged) {\n this.slideWidth = newSlideWidth;\n this.moveTo(this.getCurrSlideX());\n }\n\n this.itemHolders.forEach((itemHolder, index) => {\n if (slideWidthChanged) {\n setTransform(itemHolder.el, (index + this._containerShiftIndex) * this.slideWidth);\n }\n\n if (resizeSlides && itemHolder.slide) {\n itemHolder.slide.resize();\n }\n });\n }\n /**\r\n * Reset X position of the main scroller to zero\r\n */\n\n\n resetPosition() {\n // Position on the main scroller (offset)\n // it is independent from slide index\n this._currPositionIndex = 0;\n this._prevPositionIndex = 0; // This will force recalculation of size on next resize()\n\n this.slideWidth = 0; // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\n\n this._containerShiftIndex = -1;\n }\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */\n\n\n appendHolders() {\n this.itemHolders = []; // append our three slide holders -\n // previous, current, and next\n\n for (let i = 0; i < 3; i++) {\n const el = createElement('pswp__item', 'div', this.pswp.container);\n el.setAttribute('role', 'group');\n el.setAttribute('aria-roledescription', 'slide');\n el.setAttribute('aria-hidden', 'true'); // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\n\n el.style.display = i === 1 ? 'block' : 'none';\n this.itemHolders.push({\n el //index: -1\n\n });\n }\n }\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */\n\n\n canBeSwiped() {\n return this.pswp.getNumItems() > 1;\n }\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */\n\n\n moveIndexBy(diff, animate, velocityX) {\n const {\n pswp\n } = this;\n let newIndex = pswp.potentialIndex + diff;\n const numSlides = pswp.getNumItems();\n\n if (pswp.canLoop()) {\n newIndex = pswp.getLoopedIndex(newIndex);\n const distance = (diff + numSlides) % numSlides;\n\n if (distance <= numSlides / 2) {\n // go forward\n diff = distance;\n } else {\n // go backwards\n diff = distance - numSlides;\n }\n } else {\n if (newIndex < 0) {\n newIndex = 0;\n } else if (newIndex >= numSlides) {\n newIndex = numSlides - 1;\n }\n\n diff = newIndex - pswp.potentialIndex;\n }\n\n pswp.potentialIndex = newIndex;\n this._currPositionIndex -= diff;\n pswp.animations.stopMainScroll();\n const destinationX = this.getCurrSlideX();\n\n if (!animate) {\n this.moveTo(destinationX);\n this.updateCurrItem();\n } else {\n pswp.animations.startSpring({\n isMainScroll: true,\n start: this.x,\n end: destinationX,\n velocity: velocityX || 0,\n naturalFrequency: 30,\n dampingRatio: 1,\n //0.7,\n onUpdate: x => {\n this.moveTo(x);\n },\n onComplete: () => {\n this.updateCurrItem();\n pswp.appendHeavy();\n }\n });\n let currDiff = pswp.potentialIndex - pswp.currIndex;\n\n if (pswp.canLoop()) {\n const currDistance = (currDiff + numSlides) % numSlides;\n\n if (currDistance <= numSlides / 2) {\n // go forward\n currDiff = currDistance;\n } else {\n // go backwards\n currDiff = currDistance - numSlides;\n }\n } // Force-append new slides during transition\n // if difference between slides is more than 1\n\n\n if (Math.abs(currDiff) > 1) {\n this.updateCurrItem();\n }\n }\n\n return Boolean(diff);\n }\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */\n\n\n getCurrSlideX() {\n return this.slideWidth * this._currPositionIndex;\n }\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */\n\n\n isShifted() {\n return this.x !== this.getCurrSlideX();\n }\n /**\r\n * Update slides X positions and set their content\r\n */\n\n\n updateCurrItem() {\n var _this$itemHolders$;\n\n const {\n pswp\n } = this;\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\n\n if (!positionDifference) {\n return;\n }\n\n this._prevPositionIndex = this._currPositionIndex;\n pswp.currIndex = pswp.potentialIndex;\n let diffAbs = Math.abs(positionDifference);\n /** @type {ItemHolder | undefined} */\n\n let tempHolder;\n\n if (diffAbs >= 3) {\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\n diffAbs = 3; // If slides are changed by 3 screens or more - clean up previous slides\n\n this.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide;\n\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.destroy();\n itemHolder.slide = undefined;\n });\n }\n\n for (let i = 0; i < diffAbs; i++) {\n if (positionDifference > 0) {\n tempHolder = this.itemHolders.shift();\n\n if (tempHolder) {\n this.itemHolders[2] = tempHolder; // move first to last\n\n this._containerShiftIndex++;\n setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex - diffAbs + i + 2);\n }\n } else {\n tempHolder = this.itemHolders.pop();\n\n if (tempHolder) {\n this.itemHolders.unshift(tempHolder); // move last to first\n\n this._containerShiftIndex--;\n setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex + diffAbs - i - 2);\n }\n }\n } // Reset transfrom every 50ish navigations in one direction.\n //\n // Otherwise transform will keep growing indefinitely,\n // which might cause issues as browsers have a maximum transform limit.\n // I wasn't able to reach it, but just to be safe.\n // This should not cause noticable lag.\n\n\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\n this.resetPosition();\n this.resize();\n } // Pan transition might be running (and consntantly updating pan position)\n\n\n pswp.animations.stopAllPan();\n this.itemHolders.forEach((itemHolder, i) => {\n if (itemHolder.slide) {\n // Slide in the 2nd holder is always active\n itemHolder.slide.setIsActive(i === 1);\n }\n });\n pswp.currSlide = (_this$itemHolders$ = this.itemHolders[1]) === null || _this$itemHolders$ === void 0 ? void 0 : _this$itemHolders$.slide;\n pswp.contentLoader.updateLazy(positionDifference);\n\n if (pswp.currSlide) {\n pswp.currSlide.applyCurrentZoomPan();\n }\n\n pswp.dispatch('change');\n }\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */\n\n\n moveTo(x, dragging) {\n if (!this.pswp.canLoop() && dragging) {\n // Apply friction\n let newSlideIndexOffset = (this.slideWidth * this._currPositionIndex - x) / this.slideWidth;\n newSlideIndexOffset += this.pswp.currIndex;\n const delta = Math.round(x - this.x);\n\n if (newSlideIndexOffset < 0 && delta > 0 || newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0) {\n x = this.x + delta * MAIN_SCROLL_END_FRICTION;\n }\n }\n\n this.x = x;\n\n if (this.pswp.container) {\n setTransform(this.pswp.container, x);\n }\n\n this.pswp.dispatch('moveMainScroll', {\n x,\n dragging: dragging !== null && dragging !== void 0 ? dragging : false\n });\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */\n\nconst KeyboardKeyCodesMap = {\n Escape: 27,\n z: 90,\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n Tab: 9\n};\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */\n\nconst getKeyboardEventKey = (key, isKeySupported) => {\n return isKeySupported ? key : KeyboardKeyCodesMap[key];\n};\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */\n\n\nclass Keyboard {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n /** @private */\n\n this._wasFocused = false;\n pswp.on('bindEvents', () => {\n if (pswp.options.trapFocus) {\n // Dialog was likely opened by keyboard if initial point is not defined\n if (!pswp.options.initialPointerPos) {\n // focus causes layout,\n // which causes lag during the animation,\n // that's why we delay it until the opener transition ends\n this._focusRoot();\n }\n\n pswp.events.add(document, 'focusin',\n /** @type EventListener */\n this._onFocusIn.bind(this));\n }\n\n pswp.events.add(document, 'keydown',\n /** @type EventListener */\n this._onKeyDown.bind(this));\n });\n const lastActiveElement =\n /** @type {HTMLElement} */\n document.activeElement;\n pswp.on('destroy', () => {\n if (pswp.options.returnFocus && lastActiveElement && this._wasFocused) {\n lastActiveElement.focus();\n }\n });\n }\n /** @private */\n\n\n _focusRoot() {\n if (!this._wasFocused && this.pswp.element) {\n this.pswp.element.focus();\n this._wasFocused = true;\n }\n }\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */\n\n\n _onKeyDown(e) {\n const {\n pswp\n } = this;\n\n if (pswp.dispatch('keydown', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (specialKeyUsed(e)) {\n // don't do anything if special key pressed\n // to prevent from overriding default browser actions\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\n return;\n }\n /** @type {Methods | undefined} */\n\n\n let keydownAction;\n /** @type {'x' | 'y' | undefined} */\n\n let axis;\n let isForward = false;\n const isKeySupported = ('key' in e);\n\n switch (isKeySupported ? e.key : e.keyCode) {\n case getKeyboardEventKey('Escape', isKeySupported):\n if (pswp.options.escKey) {\n keydownAction = 'close';\n }\n\n break;\n\n case getKeyboardEventKey('z', isKeySupported):\n keydownAction = 'toggleZoom';\n break;\n\n case getKeyboardEventKey('ArrowLeft', isKeySupported):\n axis = 'x';\n break;\n\n case getKeyboardEventKey('ArrowUp', isKeySupported):\n axis = 'y';\n break;\n\n case getKeyboardEventKey('ArrowRight', isKeySupported):\n axis = 'x';\n isForward = true;\n break;\n\n case getKeyboardEventKey('ArrowDown', isKeySupported):\n isForward = true;\n axis = 'y';\n break;\n\n case getKeyboardEventKey('Tab', isKeySupported):\n this._focusRoot();\n\n break;\n } // if left/right/top/bottom key\n\n\n if (axis) {\n // prevent page scroll\n e.preventDefault();\n const {\n currSlide\n } = pswp;\n\n if (pswp.options.arrowKeys && axis === 'x' && pswp.getNumItems() > 1) {\n keydownAction = isForward ? 'next' : 'prev';\n } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\n // up/down arrow keys pan the image vertically\n // left/right arrow keys pan horizontally.\n // Unless there is only one image,\n // or arrowKeys option is disabled\n currSlide.pan[axis] += isForward ? -80 : 80;\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\n }\n }\n\n if (keydownAction) {\n e.preventDefault(); // @ts-ignore\n\n pswp[keydownAction]();\n }\n }\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */\n\n\n _onFocusIn(e) {\n const {\n template\n } = this.pswp;\n\n if (template && document !== e.target && template !== e.target && !template.contains(\n /** @type {Node} */\n e.target)) {\n // focus root element\n template.focus();\n }\n }\n\n}\n\nconst DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */\n\n/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */\n\n/**\r\n * Runs CSS transition.\r\n */\n\nclass CSSAnimation {\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */\n constructor(props) {\n var _props$prop;\n\n this.props = props;\n const {\n target,\n onComplete,\n transform,\n onFinish = () => {},\n duration = 333,\n easing = DEFAULT_EASING\n } = props;\n this.onFinish = onFinish; // support only transform and opacity\n\n const prop = transform ? 'transform' : 'opacity';\n const propValue = (_props$prop = props[prop]) !== null && _props$prop !== void 0 ? _props$prop : '';\n /** @private */\n\n this._target = target;\n /** @private */\n\n this._onComplete = onComplete;\n /** @private */\n\n this._finished = false;\n /** @private */\n\n this._onTransitionEnd = this._onTransitionEnd.bind(this); // Using timeout hack to make sure that animation\n // starts even if the animated property was changed recently,\n // otherwise transitionend might not fire or transition won't start.\n // https://drafts.csswg.org/css-transitions/#starting\n //\n // ¯\\_(ツ)_/¯\n\n /** @private */\n\n this._helperTimeout = setTimeout(() => {\n setTransitionStyle(target, prop, duration, easing);\n this._helperTimeout = setTimeout(() => {\n target.addEventListener('transitionend', this._onTransitionEnd, false);\n target.addEventListener('transitioncancel', this._onTransitionEnd, false); // Safari occasionally does not emit transitionend event\n // if element property was modified during the transition,\n // which may be caused by resize or third party component,\n // using timeout as a safety fallback\n\n this._helperTimeout = setTimeout(() => {\n this._finalizeAnimation();\n }, duration + 500);\n target.style[prop] = propValue;\n }, 30); // Do not reduce this number\n }, 0);\n }\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */\n\n\n _onTransitionEnd(e) {\n if (e.target === this._target) {\n this._finalizeAnimation();\n }\n }\n /**\r\n * @private\r\n */\n\n\n _finalizeAnimation() {\n if (!this._finished) {\n this._finished = true;\n this.onFinish();\n\n if (this._onComplete) {\n this._onComplete();\n }\n }\n } // Destroy is called automatically onFinish\n\n\n destroy() {\n if (this._helperTimeout) {\n clearTimeout(this._helperTimeout);\n }\n\n removeTransitionStyle(this._target);\n\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\n\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\n\n if (!this._finished) {\n this._finalizeAnimation();\n }\n }\n\n}\n\nconst DEFAULT_NATURAL_FREQUENCY = 12;\nconst DEFAULT_DAMPING_RATIO = 0.75;\n/**\r\n * Spring easing helper\r\n */\n\nclass SpringEaser {\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */\n constructor(initialVelocity, dampingRatio, naturalFrequency) {\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\n // https://en.wikipedia.org/wiki/Damping_ratio\n\n this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO; // https://en.wikipedia.org/wiki/Natural_frequency\n\n this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY;\n this._dampedFrequency = this._naturalFrequency;\n\n if (this._dampingRatio < 1) {\n this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\n }\n }\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */\n\n\n easeFrame(deltaPosition, deltaTime) {\n // Inspired by Apple Webkit and Android spring function implementation\n // https://en.wikipedia.org/wiki/Oscillation\n // https://en.wikipedia.org/wiki/Damping_ratio\n // we ignore mass (assume that it's 1kg)\n let displacement = 0;\n let coeff;\n deltaTime /= 1000;\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\n\n if (this._dampingRatio === 1) {\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\n this.velocity = displacement * -this._naturalFrequency + coeff * naturalDumpingPow;\n } else if (this._dampingRatio < 1) {\n coeff = 1 / this._dampedFrequency * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\n displacement = naturalDumpingPow * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\n this.velocity = displacement * -this._naturalFrequency * this._dampingRatio + naturalDumpingPow * (-this._dampedFrequency * deltaPosition * dumpedFSin + this._dampedFrequency * coeff * dumpedFCos);\n } // Overdamped (>1) damping ratio is not supported\n\n\n return displacement;\n }\n\n}\n\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */\n\n/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */\n\nclass SpringAnimation {\n /**\r\n * @param {SpringAnimationProps} props\r\n */\n constructor(props) {\n this.props = props;\n this._raf = 0;\n const {\n start,\n end,\n velocity,\n onUpdate,\n onComplete,\n onFinish = () => {},\n dampingRatio,\n naturalFrequency\n } = props;\n this.onFinish = onFinish;\n const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency);\n let prevTime = Date.now();\n let deltaPosition = start - end;\n\n const animationLoop = () => {\n if (this._raf) {\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime); // Stop the animation if velocity is low and position is close to end\n\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\n // Finalize the animation\n onUpdate(end);\n\n if (onComplete) {\n onComplete();\n }\n\n this.onFinish();\n } else {\n prevTime = Date.now();\n onUpdate(deltaPosition + end);\n this._raf = requestAnimationFrame(animationLoop);\n }\n }\n };\n\n this._raf = requestAnimationFrame(animationLoop);\n } // Destroy is called automatically onFinish\n\n\n destroy() {\n if (this._raf >= 0) {\n cancelAnimationFrame(this._raf);\n }\n\n this._raf = 0;\n }\n\n}\n\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */\n\n/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */\n\n/** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */\n\n/** @typedef {SpringAnimation | CSSAnimation} Animation */\n\n/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */\n\n/**\r\n * Manages animations\r\n */\n\nclass Animations {\n constructor() {\n /** @type {Animation[]} */\n this.activeAnimations = [];\n }\n /**\r\n * @param {SpringAnimationProps} props\r\n */\n\n\n startSpring(props) {\n this._start(props, true);\n }\n /**\r\n * @param {CssAnimationProps} props\r\n */\n\n\n startTransition(props) {\n this._start(props);\n }\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */\n\n\n _start(props, isSpring) {\n const animation = isSpring ? new SpringAnimation(\n /** @type SpringAnimationProps */\n props) : new CSSAnimation(\n /** @type CssAnimationProps */\n props);\n this.activeAnimations.push(animation);\n\n animation.onFinish = () => this.stop(animation);\n\n return animation;\n }\n /**\r\n * @param {Animation} animation\r\n */\n\n\n stop(animation) {\n animation.destroy();\n const index = this.activeAnimations.indexOf(animation);\n\n if (index > -1) {\n this.activeAnimations.splice(index, 1);\n }\n }\n\n stopAll() {\n // _stopAllAnimations\n this.activeAnimations.forEach(animation => {\n animation.destroy();\n });\n this.activeAnimations = [];\n }\n /**\r\n * Stop all pan or zoom transitions\r\n */\n\n\n stopAllPan() {\n this.activeAnimations = this.activeAnimations.filter(animation => {\n if (animation.props.isPan) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n\n stopMainScroll() {\n this.activeAnimations = this.activeAnimations.filter(animation => {\n if (animation.props.isMainScroll) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n /**\r\n * Returns true if main scroll transition is running\r\n */\n // isMainScrollRunning() {\n // return this.activeAnimations.some((animation) => {\n // return animation.props.isMainScroll;\n // });\n // }\n\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */\n\n\n isPanRunning() {\n return this.activeAnimations.some(animation => {\n return animation.props.isPan;\n });\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */\nclass ScrollWheel {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n pswp.events.add(pswp.element, 'wheel',\n /** @type EventListener */\n this._onWheel.bind(this));\n }\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */\n\n\n _onWheel(e) {\n e.preventDefault();\n const {\n currSlide\n } = this.pswp;\n let {\n deltaX,\n deltaY\n } = e;\n\n if (!currSlide) {\n return;\n }\n\n if (this.pswp.dispatch('wheel', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (e.ctrlKey || this.pswp.options.wheelToZoom) {\n // zoom\n if (currSlide.isZoomable()) {\n let zoomFactor = -deltaY;\n\n if (e.deltaMode === 1\n /* DOM_DELTA_LINE */\n ) {\n zoomFactor *= 0.05;\n } else {\n zoomFactor *= e.deltaMode ? 1 : 0.002;\n }\n\n zoomFactor = 2 ** zoomFactor;\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\n currSlide.zoomTo(destZoomLevel, {\n x: e.clientX,\n y: e.clientY\n });\n }\n } else {\n // pan\n if (currSlide.isPannable()) {\n if (e.deltaMode === 1\n /* DOM_DELTA_LINE */\n ) {\n // 18 - average line height\n deltaX *= 18;\n deltaY *= 18;\n }\n\n currSlide.panTo(currSlide.pan.x - deltaX, currSlide.pan.y - deltaY);\n }\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */\n\n/**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */\n\n/**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */\n\n/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */\n\n/** @typedef {string | UIElementMarkupProps} UIElementMarkup */\n\n/**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */\n\nfunction addElementHTML(htmlData) {\n if (typeof htmlData === 'string') {\n // Allow developers to provide full svg,\n // For example:\n // \n // \n // \n // \n // Can also be any HTML string.\n return htmlData;\n }\n\n if (!htmlData || !htmlData.isCustomSVG) {\n return '';\n }\n\n const svgData = htmlData;\n let out = ''; // replace all %d with size\n\n out = out.split('%d').join(\n /** @type {string} */\n svgData.size || 32); // Icons may contain outline/shadow,\n // to make it we \"clone\" base icon shape and add border to it.\n // Icon itself and border are styled via CSS.\n //\n // Property shadowID defines ID of element that should be cloned.\n\n if (svgData.outlineID) {\n out += '';\n }\n\n out += svgData.inner;\n out += '';\n return out;\n}\n\nclass UIElement {\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */\n constructor(pswp, data) {\n var _container;\n\n const name = data.name || data.className;\n let elementHTML = data.html; // @ts-expect-error lookup only by `data.name` maybe?\n\n if (pswp.options[name] === false) {\n // exit if element is disabled from options\n return;\n } // Allow to override SVG icons from options\n // @ts-expect-error lookup only by `data.name` maybe?\n\n\n if (typeof pswp.options[name + 'SVG'] === 'string') {\n // arrowPrevSVG\n // arrowNextSVG\n // closeSVG\n // zoomSVG\n // @ts-expect-error lookup only by `data.name` maybe?\n elementHTML = pswp.options[name + 'SVG'];\n }\n\n pswp.dispatch('uiElementCreate', {\n data\n });\n let className = '';\n\n if (data.isButton) {\n className += 'pswp__button ';\n className += data.className || `pswp__button--${data.name}`;\n } else {\n className += data.className || `pswp__${data.name}`;\n }\n\n let tagName = data.isButton ? data.tagName || 'button' : data.tagName || 'div';\n tagName =\n /** @type {keyof HTMLElementTagNameMap} */\n tagName.toLowerCase();\n /** @type {HTMLElement} */\n\n const element = createElement(className, tagName);\n\n if (data.isButton) {\n if (tagName === 'button') {\n /** @type {HTMLButtonElement} */\n element.type = 'button';\n }\n\n let {\n title\n } = data;\n const {\n ariaLabel\n } = data; // @ts-expect-error lookup only by `data.name` maybe?\n\n if (typeof pswp.options[name + 'Title'] === 'string') {\n // @ts-expect-error lookup only by `data.name` maybe?\n title = pswp.options[name + 'Title'];\n }\n\n if (title) {\n element.title = title;\n }\n\n const ariaText = ariaLabel || title;\n\n if (ariaText) {\n element.setAttribute('aria-label', ariaText);\n }\n }\n\n element.innerHTML = addElementHTML(elementHTML);\n\n if (data.onInit) {\n data.onInit(element, pswp);\n }\n\n if (data.onClick) {\n element.onclick = e => {\n if (typeof data.onClick === 'string') {\n // @ts-ignore\n pswp[data.onClick]();\n } else if (typeof data.onClick === 'function') {\n data.onClick(e, element, pswp);\n }\n };\n } // Top bar is default position\n\n\n const appendTo = data.appendTo || 'bar';\n /** @type {HTMLElement | undefined} root element by default */\n\n let container = pswp.element;\n\n if (appendTo === 'bar') {\n if (!pswp.topBar) {\n pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\n }\n\n container = pswp.topBar;\n } else {\n // element outside of top bar gets a secondary class\n // that makes element fade out on close\n element.classList.add('pswp__hide-on-close');\n\n if (appendTo === 'wrapper') {\n container = pswp.scrollWrap;\n }\n }\n\n (_container = container) === null || _container === void 0 || _container.appendChild(pswp.applyFilters('uiElement', element, data));\n }\n\n}\n\n/*\r\n Backward and forward arrow buttons\r\n */\n\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */\nfunction initArrowButton(element, pswp, isNextButton) {\n element.classList.add('pswp__button--arrow'); // TODO: this should point to a unique id for this instance\n\n element.setAttribute('aria-controls', 'pswp__items');\n pswp.on('change', () => {\n if (!pswp.options.loop) {\n if (isNextButton) {\n /** @type {HTMLButtonElement} */\n element.disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\n } else {\n /** @type {HTMLButtonElement} */\n element.disabled = !(pswp.currIndex > 0);\n }\n }\n });\n}\n/** @type {UIElementData} */\n\n\nconst arrowPrev = {\n name: 'arrowPrev',\n className: 'pswp__button--arrow--prev',\n title: 'Previous',\n order: 10,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'prev',\n onInit: initArrowButton\n};\n/** @type {UIElementData} */\n\nconst arrowNext = {\n name: 'arrowNext',\n className: 'pswp__button--arrow--next',\n title: 'Next',\n order: 11,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'next',\n onInit: (el, pswp) => {\n initArrowButton(el, pswp, true);\n }\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst closeButton = {\n name: 'close',\n title: 'Close',\n order: 20,\n isButton: true,\n html: {\n isCustomSVG: true,\n inner: '',\n outlineID: 'pswp__icn-close'\n },\n onClick: 'close'\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst zoomButton = {\n name: 'zoom',\n title: 'Zoom',\n order: 10,\n isButton: true,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '' + '' + '',\n outlineID: 'pswp__icn-zoom'\n },\n onClick: 'toggleZoom'\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst loadingIndicator = {\n name: 'preloader',\n appendTo: 'bar',\n order: 7,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-loading'\n },\n onInit: (indicatorElement, pswp) => {\n /** @type {boolean | undefined} */\n let isVisible;\n /** @type {NodeJS.Timeout | null} */\n\n let delayTimeout = null;\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */\n\n const toggleIndicatorClass = (className, add) => {\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\n };\n /**\r\n * @param {boolean} visible\r\n */\n\n\n const setIndicatorVisibility = visible => {\n if (isVisible !== visible) {\n isVisible = visible;\n toggleIndicatorClass('active', visible);\n }\n };\n\n const updatePreloaderVisibility = () => {\n var _pswp$currSlide;\n\n if (!((_pswp$currSlide = pswp.currSlide) !== null && _pswp$currSlide !== void 0 && _pswp$currSlide.content.isLoading())) {\n setIndicatorVisibility(false);\n\n if (delayTimeout) {\n clearTimeout(delayTimeout);\n delayTimeout = null;\n }\n\n return;\n }\n\n if (!delayTimeout) {\n // display loading indicator with delay\n delayTimeout = setTimeout(() => {\n var _pswp$currSlide2;\n\n setIndicatorVisibility(Boolean((_pswp$currSlide2 = pswp.currSlide) === null || _pswp$currSlide2 === void 0 ? void 0 : _pswp$currSlide2.content.isLoading()));\n delayTimeout = null;\n }, pswp.options.preloaderDelay);\n }\n };\n\n pswp.on('change', updatePreloaderVisibility);\n pswp.on('loadComplete', e => {\n if (pswp.currSlide === e.slide) {\n updatePreloaderVisibility();\n }\n }); // expose the method\n\n if (pswp.ui) {\n pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\n }\n }\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst counterIndicator = {\n name: 'counter',\n order: 5,\n onInit: (counterElement, pswp) => {\n pswp.on('change', () => {\n counterElement.innerText = pswp.currIndex + 1 + pswp.options.indexIndicatorSep + pswp.getNumItems();\n });\n }\n};\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n\n/**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */\n\nfunction setZoomedIn(el, isZoomedIn) {\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\n}\n\nclass UI {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isRegistered = false;\n /** @type {UIElementData[]} */\n\n this.uiElementsData = [];\n /** @type {(UIElement | UIElementData)[]} */\n\n this.items = [];\n /** @type {() => void} */\n\n this.updatePreloaderVisibility = () => {};\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */\n\n\n this._lastUpdatedZoomLevel = undefined;\n }\n\n init() {\n const {\n pswp\n } = this;\n this.isRegistered = false;\n this.uiElementsData = [closeButton, arrowPrev, arrowNext, zoomButton, loadingIndicator, counterIndicator];\n pswp.dispatch('uiRegister'); // sort by order\n\n this.uiElementsData.sort((a, b) => {\n // default order is 0\n return (a.order || 0) - (b.order || 0);\n });\n this.items = [];\n this.isRegistered = true;\n this.uiElementsData.forEach(uiElementData => {\n this.registerElement(uiElementData);\n });\n pswp.on('change', () => {\n var _pswp$element;\n\n (_pswp$element = pswp.element) === null || _pswp$element === void 0 || _pswp$element.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\n });\n pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate());\n }\n /**\r\n * @param {UIElementData} elementData\r\n */\n\n\n registerElement(elementData) {\n if (this.isRegistered) {\n this.items.push(new UIElement(this.pswp, elementData));\n } else {\n this.uiElementsData.push(elementData);\n }\n }\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */\n\n\n _onZoomPanUpdate() {\n const {\n template,\n currSlide,\n options\n } = this.pswp;\n\n if (this.pswp.opener.isClosing || !template || !currSlide) {\n return;\n }\n\n let {\n currZoomLevel\n } = currSlide; // if not open yet - check against initial zoom level\n\n if (!this.pswp.opener.isOpen) {\n currZoomLevel = currSlide.zoomLevels.initial;\n }\n\n if (currZoomLevel === this._lastUpdatedZoomLevel) {\n return;\n }\n\n this._lastUpdatedZoomLevel = currZoomLevel;\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary; // Initial and secondary zoom levels are almost equal\n\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\n // disable zoom\n setZoomedIn(template, false);\n template.classList.remove('pswp--zoom-allowed');\n return;\n }\n\n template.classList.add('pswp--zoom-allowed');\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\n setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\n\n if (options.imageClickAction === 'zoom' || options.imageClickAction === 'zoom-or-close') {\n template.classList.add('pswp--click-to-zoom');\n }\n }\n\n}\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */\n\n/**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */\nfunction getBoundsByElement(el) {\n const thumbAreaRect = el.getBoundingClientRect();\n return {\n x: thumbAreaRect.left,\n y: thumbAreaRect.top,\n w: thumbAreaRect.width\n };\n}\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */\n\n\nfunction getCroppedBoundsByElement(el, imageWidth, imageHeight) {\n const thumbAreaRect = el.getBoundingClientRect(); // fill image into the area\n // (do they same as object-fit:cover does to retrieve coordinates)\n\n const hRatio = thumbAreaRect.width / imageWidth;\n const vRatio = thumbAreaRect.height / imageHeight;\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */\n\n const bounds = {\n x: thumbAreaRect.left + offsetX,\n y: thumbAreaRect.top + offsetY,\n w: imageWidth * fillZoomLevel\n }; // Coordinates of inner crop area\n // relative to the image\n\n bounds.innerRect = {\n w: thumbAreaRect.width,\n h: thumbAreaRect.height,\n x: offsetX,\n y: offsetY\n };\n return bounds;\n}\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */\n\n\nfunction getThumbBounds(index, itemData, instance) {\n // legacy event, before filters were introduced\n const event = instance.dispatch('thumbBounds', {\n index,\n itemData,\n instance\n }); // @ts-expect-error\n\n if (event.thumbBounds) {\n // @ts-expect-error\n return event.thumbBounds;\n }\n\n const {\n element\n } = itemData;\n /** @type {Bounds | undefined} */\n\n let thumbBounds;\n /** @type {HTMLElement | null | undefined} */\n\n let thumbnail;\n\n if (element && instance.options.thumbSelector !== false) {\n const thumbSelector = instance.options.thumbSelector || 'img';\n thumbnail = element.matches(thumbSelector) ? element :\n /** @type {HTMLElement | null} */\n element.querySelector(thumbSelector);\n }\n\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\n\n if (thumbnail) {\n if (!itemData.thumbCropped) {\n thumbBounds = getBoundsByElement(thumbnail);\n } else {\n thumbBounds = getCroppedBoundsByElement(thumbnail, itemData.width || itemData.w || 0, itemData.height || itemData.h || 0);\n }\n }\n\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\n}\n\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n\n/** @typedef {import('../slide/slide.js').default} Slide */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\n\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\n\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\n\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\nclass PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\n\n\nclass Eventable {\n constructor() {\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\n this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\n\n this._filters = {};\n /** @type {PhotoSwipe | undefined} */\n\n this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */\n\n this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\n\n\n addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn,\n priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2) => f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\n\n\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => filter.fn !== fn);\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\n\n\n applyFilters(name, ...args) {\n var _this$_filters$name3;\n\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach(filter => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n off(name, fn) {\n var _this$pswp3;\n\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => fn !== listener);\n }\n\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\n\n\n dispatch(name, details) {\n var _this$_listeners$name2;\n\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event =\n /** @type {AugmentedEvent} */\n new PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach(listener => {\n listener.call(this, event);\n });\n return event;\n }\n\n}\n\nclass Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n\n if (imageSrc) {\n const imgEl =\n /** @type {HTMLImageElement} */\n this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n var _this$element;\n\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) {\n this.element.remove();\n }\n\n this.element = null;\n }\n\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n\n this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\n\n\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\n\n\n loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n const imageElement =\n /** @type HTMLImageElement */\n this.element;\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\n\n\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */\n\n\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n /**\r\n * Content load error handler\r\n */\n\n\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\n\n\n isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\n\n\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */\n\n\n isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch('contentResize', {\n content: this,\n width,\n height\n }).defaultPrevented) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width,\n height,\n content: this\n });\n }\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\n\n\n isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\n\n\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image =\n /** @type HTMLImageElement */\n this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\n\n\n usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */\n\n\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\n\n\n keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */\n\n\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */\n\n\n displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl =\n /** @type {HTMLDivElement} */\n this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */\n\n\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n\n /** @type {HTMLImageElement} */\n\n this.element.decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\n\n\n activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n /**\r\n * Deactivate the content\r\n */\n\n\n deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n /**\r\n * Remove the content from DOM\r\n */\n\n\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n /**\r\n * Append the image content to slide container\r\n */\n\n\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) {\n return;\n } // ensure that element exists and is not already appended\n\n\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n\n}\n\n/** @typedef {import('./content.js').default} Content */\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\nconst MIN_SLIDES_TO_CACHE = 5;\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\nfunction lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n\n let zoomLevel;\n const {\n options\n } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n let viewportSize;\n\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n }\n\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\n\nfunction lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', {\n index,\n itemData\n }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\nclass ContentLoader {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp; // Total amount of cached images\n\n this.limit = Math.max(pswp.options.preload[0] + pswp.options.preload[1] + 1, MIN_SLIDES_TO_CACHE);\n /** @type {Content[]} */\n\n this._cachedItems = [];\n }\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\n\n\n updateLazy(diff) {\n const {\n pswp\n } = this;\n\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\n return;\n }\n\n const {\n preload\n } = pswp.options;\n const isForward = diff === undefined ? true : diff >= 0;\n let i; // preload[1] - num items to preload in forward direction\n\n for (i = 0; i <= preload[1]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : -i));\n } // preload[0] - num items to preload in backward direction\n\n\n for (i = 1; i <= preload[0]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? -i : i));\n }\n }\n /**\r\n * @param {number} initialIndex\r\n */\n\n\n loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex); // try to get cached content\n\n let content = this.getContentByIndex(index);\n\n if (!content) {\n // no cached content, so try to load from scratch:\n content = lazyLoadSlide(index, this.pswp); // if content can be loaded, add it to cache:\n\n if (content) {\n this.addToCache(content);\n }\n }\n }\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\n\n\n getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n } // assign slide to content\n\n\n content.setSlide(slide);\n return content;\n }\n /**\r\n * @param {Content} content\r\n */\n\n\n addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n\n this._cachedItems.push(content);\n\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex(item => {\n return !item.isAttached && !item.hasSlide;\n });\n\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n\n removedItem.destroy();\n }\n }\n }\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\n\n\n removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\n\n if (indexToRemove !== -1) {\n this._cachedItems.splice(indexToRemove, 1);\n }\n }\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\n\n\n getContentByIndex(index) {\n return this._cachedItems.find(content => content.index === index);\n }\n\n destroy() {\n this._cachedItems.forEach(content => content.destroy());\n\n this._cachedItems = [];\n }\n\n}\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\n\nclass PhotoSwipeBase extends Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\n getNumItems() {\n var _this$options;\n\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n } // legacy event, before filters were introduced\n\n\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\n\n\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\n\n\n getItemData(index) {\n var _this$options2;\n\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */\n\n let dataSourceItem = {};\n\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n } // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n\n\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\n\n\n _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) {\n return getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n }\n\n return [galleryElement];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\n\n\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n const linkEl =\n /** @type {HTMLAnchorElement} */\n element.tagName === 'A' ? element : element.querySelector('a');\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\n\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */\n// some browsers do not paint\n// elements which opacity is set to 0,\n// since we need to pre-render elements for the animation -\n// we set it to the minimum amount\n\nconst MIN_OPACITY = 0.003;\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */\n\nclass Opener {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isClosed = true;\n this.isOpen = false;\n this.isClosing = false;\n this.isOpening = false;\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */\n\n this._duration = undefined;\n /** @private */\n\n this._useAnimation = false;\n /** @private */\n\n this._croppedZoom = false;\n /** @private */\n\n this._animateRootOpacity = false;\n /** @private */\n\n this._animateBgOpacity = false;\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */\n\n this._placeholder = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\n\n this._opacityElement = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\n\n this._cropContainer1 = undefined;\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */\n\n this._cropContainer2 = undefined;\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */\n\n this._thumbBounds = undefined;\n this._prepareOpen = this._prepareOpen.bind(this); // Override initial zoom and pan position\n\n pswp.on('firstZoomPan', this._prepareOpen);\n }\n\n open() {\n this._prepareOpen();\n\n this._start();\n }\n\n close() {\n if (this.isClosed || this.isClosing || this.isOpening) {\n // if we close during opening animation\n // for now do nothing,\n // browsers aren't good at changing the direction of the CSS transition\n return;\n }\n\n const slide = this.pswp.currSlide;\n this.isOpen = false;\n this.isOpening = false;\n this.isClosing = true;\n this._duration = this.pswp.options.hideAnimationDuration;\n\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n\n this._applyStartProps();\n\n setTimeout(() => {\n this._start();\n }, this._croppedZoom ? 30 : 0);\n }\n /** @private */\n\n\n _prepareOpen() {\n this.pswp.off('firstZoomPan', this._prepareOpen);\n\n if (!this.isOpening) {\n const slide = this.pswp.currSlide;\n this.isOpening = true;\n this.isClosing = false;\n this._duration = this.pswp.options.showAnimationDuration;\n\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n\n this._applyStartProps();\n }\n }\n /** @private */\n\n\n _applyStartProps() {\n const {\n pswp\n } = this;\n const slide = this.pswp.currSlide;\n const {\n options\n } = pswp;\n\n if (options.showHideAnimationType === 'fade') {\n options.showHideOpacity = true;\n this._thumbBounds = undefined;\n } else if (options.showHideAnimationType === 'none') {\n options.showHideOpacity = false;\n this._duration = 0;\n this._thumbBounds = undefined;\n } else if (this.isOpening && pswp._initialThumbBounds) {\n // Use initial bounds if defined\n this._thumbBounds = pswp._initialThumbBounds;\n } else {\n this._thumbBounds = this.pswp.getThumbBounds();\n }\n\n this._placeholder = slide === null || slide === void 0 ? void 0 : slide.getPlaceholderElement();\n pswp.animations.stopAll(); // Discard animations when duration is less than 50ms\n\n this._useAnimation = Boolean(this._duration && this._duration > 50);\n this._animateZoom = Boolean(this._thumbBounds) && (slide === null || slide === void 0 ? void 0 : slide.content.usePlaceholder()) && (!this.isClosing || !pswp.mainScroll.isShifted());\n\n if (!this._animateZoom) {\n this._animateRootOpacity = true;\n\n if (this.isOpening && slide) {\n slide.zoomAndPanToInitial();\n slide.applyCurrentZoomPan();\n }\n } else {\n var _options$showHideOpac;\n\n this._animateRootOpacity = (_options$showHideOpac = options.showHideOpacity) !== null && _options$showHideOpac !== void 0 ? _options$showHideOpac : false;\n }\n\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY;\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\n\n if (!this._useAnimation) {\n this._duration = 0;\n this._animateZoom = false;\n this._animateBgOpacity = false;\n this._animateRootOpacity = true;\n\n if (this.isOpening) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n\n pswp.applyBgOpacity(1);\n }\n\n return;\n }\n\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\n var _this$pswp$currSlide;\n\n // Properties are used when animation from cropped thumbnail\n this._croppedZoom = true;\n this._cropContainer1 = this.pswp.container;\n this._cropContainer2 = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.holderElement;\n\n if (pswp.container) {\n pswp.container.style.overflow = 'hidden';\n pswp.container.style.width = pswp.viewportSize.x + 'px';\n }\n } else {\n this._croppedZoom = false;\n }\n\n if (this.isOpening) {\n // Apply styles before opening transition\n if (this._animateRootOpacity) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n\n pswp.applyBgOpacity(1);\n } else {\n if (this._animateBgOpacity && pswp.bg) {\n pswp.bg.style.opacity = String(MIN_OPACITY);\n }\n\n if (pswp.element) {\n pswp.element.style.opacity = '1';\n }\n }\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan();\n\n if (this._placeholder) {\n // tell browser that we plan to animate the placeholder\n this._placeholder.style.willChange = 'transform'; // hide placeholder to allow hiding of\n // elements that overlap it (such as icons over the thumbnail)\n\n this._placeholder.style.opacity = String(MIN_OPACITY);\n }\n }\n } else if (this.isClosing) {\n // hide nearby slides to make sure that\n // they are not painted during the transition\n if (pswp.mainScroll.itemHolders[0]) {\n pswp.mainScroll.itemHolders[0].el.style.display = 'none';\n }\n\n if (pswp.mainScroll.itemHolders[2]) {\n pswp.mainScroll.itemHolders[2].el.style.display = 'none';\n }\n\n if (this._croppedZoom) {\n if (pswp.mainScroll.x !== 0) {\n // shift the main scroller to zero position\n pswp.mainScroll.resetPosition();\n pswp.mainScroll.resize();\n }\n }\n }\n }\n /** @private */\n\n\n _start() {\n if (this.isOpening && this._useAnimation && this._placeholder && this._placeholder.tagName === 'IMG') {\n // To ensure smooth animation\n // we wait till the current slide image placeholder is decoded,\n // but no longer than 250ms,\n // and no shorter than 50ms\n // (just using requestanimationframe is not enough in Firefox,\n // for some reason)\n new Promise(resolve => {\n let decoded = false;\n let isDelaying = true;\n decodeImage(\n /** @type {HTMLImageElement} */\n this._placeholder).finally(() => {\n decoded = true;\n\n if (!isDelaying) {\n resolve(true);\n }\n });\n setTimeout(() => {\n isDelaying = false;\n\n if (decoded) {\n resolve(true);\n }\n }, 50);\n setTimeout(resolve, 250);\n }).finally(() => this._initiate());\n } else {\n this._initiate();\n }\n }\n /** @private */\n\n\n _initiate() {\n var _this$pswp$element, _this$pswp$element2;\n\n (_this$pswp$element = this.pswp.element) === null || _this$pswp$element === void 0 || _this$pswp$element.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\n this.pswp.dispatch(this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'); // legacy event\n\n this.pswp.dispatch(\n /** @type {'initialZoomIn' | 'initialZoomOut'} */\n 'initialZoom' + (this.isOpening ? 'In' : 'Out'));\n (_this$pswp$element2 = this.pswp.element) === null || _this$pswp$element2 === void 0 || _this$pswp$element2.classList.toggle('pswp--ui-visible', this.isOpening);\n\n if (this.isOpening) {\n if (this._placeholder) {\n // unhide the placeholder\n this._placeholder.style.opacity = '1';\n }\n\n this._animateToOpenState();\n } else if (this.isClosing) {\n this._animateToClosedState();\n }\n\n if (!this._useAnimation) {\n this._onAnimationComplete();\n }\n }\n /** @private */\n\n\n _onAnimationComplete() {\n const {\n pswp\n } = this;\n this.isOpen = this.isOpening;\n this.isClosed = this.isClosing;\n this.isOpening = false;\n this.isClosing = false;\n pswp.dispatch(this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'); // legacy event\n\n pswp.dispatch(\n /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */\n 'initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'));\n\n if (this.isClosed) {\n pswp.destroy();\n } else if (this.isOpen) {\n var _pswp$currSlide;\n\n if (this._animateZoom && pswp.container) {\n pswp.container.style.overflow = 'visible';\n pswp.container.style.width = '100%';\n }\n\n (_pswp$currSlide = pswp.currSlide) === null || _pswp$currSlide === void 0 || _pswp$currSlide.applyCurrentZoomPan();\n }\n }\n /** @private */\n\n\n _animateToOpenState() {\n const {\n pswp\n } = this;\n\n if (this._animateZoom) {\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\n\n this._animateTo(this._cropContainer2, 'transform', 'none');\n }\n\n if (pswp.currSlide) {\n pswp.currSlide.zoomAndPanToInitial();\n\n this._animateTo(pswp.currSlide.container, 'transform', pswp.currSlide.getCurrentTransform());\n }\n }\n\n if (this._animateBgOpacity && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '1');\n }\n }\n /** @private */\n\n\n _animateToClosedState() {\n const {\n pswp\n } = this;\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan(true);\n } // do not animate opacity if it's already at 0\n\n\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', '0');\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '0');\n }\n }\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */\n\n\n _setClosedStateZoomPan(animate) {\n if (!this._thumbBounds) return;\n const {\n pswp\n } = this;\n const {\n innerRect\n } = this._thumbBounds;\n const {\n currSlide,\n viewportSize\n } = pswp;\n\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\n const containerTwoPanX = viewportSize.x - innerRect.w;\n const containerTwoPanY = viewportSize.y - innerRect.h;\n\n if (animate) {\n this._animateTo(this._cropContainer1, 'transform', toTransformString(containerOnePanX, containerOnePanY));\n\n this._animateTo(this._cropContainer2, 'transform', toTransformString(containerTwoPanX, containerTwoPanY));\n } else {\n setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\n setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\n }\n }\n\n if (currSlide) {\n equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\n\n if (animate) {\n this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\n } else {\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */\n\n\n _animateTo(target, prop, propValue) {\n if (!this._duration) {\n target.style[prop] = propValue;\n return;\n }\n\n const {\n animations\n } = this.pswp;\n /** @type {AnimationProps} */\n\n const animProps = {\n duration: this._duration,\n easing: this.pswp.options.easing,\n onComplete: () => {\n if (!animations.activeAnimations.length) {\n this._onAnimationComplete();\n }\n },\n target\n };\n animProps[prop] = propValue;\n animations.startTransition(animProps);\n }\n\n}\n\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */\n\n/** @typedef {import('./slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */\n\n/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */\n\n/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n\n/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */\n\n/** @typedef {{ x: number; y: number; id?: string | number }} Point */\n\n/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */\n\n/** @typedef {SlideData[]} DataSourceArray */\n\n/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */\n\n/** @typedef {DataSourceArray | DataSourceObject} DataSource */\n\n/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */\n\n/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */\n\n/** @typedef {Type | { default: Type }} PhotoSwipeModule */\n\n/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */\n\n/**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */\n\n/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */\n\n/**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */\n\n/** @type {PreparedPhotoSwipeOptions} */\n\nconst defaultOptions = {\n allowPanToNext: true,\n spacing: 0.1,\n loop: true,\n pinchToClose: true,\n closeOnVerticalDrag: true,\n hideAnimationDuration: 333,\n showAnimationDuration: 333,\n zoomAnimationDuration: 333,\n escKey: true,\n arrowKeys: true,\n trapFocus: true,\n returnFocus: true,\n maxWidthToAnimate: 4000,\n clickToCloseNonZoomable: true,\n imageClickAction: 'zoom-or-close',\n bgClickAction: 'close',\n tapAction: 'toggle-controls',\n doubleTapAction: 'zoom',\n indexIndicatorSep: ' / ',\n preloaderDelay: 2000,\n bgOpacity: 0.8,\n index: 0,\n errorMsg: 'The image cannot be loaded',\n preload: [1, 2],\n easing: 'cubic-bezier(.4,0,.22,1)'\n};\n/**\r\n * PhotoSwipe Core\r\n */\n\nclass PhotoSwipe extends PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\n constructor(options) {\n super();\n this.options = this._prepareOptions(options || {});\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */\n\n this.offset = {\n x: 0,\n y: 0\n };\n /**\r\n * @type {Point}\r\n * @private\r\n */\n\n this._prevViewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */\n\n this.viewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * background (backdrop) opacity\r\n */\n\n this.bgOpacity = 1;\n this.currIndex = 0;\n this.potentialIndex = 0;\n this.isOpen = false;\n this.isDestroying = false;\n this.hasMouse = false;\n /**\r\n * @private\r\n * @type {SlideData}\r\n */\n\n this._initialItemData = {};\n /** @type {Bounds | undefined} */\n\n this._initialThumbBounds = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.topBar = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.template = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.container = undefined;\n /** @type {HTMLElement | undefined} */\n\n this.scrollWrap = undefined;\n /** @type {Slide | undefined} */\n\n this.currSlide = undefined;\n this.events = new DOMEvents();\n this.animations = new Animations();\n this.mainScroll = new MainScroll(this);\n this.gestures = new Gestures(this);\n this.opener = new Opener(this);\n this.keyboard = new Keyboard(this);\n this.contentLoader = new ContentLoader(this);\n }\n /** @returns {boolean} */\n\n\n init() {\n if (this.isOpen || this.isDestroying) {\n return false;\n }\n\n this.isOpen = true;\n this.dispatch('init'); // legacy\n\n this.dispatch('beforeOpen');\n\n this._createMainStructure(); // add classes to the root element of PhotoSwipe\n\n\n let rootClasses = 'pswp--open';\n\n if (this.gestures.supportsTouch) {\n rootClasses += ' pswp--touch';\n }\n\n if (this.options.mainClass) {\n rootClasses += ' ' + this.options.mainClass;\n }\n\n if (this.element) {\n this.element.className += ' ' + rootClasses;\n }\n\n this.currIndex = this.options.index || 0;\n this.potentialIndex = this.currIndex;\n this.dispatch('firstUpdate'); // starting index can be modified here\n // initialize scroll wheel handler to block the scroll\n\n this.scrollWheel = new ScrollWheel(this); // sanitize index\n\n if (Number.isNaN(this.currIndex) || this.currIndex < 0 || this.currIndex >= this.getNumItems()) {\n this.currIndex = 0;\n }\n\n if (!this.gestures.supportsTouch) {\n // enable mouse features if no touch support detected\n this.mouseDetected();\n } // causes forced synchronous layout\n\n\n this.updateSize();\n this.offset.y = window.pageYOffset;\n this._initialItemData = this.getItemData(this.currIndex);\n this.dispatch('gettingData', {\n index: this.currIndex,\n data: this._initialItemData,\n slide: undefined\n }); // *Layout* - calculate size and position of elements here\n\n this._initialThumbBounds = this.getThumbBounds();\n this.dispatch('initialLayout');\n this.on('openingAnimationEnd', () => {\n const {\n itemHolders\n } = this.mainScroll; // Add content to the previous and next slide\n\n if (itemHolders[0]) {\n itemHolders[0].el.style.display = 'block';\n this.setContent(itemHolders[0], this.currIndex - 1);\n }\n\n if (itemHolders[2]) {\n itemHolders[2].el.style.display = 'block';\n this.setContent(itemHolders[2], this.currIndex + 1);\n }\n\n this.appendHeavy();\n this.contentLoader.updateLazy();\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\n this.dispatch('bindEvents');\n }); // set content for center slide (first time)\n\n if (this.mainScroll.itemHolders[1]) {\n this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\n }\n\n this.dispatch('change');\n this.opener.open();\n this.dispatch('afterInit');\n return true;\n }\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */\n\n\n getLoopedIndex(index) {\n const numSlides = this.getNumItems();\n\n if (this.options.loop) {\n if (index > numSlides - 1) {\n index -= numSlides;\n }\n\n if (index < 0) {\n index += numSlides;\n }\n }\n\n return clamp(index, 0, numSlides - 1);\n }\n\n appendHeavy() {\n this.mainScroll.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide;\n\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.appendHeavy();\n });\n }\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */\n\n\n goTo(index) {\n this.mainScroll.moveIndexBy(this.getLoopedIndex(index) - this.potentialIndex);\n }\n /**\r\n * Go to the next slide.\r\n */\n\n\n next() {\n this.goTo(this.potentialIndex + 1);\n }\n /**\r\n * Go to the previous slide.\r\n */\n\n\n prev() {\n this.goTo(this.potentialIndex - 1);\n }\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */\n\n\n zoomTo(...args) {\n var _this$currSlide;\n\n (_this$currSlide = this.currSlide) === null || _this$currSlide === void 0 || _this$currSlide.zoomTo(...args);\n }\n /**\r\n * @see slide/slide.js toggleZoom\r\n */\n\n\n toggleZoom() {\n var _this$currSlide2;\n\n (_this$currSlide2 = this.currSlide) === null || _this$currSlide2 === void 0 || _this$currSlide2.toggleZoom();\n }\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */\n\n\n close() {\n if (!this.opener.isOpen || this.isDestroying) {\n return;\n }\n\n this.isDestroying = true;\n this.dispatch('close');\n this.events.removeAll();\n this.opener.close();\n }\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */\n\n\n destroy() {\n var _this$element;\n\n if (!this.isDestroying) {\n this.options.showHideAnimationType = 'none';\n this.close();\n return;\n }\n\n this.dispatch('destroy');\n this._listeners = {};\n\n if (this.scrollWrap) {\n this.scrollWrap.ontouchmove = null;\n this.scrollWrap.ontouchend = null;\n }\n\n (_this$element = this.element) === null || _this$element === void 0 || _this$element.remove();\n this.mainScroll.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide2;\n\n (_itemHolder$slide2 = itemHolder.slide) === null || _itemHolder$slide2 === void 0 || _itemHolder$slide2.destroy();\n });\n this.contentLoader.destroy();\n this.events.removeAll();\n }\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */\n\n\n refreshSlideContent(slideIndex) {\n this.contentLoader.removeByIndex(slideIndex);\n this.mainScroll.itemHolders.forEach((itemHolder, i) => {\n var _this$currSlide$index, _this$currSlide3;\n\n let potentialHolderIndex = ((_this$currSlide$index = (_this$currSlide3 = this.currSlide) === null || _this$currSlide3 === void 0 ? void 0 : _this$currSlide3.index) !== null && _this$currSlide$index !== void 0 ? _this$currSlide$index : 0) - 1 + i;\n\n if (this.canLoop()) {\n potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\n }\n\n if (potentialHolderIndex === slideIndex) {\n // set the new slide content\n this.setContent(itemHolder, slideIndex, true); // activate the new slide if it's current\n\n if (i === 1) {\n var _itemHolder$slide3;\n\n this.currSlide = itemHolder.slide;\n (_itemHolder$slide3 = itemHolder.slide) === null || _itemHolder$slide3 === void 0 || _itemHolder$slide3.setIsActive(true);\n }\n }\n });\n this.dispatch('change');\n }\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */\n\n\n setContent(holder, index, force) {\n if (this.canLoop()) {\n index = this.getLoopedIndex(index);\n }\n\n if (holder.slide) {\n if (holder.slide.index === index && !force) {\n // exit if holder already contains this slide\n // this could be common when just three slides are used\n return;\n } // destroy previous slide\n\n\n holder.slide.destroy();\n holder.slide = undefined;\n } // exit if no loop and index is out of bounds\n\n\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) {\n return;\n }\n\n const itemData = this.getItemData(index);\n holder.slide = new Slide(itemData, index, this); // set current slide\n\n if (index === this.currIndex) {\n this.currSlide = holder.slide;\n }\n\n holder.slide.append(holder.el);\n }\n /** @returns {Point} */\n\n\n getViewportCenterPoint() {\n return {\n x: this.viewportSize.x / 2,\n y: this.viewportSize.y / 2\n };\n }\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */\n\n\n updateSize(force) {\n // let item;\n // let itemIndex;\n if (this.isDestroying) {\n // exit if PhotoSwipe is closed or closing\n // (to avoid errors, as resize event might be delayed)\n return;\n } //const newWidth = this.scrollWrap.clientWidth;\n //const newHeight = this.scrollWrap.clientHeight;\n\n\n const newViewportSize = getViewportSize(this.options, this);\n\n if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) {\n // Exit if dimensions were not changed\n return;\n } //this._prevViewportSize.x = newWidth;\n //this._prevViewportSize.y = newHeight;\n\n\n equalizePoints(this._prevViewportSize, newViewportSize);\n this.dispatch('beforeResize');\n equalizePoints(this.viewportSize, this._prevViewportSize);\n\n this._updatePageScrollOffset();\n\n this.dispatch('viewportSize'); // Resize slides only after opener animation is finished\n // and don't re-calculate size on inital size update\n\n this.mainScroll.resize(this.opener.isOpen);\n\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) {\n this.mouseDetected();\n }\n\n this.dispatch('resize');\n }\n /**\r\n * @param {number} opacity\r\n */\n\n\n applyBgOpacity(opacity) {\n this.bgOpacity = Math.max(opacity, 0);\n\n if (this.bg) {\n this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\n }\n }\n /**\r\n * Whether mouse is detected\r\n */\n\n\n mouseDetected() {\n if (!this.hasMouse) {\n var _this$element2;\n\n this.hasMouse = true;\n (_this$element2 = this.element) === null || _this$element2 === void 0 || _this$element2.classList.add('pswp--has_mouse');\n }\n }\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */\n\n\n _handlePageResize() {\n this.updateSize(); // In iOS webview, if element size depends on document size,\n // it'll be measured incorrectly in resize event\n //\n // https://bugs.webkit.org/show_bug.cgi?id=170595\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\n\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) {\n setTimeout(() => {\n this.updateSize();\n }, 500);\n }\n }\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */\n\n\n _updatePageScrollOffset() {\n this.setScrollOffset(0, window.pageYOffset);\n }\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */\n\n\n setScrollOffset(x, y) {\n this.offset.x = x;\n this.offset.y = y;\n this.dispatch('updateScrollOffset');\n }\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */\n\n\n _createMainStructure() {\n // root DOM element of PhotoSwipe (.pswp)\n this.element = createElement('pswp', 'div');\n this.element.setAttribute('tabindex', '-1');\n this.element.setAttribute('role', 'dialog'); // template is legacy prop\n\n this.template = this.element; // Background is added as a separate element,\n // as animating opacity is faster than animating rgba()\n\n this.bg = createElement('pswp__bg', 'div', this.element);\n this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element);\n this.container = createElement('pswp__container', 'div', this.scrollWrap); // aria pattern: carousel\n\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\n this.container.setAttribute('aria-live', 'off');\n this.container.setAttribute('id', 'pswp__items');\n this.mainScroll.appendHolders();\n this.ui = new UI(this);\n this.ui.init(); // append to DOM\n\n (this.options.appendToEl || document.body).appendChild(this.element);\n }\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */\n\n\n getThumbBounds() {\n return getThumbBounds(this.currIndex, this.currSlide ? this.currSlide.data : this._initialItemData, this);\n }\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */\n\n\n canLoop() {\n return this.options.loop && this.getNumItems() > 2;\n }\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */\n\n\n _prepareOptions(options) {\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\n options.showHideAnimationType = 'none';\n options.zoomAnimationDuration = 0;\n }\n /** @type {PreparedPhotoSwipeOptions} */\n\n\n return { ...defaultOptions,\n ...options\n };\n }\n\n}\n\nexport { PhotoSwipe as default };\n//# sourceMappingURL=photoswipe.esm.js.map\n","/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\r\nexport function createElement(className, tagName, appendToEl) {\r\n const el = document.createElement(tagName);\r\n if (className) {\r\n el.className = className;\r\n }\r\n if (appendToEl) {\r\n appendToEl.appendChild(el);\r\n }\r\n return el;\r\n}\r\n\r\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nexport function equalizePoints(p1, p2) {\r\n p1.x = p2.x;\r\n p1.y = p2.y;\r\n if (p2.id !== undefined) {\r\n p1.id = p2.id;\r\n }\r\n return p1;\r\n}\r\n\r\n/**\r\n * @param {Point} p\r\n */\r\nexport function roundPoint(p) {\r\n p.x = Math.round(p.x);\r\n p.y = Math.round(p.y);\r\n}\r\n\r\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\r\nexport function getDistanceBetween(p1, p2) {\r\n const x = Math.abs(p1.x - p2.x);\r\n const y = Math.abs(p1.y - p2.y);\r\n return Math.sqrt((x * x) + (y * y));\r\n}\r\n\r\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\r\nexport function pointsEqual(p1, p2) {\r\n return p1.x === p2.x && p1.y === p2.y;\r\n}\r\n\r\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\r\nexport function clamp(val, min, max) {\r\n return Math.min(Math.max(val, min), max);\r\n}\r\n\r\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\r\nexport function toTransformString(x, y, scale) {\r\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\r\n\r\n if (scale !== undefined) {\r\n propValue += ` scale3d(${scale},${scale},1)`;\r\n }\r\n\r\n return propValue;\r\n}\r\n\r\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\r\nexport function setTransform(el, x, y, scale) {\r\n el.style.transform = toTransformString(x, y, scale);\r\n}\r\n\r\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\r\nexport function setTransitionStyle(el, prop, duration, ease) {\r\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\r\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\r\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\r\n el.style.transition = prop\r\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\r\n : 'none';\r\n}\r\n\r\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\r\nexport function setWidthHeight(el, w, h) {\r\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\r\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n */\r\nexport function removeTransitionStyle(el) {\r\n setTransitionStyle(el);\r\n}\r\n\r\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\r\nexport function decodeImage(img) {\r\n if ('decode' in img) {\r\n return img.decode().catch(() => {});\r\n }\r\n\r\n if (img.complete) {\r\n return Promise.resolve(img);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n img.onload = () => resolve(img);\r\n img.onerror = reject;\r\n });\r\n}\r\n\r\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\r\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\r\nexport const LOAD_STATE = {\r\n IDLE: 'idle',\r\n LOADING: 'loading',\r\n LOADED: 'loaded',\r\n ERROR: 'error',\r\n};\r\n\r\n\r\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\r\nexport function specialKeyUsed(e) {\r\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\r\n}\r\n\r\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\r\nexport function getElementsFromOption(option, legacySelector, parent = document) {\r\n /** @type {HTMLElement[]} */\r\n let elements = [];\r\n\r\n if (option instanceof Element) {\r\n elements = [option];\r\n } else if (option instanceof NodeList || Array.isArray(option)) {\r\n elements = Array.from(option);\r\n } else {\r\n const selector = typeof option === 'string' ? option : legacySelector;\r\n if (selector) {\r\n elements = Array.from(parent.querySelectorAll(selector));\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\r\nexport function isPswpClass(fn) {\r\n return typeof fn === 'function'\r\n && fn.prototype\r\n && fn.prototype.goTo;\r\n}\r\n\r\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\r\nexport function isSafari() {\r\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\r\n}\r\n\r\n","// Detect passive event listener support\r\nlet supportsPassive = false;\r\n/* eslint-disable */\r\ntry {\r\n /* @ts-ignore */\r\n window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\r\n get: () => {\r\n supportsPassive = true;\r\n }\r\n }));\r\n} catch (e) {}\r\n/* eslint-enable */\r\n\r\n/**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */\r\n\r\nclass DOMEvents {\r\n constructor() {\r\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */\r\n this._pool = [];\r\n }\r\n\r\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\r\n add(target, type, listener, passive) {\r\n this._toggleListener(target, type, listener, passive);\r\n }\r\n\r\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\r\n remove(target, type, listener, passive) {\r\n this._toggleListener(target, type, listener, passive, true);\r\n }\r\n\r\n /**\r\n * Removes all bound events\r\n */\r\n removeAll() {\r\n this._pool.forEach((poolItem) => {\r\n this._toggleListener(\r\n poolItem.target,\r\n poolItem.type,\r\n poolItem.listener,\r\n poolItem.passive,\r\n true,\r\n true\r\n );\r\n });\r\n this._pool = [];\r\n }\r\n\r\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */\r\n _toggleListener(target, type, listener, passive, unbind, skipPool) {\r\n if (!target) {\r\n return;\r\n }\r\n\r\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\r\n const types = type.split(' ');\r\n types.forEach((eType) => {\r\n if (eType) {\r\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\r\n // so developer doesn't need to do this manually\r\n if (!skipPool) {\r\n if (unbind) {\r\n // Remove from the events pool\r\n this._pool = this._pool.filter((poolItem) => {\r\n return poolItem.type !== eType\r\n || poolItem.listener !== listener\r\n || poolItem.target !== target;\r\n });\r\n } else {\r\n // Add to the events pool\r\n this._pool.push({\r\n target,\r\n type: eType,\r\n listener,\r\n passive\r\n });\r\n }\r\n }\r\n\r\n // most PhotoSwipe events call preventDefault,\r\n // and we do not need browser to scroll the page\r\n const eventOptions = supportsPassive ? { passive: (passive || false) } : false;\r\n\r\n target[methodName](\r\n eType,\r\n listener,\r\n eventOptions\r\n );\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport default DOMEvents;\r\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\r\nexport function getViewportSize(options, pswp) {\r\n if (options.getViewportSizeFn) {\r\n const newViewportSize = options.getViewportSizeFn(options, pswp);\r\n if (newViewportSize) {\r\n return newViewportSize;\r\n }\r\n }\r\n\r\n return {\r\n x: document.documentElement.clientWidth,\r\n\r\n // TODO: height on mobile is very incosistent due to toolbar\r\n // find a way to improve this\r\n //\r\n // document.documentElement.clientHeight - doesn't seem to work well\r\n y: window.innerHeight\r\n };\r\n}\r\n\r\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\r\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\r\n let paddingValue = 0;\r\n\r\n if (options.paddingFn) {\r\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\r\n } else if (options.padding) {\r\n paddingValue = options.padding[prop];\r\n } else {\r\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\r\n // @ts-expect-error\r\n if (options[legacyPropName]) {\r\n // @ts-expect-error\r\n paddingValue = options[legacyPropName];\r\n }\r\n }\r\n\r\n return Number(paddingValue) || 0;\r\n}\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\r\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\r\n return {\r\n x: viewportSize.x\r\n - parsePaddingOption('left', options, viewportSize, itemData, index)\r\n - parsePaddingOption('right', options, viewportSize, itemData, index),\r\n y: viewportSize.y\r\n - parsePaddingOption('top', options, viewportSize, itemData, index)\r\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\r\n };\r\n}\r\n","import { clamp } from '../util/util.js';\r\nimport { parsePaddingOption } from '../util/viewport-size.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {Record} Point */\r\n/** @typedef {'x' | 'y'} Axis */\r\n\r\n/**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */\r\nclass PanBounds {\r\n /**\r\n * @param {Slide} slide\r\n */\r\n constructor(slide) {\r\n this.slide = slide;\r\n this.currZoomLevel = 1;\r\n this.center = /** @type {Point} */ { x: 0, y: 0 };\r\n this.max = /** @type {Point} */ { x: 0, y: 0 };\r\n this.min = /** @type {Point} */ { x: 0, y: 0 };\r\n }\r\n\r\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */\r\n update(currZoomLevel) {\r\n this.currZoomLevel = currZoomLevel;\r\n\r\n if (!this.slide.width) {\r\n this.reset();\r\n } else {\r\n this._updateAxis('x');\r\n this._updateAxis('y');\r\n this.slide.pswp.dispatch('calcBounds', { slide: this.slide });\r\n }\r\n }\r\n\r\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */\r\n _updateAxis(axis) {\r\n const { pswp } = this.slide;\r\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\r\n const paddingProp = axis === 'x' ? 'left' : 'top';\r\n const padding = parsePaddingOption(\r\n paddingProp,\r\n pswp.options,\r\n pswp.viewportSize,\r\n this.slide.data,\r\n this.slide.index\r\n );\r\n\r\n const panAreaSize = this.slide.panAreaSize[axis];\r\n\r\n // Default position of element.\r\n // By default, it is center of viewport:\r\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding;\r\n\r\n // maximum pan position\r\n this.max[axis] = (elSize > panAreaSize)\r\n ? Math.round(panAreaSize - elSize) + padding\r\n : this.center[axis];\r\n\r\n // minimum pan position\r\n this.min[axis] = (elSize > panAreaSize)\r\n ? padding\r\n : this.center[axis];\r\n }\r\n\r\n // _getZeroBounds\r\n reset() {\r\n this.center.x = 0;\r\n this.center.y = 0;\r\n this.max.x = 0;\r\n this.max.y = 0;\r\n this.min.x = 0;\r\n this.min.y = 0;\r\n }\r\n\r\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */\r\n correctPan(axis, panOffset) { // checkPanBounds\r\n return clamp(panOffset, this.max[axis], this.min[axis]);\r\n }\r\n}\r\n\r\nexport default PanBounds;\r\n","const MAX_IMAGE_WIDTH = 4000;\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\r\n\r\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\r\nclass ZoomLevel {\r\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\r\n constructor(options, itemData, index, pswp) {\r\n this.pswp = pswp;\r\n this.options = options;\r\n this.itemData = itemData;\r\n this.index = index;\r\n /** @type { Point | null } */\r\n this.panAreaSize = null;\r\n /** @type { Point | null } */\r\n this.elementSize = null;\r\n this.fit = 1;\r\n this.fill = 1;\r\n this.vFill = 1;\r\n this.initial = 1;\r\n this.secondary = 1;\r\n this.max = 1;\r\n this.min = 1;\r\n }\r\n\r\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\r\n update(maxWidth, maxHeight, panAreaSize) {\r\n /** @type {Point} */\r\n const elementSize = { x: maxWidth, y: maxHeight };\r\n this.elementSize = elementSize;\r\n this.panAreaSize = panAreaSize;\r\n\r\n const hRatio = panAreaSize.x / elementSize.x;\r\n const vRatio = panAreaSize.y / elementSize.y;\r\n\r\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\r\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\r\n\r\n // zoom.vFill defines zoom level of the image\r\n // when it has 100% of viewport vertical space (height)\r\n this.vFill = Math.min(1, vRatio);\r\n\r\n this.initial = this._getInitial();\r\n this.secondary = this._getSecondary();\r\n this.max = Math.max(\r\n this.initial,\r\n this.secondary,\r\n this._getMax()\r\n );\r\n\r\n this.min = Math.min(\r\n this.fit,\r\n this.initial,\r\n this.secondary\r\n );\r\n\r\n if (this.pswp) {\r\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\r\n }\r\n }\r\n\r\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\r\n _parseZoomLevelOption(optionPrefix) {\r\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\r\n optionPrefix + 'ZoomLevel'\r\n );\r\n const optionValue = this.options[optionName];\r\n\r\n if (!optionValue) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n return optionValue(this);\r\n }\r\n\r\n if (optionValue === 'fill') {\r\n return this.fill;\r\n }\r\n\r\n if (optionValue === 'fit') {\r\n return this.fit;\r\n }\r\n\r\n return Number(optionValue);\r\n }\r\n\r\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getSecondary() {\r\n let currZoomLevel = this._parseZoomLevelOption('secondary');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // 3x of \"fit\" state, but not larger than original\r\n currZoomLevel = Math.min(1, this.fit * 3);\r\n\r\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\r\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\r\n }\r\n\r\n return currZoomLevel;\r\n }\r\n\r\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getInitial() {\r\n return this._parseZoomLevelOption('initial') || this.fit;\r\n }\r\n\r\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getMax() {\r\n // max zoom level is x4 from \"fit state\",\r\n // used for zoom gesture and ctrl/trackpad zoom\r\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\r\n }\r\n}\r\n\r\nexport default ZoomLevel;\r\n","/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @typedef {_SlideData & Record} SlideData\r\n * @typedef {Object} _SlideData\r\n * @prop {HTMLElement} [element] thumbnail element\r\n * @prop {string} [src] image URL\r\n * @prop {string} [srcset] image srcset\r\n * @prop {number} [w] image width (deprecated)\r\n * @prop {number} [h] image height (deprecated)\r\n * @prop {number} [width] image width\r\n * @prop {number} [height] image height\r\n * @prop {string} [msrc] placeholder image URL that's displayed before large image is loaded\r\n * @prop {string} [alt] image alt text\r\n * @prop {boolean} [thumbCropped] whether thumbnail is cropped client-side or not\r\n * @prop {string} [html] html content of a slide\r\n * @prop {'image' | 'html' | string} [type] slide type\r\n */\r\n\r\nimport {\r\n createElement,\r\n setTransform,\r\n equalizePoints,\r\n roundPoint,\r\n toTransformString,\r\n clamp,\r\n} from '../util/util.js';\r\n\r\nimport PanBounds from './pan-bounds.js';\r\nimport ZoomLevel from './zoom-level.js';\r\nimport { getPanAreaSize } from '../util/viewport-size.js';\r\n\r\n/**\r\n * Renders and allows to control a single slide\r\n */\r\nclass Slide {\r\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(data, index, pswp) {\r\n this.data = data;\r\n this.index = index;\r\n this.pswp = pswp;\r\n this.isActive = (index === pswp.currIndex);\r\n this.currentResolution = 0;\r\n /** @type {Point} */\r\n this.panAreaSize = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.pan = { x: 0, y: 0 };\r\n\r\n this.isFirstSlide = (this.isActive && !pswp.opener.isOpen);\r\n\r\n this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp);\r\n\r\n this.pswp.dispatch('gettingData', {\r\n slide: this,\r\n data: this.data,\r\n index\r\n });\r\n\r\n this.content = this.pswp.contentLoader.getContentBySlide(this);\r\n this.container = createElement('pswp__zoom-wrap', 'div');\r\n /** @type {HTMLElement | null} */\r\n this.holderElement = null;\r\n\r\n this.currZoomLevel = 1;\r\n /** @type {number} */\r\n this.width = this.content.width;\r\n /** @type {number} */\r\n this.height = this.content.height;\r\n this.heavyAppended = false;\r\n this.bounds = new PanBounds(this);\r\n\r\n this.prevDisplayedWidth = -1;\r\n this.prevDisplayedHeight = -1;\r\n\r\n this.pswp.dispatch('slideInit', { slide: this });\r\n }\r\n\r\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */\r\n setIsActive(isActive) {\r\n if (isActive && !this.isActive) {\r\n // slide just became active\r\n this.activate();\r\n } else if (!isActive && this.isActive) {\r\n // slide just became non-active\r\n this.deactivate();\r\n }\r\n }\r\n\r\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */\r\n append(holderElement) {\r\n this.holderElement = holderElement;\r\n\r\n this.container.style.transformOrigin = '0 0';\r\n\r\n // Slide appended to DOM\r\n if (!this.data) {\r\n return;\r\n }\r\n\r\n this.calculateSize();\r\n\r\n this.load();\r\n this.updateContentSize();\r\n this.appendHeavy();\r\n\r\n this.holderElement.appendChild(this.container);\r\n\r\n this.zoomAndPanToInitial();\r\n\r\n this.pswp.dispatch('firstZoomPan', { slide: this });\r\n\r\n this.applyCurrentZoomPan();\r\n\r\n this.pswp.dispatch('afterSetContent', { slide: this });\r\n\r\n if (this.isActive) {\r\n this.activate();\r\n }\r\n }\r\n\r\n load() {\r\n this.content.load(false);\r\n this.pswp.dispatch('slideLoad', { slide: this });\r\n }\r\n\r\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */\r\n appendHeavy() {\r\n const { pswp } = this;\r\n const appendHeavyNearby = true; // todo\r\n\r\n // Avoid appending heavy elements during animations\r\n if (this.heavyAppended\r\n || !pswp.opener.isOpen\r\n || pswp.mainScroll.isShifted()\r\n || (!this.isActive && !appendHeavyNearby)) {\r\n return;\r\n }\r\n\r\n if (this.pswp.dispatch('appendHeavy', { slide: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.heavyAppended = true;\r\n\r\n this.content.append();\r\n\r\n this.pswp.dispatch('appendHeavyContent', { slide: this });\r\n }\r\n\r\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */\r\n activate() {\r\n this.isActive = true;\r\n this.appendHeavy();\r\n this.content.activate();\r\n this.pswp.dispatch('slideActivate', { slide: this });\r\n }\r\n\r\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */\r\n deactivate() {\r\n this.isActive = false;\r\n this.content.deactivate();\r\n\r\n if (this.currZoomLevel !== this.zoomLevels.initial) {\r\n // allow filtering\r\n this.calculateSize();\r\n }\r\n\r\n // reset zoom level\r\n this.currentResolution = 0;\r\n this.zoomAndPanToInitial();\r\n this.applyCurrentZoomPan();\r\n this.updateContentSize();\r\n\r\n this.pswp.dispatch('slideDeactivate', { slide: this });\r\n }\r\n\r\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */\r\n destroy() {\r\n this.content.hasSlide = false;\r\n this.content.remove();\r\n this.container.remove();\r\n this.pswp.dispatch('slideDestroy', { slide: this });\r\n }\r\n\r\n resize() {\r\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\r\n // Keep initial zoom level if it was before the resize,\r\n // as well as when this slide is not active\r\n\r\n // Reset position and scale to original state\r\n this.calculateSize();\r\n this.currentResolution = 0;\r\n this.zoomAndPanToInitial();\r\n this.applyCurrentZoomPan();\r\n this.updateContentSize();\r\n } else {\r\n // readjust pan position if it's beyond the bounds\r\n this.calculateSize();\r\n this.bounds.update(this.currZoomLevel);\r\n this.panTo(this.pan.x, this.pan.y);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */\r\n updateContentSize(force) {\r\n // Use initial zoom level\r\n // if resolution is not defined (user didn't zoom yet)\r\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\r\n\r\n if (!scaleMultiplier) {\r\n return;\r\n }\r\n\r\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\r\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\r\n\r\n if (!this.sizeChanged(width, height) && !force) {\r\n return;\r\n }\r\n this.content.setDisplayedSize(width, height);\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n sizeChanged(width, height) {\r\n if (width !== this.prevDisplayedWidth\r\n || height !== this.prevDisplayedHeight) {\r\n this.prevDisplayedWidth = width;\r\n this.prevDisplayedHeight = height;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */\r\n getPlaceholderElement() {\r\n return this.content.placeholder?.element;\r\n }\r\n\r\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */\r\n zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\r\n const { pswp } = this;\r\n if (!this.isZoomable()\r\n || pswp.mainScroll.isShifted()) {\r\n return;\r\n }\r\n\r\n pswp.dispatch('beforeZoomTo', {\r\n destZoomLevel, centerPoint, transitionDuration\r\n });\r\n\r\n // stop all pan and zoom transitions\r\n pswp.animations.stopAllPan();\r\n\r\n // if (!centerPoint) {\r\n // centerPoint = pswp.getViewportCenterPoint();\r\n // }\r\n\r\n const prevZoomLevel = this.currZoomLevel;\r\n\r\n if (!ignoreBounds) {\r\n destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\r\n }\r\n\r\n // if (transitionDuration === undefined) {\r\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\r\n // }\r\n\r\n this.setZoomLevel(destZoomLevel);\r\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\r\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\r\n roundPoint(this.pan);\r\n\r\n const finishTransition = () => {\r\n this._setResolution(destZoomLevel);\r\n this.applyCurrentZoomPan();\r\n };\r\n\r\n if (!transitionDuration) {\r\n finishTransition();\r\n } else {\r\n pswp.animations.startTransition({\r\n isPan: true,\r\n name: 'zoomTo',\r\n target: this.container,\r\n transform: this.getCurrentTransform(),\r\n onComplete: finishTransition,\r\n duration: transitionDuration,\r\n easing: pswp.options.easing\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} [centerPoint]\r\n */\r\n toggleZoom(centerPoint) {\r\n this.zoomTo(\r\n this.currZoomLevel === this.zoomLevels.initial\r\n ? this.zoomLevels.secondary : this.zoomLevels.initial,\r\n centerPoint,\r\n this.pswp.options.zoomAnimationDuration\r\n );\r\n }\r\n\r\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */\r\n setZoomLevel(currZoomLevel) {\r\n this.currZoomLevel = currZoomLevel;\r\n this.bounds.update(this.currZoomLevel);\r\n }\r\n\r\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */\r\n calculateZoomToPanOffset(axis, point, prevZoomLevel) {\r\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\r\n if (totalPanDistance === 0) {\r\n return this.bounds.center[axis];\r\n }\r\n\r\n if (!point) {\r\n point = this.pswp.getViewportCenterPoint();\r\n }\r\n\r\n if (!prevZoomLevel) {\r\n prevZoomLevel = this.zoomLevels.initial;\r\n }\r\n\r\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\r\n return this.bounds.correctPan(\r\n axis,\r\n (this.pan[axis] - point[axis]) * zoomFactor + point[axis]\r\n );\r\n }\r\n\r\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */\r\n panTo(panX, panY) {\r\n this.pan.x = this.bounds.correctPan('x', panX);\r\n this.pan.y = this.bounds.correctPan('y', panY);\r\n this.applyCurrentZoomPan();\r\n }\r\n\r\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */\r\n isPannable() {\r\n return Boolean(this.width) && (this.currZoomLevel > this.zoomLevels.fit);\r\n }\r\n\r\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */\r\n isZoomable() {\r\n return Boolean(this.width) && this.content.isZoomable();\r\n }\r\n\r\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */\r\n applyCurrentZoomPan() {\r\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\r\n if (this === this.pswp.currSlide) {\r\n this.pswp.dispatch('zoomPanUpdate', { slide: this });\r\n }\r\n }\r\n\r\n zoomAndPanToInitial() {\r\n this.currZoomLevel = this.zoomLevels.initial;\r\n\r\n // pan according to the zoom level\r\n this.bounds.update(this.currZoomLevel);\r\n equalizePoints(this.pan, this.bounds.center);\r\n this.pswp.dispatch('initialZoomPan', { slide: this });\r\n }\r\n\r\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */\r\n _applyZoomTransform(x, y, zoom) {\r\n zoom /= this.currentResolution || this.zoomLevels.initial;\r\n setTransform(this.container, x, y, zoom);\r\n }\r\n\r\n calculateSize() {\r\n const { pswp } = this;\r\n\r\n equalizePoints(\r\n this.panAreaSize,\r\n getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index)\r\n );\r\n\r\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\r\n\r\n pswp.dispatch('calcSlideSize', {\r\n slide: this\r\n });\r\n }\r\n\r\n /** @returns {string} */\r\n getCurrentTransform() {\r\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\r\n return toTransformString(this.pan.x, this.pan.y, scale);\r\n }\r\n\r\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */\r\n _setResolution(newResolution) {\r\n if (newResolution === this.currentResolution) {\r\n return;\r\n }\r\n\r\n this.currentResolution = newResolution;\r\n this.updateContentSize();\r\n\r\n this.pswp.dispatch('resolutionChanged');\r\n }\r\n}\r\n\r\nexport default Slide;\r\n","import {\r\n equalizePoints, roundPoint, clamp\r\n} from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n\r\nconst PAN_END_FRICTION = 0.35;\r\nconst VERTICAL_DRAG_FRICTION = 0.6;\r\n\r\n// 1 corresponds to the third of viewport height\r\nconst MIN_RATIO_TO_CLOSE = 0.4;\r\n\r\n// Minimum speed required to navigate\r\n// to next or previous slide\r\nconst MIN_NEXT_SLIDE_SPEED = 0.5;\r\n\r\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */\r\nfunction project(initialVelocity, decelerationRate) {\r\n return initialVelocity * decelerationRate / (1 - decelerationRate);\r\n}\r\n\r\n/**\r\n * Handles single pointer dragging\r\n */\r\nclass DragHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n this.pswp = gestures.pswp;\r\n /** @type {Point} */\r\n this.startPan = { x: 0, y: 0 };\r\n }\r\n\r\n start() {\r\n if (this.pswp.currSlide) {\r\n equalizePoints(this.startPan, this.pswp.currSlide.pan);\r\n }\r\n this.pswp.animations.stopAll();\r\n }\r\n\r\n change() {\r\n const { p1, prevP1, dragAxis } = this.gestures;\r\n const { currSlide } = this.pswp;\r\n\r\n if (dragAxis === 'y'\r\n && this.pswp.options.closeOnVerticalDrag\r\n && (currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit)\r\n && !this.gestures.isMultitouch) {\r\n // Handle vertical drag to close\r\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\r\n if (!this.pswp.dispatch('verticalDrag', { panY }).defaultPrevented) {\r\n this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION);\r\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\r\n this.pswp.applyBgOpacity(bgOpacity);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n } else {\r\n const mainScrollChanged = this._panOrMoveMainScroll('x');\r\n if (!mainScrollChanged) {\r\n this._panOrMoveMainScroll('y');\r\n\r\n if (currSlide) {\r\n roundPoint(currSlide.pan);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n }\r\n }\r\n }\r\n\r\n end() {\r\n const { velocity } = this.gestures;\r\n const { mainScroll, currSlide } = this.pswp;\r\n let indexDiff = 0;\r\n\r\n this.pswp.animations.stopAll();\r\n\r\n // Handle main scroll if it's shifted\r\n if (mainScroll.isShifted()) {\r\n // Position of the main scroll relative to the viewport\r\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX();\r\n\r\n // Ratio between 0 and 1:\r\n // 0 - slide is not visible at all,\r\n // 0.5 - half of the slide is visible\r\n // 1 - slide is fully visible\r\n const currentSlideVisibilityRatio = (mainScrollShiftDiff / this.pswp.viewportSize.x);\r\n\r\n // Go next slide.\r\n //\r\n // - if velocity and its direction is matched,\r\n // and we see at least tiny part of the next slide\r\n //\r\n // - or if we see less than 50% of the current slide\r\n // and velocity is close to 0\r\n //\r\n if ((velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0)\r\n || (velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5)) {\r\n // Go to next slide\r\n indexDiff = 1;\r\n velocity.x = Math.min(velocity.x, 0);\r\n } else if ((velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0)\r\n || (velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5)) {\r\n // Go to prev slide\r\n indexDiff = -1;\r\n velocity.x = Math.max(velocity.x, 0);\r\n }\r\n\r\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\r\n }\r\n\r\n // Restore zoom level\r\n if ((currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max)\r\n || this.gestures.isMultitouch) {\r\n this.gestures.zoomLevels.correctZoomPan(true);\r\n } else {\r\n // we run two animations instead of one,\r\n // as each axis has own pan boundaries and thus different spring function\r\n // (correctZoomPan does not have this functionality,\r\n // it animates all properties with single timing function)\r\n this._finishPanGestureForAxis('x');\r\n this._finishPanGestureForAxis('y');\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */\r\n _finishPanGestureForAxis(axis) {\r\n const { velocity } = this.gestures;\r\n const { currSlide } = this.pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const { pan, bounds } = currSlide;\r\n const panPos = pan[axis];\r\n const restoreBgOpacity = (this.pswp.bgOpacity < 1 && axis === 'y');\r\n\r\n // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\r\n // Increasing this number will reduce travel distance\r\n const decelerationRate = 0.995; // 0.99\r\n\r\n // Pan position if there is no bounds\r\n const projectedPosition = panPos + project(velocity[axis], decelerationRate);\r\n\r\n if (restoreBgOpacity) {\r\n const vDragRatio = this._getVerticalDragRatio(panPos);\r\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition);\r\n\r\n // If we are above and moving upwards,\r\n // or if we are below and moving downwards\r\n if ((vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE)\r\n || (vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE)) {\r\n this.pswp.close();\r\n return;\r\n }\r\n }\r\n\r\n // Pan position with corrected bounds\r\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition);\r\n\r\n // Exit if pan position should not be changed\r\n // or if speed it too low\r\n if (panPos === correctedPanPosition) {\r\n return;\r\n }\r\n\r\n // Overshoot if the final position is out of pan bounds\r\n const dampingRatio = (correctedPanPosition === projectedPosition) ? 1 : 0.82;\r\n\r\n const initialBgOpacity = this.pswp.bgOpacity;\r\n const totalPanDist = correctedPanPosition - panPos;\r\n\r\n this.pswp.animations.startSpring({\r\n name: 'panGesture' + axis,\r\n isPan: true,\r\n start: panPos,\r\n end: correctedPanPosition,\r\n velocity: velocity[axis],\r\n dampingRatio,\r\n onUpdate: (pos) => {\r\n // Animate opacity of background relative to Y pan position of an image\r\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\r\n // 0 - start of animation, 1 - end of animation\r\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist;\r\n\r\n // We clamp opacity to keep it between 0 and 1.\r\n // As progress ratio can be larger than 1 due to overshoot,\r\n // and we do not want to bounce opacity.\r\n this.pswp.applyBgOpacity(clamp(\r\n initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio,\r\n 0,\r\n 1\r\n ));\r\n }\r\n\r\n pan[axis] = Math.floor(pos);\r\n currSlide.applyCurrentZoomPan();\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */\r\n _panOrMoveMainScroll(axis) {\r\n const { p1, dragAxis, prevP1, isMultitouch } = this.gestures;\r\n const { currSlide, mainScroll } = this.pswp;\r\n const delta = (p1[axis] - prevP1[axis]);\r\n const newMainScrollX = mainScroll.x + delta;\r\n\r\n if (!delta || !currSlide) {\r\n return false;\r\n }\r\n\r\n // Always move main scroll if image can not be panned\r\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true; // changed main scroll\r\n }\r\n\r\n const { bounds } = currSlide;\r\n const newPan = currSlide.pan[axis] + delta;\r\n\r\n if (this.pswp.options.allowPanToNext\r\n && dragAxis === 'x'\r\n && axis === 'x'\r\n && !isMultitouch) {\r\n const currSlideMainScrollX = mainScroll.getCurrSlideX();\r\n\r\n // Position of the main scroll relative to the viewport\r\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\r\n\r\n const isLeftToRight = delta > 0;\r\n const isRightToLeft = !isLeftToRight;\r\n\r\n if (newPan > bounds.min[axis] && isLeftToRight) {\r\n // Panning from left to right, beyond the left edge\r\n\r\n // Wether the image was at minimum pan position (or less)\r\n // when this drag gesture started.\r\n // Minimum pan position refers to the left edge of the image.\r\n const wasAtMinPanPosition = (bounds.min[axis] <= this.startPan[axis]);\r\n\r\n if (wasAtMinPanPosition) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true;\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n //currSlide.pan[axis] = newPan;\r\n }\r\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\r\n // Paning from right to left, beyond the right edge\r\n\r\n // Maximum pan position refers to the right edge of the image.\r\n const wasAtMaxPanPosition = (this.startPan[axis] <= bounds.max[axis]);\r\n\r\n if (wasAtMaxPanPosition) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true;\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n //currSlide.pan[axis] = newPan;\r\n }\r\n } else {\r\n // If main scroll is shifted\r\n if (mainScrollShiftDiff !== 0) {\r\n // If main scroll is shifted right\r\n if (mainScrollShiftDiff > 0 /*&& isRightToLeft*/) {\r\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\r\n return true;\r\n } else if (mainScrollShiftDiff < 0 /*&& isLeftToRight*/) {\r\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\r\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\r\n return true;\r\n }\r\n } else {\r\n // We are within pan bounds, so just pan\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n }\r\n } else {\r\n if (axis === 'y') {\r\n // Do not pan vertically if main scroll is shifted o\r\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) {\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n // If we move above - the ratio is negative\r\n // If we move below the ratio is positive\r\n\r\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */\r\n _getVerticalDragRatio(panY) {\r\n return (panY - (this.pswp.currSlide?.bounds.center.y ?? 0)) / (this.pswp.viewportSize.y / 3);\r\n }\r\n\r\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */\r\n _setPanWithFriction(axis, potentialPan, customFriction) {\r\n const { currSlide } = this.pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const { pan, bounds } = currSlide;\r\n const correctedPan = bounds.correctPan(axis, potentialPan);\r\n // If we are out of pan bounds\r\n if (correctedPan !== potentialPan || customFriction) {\r\n const delta = Math.round(potentialPan - pan[axis]);\r\n pan[axis] += delta * (customFriction || PAN_END_FRICTION);\r\n } else {\r\n pan[axis] = potentialPan;\r\n }\r\n }\r\n}\r\n\r\nexport default DragHandler;\r\n","import {\r\n equalizePoints, getDistanceBetween, clamp, pointsEqual\r\n} from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n\r\nconst UPPER_ZOOM_FRICTION = 0.05;\r\nconst LOWER_ZOOM_FRICTION = 0.15;\r\n\r\n\r\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nfunction getZoomPointsCenter(p, p1, p2) {\r\n p.x = (p1.x + p2.x) / 2;\r\n p.y = (p1.y + p2.y) / 2;\r\n return p;\r\n}\r\n\r\nclass ZoomHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._startPan = { x: 0, y: 0 };\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._startZoomPoint = { x: 0, y: 0 };\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._zoomPoint = { x: 0, y: 0 };\r\n /** @private */\r\n this._wasOverFitZoomLevel = false;\r\n /** @private */\r\n this._startZoomLevel = 1;\r\n }\r\n\r\n start() {\r\n const { currSlide } = this.gestures.pswp;\r\n if (currSlide) {\r\n this._startZoomLevel = currSlide.currZoomLevel;\r\n equalizePoints(this._startPan, currSlide.pan);\r\n }\r\n\r\n this.gestures.pswp.animations.stopAllPan();\r\n this._wasOverFitZoomLevel = false;\r\n }\r\n\r\n change() {\r\n const { p1, startP1, p2, startP2, pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const minZoomLevel = currSlide.zoomLevels.min;\r\n const maxZoomLevel = currSlide.zoomLevels.max;\r\n\r\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) {\r\n return;\r\n }\r\n\r\n getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\r\n getZoomPointsCenter(this._zoomPoint, p1, p2);\r\n\r\n let currZoomLevel = (1 / getDistanceBetween(startP1, startP2))\r\n * getDistanceBetween(p1, p2)\r\n * this._startZoomLevel;\r\n\r\n // slightly over the zoom.fit\r\n if (currZoomLevel > currSlide.zoomLevels.initial + (currSlide.zoomLevels.initial / 15)) {\r\n this._wasOverFitZoomLevel = true;\r\n }\r\n\r\n if (currZoomLevel < minZoomLevel) {\r\n if (pswp.options.pinchToClose\r\n && !this._wasOverFitZoomLevel\r\n && this._startZoomLevel <= currSlide.zoomLevels.initial) {\r\n // fade out background if zooming out\r\n const bgOpacity = 1 - ((minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2));\r\n if (!pswp.dispatch('pinchClose', { bgOpacity }).defaultPrevented) {\r\n pswp.applyBgOpacity(bgOpacity);\r\n }\r\n } else {\r\n // Apply the friction if zoom level is below the min\r\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION;\r\n }\r\n } else if (currZoomLevel > maxZoomLevel) {\r\n // Apply the friction if zoom level is above the max\r\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION;\r\n }\r\n\r\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\r\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\r\n\r\n currSlide.setZoomLevel(currZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n end() {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial)\r\n && !this._wasOverFitZoomLevel\r\n && pswp.options.pinchToClose) {\r\n pswp.close();\r\n } else {\r\n this.correctZoomPan();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */\r\n _calculatePanForZoomLevel(axis, currZoomLevel) {\r\n const zoomFactor = currZoomLevel / this._startZoomLevel;\r\n return this._zoomPoint[axis]\r\n - ((this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor);\r\n }\r\n\r\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */\r\n correctZoomPan(ignoreGesture) {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n\r\n if (!currSlide?.isZoomable()) {\r\n return;\r\n }\r\n\r\n if (this._zoomPoint.x === 0) {\r\n ignoreGesture = true;\r\n }\r\n\r\n const prevZoomLevel = currSlide.currZoomLevel;\r\n\r\n /** @type {number} */\r\n let destinationZoomLevel;\r\n let currZoomLevelNeedsChange = true;\r\n\r\n if (prevZoomLevel < currSlide.zoomLevels.initial) {\r\n destinationZoomLevel = currSlide.zoomLevels.initial;\r\n // zoom to min\r\n } else if (prevZoomLevel > currSlide.zoomLevels.max) {\r\n destinationZoomLevel = currSlide.zoomLevels.max;\r\n // zoom to max\r\n } else {\r\n currZoomLevelNeedsChange = false;\r\n destinationZoomLevel = prevZoomLevel;\r\n }\r\n\r\n const initialBgOpacity = pswp.bgOpacity;\r\n const restoreBgOpacity = pswp.bgOpacity < 1;\r\n\r\n const initialPan = equalizePoints({ x: 0, y: 0 }, currSlide.pan);\r\n let destinationPan = equalizePoints({ x: 0, y: 0 }, initialPan);\r\n\r\n if (ignoreGesture) {\r\n this._zoomPoint.x = 0;\r\n this._zoomPoint.y = 0;\r\n this._startZoomPoint.x = 0;\r\n this._startZoomPoint.y = 0;\r\n this._startZoomLevel = prevZoomLevel;\r\n equalizePoints(this._startPan, initialPan);\r\n }\r\n\r\n if (currZoomLevelNeedsChange) {\r\n destinationPan = {\r\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\r\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\r\n };\r\n }\r\n\r\n // set zoom level, so pan bounds are updated according to it\r\n currSlide.setZoomLevel(destinationZoomLevel);\r\n\r\n destinationPan = {\r\n x: currSlide.bounds.correctPan('x', destinationPan.x),\r\n y: currSlide.bounds.correctPan('y', destinationPan.y)\r\n };\r\n\r\n // return zoom level and its bounds to initial\r\n currSlide.setZoomLevel(prevZoomLevel);\r\n\r\n const panNeedsChange = !pointsEqual(destinationPan, initialPan);\r\n\r\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\r\n // update resolution after gesture\r\n currSlide._setResolution(destinationZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n\r\n // nothing to animate\r\n return;\r\n }\r\n\r\n pswp.animations.stopAllPan();\r\n\r\n pswp.animations.startSpring({\r\n isPan: true,\r\n start: 0,\r\n end: 1000,\r\n velocity: 0,\r\n dampingRatio: 1,\r\n naturalFrequency: 40,\r\n onUpdate: (now) => {\r\n now /= 1000; // 0 - start, 1 - end\r\n\r\n if (panNeedsChange || currZoomLevelNeedsChange) {\r\n if (panNeedsChange) {\r\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\r\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\r\n }\r\n\r\n if (currZoomLevelNeedsChange) {\r\n const newZoomLevel = prevZoomLevel\r\n + (destinationZoomLevel - prevZoomLevel) * now;\r\n currSlide.setZoomLevel(newZoomLevel);\r\n }\r\n\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n // Restore background opacity\r\n if (restoreBgOpacity && pswp.bgOpacity < 1) {\r\n // We clamp opacity to keep it between 0 and 1.\r\n // As progress ratio can be larger than 1 due to overshoot,\r\n // and we do not want to bounce opacity.\r\n pswp.applyBgOpacity(clamp(\r\n initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1\r\n ));\r\n }\r\n },\r\n onComplete: () => {\r\n // update resolution after transition ends\r\n currSlide._setResolution(destinationZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport default ZoomHandler;\r\n","/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */\r\n\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */\r\n\r\n/**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */\r\nfunction didTapOnMainContent(event) {\r\n return !!(/** @type {HTMLElement} */ (event.target).closest('.pswp__container'));\r\n}\r\n\r\n/**\r\n * Tap, double-tap handler.\r\n */\r\nclass TapHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n click(point, originalEvent) {\r\n const targetClassList = /** @type {HTMLElement} */ (originalEvent.target).classList;\r\n const isImageClick = targetClassList.contains('pswp__img');\r\n const isBackgroundClick = targetClassList.contains('pswp__item')\r\n || targetClassList.contains('pswp__zoom-wrap');\r\n\r\n if (isImageClick) {\r\n this._doClickOrTapAction('imageClick', point, originalEvent);\r\n } else if (isBackgroundClick) {\r\n this._doClickOrTapAction('bgClick', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n tap(point, originalEvent) {\r\n if (didTapOnMainContent(originalEvent)) {\r\n this._doClickOrTapAction('tap', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n doubleTap(point, originalEvent) {\r\n if (didTapOnMainContent(originalEvent)) {\r\n this._doClickOrTapAction('doubleTap', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n _doClickOrTapAction(actionName, point, originalEvent) {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n const actionFullName = /** @type {AddPostfix} */ (actionName + 'Action');\r\n const optionValue = pswp.options[actionFullName];\r\n\r\n if (pswp.dispatch(actionFullName, { point, originalEvent }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n optionValue.call(pswp, point, originalEvent);\r\n return;\r\n }\r\n\r\n switch (optionValue) {\r\n case 'close':\r\n case 'next':\r\n pswp[optionValue]();\r\n break;\r\n case 'zoom':\r\n currSlide?.toggleZoom(point);\r\n break;\r\n case 'zoom-or-close':\r\n // by default click zooms current image,\r\n // if it can not be zoomed - gallery will be closed\r\n if (currSlide?.isZoomable()\r\n && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) {\r\n currSlide.toggleZoom(point);\r\n } else if (pswp.options.clickToCloseNonZoomable) {\r\n pswp.close();\r\n }\r\n break;\r\n case 'toggle-controls':\r\n this.gestures.pswp.element?.classList.toggle('pswp--ui-visible');\r\n // if (_controlsVisible) {\r\n // _ui.hideControls();\r\n // } else {\r\n // _ui.showControls();\r\n // }\r\n break;\r\n }\r\n }\r\n}\r\n\r\nexport default TapHandler;\r\n","import {\r\n equalizePoints, pointsEqual, getDistanceBetween\r\n} from '../util/util.js';\r\n\r\nimport DragHandler from './drag-handler.js';\r\nimport ZoomHandler from './zoom-handler.js';\r\nimport TapHandler from './tap-handler.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n// How far should user should drag\r\n// until we can determine that the gesture is swipe and its direction\r\nconst AXIS_SWIPE_HYSTERISIS = 10;\r\n//const PAN_END_FRICTION = 0.35;\r\n\r\nconst DOUBLE_TAP_DELAY = 300; // ms\r\nconst MIN_TAP_DISTANCE = 25; // px\r\n\r\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */\r\nclass Gestures {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n\r\n /** @type {'x' | 'y' | null} */\r\n this.dragAxis = null;\r\n\r\n // point objects are defined once and reused\r\n // PhotoSwipe keeps track only of two pointers, others are ignored\r\n /** @type {Point} */\r\n this.p1 = { x: 0, y: 0 }; // the first pressed pointer\r\n /** @type {Point} */\r\n this.p2 = { x: 0, y: 0 }; // the second pressed pointer\r\n /** @type {Point} */\r\n this.prevP1 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.prevP2 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.startP1 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.startP2 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.velocity = { x: 0, y: 0 };\r\n\r\n /** @type {Point}\r\n * @private\r\n */\r\n this._lastStartP1 = { x: 0, y: 0 };\r\n /** @type {Point}\r\n * @private\r\n */\r\n this._intervalP1 = { x: 0, y: 0 };\r\n /** @private */\r\n this._numActivePoints = 0;\r\n /** @type {Point[]}\r\n * @private\r\n */\r\n this._ongoingPointers = [];\r\n /** @private */\r\n this._touchEventEnabled = 'ontouchstart' in window;\r\n /** @private */\r\n this._pointerEventEnabled = !!(window.PointerEvent);\r\n this.supportsTouch = this._touchEventEnabled\r\n || (this._pointerEventEnabled && navigator.maxTouchPoints > 1);\r\n /** @private */\r\n this._numActivePoints = 0;\r\n /** @private */\r\n this._intervalTime = 0;\r\n /** @private */\r\n this._velocityCalculated = false;\r\n this.isMultitouch = false;\r\n this.isDragging = false;\r\n this.isZooming = false;\r\n /** @type {number | null} */\r\n this.raf = null;\r\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */\r\n this._tapTimer = null;\r\n\r\n if (!this.supportsTouch) {\r\n // disable pan to next slide for non-touch devices\r\n pswp.options.allowPanToNext = false;\r\n }\r\n\r\n this.drag = new DragHandler(this);\r\n this.zoomLevels = new ZoomHandler(this);\r\n this.tapHandler = new TapHandler(this);\r\n\r\n pswp.on('bindEvents', () => {\r\n pswp.events.add(\r\n pswp.scrollWrap,\r\n 'click',\r\n /** @type EventListener */(this._onClick.bind(this))\r\n );\r\n\r\n if (this._pointerEventEnabled) {\r\n this._bindEvents('pointer', 'down', 'up', 'cancel');\r\n } else if (this._touchEventEnabled) {\r\n this._bindEvents('touch', 'start', 'end', 'cancel');\r\n\r\n // In previous versions we also bound mouse event here,\r\n // in case device supports both touch and mouse events,\r\n // but newer versions of browsers now support PointerEvent.\r\n\r\n // on iOS10 if you bind touchmove/end after touchstart,\r\n // and you don't preventDefault touchstart (which PhotoSwipe does),\r\n // preventDefault will have no effect on touchmove and touchend.\r\n // Unless you bind it previously.\r\n if (pswp.scrollWrap) {\r\n pswp.scrollWrap.ontouchmove = () => {};\r\n pswp.scrollWrap.ontouchend = () => {};\r\n }\r\n } else {\r\n this._bindEvents('mouse', 'down', 'up');\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */\r\n _bindEvents(pref, down, up, cancel) {\r\n const { pswp } = this;\r\n const { events } = pswp;\r\n\r\n const cancelEvent = cancel ? pref + cancel : '';\r\n\r\n events.add(\r\n pswp.scrollWrap,\r\n pref + down,\r\n /** @type EventListener */(this.onPointerDown.bind(this))\r\n );\r\n events.add(window, pref + 'move', /** @type EventListener */(this.onPointerMove.bind(this)));\r\n events.add(window, pref + up, /** @type EventListener */(this.onPointerUp.bind(this)));\r\n if (cancelEvent) {\r\n events.add(\r\n pswp.scrollWrap,\r\n cancelEvent,\r\n /** @type EventListener */(this.onPointerUp.bind(this))\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerDown(e) {\r\n // We do not call preventDefault for touch events\r\n // to allow browser to show native dialog on longpress\r\n // (the one that allows to save image or open it in new tab).\r\n //\r\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\r\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\r\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse';\r\n\r\n // Allow dragging only via left mouse button.\r\n // http://www.quirksmode.org/js/events_properties.html\r\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\r\n if (isMousePointer && e.button > 0) {\r\n return;\r\n }\r\n\r\n const { pswp } = this;\r\n\r\n // if PhotoSwipe is opening or closing\r\n if (!pswp.opener.isOpen) {\r\n e.preventDefault();\r\n return;\r\n }\r\n\r\n if (pswp.dispatch('pointerDown', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (isMousePointer) {\r\n pswp.mouseDetected();\r\n\r\n // preventDefault mouse event to prevent\r\n // browser image drag feature\r\n this._preventPointerEventBehaviour(e, 'down');\r\n }\r\n\r\n pswp.animations.stopAll();\r\n\r\n this._updatePoints(e, 'down');\r\n\r\n if (this._numActivePoints === 1) {\r\n this.dragAxis = null;\r\n // we need to store initial point to determine the main axis,\r\n // drag is activated only after the axis is determined\r\n equalizePoints(this.startP1, this.p1);\r\n }\r\n\r\n if (this._numActivePoints > 1) {\r\n // Tap or double tap should not trigger if more than one pointer\r\n this._clearTapTimer();\r\n this.isMultitouch = true;\r\n } else {\r\n this.isMultitouch = false;\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerMove(e) {\r\n this._preventPointerEventBehaviour(e, 'move');\r\n\r\n if (!this._numActivePoints) {\r\n return;\r\n }\r\n\r\n this._updatePoints(e, 'move');\r\n\r\n if (this.pswp.dispatch('pointerMove', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this._numActivePoints === 1 && !this.isDragging) {\r\n if (!this.dragAxis) {\r\n this._calculateDragDirection();\r\n }\r\n\r\n // Drag axis was detected, emit drag.start\r\n if (this.dragAxis && !this.isDragging) {\r\n if (this.isZooming) {\r\n this.isZooming = false;\r\n this.zoomLevels.end();\r\n }\r\n\r\n this.isDragging = true;\r\n this._clearTapTimer(); // Tap can not trigger after drag\r\n\r\n // Adjust starting point\r\n this._updateStartPoints();\r\n this._intervalTime = Date.now();\r\n //this._startTime = this._intervalTime;\r\n this._velocityCalculated = false;\r\n equalizePoints(this._intervalP1, this.p1);\r\n this.velocity.x = 0;\r\n this.velocity.y = 0;\r\n this.drag.start();\r\n\r\n this._rafStopLoop();\r\n this._rafRenderLoop();\r\n }\r\n } else if (this._numActivePoints > 1 && !this.isZooming) {\r\n this._finishDrag();\r\n\r\n this.isZooming = true;\r\n\r\n // Adjust starting points\r\n this._updateStartPoints();\r\n\r\n this.zoomLevels.start();\r\n\r\n this._rafStopLoop();\r\n this._rafRenderLoop();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _finishDrag() {\r\n if (this.isDragging) {\r\n this.isDragging = false;\r\n\r\n // Try to calculate velocity,\r\n // if it wasn't calculated yet in drag.change\r\n if (!this._velocityCalculated) {\r\n this._updateVelocity(true);\r\n }\r\n\r\n this.drag.end();\r\n this.dragAxis = null;\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerUp(e) {\r\n if (!this._numActivePoints) {\r\n return;\r\n }\r\n\r\n this._updatePoints(e, 'up');\r\n\r\n if (this.pswp.dispatch('pointerUp', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this._numActivePoints === 0) {\r\n this._rafStopLoop();\r\n\r\n if (this.isDragging) {\r\n this._finishDrag();\r\n } else if (!this.isZooming && !this.isMultitouch) {\r\n //this.zoomLevels.correctZoomPan();\r\n this._finishTap(e);\r\n }\r\n }\r\n\r\n if (this._numActivePoints < 2 && this.isZooming) {\r\n this.isZooming = false;\r\n this.zoomLevels.end();\r\n\r\n if (this._numActivePoints === 1) {\r\n // Since we have 1 point left, we need to reinitiate drag\r\n this.dragAxis = null;\r\n this._updateStartPoints();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _rafRenderLoop() {\r\n if (this.isDragging || this.isZooming) {\r\n this._updateVelocity();\r\n\r\n if (this.isDragging) {\r\n // make sure that pointer moved since the last update\r\n if (!pointsEqual(this.p1, this.prevP1)) {\r\n this.drag.change();\r\n }\r\n } else /* if (this.isZooming) */ {\r\n if (!pointsEqual(this.p1, this.prevP1)\r\n || !pointsEqual(this.p2, this.prevP2)) {\r\n this.zoomLevels.change();\r\n }\r\n }\r\n\r\n this._updatePrevPoints();\r\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\r\n }\r\n }\r\n\r\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */\r\n _updateVelocity(force) {\r\n const time = Date.now();\r\n const duration = time - this._intervalTime;\r\n\r\n if (duration < 50 && !force) {\r\n return;\r\n }\r\n\r\n\r\n this.velocity.x = this._getVelocity('x', duration);\r\n this.velocity.y = this._getVelocity('y', duration);\r\n\r\n this._intervalTime = time;\r\n equalizePoints(this._intervalP1, this.p1);\r\n this._velocityCalculated = true;\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\r\n _finishTap(e) {\r\n const { mainScroll } = this.pswp;\r\n\r\n // Do not trigger tap events if main scroll is shifted\r\n if (mainScroll.isShifted()) {\r\n // restore main scroll position\r\n // (usually happens if stopped in the middle of animation)\r\n mainScroll.moveIndexBy(0, true);\r\n return;\r\n }\r\n\r\n // Do not trigger tap for touchcancel or pointercancel\r\n if (e.type.indexOf('cancel') > 0) {\r\n return;\r\n }\r\n\r\n // Trigger click instead of tap for mouse events\r\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\r\n this.tapHandler.click(this.startP1, e);\r\n return;\r\n }\r\n\r\n // Disable delay if there is no doubleTapAction\r\n const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0;\r\n\r\n // If tapTimer is defined - we tapped recently,\r\n // check if the current tap is close to the previous one,\r\n // if yes - trigger double tap\r\n if (this._tapTimer) {\r\n this._clearTapTimer();\r\n // Check if two taps were more or less on the same place\r\n if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) {\r\n this.tapHandler.doubleTap(this.startP1, e);\r\n }\r\n } else {\r\n equalizePoints(this._lastStartP1, this.startP1);\r\n this._tapTimer = setTimeout(() => {\r\n this.tapHandler.tap(this.startP1, e);\r\n this._clearTapTimer();\r\n }, tapDelay);\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _clearTapTimer() {\r\n if (this._tapTimer) {\r\n clearTimeout(this._tapTimer);\r\n this._tapTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */\r\n _getVelocity(axis, duration) {\r\n // displacement is like distance, but can be negative.\r\n const displacement = this.p1[axis] - this._intervalP1[axis];\r\n\r\n if (Math.abs(displacement) > 1 && duration > 5) {\r\n return displacement / duration;\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _rafStopLoop() {\r\n if (this.raf) {\r\n cancelAnimationFrame(this.raf);\r\n this.raf = null;\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\r\n _preventPointerEventBehaviour(e, pointerType) {\r\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\r\n if (preventPointerEvent) {\r\n e.preventDefault();\r\n }\r\n }\r\n\r\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\r\n _updatePoints(e, pointerType) {\r\n if (this._pointerEventEnabled) {\r\n const pointerEvent = /** @type {PointerEvent} */ (e);\r\n // Try to find the current pointer in ongoing pointers by its ID\r\n const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer) => {\r\n return ongoingPointer.id === pointerEvent.pointerId;\r\n });\r\n\r\n if (pointerType === 'up' && pointerIndex > -1) {\r\n // release the pointer - remove it from ongoing\r\n this._ongoingPointers.splice(pointerIndex, 1);\r\n } else if (pointerType === 'down' && pointerIndex === -1) {\r\n // add new pointer\r\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, { x: 0, y: 0 }));\r\n } else if (pointerIndex > -1) {\r\n // update existing pointer\r\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\r\n }\r\n\r\n this._numActivePoints = this._ongoingPointers.length;\r\n\r\n // update points that PhotoSwipe uses\r\n // to calculate position and scale\r\n if (this._numActivePoints > 0) {\r\n equalizePoints(this.p1, this._ongoingPointers[0]);\r\n }\r\n\r\n if (this._numActivePoints > 1) {\r\n equalizePoints(this.p2, this._ongoingPointers[1]);\r\n }\r\n } else {\r\n const touchEvent = /** @type {TouchEvent} */ (e);\r\n\r\n this._numActivePoints = 0;\r\n if (touchEvent.type.indexOf('touch') > -1) {\r\n // Touch Event\r\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\r\n if (touchEvent.touches && touchEvent.touches.length > 0) {\r\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\r\n this._numActivePoints++;\r\n if (touchEvent.touches.length > 1) {\r\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\r\n this._numActivePoints++;\r\n }\r\n }\r\n } else {\r\n // Mouse Event\r\n this._convertEventPosToPoint(/** @type {PointerEvent} */ (e), this.p1);\r\n if (pointerType === 'up') {\r\n // clear all points on mouseup\r\n this._numActivePoints = 0;\r\n } else {\r\n this._numActivePoints++;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** update points that were used during previous rAF tick\r\n * @private\r\n */\r\n _updatePrevPoints() {\r\n equalizePoints(this.prevP1, this.p1);\r\n equalizePoints(this.prevP2, this.p2);\r\n }\r\n\r\n /** update points at the start of gesture\r\n * @private\r\n */\r\n _updateStartPoints() {\r\n equalizePoints(this.startP1, this.p1);\r\n equalizePoints(this.startP2, this.p2);\r\n this._updatePrevPoints();\r\n }\r\n\r\n /** @private */\r\n _calculateDragDirection() {\r\n if (this.pswp.mainScroll.isShifted()) {\r\n // if main scroll position is shifted – direction is always horizontal\r\n this.dragAxis = 'x';\r\n } else {\r\n // calculate delta of the last touchmove tick\r\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\r\n\r\n if (diff !== 0) {\r\n // check if pointer was shifted horizontally or vertically\r\n const axisToCheck = diff > 0 ? 'x' : 'y';\r\n\r\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) {\r\n this.dragAxis = axisToCheck;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */\r\n _convertEventPosToPoint(e, p) {\r\n p.x = e.pageX - this.pswp.offset.x;\r\n p.y = e.pageY - this.pswp.offset.y;\r\n\r\n if ('pointerId' in e) {\r\n p.id = e.pointerId;\r\n } else if (e.identifier !== undefined) {\r\n p.id = e.identifier;\r\n }\r\n\r\n return p;\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\r\n _onClick(e) {\r\n // Do not allow click event to pass through after drag\r\n if (this.pswp.mainScroll.isShifted()) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n }\r\n}\r\n\r\nexport default Gestures;\r\n","import {\r\n setTransform,\r\n createElement,\r\n} from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./slide/slide.js').default} Slide */\r\n\r\n/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */\r\n\r\nconst MAIN_SCROLL_END_FRICTION = 0.35;\r\n\r\n\r\n// const MIN_SWIPE_TRANSITION_DURATION = 250;\r\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\r\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\r\n\r\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */\r\nclass MainScroll {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.x = 0;\r\n this.slideWidth = 0;\r\n /** @private */\r\n this._currPositionIndex = 0;\r\n /** @private */\r\n this._prevPositionIndex = 0;\r\n /** @private */\r\n this._containerShiftIndex = -1;\r\n\r\n /** @type {ItemHolder[]} */\r\n this.itemHolders = [];\r\n }\r\n\r\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */\r\n resize(resizeSlides) {\r\n const { pswp } = this;\r\n const newSlideWidth = Math.round(\r\n pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing\r\n );\r\n // Mobile browsers might trigger a resize event during a gesture.\r\n // (due to toolbar appearing or hiding).\r\n // Avoid re-adjusting main scroll position if width wasn't changed\r\n const slideWidthChanged = (newSlideWidth !== this.slideWidth);\r\n\r\n if (slideWidthChanged) {\r\n this.slideWidth = newSlideWidth;\r\n this.moveTo(this.getCurrSlideX());\r\n }\r\n\r\n this.itemHolders.forEach((itemHolder, index) => {\r\n if (slideWidthChanged) {\r\n setTransform(itemHolder.el, (index + this._containerShiftIndex)\r\n * this.slideWidth);\r\n }\r\n\r\n if (resizeSlides && itemHolder.slide) {\r\n itemHolder.slide.resize();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Reset X position of the main scroller to zero\r\n */\r\n resetPosition() {\r\n // Position on the main scroller (offset)\r\n // it is independent from slide index\r\n this._currPositionIndex = 0;\r\n this._prevPositionIndex = 0;\r\n\r\n // This will force recalculation of size on next resize()\r\n this.slideWidth = 0;\r\n\r\n // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\r\n this._containerShiftIndex = -1;\r\n }\r\n\r\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */\r\n appendHolders() {\r\n this.itemHolders = [];\r\n\r\n // append our three slide holders -\r\n // previous, current, and next\r\n for (let i = 0; i < 3; i++) {\r\n const el = createElement('pswp__item', 'div', this.pswp.container);\r\n el.setAttribute('role', 'group');\r\n el.setAttribute('aria-roledescription', 'slide');\r\n el.setAttribute('aria-hidden', 'true');\r\n\r\n // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\r\n el.style.display = (i === 1) ? 'block' : 'none';\r\n\r\n this.itemHolders.push({\r\n el,\r\n //index: -1\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */\r\n canBeSwiped() {\r\n return this.pswp.getNumItems() > 1;\r\n }\r\n\r\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */\r\n moveIndexBy(diff, animate, velocityX) {\r\n const { pswp } = this;\r\n let newIndex = pswp.potentialIndex + diff;\r\n const numSlides = pswp.getNumItems();\r\n\r\n if (pswp.canLoop()) {\r\n newIndex = pswp.getLoopedIndex(newIndex);\r\n const distance = (diff + numSlides) % numSlides;\r\n if (distance <= numSlides / 2) {\r\n // go forward\r\n diff = distance;\r\n } else {\r\n // go backwards\r\n diff = distance - numSlides;\r\n }\r\n } else {\r\n if (newIndex < 0) {\r\n newIndex = 0;\r\n } else if (newIndex >= numSlides) {\r\n newIndex = numSlides - 1;\r\n }\r\n diff = newIndex - pswp.potentialIndex;\r\n }\r\n\r\n pswp.potentialIndex = newIndex;\r\n this._currPositionIndex -= diff;\r\n\r\n pswp.animations.stopMainScroll();\r\n\r\n const destinationX = this.getCurrSlideX();\r\n if (!animate) {\r\n this.moveTo(destinationX);\r\n this.updateCurrItem();\r\n } else {\r\n pswp.animations.startSpring({\r\n isMainScroll: true,\r\n start: this.x,\r\n end: destinationX,\r\n velocity: velocityX || 0,\r\n naturalFrequency: 30,\r\n dampingRatio: 1, //0.7,\r\n onUpdate: (x) => {\r\n this.moveTo(x);\r\n },\r\n onComplete: () => {\r\n this.updateCurrItem();\r\n pswp.appendHeavy();\r\n }\r\n });\r\n\r\n let currDiff = pswp.potentialIndex - pswp.currIndex;\r\n if (pswp.canLoop()) {\r\n const currDistance = (currDiff + numSlides) % numSlides;\r\n if (currDistance <= numSlides / 2) {\r\n // go forward\r\n currDiff = currDistance;\r\n } else {\r\n // go backwards\r\n currDiff = currDistance - numSlides;\r\n }\r\n }\r\n\r\n // Force-append new slides during transition\r\n // if difference between slides is more than 1\r\n if (Math.abs(currDiff) > 1) {\r\n this.updateCurrItem();\r\n }\r\n }\r\n\r\n return Boolean(diff);\r\n }\r\n\r\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */\r\n getCurrSlideX() {\r\n return this.slideWidth * this._currPositionIndex;\r\n }\r\n\r\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */\r\n isShifted() {\r\n return this.x !== this.getCurrSlideX();\r\n }\r\n\r\n /**\r\n * Update slides X positions and set their content\r\n */\r\n updateCurrItem() {\r\n const { pswp } = this;\r\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\r\n\r\n if (!positionDifference) {\r\n return;\r\n }\r\n\r\n this._prevPositionIndex = this._currPositionIndex;\r\n\r\n pswp.currIndex = pswp.potentialIndex;\r\n\r\n let diffAbs = Math.abs(positionDifference);\r\n /** @type {ItemHolder | undefined} */\r\n let tempHolder;\r\n\r\n if (diffAbs >= 3) {\r\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\r\n diffAbs = 3;\r\n\r\n // If slides are changed by 3 screens or more - clean up previous slides\r\n this.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.destroy();\r\n itemHolder.slide = undefined;\r\n });\r\n }\r\n\r\n for (let i = 0; i < diffAbs; i++) {\r\n if (positionDifference > 0) {\r\n tempHolder = this.itemHolders.shift();\r\n if (tempHolder) {\r\n this.itemHolders[2] = tempHolder; // move first to last\r\n\r\n this._containerShiftIndex++;\r\n\r\n setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\r\n\r\n pswp.setContent(tempHolder, (pswp.currIndex - diffAbs) + i + 2);\r\n }\r\n } else {\r\n tempHolder = this.itemHolders.pop();\r\n if (tempHolder) {\r\n this.itemHolders.unshift(tempHolder); // move last to first\r\n\r\n this._containerShiftIndex--;\r\n\r\n setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\r\n\r\n pswp.setContent(tempHolder, (pswp.currIndex + diffAbs) - i - 2);\r\n }\r\n }\r\n }\r\n\r\n // Reset transfrom every 50ish navigations in one direction.\r\n //\r\n // Otherwise transform will keep growing indefinitely,\r\n // which might cause issues as browsers have a maximum transform limit.\r\n // I wasn't able to reach it, but just to be safe.\r\n // This should not cause noticable lag.\r\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\r\n this.resetPosition();\r\n this.resize();\r\n }\r\n\r\n // Pan transition might be running (and consntantly updating pan position)\r\n pswp.animations.stopAllPan();\r\n\r\n this.itemHolders.forEach((itemHolder, i) => {\r\n if (itemHolder.slide) {\r\n // Slide in the 2nd holder is always active\r\n itemHolder.slide.setIsActive(i === 1);\r\n }\r\n });\r\n\r\n pswp.currSlide = this.itemHolders[1]?.slide;\r\n pswp.contentLoader.updateLazy(positionDifference);\r\n\r\n if (pswp.currSlide) {\r\n pswp.currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n pswp.dispatch('change');\r\n }\r\n\r\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */\r\n moveTo(x, dragging) {\r\n if (!this.pswp.canLoop() && dragging) {\r\n // Apply friction\r\n let newSlideIndexOffset = ((this.slideWidth * this._currPositionIndex) - x) / this.slideWidth;\r\n newSlideIndexOffset += this.pswp.currIndex;\r\n const delta = Math.round(x - this.x);\r\n\r\n if ((newSlideIndexOffset < 0 && delta > 0)\r\n || (newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0)) {\r\n x = this.x + (delta * MAIN_SCROLL_END_FRICTION);\r\n }\r\n }\r\n\r\n this.x = x;\r\n\r\n if (this.pswp.container) {\r\n setTransform(this.pswp.container, x);\r\n }\r\n\r\n this.pswp.dispatch('moveMainScroll', { x, dragging: dragging ?? false });\r\n }\r\n}\r\n\r\nexport default MainScroll;\r\n","import { specialKeyUsed } from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */\r\n\r\nconst KeyboardKeyCodesMap = {\r\n Escape: 27,\r\n z: 90,\r\n ArrowLeft: 37,\r\n ArrowUp: 38,\r\n ArrowRight: 39,\r\n ArrowDown: 40,\r\n Tab: 9,\r\n};\r\n\r\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */\r\nconst getKeyboardEventKey = (key, isKeySupported) => {\r\n return isKeySupported ? key : KeyboardKeyCodesMap[key];\r\n};\r\n\r\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */\r\nclass Keyboard {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n /** @private */\r\n this._wasFocused = false;\r\n\r\n pswp.on('bindEvents', () => {\r\n if (pswp.options.trapFocus) {\r\n // Dialog was likely opened by keyboard if initial point is not defined\r\n if (!pswp.options.initialPointerPos) {\r\n // focus causes layout,\r\n // which causes lag during the animation,\r\n // that's why we delay it until the opener transition ends\r\n this._focusRoot();\r\n }\r\n\r\n pswp.events.add(\r\n document,\r\n 'focusin',\r\n /** @type EventListener */(this._onFocusIn.bind(this))\r\n );\r\n }\r\n\r\n pswp.events.add(document, 'keydown', /** @type EventListener */(this._onKeyDown.bind(this)));\r\n });\r\n\r\n const lastActiveElement = /** @type {HTMLElement} */ (document.activeElement);\r\n pswp.on('destroy', () => {\r\n if (pswp.options.returnFocus\r\n && lastActiveElement\r\n && this._wasFocused) {\r\n lastActiveElement.focus();\r\n }\r\n });\r\n }\r\n\r\n /** @private */\r\n _focusRoot() {\r\n if (!this._wasFocused && this.pswp.element) {\r\n this.pswp.element.focus();\r\n this._wasFocused = true;\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */\r\n _onKeyDown(e) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('keydown', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (specialKeyUsed(e)) {\r\n // don't do anything if special key pressed\r\n // to prevent from overriding default browser actions\r\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\r\n return;\r\n }\r\n\r\n /** @type {Methods | undefined} */\r\n let keydownAction;\r\n /** @type {'x' | 'y' | undefined} */\r\n let axis;\r\n let isForward = false;\r\n const isKeySupported = 'key' in e;\r\n\r\n switch (isKeySupported ? e.key : e.keyCode) {\r\n case getKeyboardEventKey('Escape', isKeySupported):\r\n if (pswp.options.escKey) {\r\n keydownAction = 'close';\r\n }\r\n break;\r\n case getKeyboardEventKey('z', isKeySupported):\r\n keydownAction = 'toggleZoom';\r\n break;\r\n case getKeyboardEventKey('ArrowLeft', isKeySupported):\r\n axis = 'x';\r\n break;\r\n case getKeyboardEventKey('ArrowUp', isKeySupported):\r\n axis = 'y';\r\n break;\r\n case getKeyboardEventKey('ArrowRight', isKeySupported):\r\n axis = 'x';\r\n isForward = true;\r\n break;\r\n case getKeyboardEventKey('ArrowDown', isKeySupported):\r\n isForward = true;\r\n axis = 'y';\r\n break;\r\n case getKeyboardEventKey('Tab', isKeySupported):\r\n this._focusRoot();\r\n break;\r\n default:\r\n }\r\n\r\n // if left/right/top/bottom key\r\n if (axis) {\r\n // prevent page scroll\r\n e.preventDefault();\r\n\r\n const { currSlide } = pswp;\r\n\r\n if (pswp.options.arrowKeys\r\n && axis === 'x'\r\n && pswp.getNumItems() > 1) {\r\n keydownAction = isForward ? 'next' : 'prev';\r\n } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\r\n // up/down arrow keys pan the image vertically\r\n // left/right arrow keys pan horizontally.\r\n // Unless there is only one image,\r\n // or arrowKeys option is disabled\r\n currSlide.pan[axis] += isForward ? -80 : 80;\r\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\r\n }\r\n }\r\n\r\n if (keydownAction) {\r\n e.preventDefault();\r\n // @ts-ignore\r\n pswp[keydownAction]();\r\n }\r\n }\r\n\r\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */\r\n _onFocusIn(e) {\r\n const { template } = this.pswp;\r\n if (template\r\n && document !== e.target\r\n && template !== e.target\r\n && !template.contains(/** @type {Node} */ (e.target))) {\r\n // focus root element\r\n template.focus();\r\n }\r\n }\r\n}\r\n\r\nexport default Keyboard;\r\n","import { setTransitionStyle, removeTransitionStyle } from './util.js';\r\n\r\nconst DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\r\n\r\n/** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */\r\n\r\n/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */\r\n\r\n/**\r\n * Runs CSS transition.\r\n */\r\nclass CSSAnimation {\r\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */\r\n constructor(props) {\r\n this.props = props;\r\n const {\r\n target,\r\n onComplete,\r\n transform,\r\n onFinish = () => {},\r\n duration = 333,\r\n easing = DEFAULT_EASING,\r\n } = props;\r\n\r\n this.onFinish = onFinish;\r\n\r\n // support only transform and opacity\r\n const prop = transform ? 'transform' : 'opacity';\r\n const propValue = props[prop] ?? '';\r\n\r\n /** @private */\r\n this._target = target;\r\n /** @private */\r\n this._onComplete = onComplete;\r\n /** @private */\r\n this._finished = false;\r\n\r\n /** @private */\r\n this._onTransitionEnd = this._onTransitionEnd.bind(this);\r\n\r\n // Using timeout hack to make sure that animation\r\n // starts even if the animated property was changed recently,\r\n // otherwise transitionend might not fire or transition won't start.\r\n // https://drafts.csswg.org/css-transitions/#starting\r\n //\r\n // ¯\\_(ツ)_/¯\r\n /** @private */\r\n this._helperTimeout = setTimeout(() => {\r\n setTransitionStyle(target, prop, duration, easing);\r\n this._helperTimeout = setTimeout(() => {\r\n target.addEventListener('transitionend', this._onTransitionEnd, false);\r\n target.addEventListener('transitioncancel', this._onTransitionEnd, false);\r\n\r\n // Safari occasionally does not emit transitionend event\r\n // if element property was modified during the transition,\r\n // which may be caused by resize or third party component,\r\n // using timeout as a safety fallback\r\n this._helperTimeout = setTimeout(() => {\r\n this._finalizeAnimation();\r\n }, duration + 500);\r\n target.style[prop] = propValue;\r\n }, 30); // Do not reduce this number\r\n }, 0);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */\r\n _onTransitionEnd(e) {\r\n if (e.target === this._target) {\r\n this._finalizeAnimation();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _finalizeAnimation() {\r\n if (!this._finished) {\r\n this._finished = true;\r\n this.onFinish();\r\n if (this._onComplete) {\r\n this._onComplete();\r\n }\r\n }\r\n }\r\n\r\n // Destroy is called automatically onFinish\r\n destroy() {\r\n if (this._helperTimeout) {\r\n clearTimeout(this._helperTimeout);\r\n }\r\n removeTransitionStyle(this._target);\r\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\r\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\r\n if (!this._finished) {\r\n this._finalizeAnimation();\r\n }\r\n }\r\n}\r\n\r\nexport default CSSAnimation;\r\n","const DEFAULT_NATURAL_FREQUENCY = 12;\r\nconst DEFAULT_DAMPING_RATIO = 0.75;\r\n\r\n/**\r\n * Spring easing helper\r\n */\r\nclass SpringEaser {\r\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */\r\n constructor(initialVelocity, dampingRatio, naturalFrequency) {\r\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\r\n\r\n // https://en.wikipedia.org/wiki/Damping_ratio\r\n this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO;\r\n\r\n // https://en.wikipedia.org/wiki/Natural_frequency\r\n this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY;\r\n\r\n this._dampedFrequency = this._naturalFrequency;\r\n\r\n if (this._dampingRatio < 1) {\r\n this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */\r\n easeFrame(deltaPosition, deltaTime) {\r\n // Inspired by Apple Webkit and Android spring function implementation\r\n // https://en.wikipedia.org/wiki/Oscillation\r\n // https://en.wikipedia.org/wiki/Damping_ratio\r\n // we ignore mass (assume that it's 1kg)\r\n\r\n let displacement = 0;\r\n let coeff;\r\n\r\n deltaTime /= 1000;\r\n\r\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\r\n\r\n if (this._dampingRatio === 1) {\r\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\r\n\r\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\r\n\r\n this.velocity = displacement\r\n * (-this._naturalFrequency) + coeff\r\n * naturalDumpingPow;\r\n } else if (this._dampingRatio < 1) {\r\n coeff = (1 / this._dampedFrequency)\r\n * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\r\n\r\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\r\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\r\n\r\n displacement = naturalDumpingPow\r\n * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\r\n\r\n this.velocity = displacement\r\n * (-this._naturalFrequency)\r\n * this._dampingRatio\r\n + naturalDumpingPow\r\n * (-this._dampedFrequency * deltaPosition * dumpedFSin\r\n + this._dampedFrequency * coeff * dumpedFCos);\r\n }\r\n\r\n // Overdamped (>1) damping ratio is not supported\r\n\r\n return displacement;\r\n }\r\n}\r\n\r\nexport default SpringEaser;\r\n","import SpringEaser from './spring-easer.js';\r\n\r\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\r\n\r\n/**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */\r\n\r\n/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */\r\n\r\nclass SpringAnimation {\r\n /**\r\n * @param {SpringAnimationProps} props\r\n */\r\n constructor(props) {\r\n this.props = props;\r\n this._raf = 0;\r\n\r\n const {\r\n start,\r\n end,\r\n velocity,\r\n onUpdate,\r\n onComplete,\r\n onFinish = () => {},\r\n dampingRatio,\r\n naturalFrequency\r\n } = props;\r\n\r\n this.onFinish = onFinish;\r\n\r\n const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency);\r\n let prevTime = Date.now();\r\n let deltaPosition = start - end;\r\n\r\n const animationLoop = () => {\r\n if (this._raf) {\r\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime);\r\n\r\n // Stop the animation if velocity is low and position is close to end\r\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\r\n // Finalize the animation\r\n onUpdate(end);\r\n if (onComplete) {\r\n onComplete();\r\n }\r\n this.onFinish();\r\n } else {\r\n prevTime = Date.now();\r\n onUpdate(deltaPosition + end);\r\n this._raf = requestAnimationFrame(animationLoop);\r\n }\r\n }\r\n };\r\n\r\n this._raf = requestAnimationFrame(animationLoop);\r\n }\r\n\r\n // Destroy is called automatically onFinish\r\n destroy() {\r\n if (this._raf >= 0) {\r\n cancelAnimationFrame(this._raf);\r\n }\r\n this._raf = 0;\r\n }\r\n}\r\n\r\nexport default SpringAnimation;\r\n","import CSSAnimation from './css-animation.js';\r\nimport SpringAnimation from './spring-animation.js';\r\n\r\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */\r\n/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */\r\n\r\n/** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */\r\n\r\n/** @typedef {SpringAnimation | CSSAnimation} Animation */\r\n/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */\r\n\r\n/**\r\n * Manages animations\r\n */\r\nclass Animations {\r\n constructor() {\r\n /** @type {Animation[]} */\r\n this.activeAnimations = [];\r\n }\r\n\r\n /**\r\n * @param {SpringAnimationProps} props\r\n */\r\n startSpring(props) {\r\n this._start(props, true);\r\n }\r\n\r\n /**\r\n * @param {CssAnimationProps} props\r\n */\r\n startTransition(props) {\r\n this._start(props);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */\r\n _start(props, isSpring) {\r\n const animation = isSpring\r\n ? new SpringAnimation(/** @type SpringAnimationProps */ (props))\r\n : new CSSAnimation(/** @type CssAnimationProps */ (props));\r\n\r\n this.activeAnimations.push(animation);\r\n animation.onFinish = () => this.stop(animation);\r\n\r\n return animation;\r\n }\r\n\r\n /**\r\n * @param {Animation} animation\r\n */\r\n stop(animation) {\r\n animation.destroy();\r\n const index = this.activeAnimations.indexOf(animation);\r\n if (index > -1) {\r\n this.activeAnimations.splice(index, 1);\r\n }\r\n }\r\n\r\n stopAll() { // _stopAllAnimations\r\n this.activeAnimations.forEach((animation) => {\r\n animation.destroy();\r\n });\r\n this.activeAnimations = [];\r\n }\r\n\r\n /**\r\n * Stop all pan or zoom transitions\r\n */\r\n stopAllPan() {\r\n this.activeAnimations = this.activeAnimations.filter((animation) => {\r\n if (animation.props.isPan) {\r\n animation.destroy();\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n stopMainScroll() {\r\n this.activeAnimations = this.activeAnimations.filter((animation) => {\r\n if (animation.props.isMainScroll) {\r\n animation.destroy();\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n /**\r\n * Returns true if main scroll transition is running\r\n */\r\n // isMainScrollRunning() {\r\n // return this.activeAnimations.some((animation) => {\r\n // return animation.props.isMainScroll;\r\n // });\r\n // }\r\n\r\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */\r\n isPanRunning() {\r\n return this.activeAnimations.some((animation) => {\r\n return animation.props.isPan;\r\n });\r\n }\r\n}\r\n\r\nexport default Animations;\r\n","/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */\r\nclass ScrollWheel {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n pswp.events.add(pswp.element, 'wheel', /** @type EventListener */(this._onWheel.bind(this)));\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */\r\n _onWheel(e) {\r\n e.preventDefault();\r\n const { currSlide } = this.pswp;\r\n let { deltaX, deltaY } = e;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n if (this.pswp.dispatch('wheel', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (e.ctrlKey || this.pswp.options.wheelToZoom) {\r\n // zoom\r\n if (currSlide.isZoomable()) {\r\n let zoomFactor = -deltaY;\r\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\r\n zoomFactor *= 0.05;\r\n } else {\r\n zoomFactor *= e.deltaMode ? 1 : 0.002;\r\n }\r\n zoomFactor = 2 ** zoomFactor;\r\n\r\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\r\n currSlide.zoomTo(destZoomLevel, {\r\n x: e.clientX,\r\n y: e.clientY\r\n });\r\n }\r\n } else {\r\n // pan\r\n if (currSlide.isPannable()) {\r\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\r\n // 18 - average line height\r\n deltaX *= 18;\r\n deltaY *= 18;\r\n }\r\n\r\n currSlide.panTo(\r\n currSlide.pan.x - deltaX,\r\n currSlide.pan.y - deltaY\r\n );\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport default ScrollWheel;\r\n","import { createElement } from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */\r\n\r\n/**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */\r\n\r\n/**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */\r\n\r\n/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */\r\n\r\n/** @typedef {string | UIElementMarkupProps} UIElementMarkup */\r\n\r\n/**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */\r\nfunction addElementHTML(htmlData) {\r\n if (typeof htmlData === 'string') {\r\n // Allow developers to provide full svg,\r\n // For example:\r\n // \r\n // \r\n // \r\n // \r\n // Can also be any HTML string.\r\n return htmlData;\r\n }\r\n\r\n if (!htmlData || !htmlData.isCustomSVG) {\r\n return '';\r\n }\r\n\r\n const svgData = htmlData;\r\n let out = '';\r\n // replace all %d with size\r\n out = out.split('%d').join(/** @type {string} */ (svgData.size || 32));\r\n\r\n // Icons may contain outline/shadow,\r\n // to make it we \"clone\" base icon shape and add border to it.\r\n // Icon itself and border are styled via CSS.\r\n //\r\n // Property shadowID defines ID of element that should be cloned.\r\n if (svgData.outlineID) {\r\n out += '';\r\n }\r\n\r\n out += svgData.inner;\r\n\r\n out += '';\r\n\r\n return out;\r\n}\r\n\r\nclass UIElement {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */\r\n constructor(pswp, data) {\r\n const name = data.name || data.className;\r\n let elementHTML = data.html;\r\n\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (pswp.options[name] === false) {\r\n // exit if element is disabled from options\r\n return;\r\n }\r\n\r\n // Allow to override SVG icons from options\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (typeof pswp.options[name + 'SVG'] === 'string') {\r\n // arrowPrevSVG\r\n // arrowNextSVG\r\n // closeSVG\r\n // zoomSVG\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n elementHTML = pswp.options[name + 'SVG'];\r\n }\r\n\r\n pswp.dispatch('uiElementCreate', { data });\r\n\r\n let className = '';\r\n if (data.isButton) {\r\n className += 'pswp__button ';\r\n className += (data.className || `pswp__button--${data.name}`);\r\n } else {\r\n className += (data.className || `pswp__${data.name}`);\r\n }\r\n\r\n let tagName = data.isButton ? (data.tagName || 'button') : (data.tagName || 'div');\r\n tagName = /** @type {keyof HTMLElementTagNameMap} */ (tagName.toLowerCase());\r\n /** @type {HTMLElement} */\r\n const element = createElement(className, tagName);\r\n\r\n if (data.isButton) {\r\n if (tagName === 'button') {\r\n /** @type {HTMLButtonElement} */ (element).type = 'button';\r\n }\r\n\r\n let { title } = data;\r\n const { ariaLabel } = data;\r\n\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (typeof pswp.options[name + 'Title'] === 'string') {\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n title = pswp.options[name + 'Title'];\r\n }\r\n\r\n if (title) {\r\n element.title = title;\r\n }\r\n\r\n const ariaText = ariaLabel || title;\r\n if (ariaText) {\r\n element.setAttribute('aria-label', ariaText);\r\n }\r\n }\r\n\r\n element.innerHTML = addElementHTML(elementHTML);\r\n\r\n if (data.onInit) {\r\n data.onInit(element, pswp);\r\n }\r\n\r\n if (data.onClick) {\r\n element.onclick = (e) => {\r\n if (typeof data.onClick === 'string') {\r\n // @ts-ignore\r\n pswp[data.onClick]();\r\n } else if (typeof data.onClick === 'function') {\r\n data.onClick(e, element, pswp);\r\n }\r\n };\r\n }\r\n\r\n // Top bar is default position\r\n const appendTo = data.appendTo || 'bar';\r\n /** @type {HTMLElement | undefined} root element by default */\r\n let container = pswp.element;\r\n if (appendTo === 'bar') {\r\n if (!pswp.topBar) {\r\n pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\r\n }\r\n container = pswp.topBar;\r\n } else {\r\n // element outside of top bar gets a secondary class\r\n // that makes element fade out on close\r\n element.classList.add('pswp__hide-on-close');\r\n\r\n if (appendTo === 'wrapper') {\r\n container = pswp.scrollWrap;\r\n }\r\n }\r\n\r\n container?.appendChild(pswp.applyFilters('uiElement', element, data));\r\n }\r\n}\r\n\r\nexport default UIElement;\r\n","/*\r\n Backward and forward arrow buttons\r\n */\r\n\r\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */\r\nfunction initArrowButton(element, pswp, isNextButton) {\r\n element.classList.add('pswp__button--arrow');\r\n // TODO: this should point to a unique id for this instance\r\n element.setAttribute('aria-controls', 'pswp__items');\r\n pswp.on('change', () => {\r\n if (!pswp.options.loop) {\r\n if (isNextButton) {\r\n /** @type {HTMLButtonElement} */\r\n (element).disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\r\n } else {\r\n /** @type {HTMLButtonElement} */\r\n (element).disabled = !(pswp.currIndex > 0);\r\n }\r\n }\r\n });\r\n}\r\n\r\n/** @type {UIElementData} */\r\nexport const arrowPrev = {\r\n name: 'arrowPrev',\r\n className: 'pswp__button--arrow--prev',\r\n title: 'Previous',\r\n order: 10,\r\n isButton: true,\r\n appendTo: 'wrapper',\r\n html: {\r\n isCustomSVG: true,\r\n size: 60,\r\n inner: '',\r\n outlineID: 'pswp__icn-arrow'\r\n },\r\n onClick: 'prev',\r\n onInit: initArrowButton\r\n};\r\n\r\n/** @type {UIElementData} */\r\nexport const arrowNext = {\r\n name: 'arrowNext',\r\n className: 'pswp__button--arrow--next',\r\n title: 'Next',\r\n order: 11,\r\n isButton: true,\r\n appendTo: 'wrapper',\r\n html: {\r\n isCustomSVG: true,\r\n size: 60,\r\n inner: '',\r\n outlineID: 'pswp__icn-arrow'\r\n },\r\n onClick: 'next',\r\n onInit: (el, pswp) => {\r\n initArrowButton(el, pswp, true);\r\n }\r\n};\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nconst closeButton = {\r\n name: 'close',\r\n title: 'Close',\r\n order: 20,\r\n isButton: true,\r\n html: {\r\n isCustomSVG: true,\r\n inner: '',\r\n outlineID: 'pswp__icn-close'\r\n },\r\n onClick: 'close'\r\n};\r\n\r\nexport default closeButton;\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nconst zoomButton = {\r\n name: 'zoom',\r\n title: 'Zoom',\r\n order: 10,\r\n isButton: true,\r\n html: {\r\n isCustomSVG: true,\r\n // eslint-disable-next-line max-len\r\n inner: ''\r\n + ''\r\n + '',\r\n outlineID: 'pswp__icn-zoom'\r\n },\r\n onClick: 'toggleZoom'\r\n};\r\n\r\nexport default zoomButton;\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nexport const loadingIndicator = {\r\n name: 'preloader',\r\n appendTo: 'bar',\r\n order: 7,\r\n html: {\r\n isCustomSVG: true,\r\n // eslint-disable-next-line max-len\r\n inner: '',\r\n outlineID: 'pswp__icn-loading'\r\n },\r\n onInit: (indicatorElement, pswp) => {\r\n /** @type {boolean | undefined} */\r\n let isVisible;\r\n /** @type {NodeJS.Timeout | null} */\r\n let delayTimeout = null;\r\n\r\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */\r\n const toggleIndicatorClass = (className, add) => {\r\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\r\n };\r\n\r\n /**\r\n * @param {boolean} visible\r\n */\r\n const setIndicatorVisibility = (visible) => {\r\n if (isVisible !== visible) {\r\n isVisible = visible;\r\n toggleIndicatorClass('active', visible);\r\n }\r\n };\r\n\r\n const updatePreloaderVisibility = () => {\r\n if (!pswp.currSlide?.content.isLoading()) {\r\n setIndicatorVisibility(false);\r\n if (delayTimeout) {\r\n clearTimeout(delayTimeout);\r\n delayTimeout = null;\r\n }\r\n return;\r\n }\r\n\r\n if (!delayTimeout) {\r\n // display loading indicator with delay\r\n delayTimeout = setTimeout(() => {\r\n setIndicatorVisibility(Boolean(pswp.currSlide?.content.isLoading()));\r\n delayTimeout = null;\r\n }, pswp.options.preloaderDelay);\r\n }\r\n };\r\n\r\n pswp.on('change', updatePreloaderVisibility);\r\n\r\n pswp.on('loadComplete', (e) => {\r\n if (pswp.currSlide === e.slide) {\r\n updatePreloaderVisibility();\r\n }\r\n });\r\n\r\n // expose the method\r\n if (pswp.ui) {\r\n pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\r\n }\r\n }\r\n};\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nexport const counterIndicator = {\r\n name: 'counter',\r\n order: 5,\r\n onInit: (counterElement, pswp) => {\r\n pswp.on('change', () => {\r\n counterElement.innerText = (pswp.currIndex + 1)\r\n + pswp.options.indexIndicatorSep\r\n + pswp.getNumItems();\r\n });\r\n }\r\n};\r\n","import UIElement from './ui-element.js';\r\nimport { arrowPrev, arrowNext } from './button-arrow.js';\r\nimport closeButton from './button-close.js';\r\nimport zoomButton from './button-zoom.js';\r\nimport { loadingIndicator } from './loading-indicator.js';\r\nimport { counterIndicator } from './counter-indicator.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\r\n\r\n/**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */\r\nfunction setZoomedIn(el, isZoomedIn) {\r\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\r\n}\r\n\r\nclass UI {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.isRegistered = false;\r\n /** @type {UIElementData[]} */\r\n this.uiElementsData = [];\r\n /** @type {(UIElement | UIElementData)[]} */\r\n this.items = [];\r\n /** @type {() => void} */\r\n this.updatePreloaderVisibility = () => {};\r\n\r\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */\r\n this._lastUpdatedZoomLevel = undefined;\r\n }\r\n\r\n init() {\r\n const { pswp } = this;\r\n this.isRegistered = false;\r\n this.uiElementsData = [\r\n closeButton,\r\n arrowPrev,\r\n arrowNext,\r\n zoomButton,\r\n loadingIndicator,\r\n counterIndicator\r\n ];\r\n\r\n pswp.dispatch('uiRegister');\r\n\r\n // sort by order\r\n this.uiElementsData.sort((a, b) => {\r\n // default order is 0\r\n return (a.order || 0) - (b.order || 0);\r\n });\r\n\r\n this.items = [];\r\n\r\n this.isRegistered = true;\r\n this.uiElementsData.forEach((uiElementData) => {\r\n this.registerElement(uiElementData);\r\n });\r\n\r\n pswp.on('change', () => {\r\n pswp.element?.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\r\n });\r\n\r\n pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate());\r\n }\r\n\r\n /**\r\n * @param {UIElementData} elementData\r\n */\r\n registerElement(elementData) {\r\n if (this.isRegistered) {\r\n this.items.push(\r\n new UIElement(this.pswp, elementData)\r\n );\r\n } else {\r\n this.uiElementsData.push(elementData);\r\n }\r\n }\r\n\r\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */\r\n _onZoomPanUpdate() {\r\n const { template, currSlide, options } = this.pswp;\r\n\r\n if (this.pswp.opener.isClosing || !template || !currSlide) {\r\n return;\r\n }\r\n\r\n let { currZoomLevel } = currSlide;\r\n\r\n // if not open yet - check against initial zoom level\r\n if (!this.pswp.opener.isOpen) {\r\n currZoomLevel = currSlide.zoomLevels.initial;\r\n }\r\n\r\n if (currZoomLevel === this._lastUpdatedZoomLevel) {\r\n return;\r\n }\r\n this._lastUpdatedZoomLevel = currZoomLevel;\r\n\r\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary;\r\n\r\n // Initial and secondary zoom levels are almost equal\r\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\r\n // disable zoom\r\n setZoomedIn(template, false);\r\n template.classList.remove('pswp--zoom-allowed');\r\n return;\r\n }\r\n\r\n template.classList.add('pswp--zoom-allowed');\r\n\r\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial\r\n ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\r\n\r\n setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\r\n\r\n if (options.imageClickAction === 'zoom'\r\n || options.imageClickAction === 'zoom-or-close') {\r\n template.classList.add('pswp--click-to-zoom');\r\n }\r\n }\r\n}\r\n\r\nexport default UI;\r\n","/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */\r\nfunction getBoundsByElement(el) {\r\n const thumbAreaRect = el.getBoundingClientRect();\r\n return {\r\n x: thumbAreaRect.left,\r\n y: thumbAreaRect.top,\r\n w: thumbAreaRect.width\r\n };\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */\r\nfunction getCroppedBoundsByElement(el, imageWidth, imageHeight) {\r\n const thumbAreaRect = el.getBoundingClientRect();\r\n\r\n // fill image into the area\r\n // (do they same as object-fit:cover does to retrieve coordinates)\r\n const hRatio = thumbAreaRect.width / imageWidth;\r\n const vRatio = thumbAreaRect.height / imageHeight;\r\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\r\n\r\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\r\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\r\n\r\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */\r\n const bounds = {\r\n x: thumbAreaRect.left + offsetX,\r\n y: thumbAreaRect.top + offsetY,\r\n w: imageWidth * fillZoomLevel\r\n };\r\n\r\n // Coordinates of inner crop area\r\n // relative to the image\r\n bounds.innerRect = {\r\n w: thumbAreaRect.width,\r\n h: thumbAreaRect.height,\r\n x: offsetX,\r\n y: offsetY\r\n };\r\n\r\n return bounds;\r\n}\r\n\r\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */\r\nexport function getThumbBounds(index, itemData, instance) {\r\n // legacy event, before filters were introduced\r\n const event = instance.dispatch('thumbBounds', {\r\n index,\r\n itemData,\r\n instance\r\n });\r\n // @ts-expect-error\r\n if (event.thumbBounds) {\r\n // @ts-expect-error\r\n return event.thumbBounds;\r\n }\r\n\r\n const { element } = itemData;\r\n /** @type {Bounds | undefined} */\r\n let thumbBounds;\r\n /** @type {HTMLElement | null | undefined} */\r\n let thumbnail;\r\n\r\n if (element && instance.options.thumbSelector !== false) {\r\n const thumbSelector = instance.options.thumbSelector || 'img';\r\n thumbnail = element.matches(thumbSelector)\r\n ? element : /** @type {HTMLElement | null} */ (element.querySelector(thumbSelector));\r\n }\r\n\r\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\r\n\r\n if (thumbnail) {\r\n if (!itemData.thumbCropped) {\r\n thumbBounds = getBoundsByElement(thumbnail);\r\n } else {\r\n thumbBounds = getCroppedBoundsByElement(\r\n thumbnail,\r\n itemData.width || itemData.w || 0,\r\n itemData.height || itemData.h || 0\r\n );\r\n }\r\n }\r\n\r\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\r\n}\r\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../slide/content.js').default} ContentDefault */\r\n/** @typedef {import('../slide/slide.js').default} Slide */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\r\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\r\n\r\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\r\n/** @typedef {{ x?: number; y?: number }} Point */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\r\n\r\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\r\nclass PhotoSwipeEvent {\r\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\r\n constructor(type, details) {\r\n this.type = type;\r\n this.defaultPrevented = false;\r\n if (details) {\r\n Object.assign(this, details);\r\n }\r\n }\r\n\r\n preventDefault() {\r\n this.defaultPrevented = true;\r\n }\r\n}\r\n\r\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\r\nclass Eventable {\r\n constructor() {\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\r\n this._listeners = {};\r\n\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\r\n this._filters = {};\r\n\r\n /** @type {PhotoSwipe | undefined} */\r\n this.pswp = undefined;\r\n\r\n /** @type {PhotoSwipeOptions | undefined} */\r\n this.options = undefined;\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\r\n addFilter(name, fn, priority = 100) {\r\n if (!this._filters[name]) {\r\n this._filters[name] = [];\r\n }\r\n\r\n this._filters[name]?.push({ fn, priority });\r\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\r\n\r\n this.pswp?.addFilter(name, fn, priority);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\r\n removeFilter(name, fn) {\r\n if (this._filters[name]) {\r\n // @ts-expect-error\r\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\r\n }\r\n\r\n if (this.pswp) {\r\n this.pswp.removeFilter(name, fn);\r\n }\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\r\n applyFilters(name, ...args) {\r\n this._filters[name]?.forEach((filter) => {\r\n // @ts-expect-error\r\n args[0] = filter.fn.apply(this, args);\r\n });\r\n return args[0];\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n on(name, fn) {\r\n if (!this._listeners[name]) {\r\n this._listeners[name] = [];\r\n }\r\n this._listeners[name]?.push(fn);\r\n\r\n // When binding events to lightbox,\r\n // also bind events to PhotoSwipe Core,\r\n // if it's open.\r\n this.pswp?.on(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n off(name, fn) {\r\n if (this._listeners[name]) {\r\n // @ts-expect-error\r\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\r\n }\r\n\r\n this.pswp?.off(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\r\n dispatch(name, details) {\r\n if (this.pswp) {\r\n return this.pswp.dispatch(name, details);\r\n }\r\n\r\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\r\n\r\n this._listeners[name]?.forEach((listener) => {\r\n listener.call(this, event);\r\n });\r\n\r\n return event;\r\n }\r\n}\r\n\r\nexport default Eventable;\r\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\r\n\r\nclass Placeholder {\r\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\r\n constructor(imageSrc, container) {\r\n // Create placeholder\r\n // (stretched thumbnail or simple div behind the main image)\r\n /** @type {HTMLImageElement | HTMLDivElement | null} */\r\n this.element = createElement(\r\n 'pswp__img pswp__img--placeholder',\r\n imageSrc ? 'img' : 'div',\r\n container\r\n );\r\n\r\n if (imageSrc) {\r\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\r\n imgEl.decoding = 'async';\r\n imgEl.alt = '';\r\n imgEl.src = imageSrc;\r\n imgEl.setAttribute('role', 'presentation');\r\n }\r\n\r\n this.element.setAttribute('aria-hidden', 'true');\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.element.tagName === 'IMG') {\r\n // Use transform scale() to modify img placeholder size\r\n // (instead of changing width/height directly).\r\n // This helps with performance, specifically in iOS15 Safari.\r\n setWidthHeight(this.element, 250, 'auto');\r\n this.element.style.transformOrigin = '0 0';\r\n this.element.style.transform = toTransformString(0, 0, width / 250);\r\n } else {\r\n setWidthHeight(this.element, width, height);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.element?.parentNode) {\r\n this.element.remove();\r\n }\r\n this.element = null;\r\n }\r\n}\r\n\r\nexport default Placeholder;\r\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\r\nimport Placeholder from './placeholder.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../util/util.js').LoadState} LoadState */\r\n\r\nclass Content {\r\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\r\n constructor(itemData, instance, index) {\r\n this.instance = instance;\r\n this.data = itemData;\r\n this.index = index;\r\n\r\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {Placeholder | undefined} */\r\n this.placeholder = undefined;\r\n /** @type {Slide | undefined} */\r\n this.slide = undefined;\r\n\r\n this.displayedImageWidth = 0;\r\n this.displayedImageHeight = 0;\r\n\r\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\r\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\r\n\r\n this.isAttached = false;\r\n this.hasSlide = false;\r\n this.isDecoding = false;\r\n /** @type {LoadState} */\r\n this.state = LOAD_STATE.IDLE;\r\n\r\n if (this.data.type) {\r\n this.type = this.data.type;\r\n } else if (this.data.src) {\r\n this.type = 'image';\r\n } else {\r\n this.type = 'html';\r\n }\r\n\r\n this.instance.dispatch('contentInit', { content: this });\r\n }\r\n\r\n removePlaceholder() {\r\n if (this.placeholder && !this.keepPlaceholder()) {\r\n // With delay, as image might be loaded, but not rendered\r\n setTimeout(() => {\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\r\n load(isLazy, reload) {\r\n if (this.slide && this.usePlaceholder()) {\r\n if (!this.placeholder) {\r\n const placeholderSrc = this.instance.applyFilters(\r\n 'placeholderSrc',\r\n // use image-based placeholder only for the first slide,\r\n // as rendering (even small stretched thumbnail) is an expensive operation\r\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\r\n this\r\n );\r\n this.placeholder = new Placeholder(\r\n placeholderSrc,\r\n this.slide.container\r\n );\r\n } else {\r\n const placeholderEl = this.placeholder.element;\r\n // Add placeholder to DOM if it was already created\r\n if (placeholderEl && !placeholderEl.parentElement) {\r\n this.slide.container.prepend(placeholderEl);\r\n }\r\n }\r\n }\r\n\r\n if (this.element && !reload) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent()) {\r\n this.element = createElement('pswp__img', 'img');\r\n // Start loading only after width is defined, as sizes might depend on it.\r\n // Due to Safari feature, we must define sizes before srcset.\r\n if (this.displayedImageWidth) {\r\n this.loadImage(isLazy);\r\n }\r\n } else {\r\n this.element = createElement('pswp__content', 'div');\r\n this.element.innerHTML = this.data.html || '';\r\n }\r\n\r\n if (reload && this.slide) {\r\n this.slide.updateContentSize(true);\r\n }\r\n }\r\n\r\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\r\n loadImage(isLazy) {\r\n if (!this.isImageContent()\r\n || !this.element\r\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const imageElement = /** @type HTMLImageElement */ (this.element);\r\n\r\n this.updateSrcsetSizes();\r\n\r\n if (this.data.srcset) {\r\n imageElement.srcset = this.data.srcset;\r\n }\r\n\r\n imageElement.src = this.data.src ?? '';\r\n imageElement.alt = this.data.alt ?? '';\r\n\r\n this.state = LOAD_STATE.LOADING;\r\n\r\n if (imageElement.complete) {\r\n this.onLoaded();\r\n } else {\r\n imageElement.onload = () => {\r\n this.onLoaded();\r\n };\r\n\r\n imageElement.onerror = () => {\r\n this.onError();\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\r\n setSlide(slide) {\r\n this.slide = slide;\r\n this.hasSlide = true;\r\n this.instance = slide.pswp;\r\n\r\n // todo: do we need to unset slide?\r\n }\r\n\r\n /**\r\n * Content load success handler\r\n */\r\n onLoaded() {\r\n this.state = LOAD_STATE.LOADED;\r\n\r\n if (this.slide && this.element) {\r\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\r\n\r\n // if content is reloaded\r\n if (this.slide.isActive\r\n && this.slide.heavyAppended\r\n && !this.element.parentNode) {\r\n this.append();\r\n this.slide.updateContentSize(true);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Content load error handler\r\n */\r\n onError() {\r\n this.state = LOAD_STATE.ERROR;\r\n\r\n if (this.slide) {\r\n this.displayError();\r\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\r\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\r\n }\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\r\n isLoading() {\r\n return this.instance.applyFilters(\r\n 'isContentLoading',\r\n this.state === LOAD_STATE.LOADING,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\r\n isError() {\r\n return this.state === LOAD_STATE.ERROR;\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content is image\r\n */\r\n isImageContent() {\r\n return this.type === 'image';\r\n }\r\n\r\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.placeholder) {\r\n this.placeholder.setDisplayedSize(width, height);\r\n }\r\n\r\n if (this.instance.dispatch(\r\n 'contentResize',\r\n { content: this, width, height }).defaultPrevented\r\n ) {\r\n return;\r\n }\r\n\r\n setWidthHeight(this.element, width, height);\r\n\r\n if (this.isImageContent() && !this.isError()) {\r\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\r\n\r\n this.displayedImageWidth = width;\r\n this.displayedImageHeight = height;\r\n\r\n if (isInitialSizeUpdate) {\r\n this.loadImage(false);\r\n } else {\r\n this.updateSrcsetSizes();\r\n }\r\n\r\n if (this.slide) {\r\n this.instance.dispatch(\r\n 'imageSizeChange',\r\n { slide: this.slide, width, height, content: this }\r\n );\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\r\n isZoomable() {\r\n return this.instance.applyFilters(\r\n 'isContentZoomable',\r\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\r\n updateSrcsetSizes() {\r\n // Handle srcset sizes attribute.\r\n //\r\n // Never lower quality, if it was increased previously.\r\n // Chrome does this automatically, Firefox and Safari do not,\r\n // so we store largest used size in dataset.\r\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\r\n return;\r\n }\r\n\r\n const image = /** @type HTMLImageElement */ (this.element);\r\n const sizesWidth = this.instance.applyFilters(\r\n 'srcsetSizesWidth',\r\n this.displayedImageWidth,\r\n this\r\n );\r\n\r\n if (\r\n !image.dataset.largestUsedSize\r\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\r\n ) {\r\n image.sizes = sizesWidth + 'px';\r\n image.dataset.largestUsedSize = String(sizesWidth);\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\r\n usePlaceholder() {\r\n return this.instance.applyFilters(\r\n 'useContentPlaceholder',\r\n this.isImageContent(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Preload content with lazy-loading param\r\n */\r\n lazyLoad() {\r\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.load(true);\r\n }\r\n\r\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\r\n keepPlaceholder() {\r\n return this.instance.applyFilters(\r\n 'isKeepingPlaceholder',\r\n this.isLoading(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Destroy the content\r\n */\r\n destroy() {\r\n this.hasSlide = false;\r\n this.slide = undefined;\r\n\r\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.remove();\r\n\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n\r\n if (this.isImageContent() && this.element) {\r\n this.element.onload = null;\r\n this.element.onerror = null;\r\n this.element = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * Display error message\r\n */\r\n displayError() {\r\n if (this.slide) {\r\n let errorMsgEl = createElement('pswp__error-msg', 'div');\r\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\r\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\r\n 'contentErrorElement',\r\n errorMsgEl,\r\n this\r\n ));\r\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\r\n this.element.appendChild(errorMsgEl);\r\n this.slide.container.innerText = '';\r\n this.slide.container.appendChild(this.element);\r\n this.slide.updateContentSize(true);\r\n this.removePlaceholder();\r\n }\r\n }\r\n\r\n /**\r\n * Append the content\r\n */\r\n append() {\r\n if (this.isAttached || !this.element) {\r\n return;\r\n }\r\n\r\n this.isAttached = true;\r\n\r\n if (this.state === LOAD_STATE.ERROR) {\r\n this.displayError();\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const supportsDecode = ('decode' in this.element);\r\n\r\n if (this.isImageContent()) {\r\n // Use decode() on nearby slides\r\n //\r\n // Nearby slide images are in DOM and not hidden via display:none.\r\n // However, they are placed offscreen (to the left and right side).\r\n //\r\n // Some browsers do not composite the image until it's actually visible,\r\n // using decode() helps.\r\n //\r\n // You might ask \"why dont you just decode() and then append all images\",\r\n // that's because I want to show image before it's fully loaded,\r\n // as browser can render parts of image while it is loading.\r\n // We do not do this in Safari due to partial loading bug.\r\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\r\n this.isDecoding = true;\r\n // purposefully using finally instead of then,\r\n // as if srcset sizes changes dynamically - it may cause decode error\r\n /** @type {HTMLImageElement} */\r\n (this.element).decode().catch(() => {}).finally(() => {\r\n this.isDecoding = false;\r\n this.appendImage();\r\n });\r\n } else {\r\n this.appendImage();\r\n }\r\n } else if (this.slide && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n }\r\n\r\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\r\n activate() {\r\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\r\n || !this.slide) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\r\n // add image to slide when it becomes active,\r\n // even if it's not finished decoding\r\n this.appendImage();\r\n } else if (this.isError()) {\r\n this.load(false, true); // try to reload\r\n }\r\n\r\n if (this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\r\n }\r\n }\r\n\r\n /**\r\n * Deactivate the content\r\n */\r\n deactivate() {\r\n this.instance.dispatch('contentDeactivate', { content: this });\r\n if (this.slide && this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Remove the content from DOM\r\n */\r\n remove() {\r\n this.isAttached = false;\r\n\r\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.element && this.element.parentNode) {\r\n this.element.remove();\r\n }\r\n\r\n if (this.placeholder && this.placeholder.element) {\r\n this.placeholder.element.remove();\r\n }\r\n }\r\n\r\n /**\r\n * Append the image content to slide container\r\n */\r\n appendImage() {\r\n if (!this.isAttached) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n // ensure that element exists and is not already appended\r\n if (this.slide && this.element && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n}\r\n\r\nexport default Content;\r\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\r\nimport ZoomLevel from './zoom-level.js';\r\n\r\n/** @typedef {import('./content.js').default} Content */\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\nconst MIN_SLIDES_TO_CACHE = 5;\r\n\r\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\nexport function lazyLoadData(itemData, instance, index) {\r\n const content = instance.createContentFromData(itemData, index);\r\n /** @type {ZoomLevel | undefined} */\r\n let zoomLevel;\r\n\r\n const { options } = instance;\r\n\r\n // We need to know dimensions of the image to preload it,\r\n // as it might use srcset, and we need to define sizes\r\n if (options) {\r\n zoomLevel = new ZoomLevel(options, itemData, -1);\r\n\r\n let viewportSize;\r\n if (instance.pswp) {\r\n viewportSize = instance.pswp.viewportSize;\r\n } else {\r\n viewportSize = getViewportSize(options, instance);\r\n }\r\n\r\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\r\n zoomLevel.update(content.width, content.height, panAreaSize);\r\n }\r\n\r\n content.lazyLoad();\r\n\r\n if (zoomLevel) {\r\n content.setDisplayedSize(\r\n Math.ceil(content.width * zoomLevel.initial),\r\n Math.ceil(content.height * zoomLevel.initial)\r\n );\r\n }\r\n\r\n return content;\r\n}\r\n\r\n\r\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\r\nexport function lazyLoadSlide(index, instance) {\r\n const itemData = instance.getItemData(index);\r\n\r\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n return lazyLoadData(itemData, instance, index);\r\n}\r\n\r\nclass ContentLoader {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n // Total amount of cached images\r\n this.limit = Math.max(\r\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\r\n MIN_SLIDES_TO_CACHE\r\n );\r\n /** @type {Content[]} */\r\n this._cachedItems = [];\r\n }\r\n\r\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\r\n updateLazy(diff) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\r\n return;\r\n }\r\n\r\n const { preload } = pswp.options;\r\n const isForward = diff === undefined ? true : (diff >= 0);\r\n let i;\r\n\r\n // preload[1] - num items to preload in forward direction\r\n for (i = 0; i <= preload[1]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\r\n }\r\n\r\n // preload[0] - num items to preload in backward direction\r\n for (i = 1; i <= preload[0]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} initialIndex\r\n */\r\n loadSlideByIndex(initialIndex) {\r\n const index = this.pswp.getLoopedIndex(initialIndex);\r\n // try to get cached content\r\n let content = this.getContentByIndex(index);\r\n if (!content) {\r\n // no cached content, so try to load from scratch:\r\n content = lazyLoadSlide(index, this.pswp);\r\n // if content can be loaded, add it to cache:\r\n if (content) {\r\n this.addToCache(content);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\r\n getContentBySlide(slide) {\r\n let content = this.getContentByIndex(slide.index);\r\n if (!content) {\r\n // create content if not found in cache\r\n content = this.pswp.createContentFromData(slide.data, slide.index);\r\n this.addToCache(content);\r\n }\r\n\r\n // assign slide to content\r\n content.setSlide(slide);\r\n\r\n return content;\r\n }\r\n\r\n /**\r\n * @param {Content} content\r\n */\r\n addToCache(content) {\r\n // move to the end of array\r\n this.removeByIndex(content.index);\r\n this._cachedItems.push(content);\r\n\r\n if (this._cachedItems.length > this.limit) {\r\n // Destroy the first content that's not attached\r\n const indexToRemove = this._cachedItems.findIndex((item) => {\r\n return !item.isAttached && !item.hasSlide;\r\n });\r\n if (indexToRemove !== -1) {\r\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\r\n removedItem.destroy();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\r\n removeByIndex(index) {\r\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\r\n if (indexToRemove !== -1) {\r\n this._cachedItems.splice(indexToRemove, 1);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\r\n getContentByIndex(index) {\r\n return this._cachedItems.find(content => content.index === index);\r\n }\r\n\r\n destroy() {\r\n this._cachedItems.forEach(content => content.destroy());\r\n this._cachedItems = [];\r\n }\r\n}\r\n\r\nexport default ContentLoader;\r\n","import Eventable from './eventable.js';\r\nimport { getElementsFromOption } from '../util/util.js';\r\nimport Content from '../slide/content.js';\r\nimport { lazyLoadData } from '../slide/loader.js';\r\n\r\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\r\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\r\n\r\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\r\nclass PhotoSwipeBase extends Eventable {\r\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\r\n getNumItems() {\r\n let numItems = 0;\r\n const dataSource = this.options?.dataSource;\r\n\r\n if (dataSource && 'length' in dataSource) {\r\n // may be an array or just object with length property\r\n numItems = dataSource.length;\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n if (dataSource.items) {\r\n numItems = dataSource.items.length;\r\n }\r\n }\r\n\r\n // legacy event, before filters were introduced\r\n const event = this.dispatch('numItems', {\r\n dataSource,\r\n numItems\r\n });\r\n return this.applyFilters('numItems', event.numItems, dataSource);\r\n }\r\n\r\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\r\n createContentFromData(slideData, index) {\r\n return new Content(slideData, this, index);\r\n }\r\n\r\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\r\n getItemData(index) {\r\n const dataSource = this.options?.dataSource;\r\n /** @type {SlideData | HTMLElement} */\r\n let dataSourceItem = {};\r\n if (Array.isArray(dataSource)) {\r\n // Datasource is an array of elements\r\n dataSourceItem = dataSource[index];\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // dataSource has gallery property,\r\n // thus it was created by Lightbox, based on\r\n // gallery and children options\r\n\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n dataSourceItem = dataSource.items[index];\r\n }\r\n\r\n let itemData = dataSourceItem;\r\n\r\n if (itemData instanceof Element) {\r\n itemData = this._domElementToItemData(itemData);\r\n }\r\n\r\n // Dispatching the itemData event,\r\n // it's a legacy verion before filters were introduced\r\n const event = this.dispatch('itemData', {\r\n itemData: itemData || {},\r\n index\r\n });\r\n\r\n return this.applyFilters('itemData', event.itemData, index);\r\n }\r\n\r\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\r\n _getGalleryDOMElements(galleryElement) {\r\n if (this.options?.children || this.options?.childSelector) {\r\n return getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n galleryElement\r\n ) || [];\r\n }\r\n\r\n return [galleryElement];\r\n }\r\n\r\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\r\n _domElementToItemData(element) {\r\n /** @type {SlideData} */\r\n const itemData = {\r\n element\r\n };\r\n\r\n const linkEl = /** @type {HTMLAnchorElement} */ (\r\n element.tagName === 'A'\r\n ? element\r\n : element.querySelector('a')\r\n );\r\n\r\n if (linkEl) {\r\n // src comes from data-pswp-src attribute,\r\n // if it's empty link href is used\r\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\r\n\r\n if (linkEl.dataset.pswpSrcset) {\r\n itemData.srcset = linkEl.dataset.pswpSrcset;\r\n }\r\n\r\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\r\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\r\n\r\n // support legacy w & h properties\r\n itemData.w = itemData.width;\r\n itemData.h = itemData.height;\r\n\r\n if (linkEl.dataset.pswpType) {\r\n itemData.type = linkEl.dataset.pswpType;\r\n }\r\n\r\n const thumbnailEl = element.querySelector('img');\r\n\r\n if (thumbnailEl) {\r\n // msrc is URL to placeholder image that's displayed before large image is loaded\r\n // by default it's displayed only for the first slide\r\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\r\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\r\n }\r\n\r\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\r\n itemData.thumbCropped = true;\r\n }\r\n }\r\n\r\n return this.applyFilters('domItemData', itemData, element, linkEl);\r\n }\r\n\r\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\n lazyLoadData(itemData, index) {\r\n return lazyLoadData(itemData, this, index);\r\n }\r\n}\r\n\r\nexport default PhotoSwipeBase;\r\n","import {\r\n setTransform,\r\n equalizePoints,\r\n decodeImage,\r\n toTransformString\r\n} from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */\r\n/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */\r\n\r\n// some browsers do not paint\r\n// elements which opacity is set to 0,\r\n// since we need to pre-render elements for the animation -\r\n// we set it to the minimum amount\r\nconst MIN_OPACITY = 0.003;\r\n\r\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */\r\nclass Opener {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.isClosed = true;\r\n this.isOpen = false;\r\n this.isClosing = false;\r\n this.isOpening = false;\r\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */\r\n this._duration = undefined;\r\n /** @private */\r\n this._useAnimation = false;\r\n /** @private */\r\n this._croppedZoom = false;\r\n /** @private */\r\n this._animateRootOpacity = false;\r\n /** @private */\r\n this._animateBgOpacity = false;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */\r\n this._placeholder = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\r\n this._opacityElement = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\r\n this._cropContainer1 = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */\r\n this._cropContainer2 = undefined;\r\n\r\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */\r\n this._thumbBounds = undefined;\r\n\r\n\r\n this._prepareOpen = this._prepareOpen.bind(this);\r\n\r\n // Override initial zoom and pan position\r\n pswp.on('firstZoomPan', this._prepareOpen);\r\n }\r\n\r\n open() {\r\n this._prepareOpen();\r\n this._start();\r\n }\r\n\r\n close() {\r\n if (this.isClosed || this.isClosing || this.isOpening) {\r\n // if we close during opening animation\r\n // for now do nothing,\r\n // browsers aren't good at changing the direction of the CSS transition\r\n return;\r\n }\r\n\r\n const slide = this.pswp.currSlide;\r\n\r\n this.isOpen = false;\r\n this.isOpening = false;\r\n this.isClosing = true;\r\n this._duration = this.pswp.options.hideAnimationDuration;\r\n\r\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) {\r\n this._duration = 0;\r\n }\r\n\r\n this._applyStartProps();\r\n setTimeout(() => {\r\n this._start();\r\n }, this._croppedZoom ? 30 : 0);\r\n }\r\n\r\n /** @private */\r\n _prepareOpen() {\r\n this.pswp.off('firstZoomPan', this._prepareOpen);\r\n if (!this.isOpening) {\r\n const slide = this.pswp.currSlide;\r\n this.isOpening = true;\r\n this.isClosing = false;\r\n this._duration = this.pswp.options.showAnimationDuration;\r\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) {\r\n this._duration = 0;\r\n }\r\n this._applyStartProps();\r\n }\r\n }\r\n\r\n /** @private */\r\n _applyStartProps() {\r\n const { pswp } = this;\r\n const slide = this.pswp.currSlide;\r\n const { options } = pswp;\r\n\r\n if (options.showHideAnimationType === 'fade') {\r\n options.showHideOpacity = true;\r\n this._thumbBounds = undefined;\r\n } else if (options.showHideAnimationType === 'none') {\r\n options.showHideOpacity = false;\r\n this._duration = 0;\r\n this._thumbBounds = undefined;\r\n } else if (this.isOpening && pswp._initialThumbBounds) {\r\n // Use initial bounds if defined\r\n this._thumbBounds = pswp._initialThumbBounds;\r\n } else {\r\n this._thumbBounds = this.pswp.getThumbBounds();\r\n }\r\n\r\n this._placeholder = slide?.getPlaceholderElement();\r\n\r\n pswp.animations.stopAll();\r\n\r\n // Discard animations when duration is less than 50ms\r\n this._useAnimation = Boolean(this._duration && this._duration > 50);\r\n this._animateZoom = Boolean(this._thumbBounds)\r\n && slide?.content.usePlaceholder()\r\n && (!this.isClosing || !pswp.mainScroll.isShifted());\r\n if (!this._animateZoom) {\r\n this._animateRootOpacity = true;\r\n\r\n if (this.isOpening && slide) {\r\n slide.zoomAndPanToInitial();\r\n slide.applyCurrentZoomPan();\r\n }\r\n } else {\r\n this._animateRootOpacity = options.showHideOpacity ?? false;\r\n }\r\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY;\r\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\r\n\r\n if (!this._useAnimation) {\r\n this._duration = 0;\r\n this._animateZoom = false;\r\n this._animateBgOpacity = false;\r\n this._animateRootOpacity = true;\r\n if (this.isOpening) {\r\n if (pswp.element) {\r\n pswp.element.style.opacity = String(MIN_OPACITY);\r\n }\r\n pswp.applyBgOpacity(1);\r\n }\r\n return;\r\n }\r\n\r\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\r\n // Properties are used when animation from cropped thumbnail\r\n this._croppedZoom = true;\r\n this._cropContainer1 = this.pswp.container;\r\n this._cropContainer2 = this.pswp.currSlide?.holderElement;\r\n\r\n if (pswp.container) {\r\n pswp.container.style.overflow = 'hidden';\r\n pswp.container.style.width = pswp.viewportSize.x + 'px';\r\n }\r\n } else {\r\n this._croppedZoom = false;\r\n }\r\n\r\n if (this.isOpening) {\r\n // Apply styles before opening transition\r\n if (this._animateRootOpacity) {\r\n if (pswp.element) {\r\n pswp.element.style.opacity = String(MIN_OPACITY);\r\n }\r\n pswp.applyBgOpacity(1);\r\n } else {\r\n if (this._animateBgOpacity && pswp.bg) {\r\n pswp.bg.style.opacity = String(MIN_OPACITY);\r\n }\r\n if (pswp.element) {\r\n pswp.element.style.opacity = '1';\r\n }\r\n }\r\n\r\n if (this._animateZoom) {\r\n this._setClosedStateZoomPan();\r\n if (this._placeholder) {\r\n // tell browser that we plan to animate the placeholder\r\n this._placeholder.style.willChange = 'transform';\r\n\r\n // hide placeholder to allow hiding of\r\n // elements that overlap it (such as icons over the thumbnail)\r\n this._placeholder.style.opacity = String(MIN_OPACITY);\r\n }\r\n }\r\n } else if (this.isClosing) {\r\n // hide nearby slides to make sure that\r\n // they are not painted during the transition\r\n if (pswp.mainScroll.itemHolders[0]) {\r\n pswp.mainScroll.itemHolders[0].el.style.display = 'none';\r\n }\r\n if (pswp.mainScroll.itemHolders[2]) {\r\n pswp.mainScroll.itemHolders[2].el.style.display = 'none';\r\n }\r\n\r\n if (this._croppedZoom) {\r\n if (pswp.mainScroll.x !== 0) {\r\n // shift the main scroller to zero position\r\n pswp.mainScroll.resetPosition();\r\n pswp.mainScroll.resize();\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** @private */\r\n _start() {\r\n if (this.isOpening\r\n && this._useAnimation\r\n && this._placeholder\r\n && this._placeholder.tagName === 'IMG') {\r\n // To ensure smooth animation\r\n // we wait till the current slide image placeholder is decoded,\r\n // but no longer than 250ms,\r\n // and no shorter than 50ms\r\n // (just using requestanimationframe is not enough in Firefox,\r\n // for some reason)\r\n new Promise((resolve) => {\r\n let decoded = false;\r\n let isDelaying = true;\r\n decodeImage(/** @type {HTMLImageElement} */ (this._placeholder)).finally(() => {\r\n decoded = true;\r\n if (!isDelaying) {\r\n resolve(true);\r\n }\r\n });\r\n setTimeout(() => {\r\n isDelaying = false;\r\n if (decoded) {\r\n resolve(true);\r\n }\r\n }, 50);\r\n setTimeout(resolve, 250);\r\n }).finally(() => this._initiate());\r\n } else {\r\n this._initiate();\r\n }\r\n }\r\n\r\n /** @private */\r\n _initiate() {\r\n this.pswp.element?.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\r\n\r\n this.pswp.dispatch(\r\n this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'\r\n );\r\n\r\n // legacy event\r\n this.pswp.dispatch(\r\n /** @type {'initialZoomIn' | 'initialZoomOut'} */\r\n ('initialZoom' + (this.isOpening ? 'In' : 'Out'))\r\n );\r\n\r\n this.pswp.element?.classList.toggle('pswp--ui-visible', this.isOpening);\r\n\r\n if (this.isOpening) {\r\n if (this._placeholder) {\r\n // unhide the placeholder\r\n this._placeholder.style.opacity = '1';\r\n }\r\n this._animateToOpenState();\r\n } else if (this.isClosing) {\r\n this._animateToClosedState();\r\n }\r\n\r\n if (!this._useAnimation) {\r\n this._onAnimationComplete();\r\n }\r\n }\r\n\r\n /** @private */\r\n _onAnimationComplete() {\r\n const { pswp } = this;\r\n this.isOpen = this.isOpening;\r\n this.isClosed = this.isClosing;\r\n this.isOpening = false;\r\n this.isClosing = false;\r\n\r\n pswp.dispatch(\r\n this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'\r\n );\r\n\r\n // legacy event\r\n pswp.dispatch(\r\n /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */\r\n ('initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'))\r\n );\r\n\r\n if (this.isClosed) {\r\n pswp.destroy();\r\n } else if (this.isOpen) {\r\n if (this._animateZoom && pswp.container) {\r\n pswp.container.style.overflow = 'visible';\r\n pswp.container.style.width = '100%';\r\n }\r\n pswp.currSlide?.applyCurrentZoomPan();\r\n }\r\n }\r\n\r\n /** @private */\r\n _animateToOpenState() {\r\n const { pswp } = this;\r\n if (this._animateZoom) {\r\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\r\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\r\n this._animateTo(this._cropContainer2, 'transform', 'none');\r\n }\r\n\r\n if (pswp.currSlide) {\r\n pswp.currSlide.zoomAndPanToInitial();\r\n this._animateTo(\r\n pswp.currSlide.container,\r\n 'transform',\r\n pswp.currSlide.getCurrentTransform()\r\n );\r\n }\r\n }\r\n\r\n if (this._animateBgOpacity && pswp.bg) {\r\n this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\r\n }\r\n\r\n if (this._animateRootOpacity && pswp.element) {\r\n this._animateTo(pswp.element, 'opacity', '1');\r\n }\r\n }\r\n\r\n /** @private */\r\n _animateToClosedState() {\r\n const { pswp } = this;\r\n\r\n if (this._animateZoom) {\r\n this._setClosedStateZoomPan(true);\r\n }\r\n\r\n // do not animate opacity if it's already at 0\r\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) {\r\n this._animateTo(pswp.bg, 'opacity', '0');\r\n }\r\n\r\n if (this._animateRootOpacity && pswp.element) {\r\n this._animateTo(pswp.element, 'opacity', '0');\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */\r\n _setClosedStateZoomPan(animate) {\r\n if (!this._thumbBounds) return;\r\n\r\n const { pswp } = this;\r\n const { innerRect } = this._thumbBounds;\r\n const { currSlide, viewportSize } = pswp;\r\n\r\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\r\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\r\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\r\n const containerTwoPanX = viewportSize.x - innerRect.w;\r\n const containerTwoPanY = viewportSize.y - innerRect.h;\r\n\r\n\r\n if (animate) {\r\n this._animateTo(\r\n this._cropContainer1,\r\n 'transform',\r\n toTransformString(containerOnePanX, containerOnePanY)\r\n );\r\n\r\n this._animateTo(\r\n this._cropContainer2,\r\n 'transform',\r\n toTransformString(containerTwoPanX, containerTwoPanY)\r\n );\r\n } else {\r\n setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\r\n setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\r\n }\r\n }\r\n\r\n if (currSlide) {\r\n equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\r\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\r\n if (animate) {\r\n this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\r\n } else {\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */\r\n _animateTo(target, prop, propValue) {\r\n if (!this._duration) {\r\n target.style[prop] = propValue;\r\n return;\r\n }\r\n\r\n const { animations } = this.pswp;\r\n /** @type {AnimationProps} */\r\n const animProps = {\r\n duration: this._duration,\r\n easing: this.pswp.options.easing,\r\n onComplete: () => {\r\n if (!animations.activeAnimations.length) {\r\n this._onAnimationComplete();\r\n }\r\n },\r\n target,\r\n };\r\n animProps[prop] = propValue;\r\n animations.startTransition(animProps);\r\n }\r\n}\r\n\r\nexport default Opener;\r\n","import {\r\n createElement,\r\n equalizePoints,\r\n pointsEqual,\r\n clamp,\r\n} from './util/util.js';\r\n\r\nimport DOMEvents from './util/dom-events.js';\r\nimport Slide from './slide/slide.js';\r\nimport Gestures from './gestures/gestures.js';\r\nimport MainScroll from './main-scroll.js';\r\n\r\nimport Keyboard from './keyboard.js';\r\nimport Animations from './util/animations.js';\r\nimport ScrollWheel from './scroll-wheel.js';\r\nimport UI from './ui/ui.js';\r\nimport { getViewportSize } from './util/viewport-size.js';\r\nimport { getThumbBounds } from './slide/get-thumb-bounds.js';\r\nimport PhotoSwipeBase from './core/base.js';\r\nimport Opener from './opener.js';\r\nimport ContentLoader from './slide/loader.js';\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */\r\n\r\n/** @typedef {import('./slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */\r\n/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */\r\n/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\r\n/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\r\n/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */\r\n\r\n/** @typedef {{ x: number; y: number; id?: string | number }} Point */\r\n/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */\r\n/** @typedef {SlideData[]} DataSourceArray */\r\n/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */\r\n/** @typedef {DataSourceArray | DataSourceObject} DataSource */\r\n/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */\r\n/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */\r\n/** @typedef {Type | { default: Type }} PhotoSwipeModule */\r\n/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */\r\n\r\n/**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */\r\n\r\n/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */\r\n/**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */\r\n\r\n/** @type {PreparedPhotoSwipeOptions} */\r\nconst defaultOptions = {\r\n allowPanToNext: true,\r\n spacing: 0.1,\r\n loop: true,\r\n pinchToClose: true,\r\n closeOnVerticalDrag: true,\r\n hideAnimationDuration: 333,\r\n showAnimationDuration: 333,\r\n zoomAnimationDuration: 333,\r\n escKey: true,\r\n arrowKeys: true,\r\n trapFocus: true,\r\n returnFocus: true,\r\n maxWidthToAnimate: 4000,\r\n clickToCloseNonZoomable: true,\r\n imageClickAction: 'zoom-or-close',\r\n bgClickAction: 'close',\r\n tapAction: 'toggle-controls',\r\n doubleTapAction: 'zoom',\r\n indexIndicatorSep: ' / ',\r\n preloaderDelay: 2000,\r\n bgOpacity: 0.8,\r\n\r\n index: 0,\r\n errorMsg: 'The image cannot be loaded',\r\n preload: [1, 2],\r\n easing: 'cubic-bezier(.4,0,.22,1)'\r\n};\r\n\r\n/**\r\n * PhotoSwipe Core\r\n */\r\nclass PhotoSwipe extends PhotoSwipeBase {\r\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\r\n constructor(options) {\r\n super();\r\n\r\n this.options = this._prepareOptions(options || {});\r\n\r\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */\r\n this.offset = { x: 0, y: 0 };\r\n\r\n /**\r\n * @type {Point}\r\n * @private\r\n */\r\n this._prevViewportSize = { x: 0, y: 0 };\r\n\r\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */\r\n this.viewportSize = { x: 0, y: 0 };\r\n\r\n /**\r\n * background (backdrop) opacity\r\n */\r\n this.bgOpacity = 1;\r\n this.currIndex = 0;\r\n this.potentialIndex = 0;\r\n this.isOpen = false;\r\n this.isDestroying = false;\r\n this.hasMouse = false;\r\n\r\n /**\r\n * @private\r\n * @type {SlideData}\r\n */\r\n this._initialItemData = {};\r\n /** @type {Bounds | undefined} */\r\n this._initialThumbBounds = undefined;\r\n\r\n /** @type {HTMLDivElement | undefined} */\r\n this.topBar = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.template = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.container = undefined;\r\n /** @type {HTMLElement | undefined} */\r\n this.scrollWrap = undefined;\r\n /** @type {Slide | undefined} */\r\n this.currSlide = undefined;\r\n\r\n this.events = new DOMEvents();\r\n this.animations = new Animations();\r\n this.mainScroll = new MainScroll(this);\r\n this.gestures = new Gestures(this);\r\n this.opener = new Opener(this);\r\n this.keyboard = new Keyboard(this);\r\n this.contentLoader = new ContentLoader(this);\r\n }\r\n\r\n /** @returns {boolean} */\r\n init() {\r\n if (this.isOpen || this.isDestroying) {\r\n return false;\r\n }\r\n\r\n this.isOpen = true;\r\n this.dispatch('init'); // legacy\r\n this.dispatch('beforeOpen');\r\n\r\n this._createMainStructure();\r\n\r\n // add classes to the root element of PhotoSwipe\r\n let rootClasses = 'pswp--open';\r\n if (this.gestures.supportsTouch) {\r\n rootClasses += ' pswp--touch';\r\n }\r\n if (this.options.mainClass) {\r\n rootClasses += ' ' + this.options.mainClass;\r\n }\r\n if (this.element) {\r\n this.element.className += ' ' + rootClasses;\r\n }\r\n\r\n this.currIndex = this.options.index || 0;\r\n this.potentialIndex = this.currIndex;\r\n this.dispatch('firstUpdate'); // starting index can be modified here\r\n\r\n // initialize scroll wheel handler to block the scroll\r\n this.scrollWheel = new ScrollWheel(this);\r\n\r\n // sanitize index\r\n if (Number.isNaN(this.currIndex)\r\n || this.currIndex < 0\r\n || this.currIndex >= this.getNumItems()) {\r\n this.currIndex = 0;\r\n }\r\n\r\n if (!this.gestures.supportsTouch) {\r\n // enable mouse features if no touch support detected\r\n this.mouseDetected();\r\n }\r\n\r\n // causes forced synchronous layout\r\n this.updateSize();\r\n\r\n this.offset.y = window.pageYOffset;\r\n\r\n this._initialItemData = this.getItemData(this.currIndex);\r\n this.dispatch('gettingData', {\r\n index: this.currIndex,\r\n data: this._initialItemData,\r\n slide: undefined\r\n });\r\n\r\n // *Layout* - calculate size and position of elements here\r\n this._initialThumbBounds = this.getThumbBounds();\r\n this.dispatch('initialLayout');\r\n\r\n this.on('openingAnimationEnd', () => {\r\n const { itemHolders } = this.mainScroll;\r\n\r\n // Add content to the previous and next slide\r\n if (itemHolders[0]) {\r\n itemHolders[0].el.style.display = 'block';\r\n this.setContent(itemHolders[0], this.currIndex - 1);\r\n }\r\n if (itemHolders[2]) {\r\n itemHolders[2].el.style.display = 'block';\r\n this.setContent(itemHolders[2], this.currIndex + 1);\r\n }\r\n\r\n this.appendHeavy();\r\n\r\n this.contentLoader.updateLazy();\r\n\r\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\r\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\r\n this.dispatch('bindEvents');\r\n });\r\n\r\n // set content for center slide (first time)\r\n if (this.mainScroll.itemHolders[1]) {\r\n this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\r\n }\r\n this.dispatch('change');\r\n\r\n this.opener.open();\r\n\r\n this.dispatch('afterInit');\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */\r\n getLoopedIndex(index) {\r\n const numSlides = this.getNumItems();\r\n\r\n if (this.options.loop) {\r\n if (index > numSlides - 1) {\r\n index -= numSlides;\r\n }\r\n\r\n if (index < 0) {\r\n index += numSlides;\r\n }\r\n }\r\n\r\n return clamp(index, 0, numSlides - 1);\r\n }\r\n\r\n appendHeavy() {\r\n this.mainScroll.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.appendHeavy();\r\n });\r\n }\r\n\r\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */\r\n goTo(index) {\r\n this.mainScroll.moveIndexBy(\r\n this.getLoopedIndex(index) - this.potentialIndex\r\n );\r\n }\r\n\r\n /**\r\n * Go to the next slide.\r\n */\r\n next() {\r\n this.goTo(this.potentialIndex + 1);\r\n }\r\n\r\n /**\r\n * Go to the previous slide.\r\n */\r\n prev() {\r\n this.goTo(this.potentialIndex - 1);\r\n }\r\n\r\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */\r\n zoomTo(...args) {\r\n this.currSlide?.zoomTo(...args);\r\n }\r\n\r\n /**\r\n * @see slide/slide.js toggleZoom\r\n */\r\n toggleZoom() {\r\n this.currSlide?.toggleZoom();\r\n }\r\n\r\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */\r\n close() {\r\n if (!this.opener.isOpen || this.isDestroying) {\r\n return;\r\n }\r\n\r\n this.isDestroying = true;\r\n\r\n this.dispatch('close');\r\n\r\n this.events.removeAll();\r\n this.opener.close();\r\n }\r\n\r\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */\r\n destroy() {\r\n if (!this.isDestroying) {\r\n this.options.showHideAnimationType = 'none';\r\n this.close();\r\n return;\r\n }\r\n\r\n this.dispatch('destroy');\r\n\r\n this._listeners = {};\r\n\r\n if (this.scrollWrap) {\r\n this.scrollWrap.ontouchmove = null;\r\n this.scrollWrap.ontouchend = null;\r\n }\r\n\r\n this.element?.remove();\r\n\r\n this.mainScroll.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.destroy();\r\n });\r\n\r\n this.contentLoader.destroy();\r\n this.events.removeAll();\r\n }\r\n\r\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */\r\n refreshSlideContent(slideIndex) {\r\n this.contentLoader.removeByIndex(slideIndex);\r\n this.mainScroll.itemHolders.forEach((itemHolder, i) => {\r\n let potentialHolderIndex = (this.currSlide?.index ?? 0) - 1 + i;\r\n if (this.canLoop()) {\r\n potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\r\n }\r\n if (potentialHolderIndex === slideIndex) {\r\n // set the new slide content\r\n this.setContent(itemHolder, slideIndex, true);\r\n\r\n // activate the new slide if it's current\r\n if (i === 1) {\r\n this.currSlide = itemHolder.slide;\r\n itemHolder.slide?.setIsActive(true);\r\n }\r\n }\r\n });\r\n\r\n this.dispatch('change');\r\n }\r\n\r\n\r\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */\r\n setContent(holder, index, force) {\r\n if (this.canLoop()) {\r\n index = this.getLoopedIndex(index);\r\n }\r\n\r\n if (holder.slide) {\r\n if (holder.slide.index === index && !force) {\r\n // exit if holder already contains this slide\r\n // this could be common when just three slides are used\r\n return;\r\n }\r\n\r\n // destroy previous slide\r\n holder.slide.destroy();\r\n holder.slide = undefined;\r\n }\r\n\r\n // exit if no loop and index is out of bounds\r\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) {\r\n return;\r\n }\r\n\r\n const itemData = this.getItemData(index);\r\n holder.slide = new Slide(itemData, index, this);\r\n\r\n // set current slide\r\n if (index === this.currIndex) {\r\n this.currSlide = holder.slide;\r\n }\r\n\r\n holder.slide.append(holder.el);\r\n }\r\n\r\n /** @returns {Point} */\r\n getViewportCenterPoint() {\r\n return {\r\n x: this.viewportSize.x / 2,\r\n y: this.viewportSize.y / 2\r\n };\r\n }\r\n\r\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */\r\n updateSize(force) {\r\n // let item;\r\n // let itemIndex;\r\n\r\n if (this.isDestroying) {\r\n // exit if PhotoSwipe is closed or closing\r\n // (to avoid errors, as resize event might be delayed)\r\n return;\r\n }\r\n\r\n //const newWidth = this.scrollWrap.clientWidth;\r\n //const newHeight = this.scrollWrap.clientHeight;\r\n\r\n const newViewportSize = getViewportSize(this.options, this);\r\n\r\n if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) {\r\n // Exit if dimensions were not changed\r\n return;\r\n }\r\n\r\n //this._prevViewportSize.x = newWidth;\r\n //this._prevViewportSize.y = newHeight;\r\n equalizePoints(this._prevViewportSize, newViewportSize);\r\n\r\n this.dispatch('beforeResize');\r\n\r\n equalizePoints(this.viewportSize, this._prevViewportSize);\r\n\r\n this._updatePageScrollOffset();\r\n\r\n this.dispatch('viewportSize');\r\n\r\n // Resize slides only after opener animation is finished\r\n // and don't re-calculate size on inital size update\r\n this.mainScroll.resize(this.opener.isOpen);\r\n\r\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) {\r\n this.mouseDetected();\r\n }\r\n\r\n this.dispatch('resize');\r\n }\r\n\r\n /**\r\n * @param {number} opacity\r\n */\r\n applyBgOpacity(opacity) {\r\n this.bgOpacity = Math.max(opacity, 0);\r\n if (this.bg) {\r\n this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\r\n }\r\n }\r\n\r\n /**\r\n * Whether mouse is detected\r\n */\r\n mouseDetected() {\r\n if (!this.hasMouse) {\r\n this.hasMouse = true;\r\n this.element?.classList.add('pswp--has_mouse');\r\n }\r\n }\r\n\r\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */\r\n _handlePageResize() {\r\n this.updateSize();\r\n\r\n // In iOS webview, if element size depends on document size,\r\n // it'll be measured incorrectly in resize event\r\n //\r\n // https://bugs.webkit.org/show_bug.cgi?id=170595\r\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\r\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) {\r\n setTimeout(() => {\r\n this.updateSize();\r\n }, 500);\r\n }\r\n }\r\n\r\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */\r\n _updatePageScrollOffset() {\r\n this.setScrollOffset(0, window.pageYOffset);\r\n }\r\n\r\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */\r\n setScrollOffset(x, y) {\r\n this.offset.x = x;\r\n this.offset.y = y;\r\n this.dispatch('updateScrollOffset');\r\n }\r\n\r\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */\r\n _createMainStructure() {\r\n // root DOM element of PhotoSwipe (.pswp)\r\n this.element = createElement('pswp', 'div');\r\n this.element.setAttribute('tabindex', '-1');\r\n this.element.setAttribute('role', 'dialog');\r\n\r\n // template is legacy prop\r\n this.template = this.element;\r\n\r\n // Background is added as a separate element,\r\n // as animating opacity is faster than animating rgba()\r\n this.bg = createElement('pswp__bg', 'div', this.element);\r\n this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element);\r\n this.container = createElement('pswp__container', 'div', this.scrollWrap);\r\n\r\n // aria pattern: carousel\r\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\r\n this.container.setAttribute('aria-live', 'off');\r\n this.container.setAttribute('id', 'pswp__items');\r\n\r\n this.mainScroll.appendHolders();\r\n\r\n this.ui = new UI(this);\r\n this.ui.init();\r\n\r\n // append to DOM\r\n (this.options.appendToEl || document.body).appendChild(this.element);\r\n }\r\n\r\n\r\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */\r\n getThumbBounds() {\r\n return getThumbBounds(\r\n this.currIndex,\r\n this.currSlide ? this.currSlide.data : this._initialItemData,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */\r\n canLoop() {\r\n return (this.options.loop && this.getNumItems() > 2);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */\r\n _prepareOptions(options) {\r\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\r\n options.showHideAnimationType = 'none';\r\n options.zoomAnimationDuration = 0;\r\n }\r\n\r\n /** @type {PreparedPhotoSwipeOptions} */\r\n return {\r\n ...defaultOptions,\r\n ...options\r\n };\r\n }\r\n}\r\n\r\nexport default PhotoSwipe;\r\n"],"names":["parcelRequire","$parcel$global","globalThis","self","window","global","register","module","exports","$c246d27966689419$var$createElement","className","tagName","appendToEl","el","document","createElement","appendChild","$c246d27966689419$var$equalizePoints","p1","p2","x","y","undefined","id","$c246d27966689419$var$roundPoint","p","Math","round","$c246d27966689419$var$getDistanceBetween","abs","sqrt","$c246d27966689419$var$pointsEqual","$c246d27966689419$var$clamp","val","min","max","$c246d27966689419$var$toTransformString","scale","propValue","$c246d27966689419$var$setTransform","style","transform","$c246d27966689419$var$setTransitionStyle","prop","duration","ease","transition","$c246d27966689419$var$setWidthHeight","w","h","width","height","Object","defineProperty","value","configurable","get","$c246d27966689419$export$2e2bcd8739ae039","set","s","enumerable","$c246d27966689419$var$LOAD_STATE","IDLE","LOADING","LOADED","ERROR","$c246d27966689419$var$isSafari","navigator","vendor","match","$c246d27966689419$var$supportsPassive","addEventListener","e","$c246d27966689419$var$DOMEvents","constructor","_pool","add","target","type","listener","passive","_toggleListener","remove","removeAll","forEach","poolItem","unbind","skipPool","methodName","types","split","eType","filter","push","eventOptions","$c246d27966689419$var$getViewportSize","options","pswp","getViewportSizeFn","newViewportSize","documentElement","clientWidth","innerHeight","$c246d27966689419$var$parsePaddingOption","viewportSize","itemData","index","paddingValue","paddingFn","padding","legacyPropName","toUpperCase","slice","Number","$c246d27966689419$var$getPanAreaSize","$c246d27966689419$var$PanBounds","slide","currZoomLevel","center","update","_updateAxis","dispatch","reset","axis","elSize","data","panAreaSize","correctPan","panOffset","$c246d27966689419$var$ZoomLevel","elementSize","fit","fill","vFill","initial","secondary","maxWidth","maxHeight","hRatio","vRatio","_getInitial","_getSecondary","_getMax","zoomLevels","slideData","_parseZoomLevelOption","optionPrefix","optionValue","$c246d27966689419$var$MAX_IMAGE_WIDTH","$c246d27966689419$var$Slide","isActive","currIndex","currentResolution","pan","isFirstSlide","opener","isOpen","content","contentLoader","getContentBySlide","container","holderElement","heavyAppended","bounds","prevDisplayedWidth","prevDisplayedHeight","setIsActive","activate","deactivate","append","transformOrigin","calculateSize","load","updateContentSize","appendHeavy","zoomAndPanToInitial","applyCurrentZoomPan","mainScroll","isShifted","defaultPrevented","destroy","hasSlide","resize","panTo","force","scaleMultiplier","sizeChanged","setDisplayedSize","getPlaceholderElement","_this$content$placeho","placeholder","element","zoomTo","destZoomLevel","centerPoint","transitionDuration","ignoreBounds","isZoomable","animations","stopAllPan","prevZoomLevel","setZoomLevel","calculateZoomToPanOffset","finishTransition","_setResolution","startTransition","isPan","name","getCurrentTransform","onComplete","easing","toggleZoom","zoomAnimationDuration","point","totalPanDistance","getViewportCenterPoint","zoomFactor","panX","panY","isPannable","Boolean","_applyZoomTransform","currSlide","zoom","newResolution","$c246d27966689419$var$DragHandler","gestures","startPan","start","stopAll","change","prevP1","dragAxis","closeOnVerticalDrag","isMultitouch","_setPanWithFriction","bgOpacity","_getVerticalDragRatio","applyBgOpacity","_panOrMoveMainScroll","end","velocity","indexDiff","currentSlideVisibilityRatio","mainScrollShiftDiff","getCurrSlideX","moveIndexBy","correctZoomPan","_finishPanGestureForAxis","panPos","restoreBgOpacity","projectedPosition","vDragRatio","projectedVDragRatio","close","correctedPanPosition","dampingRatio","initialBgOpacity","totalPanDist","startSpring","onUpdate","pos","animationProgressRatio","floor","delta","newMainScrollX","moveTo","newPan","allowPanToNext","currSlideMainScrollX","isLeftToRight","_this$pswp$currSlide$","_this$pswp$currSlide","potentialPan","customFriction","correctedPan","$c246d27966689419$var$getZoomPointsCenter","$c246d27966689419$var$ZoomHandler","_startPan","_startZoomPoint","_zoomPoint","_wasOverFitZoomLevel","_startZoomLevel","startP1","startP2","minZoomLevel","maxZoomLevel","pinchToClose","_calculatePanForZoomLevel","ignoreGesture","destinationZoomLevel","currZoomLevelNeedsChange","initialPan","destinationPan","panNeedsChange","naturalFrequency","now","newZoomLevel","$c246d27966689419$var$didTapOnMainContent","event","closest","$c246d27966689419$var$TapHandler","click","originalEvent","targetClassList","classList","isImageClick","contains","isBackgroundClick","_doClickOrTapAction","tap","doubleTap","actionName","_this$gestures$pswp$e","actionFullName","call","clickToCloseNonZoomable","toggle","$c246d27966689419$var$Gestures","prevP2","_lastStartP1","_intervalP1","_numActivePoints","_ongoingPointers","_touchEventEnabled","_pointerEventEnabled","PointerEvent","supportsTouch","maxTouchPoints","_intervalTime","_velocityCalculated","isDragging","isZooming","raf","_tapTimer","drag","tapHandler","on","events","scrollWrap","_onClick","bind","_bindEvents","ontouchmove","ontouchend","pref","down","up","cancel","cancelEvent","onPointerDown","onPointerMove","onPointerUp","isMousePointer","pointerType","button","preventDefault","mouseDetected","_preventPointerEventBehaviour","_updatePoints","_clearTapTimer","_finishDrag","_updateStartPoints","_rafStopLoop","_rafRenderLoop","_calculateDragDirection","Date","_updateVelocity","_finishTap","_updatePrevPoints","requestAnimationFrame","time","_getVelocity","indexOf","tapDelay","doubleTapAction","setTimeout","clearTimeout","displacement","cancelAnimationFrame","applyFilters","pointerIndex","findIndex","ongoingPointer","pointerEvent","pointerId","splice","_convertEventPosToPoint","length","touchEvent","touches","diff","axisToCheck","pageX","offset","pageY","identifier","stopPropagation","$c246d27966689419$var$MainScroll","slideWidth","_currPositionIndex","_prevPositionIndex","_containerShiftIndex","itemHolders","resizeSlides","newSlideWidth","spacing","slideWidthChanged","itemHolder","resetPosition","appendHolders","i","setAttribute","display","canBeSwiped","getNumItems","animate","velocityX","newIndex","potentialIndex","numSlides","canLoop","getLoopedIndex","distance","stopMainScroll","destinationX","isMainScroll","updateCurrItem","currDiff","currDistance","_this$itemHolders$","tempHolder","positionDifference","diffAbs","_itemHolder$slide","shift","setContent","pop","unshift","updateLazy","dragging","newSlideIndexOffset","$c246d27966689419$var$KeyboardKeyCodesMap","Escape","z","ArrowLeft","ArrowUp","ArrowRight","ArrowDown","Tab","$c246d27966689419$var$getKeyboardEventKey","key","isKeySupported","$c246d27966689419$var$Keyboard","_wasFocused","trapFocus","initialPointerPos","_focusRoot","_onFocusIn","_onKeyDown","lastActiveElement","activeElement","returnFocus","focus","keydownAction","ctrlKey","metaKey","altKey","shiftKey","isForward","keyCode","escKey","arrowKeys","template","$c246d27966689419$var$CSSAnimation","props","_props$prop","onFinish","_target","_onComplete","_finished","_onTransitionEnd","_helperTimeout","_finalizeAnimation","removeEventListener","$c246d27966689419$var$SpringEaser","initialVelocity","_dampingRatio","_naturalFrequency","_dampedFrequency","easeFrame","deltaPosition","deltaTime","coeff","naturalDumpingPow","E","dumpedFCos","cos","dumpedFSin","sin","$c246d27966689419$var$SpringAnimation","_raf","easer","prevTime","animationLoop","$c246d27966689419$var$Animations","activeAnimations","_start","isSpring","animation","stop","isPanRunning","some","$c246d27966689419$var$ScrollWheel","_onWheel","deltaX","deltaY","wheelToZoom","deltaMode","clientX","clientY","$c246d27966689419$var$UIElement","_container","elementHTML","html","isButton","toLowerCase","title","ariaLabel","ariaText","innerHTML","$c246d27966689419$var$addElementHTML","htmlData","isCustomSVG","out","join","svgData","size","outlineID","inner","onInit","onClick","onclick","appendTo","topBar","$c246d27966689419$var$initArrowButton","isNextButton","loop","disabled","$c246d27966689419$var$arrowPrev","order","$c246d27966689419$var$arrowNext","$c246d27966689419$var$closeButton","$c246d27966689419$var$zoomButton","$c246d27966689419$var$loadingIndicator","indicatorElement","isVisible","delayTimeout","toggleIndicatorClass","setIndicatorVisibility","visible","updatePreloaderVisibility","_pswp$currSlide","isLoading","_pswp$currSlide2","preloaderDelay","ui","$c246d27966689419$var$counterIndicator","counterElement","innerText","indexIndicatorSep","$c246d27966689419$var$setZoomedIn","isZoomedIn","$c246d27966689419$var$UI","isRegistered","uiElementsData","items","_lastUpdatedZoomLevel","init","sort","a","b","uiElementData","registerElement","_pswp$element","_onZoomPanUpdate","elementData","isClosing","potentialZoomLevel","imageClickAction","$c246d27966689419$var$PhotoSwipeEvent","details","assign","$c246d27966689419$var$Eventable","_listeners","_filters","addFilter","fn","priority","_this$_filters$name","_this$_filters$name2","_this$pswp","f1","f2","removeFilter","args","_this$_filters$name3","apply","_this$_listeners$name","_this$pswp2","off","_this$pswp3","_this$_listeners$name2","$c246d27966689419$var$Placeholder","imageSrc","imgEl","decoding","alt","src","_this$element","parentNode","$c246d27966689419$var$Content","instance","displayedImageWidth","displayedImageHeight","isAttached","isDecoding","state","removePlaceholder","keepPlaceholder","isLazy","reload","usePlaceholder","placeholderEl","parentElement","prepend","placeholderSrc","msrc","isImageContent","loadImage","_this$data$src","_this$data$alt","imageElement","updateSrcsetSizes","srcset","complete","onLoaded","onload","onerror","onError","setSlide","displayError","isError","isInitialSizeUpdate","image","sizesWidth","dataset","largestUsedSize","parseInt","sizes","String","lazyLoad","_this$instance$option","_this$instance$option2","errorMsgEl","errorMsg","supportsDecode","decode","catch","finally","appendImage","$c246d27966689419$var$lazyLoadData","zoomLevel","createContentFromData","ceil","$c246d27966689419$var$ContentLoader","limit","preload","_cachedItems","loadSlideByIndex","initialIndex","getContentByIndex","$c246d27966689419$var$lazyLoadSlide","getItemData","addToCache","removeByIndex","indexToRemove","item","removedItem","find","$c246d27966689419$var$PhotoSwipeBase","_this$options","numItems","dataSource","_getGalleryDOMElements","gallery","_this$options2","dataSourceItem","Array","isArray","Element","_domElementToItemData","galleryElement","_this$options3","_this$options4","children","childSelector","$c246d27966689419$var$getElementsFromOption","option","legacySelector","parent","elements","NodeList","from","selector","querySelectorAll","linkEl","querySelector","pswpSrc","href","pswpSrcset","pswpWidth","pswpHeight","pswpType","thumbnailEl","_thumbnailEl$getAttri","currentSrc","getAttribute","pswpCropped","cropped","thumbCropped","lazyLoadData","$c246d27966689419$var$Opener","isClosed","isOpening","_duration","_useAnimation","_croppedZoom","_animateRootOpacity","_animateBgOpacity","_placeholder","_opacityElement","_cropContainer1","_cropContainer2","_thumbBounds","_prepareOpen","open","hideAnimationDuration","maxWidthToAnimate","_applyStartProps","showAnimationDuration","_options$showHideOpac","showHideAnimationType","showHideOpacity","_initialThumbBounds","getThumbBounds","_animateZoom","bg","opacity","innerRect","overflow","_setClosedStateZoomPan","willChange","Promise","resolve","img","decoded","isDelaying","$c246d27966689419$var$decodeImage","reject","_initiate","_this$pswp$element","_this$pswp$element2","setProperty","_animateToOpenState","_animateToClosedState","_onAnimationComplete","_animateTo","containerOnePanX","containerOnePanY","containerTwoPanX","containerTwoPanY","animProps","$c246d27966689419$var$defaultOptions","bgClickAction","tapAction","_prepareOptions","_prevViewportSize","isDestroying","hasMouse","_initialItemData","keyboard","_createMainStructure","rootClasses","mainClass","scrollWheel","isNaN","updateSize","pageYOffset","_handlePageResize","_updatePageScrollOffset","goTo","next","prev","_this$currSlide","_this$currSlide2","_itemHolder$slide2","refreshSlideContent","slideIndex","_this$currSlide$index","_this$currSlide3","_itemHolder$slide3","potentialHolderIndex","holder","matchMedia","matches","_this$element2","test","userAgent","setScrollOffset","body","$c246d27966689419$var$getThumbBounds","thumbBounds","thumbnail","thumbSelector","$c246d27966689419$var$getCroppedBoundsByElement","imageWidth","imageHeight","thumbAreaRect","getBoundingClientRect","fillZoomLevel","offsetX","offsetY","left","top","$c246d27966689419$var$getBoundsByElement","equalizePoints","roundPoint","getDistanceBetween","pointsEqual","clamp","toTransformString","setTransform","defaultCSSEasing","setTransitionStyle","setWidthHeight","removeTransitionStyle","decodeImage","LOAD_STATE","specialKeyUsed","getElementsFromOption","isSafari","supportsPassive","DOMEvents","getViewportSize","parsePaddingOption","getPanAreaSize","PanBounds","paddingProp","MAX_IMAGE_WIDTH","ZoomLevel","optionName","Slide","appendHeavyNearby","PAN_END_FRICTION","VERTICAL_DRAG_FRICTION","MIN_RATIO_TO_CLOSE","MIN_NEXT_SLIDE_SPEED","project","decelerationRate","DragHandler","mainScrollChanged","isRightToLeft","wasAtMinPanPosition","wasAtMaxPanPosition","UPPER_ZOOM_FRICTION","LOWER_ZOOM_FRICTION","getZoomPointsCenter","ZoomHandler","didTapOnMainContent","TapHandler","AXIS_SWIPE_HYSTERISIS","DOUBLE_TAP_DELAY","MIN_TAP_DISTANCE","Gestures","preventPointerEvent","MAIN_SCROLL_END_FRICTION","MainScroll","KeyboardKeyCodesMap","getKeyboardEventKey","Keyboard","DEFAULT_EASING","CSSAnimation","DEFAULT_NATURAL_FREQUENCY","DEFAULT_DAMPING_RATIO","SpringEaser","SpringAnimation","Animations","ScrollWheel","addElementHTML","UIElement","initArrowButton","arrowPrev","arrowNext","closeButton","zoomButton","loadingIndicator","counterIndicator","setZoomedIn","UI","currZoomLevelDiff","getBoundsByElement","getCroppedBoundsByElement","PhotoSwipeEvent","Eventable","Placeholder","Content","MIN_SLIDES_TO_CACHE","lazyLoadSlide","ContentLoader","PhotoSwipeBase","MIN_OPACITY","Opener","defaultOptions","PhotoSwipe"],"version":3,"file":"photoswipe.esm.2e2aa850.js.map"} \ No newline at end of file diff --git a/photoswipe.esm.b9f46f1c.js b/photoswipe.esm.b9f46f1c.js new file mode 100644 index 0000000..bc6c80d --- /dev/null +++ b/photoswipe.esm.b9f46f1c.js @@ -0,0 +1,5 @@ +(0,("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{}).parcelRequire94c2.register)("lxZQh",function(t,i){/*! + * PhotoSwipe 5.4.4 - https://photoswipe.com + * (c) 2024 Dmytro Semenov + */function e(t,i,e){let s=document.createElement(i);return t&&(s.className=t),e&&e.appendChild(s),s}function s(t,i){return t.x=i.x,t.y=i.y,void 0!==i.id&&(t.id=i.id),t}function n(t){t.x=Math.round(t.x),t.y=Math.round(t.y)}function o(t,i){let e=Math.abs(t.x-i.x),s=Math.abs(t.y-i.y);return Math.sqrt(e*e+s*s)}function a(t,i){return t.x===i.x&&t.y===i.y}function r(t,i,e){return Math.min(Math.max(t,i),e)}function h(t,i,e){let s=`translate3d(${t}px,${i||0}px,0)`;return void 0!==e&&(s+=` scale3d(${e},${e},1)`),s}function l(t,i,e,s){t.style.transform=h(i,e,s)}function p(t,i,e,s){t.style.transition=i?`${i} ${e}ms ${s||"cubic-bezier(.4,0,.22,1)"}`:"none"}function d(t,i,e){t.style.width="number"==typeof i?`${i}px`:i,t.style.height="number"==typeof e?`${e}px`:e}Object.defineProperty(t.exports,"__esModule",{value:!0,configurable:!0}),Object.defineProperty(t.exports,"default",{get:function(){return te},set:void 0,enumerable:!0,configurable:!0});let c={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function m(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}let u=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{u=!0}}))}catch(t){}class v{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach(t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)}),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;let a=n?"removeEventListener":"addEventListener";i.split(" ").forEach(i=>{if(i){o||(n?this._pool=this._pool.filter(s=>s.type!==i||s.listener!==e||s.target!==t):this._pool.push({target:t,type:i,listener:e,passive:s}));let r=!!u&&{passive:s||!1};t[a](i,e,r)}})}}function _(t,i){if(t.getViewportSizeFn){let e=t.getViewportSizeFn(t,i);if(e)return e}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function g(t,i,e,s,n){let o=0;if(i.paddingFn)o=i.paddingFn(e,s,n)[t];else if(i.padding)o=i.padding[t];else{let e="padding"+t[0].toUpperCase()+t.slice(1);i[e]&&(o=i[e])}return Number(o)||0}function y(t,i,e,s){return{x:i.x-g("left",t,i,e,s)-g("right",t,i,e,s),y:i.y-g("top",t,i,e,s)-g("bottom",t,i,e,s)}}class f{constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){let{pswp:i}=this.slide,e=this.slide["x"===t?"width":"height"]*this.currZoomLevel,s=g("x"===t?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),n=this.slide.panAreaSize[t];this.center[t]=Math.round((n-e)/2)+s,this.max[t]=e>n?Math.round(n-e)+s:this.center[t],this.min[t]=e>n?s:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return r(i,this.max[t],this.min[t])}}class w{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){let s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;let n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,no?n:o),this.vFill=Math.min(1,o),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){let i=this.options[t+"ZoomLevel"];if(i)return"function"==typeof i?i(this):"fill"===i?this.fill:"fit"===i?this.fit:Number(i)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,3*this.fit),this.elementSize&&t*this.elementSize.x>4e3&&(t=4e3/this.elementSize.x)),t}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,4*this.fit)}}class x{constructor(t,i,s){this.data=t,this.index=i,this.pswp=s,this.isActive=i===s.currIndex,this.currentResolution=0,this.panAreaSize={x:0,y:0},this.pan={x:0,y:0},this.isFirstSlide=this.isActive&&!s.opener.isOpen,this.zoomLevels=new w(s.options,t,i,s),this.pswp.dispatch("gettingData",{slide:this,data:this.data,index:i}),this.content=this.pswp.contentLoader.getContentBySlide(this),this.container=e("pswp__zoom-wrap","div"),this.holderElement=null,this.currZoomLevel=1,this.width=this.content.width,this.height=this.content.height,this.heavyAppended=!1,this.bounds=new f(this),this.prevDisplayedWidth=-1,this.prevDisplayedHeight=-1,this.pswp.dispatch("slideInit",{slide:this})}setIsActive(t){t&&!this.isActive?this.activate():!t&&this.isActive&&this.deactivate()}append(t){this.holderElement=t,this.container.style.transformOrigin="0 0",this.data&&(this.calculateSize(),this.load(),this.updateContentSize(),this.appendHeavy(),this.holderElement.appendChild(this.container),this.zoomAndPanToInitial(),this.pswp.dispatch("firstZoomPan",{slide:this}),this.applyCurrentZoomPan(),this.pswp.dispatch("afterSetContent",{slide:this}),this.isActive&&this.activate())}load(){this.content.load(!1),this.pswp.dispatch("slideLoad",{slide:this})}appendHeavy(){let{pswp:t}=this;this.heavyAppended||!t.opener.isOpen||t.mainScroll.isShifted()||(this.isActive,0)||this.pswp.dispatch("appendHeavy",{slide:this}).defaultPrevented||(this.heavyAppended=!0,this.content.append(),this.pswp.dispatch("appendHeavyContent",{slide:this}))}activate(){this.isActive=!0,this.appendHeavy(),this.content.activate(),this.pswp.dispatch("slideActivate",{slide:this})}deactivate(){this.isActive=!1,this.content.deactivate(),this.currZoomLevel!==this.zoomLevels.initial&&this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize(),this.pswp.dispatch("slideDeactivate",{slide:this})}destroy(){this.content.hasSlide=!1,this.content.remove(),this.container.remove(),this.pswp.dispatch("slideDestroy",{slide:this})}resize(){this.currZoomLevel!==this.zoomLevels.initial&&this.isActive?(this.calculateSize(),this.bounds.update(this.currZoomLevel),this.panTo(this.pan.x,this.pan.y)):(this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize())}updateContentSize(t){let i=this.currentResolution||this.zoomLevels.initial;if(!i)return;let e=Math.round(this.width*i)||this.pswp.viewportSize.x,s=Math.round(this.height*i)||this.pswp.viewportSize.y;(this.sizeChanged(e,s)||t)&&this.content.setDisplayedSize(e,s)}sizeChanged(t,i){return(t!==this.prevDisplayedWidth||i!==this.prevDisplayedHeight)&&(this.prevDisplayedWidth=t,this.prevDisplayedHeight=i,!0)}getPlaceholderElement(){var t;return null===(t=this.content.placeholder)||void 0===t?void 0:t.element}zoomTo(t,i,e,s){let{pswp:o}=this;if(!this.isZoomable()||o.mainScroll.isShifted())return;o.dispatch("beforeZoomTo",{destZoomLevel:t,centerPoint:i,transitionDuration:e}),o.animations.stopAllPan();let a=this.currZoomLevel;s||(t=r(t,this.zoomLevels.min,this.zoomLevels.max)),this.setZoomLevel(t),this.pan.x=this.calculateZoomToPanOffset("x",i,a),this.pan.y=this.calculateZoomToPanOffset("y",i,a),n(this.pan);let h=()=>{this._setResolution(t),this.applyCurrentZoomPan()};e?o.animations.startTransition({isPan:!0,name:"zoomTo",target:this.container,transform:this.getCurrentTransform(),onComplete:h,duration:e,easing:o.options.easing}):h()}toggleZoom(t){this.zoomTo(this.currZoomLevel===this.zoomLevels.initial?this.zoomLevels.secondary:this.zoomLevels.initial,t,this.pswp.options.zoomAnimationDuration)}setZoomLevel(t){this.currZoomLevel=t,this.bounds.update(this.currZoomLevel)}calculateZoomToPanOffset(t,i,e){if(0==this.bounds.max[t]-this.bounds.min[t])return this.bounds.center[t];i||(i=this.pswp.getViewportCenterPoint()),e||(e=this.zoomLevels.initial);let s=this.currZoomLevel/e;return this.bounds.correctPan(t,(this.pan[t]-i[t])*s+i[t])}panTo(t,i){this.pan.x=this.bounds.correctPan("x",t),this.pan.y=this.bounds.correctPan("y",i),this.applyCurrentZoomPan()}isPannable(){return!!this.width&&this.currZoomLevel>this.zoomLevels.fit}isZoomable(){return!!this.width&&this.content.isZoomable()}applyCurrentZoomPan(){this._applyZoomTransform(this.pan.x,this.pan.y,this.currZoomLevel),this===this.pswp.currSlide&&this.pswp.dispatch("zoomPanUpdate",{slide:this})}zoomAndPanToInitial(){this.currZoomLevel=this.zoomLevels.initial,this.bounds.update(this.currZoomLevel),s(this.pan,this.bounds.center),this.pswp.dispatch("initialZoomPan",{slide:this})}_applyZoomTransform(t,i,e){e/=this.currentResolution||this.zoomLevels.initial,l(this.container,t,i,e)}calculateSize(){let{pswp:t}=this;s(this.panAreaSize,y(t.options,t.viewportSize,this.data,this.index)),this.zoomLevels.update(this.width,this.height,this.panAreaSize),t.dispatch("calcSlideSize",{slide:this})}getCurrentTransform(){let t=this.currZoomLevel/(this.currentResolution||this.zoomLevels.initial);return h(this.pan.x,this.pan.y,t)}_setResolution(t){t!==this.currentResolution&&(this.currentResolution=t,this.updateContentSize(),this.pswp.dispatch("resolutionChanged"))}}class P{constructor(t){this.gestures=t,this.pswp=t.pswp,this.startPan={x:0,y:0}}start(){this.pswp.currSlide&&s(this.startPan,this.pswp.currSlide.pan),this.pswp.animations.stopAll()}change(){let{p1:t,prevP1:i,dragAxis:e}=this.gestures,{currSlide:s}=this.pswp;if("y"===e&&this.pswp.options.closeOnVerticalDrag&&s&&s.currZoomLevel<=s.zoomLevels.fit&&!this.gestures.isMultitouch){let e=s.pan.y+(t.y-i.y);if(!this.pswp.dispatch("verticalDrag",{panY:e}).defaultPrevented){this._setPanWithFriction("y",e,.6);let t=1-Math.abs(this._getVerticalDragRatio(s.pan.y));this.pswp.applyBgOpacity(t),s.applyCurrentZoomPan()}}else!this._panOrMoveMainScroll("x")&&(this._panOrMoveMainScroll("y"),s&&(n(s.pan),s.applyCurrentZoomPan()))}end(){let{velocity:t}=this.gestures,{mainScroll:i,currSlide:e}=this.pswp,s=0;if(this.pswp.animations.stopAll(),i.isShifted()){let e=(i.x-i.getCurrSlideX())/this.pswp.viewportSize.x;t.x<-.5&&e<0||t.x<.1&&e<-.5?(s=1,t.x=Math.min(t.x,0)):(t.x>.5&&e>0||t.x>-.1&&e>.5)&&(s=-1,t.x=Math.max(t.x,0)),i.moveIndexBy(s,!0,t.x)}e&&e.currZoomLevel>e.zoomLevels.max||this.gestures.isMultitouch?this.gestures.zoomLevels.correctZoomPan(!0):(this._finishPanGestureForAxis("x"),this._finishPanGestureForAxis("y"))}_finishPanGestureForAxis(t){let{velocity:i}=this.gestures,{currSlide:e}=this.pswp;if(!e)return;let{pan:s,bounds:n}=e,o=s[t],a=this.pswp.bgOpacity<1&&"y"===t,h=o+.995*i[t]/(1-.995);if(a){let t=this._getVerticalDragRatio(o),i=this._getVerticalDragRatio(h);if(t<0&&i<-.4||t>0&&i>.4){this.pswp.close();return}}let l=n.correctPan(t,h);if(o===l)return;let p=l===h?1:.82,d=this.pswp.bgOpacity,c=l-o;this.pswp.animations.startSpring({name:"panGesture"+t,isPan:!0,start:o,end:l,velocity:i[t],dampingRatio:p,onUpdate:i=>{if(a&&this.pswp.bgOpacity<1){let t=1-(l-i)/c;this.pswp.applyBgOpacity(r(d+(1-d)*t,0,1))}s[t]=Math.floor(i),e.applyCurrentZoomPan()}})}_panOrMoveMainScroll(t){let{p1:i,dragAxis:e,prevP1:s,isMultitouch:n}=this.gestures,{currSlide:o,mainScroll:a}=this.pswp,r=i[t]-s[t],h=a.x+r;if(!r||!o)return!1;if("x"===t&&!o.isPannable()&&!n)return a.moveTo(h,!0),!0;let{bounds:l}=o,p=o.pan[t]+r;if(this.pswp.options.allowPanToNext&&"x"===e&&"x"===t&&!n){let i=a.getCurrSlideX(),e=a.x-i,s=r>0;if(p>l.min[t]&&s){if(l.min[t]<=this.startPan[t])return a.moveTo(h,!0),!0;this._setPanWithFriction(t,p)}else if(p0)return a.moveTo(Math.max(h,i),!0),!0;if(e<0)return a.moveTo(Math.min(h,i),!0),!0}else this._setPanWithFriction(t,p)}else"y"===t&&(a.isShifted()||l.min.y===l.max.y)||this._setPanWithFriction(t,p);return!1}_getVerticalDragRatio(t){var i,e;return(t-(null!==(i=null===(e=this.pswp.currSlide)||void 0===e?void 0:e.bounds.center.y)&&void 0!==i?i:0))/(this.pswp.viewportSize.y/3)}_setPanWithFriction(t,i,e){let{currSlide:s}=this.pswp;if(!s)return;let{pan:n,bounds:o}=s;if(o.correctPan(t,i)!==i||e){let s=Math.round(i-n[t]);n[t]+=s*(e||.35)}else n[t]=i}}function S(t,i,e){return t.x=(i.x+e.x)/2,t.y=(i.y+e.y)/2,t}class b{constructor(t){this.gestures=t,this._startPan={x:0,y:0},this._startZoomPoint={x:0,y:0},this._zoomPoint={x:0,y:0},this._wasOverFitZoomLevel=!1,this._startZoomLevel=1}start(){let{currSlide:t}=this.gestures.pswp;t&&(this._startZoomLevel=t.currZoomLevel,s(this._startPan,t.pan)),this.gestures.pswp.animations.stopAllPan(),this._wasOverFitZoomLevel=!1}change(){let{p1:t,startP1:i,p2:e,startP2:s,pswp:n}=this.gestures,{currSlide:a}=n;if(!a)return;let r=a.zoomLevels.min,h=a.zoomLevels.max;if(!a.isZoomable()||n.mainScroll.isShifted())return;S(this._startZoomPoint,i,s),S(this._zoomPoint,t,e);let l=1/o(i,s)*o(t,e)*this._startZoomLevel;if(l>a.zoomLevels.initial+a.zoomLevels.initial/15&&(this._wasOverFitZoomLevel=!0),lh&&(l=h+(l-h)*.05);a.pan.x=this._calculatePanForZoomLevel("x",l),a.pan.y=this._calculatePanForZoomLevel("y",l),a.setZoomLevel(l),a.applyCurrentZoomPan()}end(){let{pswp:t}=this.gestures,{currSlide:i}=t;(!i||i.currZoomLeveln.zoomLevels.max?i=n.zoomLevels.max:(h=!1,i=o);let l=e.bgOpacity,p=e.bgOpacity<1,d=s({x:0,y:0},n.pan),c=s({x:0,y:0},d);t&&(this._zoomPoint.x=0,this._zoomPoint.y=0,this._startZoomPoint.x=0,this._startZoomPoint.y=0,this._startZoomLevel=o,s(this._startPan,d)),h&&(c={x:this._calculatePanForZoomLevel("x",i),y:this._calculatePanForZoomLevel("y",i)}),n.setZoomLevel(i),c={x:n.bounds.correctPan("x",c.x),y:n.bounds.correctPan("y",c.y)},n.setZoomLevel(o);let m=!a(c,d);if(!m&&!h&&!p){n._setResolution(i),n.applyCurrentZoomPan();return}e.animations.stopAllPan(),e.animations.startSpring({isPan:!0,start:0,end:1e3,velocity:0,dampingRatio:1,naturalFrequency:40,onUpdate:t=>{if(t/=1e3,m||h){if(m&&(n.pan.x=d.x+(c.x-d.x)*t,n.pan.y=d.y+(c.y-d.y)*t),h){let e=o+(i-o)*t;n.setZoomLevel(e)}n.applyCurrentZoomPan()}p&&e.bgOpacity<1&&e.applyBgOpacity(r(l+(1-l)*t,0,1))},onComplete:()=>{n._setResolution(i),n.applyCurrentZoomPan()}})}}function L(t){return!!t.target.closest(".pswp__container")}class z{constructor(t){this.gestures=t}click(t,i){let e=i.target.classList,s=e.contains("pswp__img"),n=e.contains("pswp__item")||e.contains("pswp__zoom-wrap");s?this._doClickOrTapAction("imageClick",t,i):n&&this._doClickOrTapAction("bgClick",t,i)}tap(t,i){L(i)&&this._doClickOrTapAction("tap",t,i)}doubleTap(t,i){L(i)&&this._doClickOrTapAction("doubleTap",t,i)}_doClickOrTapAction(t,i,e){var s;let{pswp:n}=this.gestures,{currSlide:o}=n,a=t+"Action",r=n.options[a];if(!n.dispatch(a,{point:i,originalEvent:e}).defaultPrevented){if("function"==typeof r){r.call(n,i,e);return}switch(r){case"close":case"next":n[r]();break;case"zoom":null==o||o.toggleZoom(i);break;case"zoom-or-close":null!=o&&o.isZoomable()&&o.zoomLevels.secondary!==o.zoomLevels.initial?o.toggleZoom(i):n.options.clickToCloseNonZoomable&&n.close();break;case"toggle-controls":null===(s=this.gestures.pswp.element)||void 0===s||s.classList.toggle("pswp--ui-visible")}}}}class I{constructor(t){this.pswp=t,this.dragAxis=null,this.p1={x:0,y:0},this.p2={x:0,y:0},this.prevP1={x:0,y:0},this.prevP2={x:0,y:0},this.startP1={x:0,y:0},this.startP2={x:0,y:0},this.velocity={x:0,y:0},this._lastStartP1={x:0,y:0},this._intervalP1={x:0,y:0},this._numActivePoints=0,this._ongoingPointers=[],this._touchEventEnabled="ontouchstart"in window,this._pointerEventEnabled=!!window.PointerEvent,this.supportsTouch=this._touchEventEnabled||this._pointerEventEnabled&&navigator.maxTouchPoints>1,this._numActivePoints=0,this._intervalTime=0,this._velocityCalculated=!1,this.isMultitouch=!1,this.isDragging=!1,this.isZooming=!1,this.raf=null,this._tapTimer=null,this.supportsTouch||(t.options.allowPanToNext=!1),this.drag=new P(this),this.zoomLevels=new b(this),this.tapHandler=new z(this),t.on("bindEvents",()=>{t.events.add(t.scrollWrap,"click",this._onClick.bind(this)),this._pointerEventEnabled?this._bindEvents("pointer","down","up","cancel"):this._touchEventEnabled?(this._bindEvents("touch","start","end","cancel"),t.scrollWrap&&(t.scrollWrap.ontouchmove=()=>{},t.scrollWrap.ontouchend=()=>{})):this._bindEvents("mouse","down","up")})}_bindEvents(t,i,e,s){let{pswp:n}=this,{events:o}=n,a=s?t+s:"";o.add(n.scrollWrap,t+i,this.onPointerDown.bind(this)),o.add(window,t+"move",this.onPointerMove.bind(this)),o.add(window,t+e,this.onPointerUp.bind(this)),a&&o.add(n.scrollWrap,a,this.onPointerUp.bind(this))}onPointerDown(t){let i="mousedown"===t.type||"mouse"===t.pointerType;if(i&&t.button>0)return;let{pswp:e}=this;if(!e.opener.isOpen){t.preventDefault();return}e.dispatch("pointerDown",{originalEvent:t}).defaultPrevented||(i&&(e.mouseDetected(),this._preventPointerEventBehaviour(t,"down")),e.animations.stopAll(),this._updatePoints(t,"down"),1===this._numActivePoints&&(this.dragAxis=null,s(this.startP1,this.p1)),this._numActivePoints>1?(this._clearTapTimer(),this.isMultitouch=!0):this.isMultitouch=!1)}onPointerMove(t){this._preventPointerEventBehaviour(t,"move"),this._numActivePoints&&(this._updatePoints(t,"move"),this.pswp.dispatch("pointerMove",{originalEvent:t}).defaultPrevented||(1!==this._numActivePoints||this.isDragging?this._numActivePoints>1&&!this.isZooming&&(this._finishDrag(),this.isZooming=!0,this._updateStartPoints(),this.zoomLevels.start(),this._rafStopLoop(),this._rafRenderLoop()):(this.dragAxis||this._calculateDragDirection(),this.dragAxis&&!this.isDragging&&(this.isZooming&&(this.isZooming=!1,this.zoomLevels.end()),this.isDragging=!0,this._clearTapTimer(),this._updateStartPoints(),this._intervalTime=Date.now(),this._velocityCalculated=!1,s(this._intervalP1,this.p1),this.velocity.x=0,this.velocity.y=0,this.drag.start(),this._rafStopLoop(),this._rafRenderLoop()))))}_finishDrag(){this.isDragging&&(this.isDragging=!1,this._velocityCalculated||this._updateVelocity(!0),this.drag.end(),this.dragAxis=null)}onPointerUp(t){this._numActivePoints&&(this._updatePoints(t,"up"),!this.pswp.dispatch("pointerUp",{originalEvent:t}).defaultPrevented&&(0!==this._numActivePoints||(this._rafStopLoop(),this.isDragging?this._finishDrag():this.isZooming||this.isMultitouch||this._finishTap(t)),this._numActivePoints<2&&this.isZooming&&(this.isZooming=!1,this.zoomLevels.end(),1===this._numActivePoints&&(this.dragAxis=null,this._updateStartPoints()))))}_rafRenderLoop(){(this.isDragging||this.isZooming)&&(this._updateVelocity(),this.isDragging?a(this.p1,this.prevP1)||this.drag.change():a(this.p1,this.prevP1)&&a(this.p2,this.prevP2)||this.zoomLevels.change(),this._updatePrevPoints(),this.raf=requestAnimationFrame(this._rafRenderLoop.bind(this)))}_updateVelocity(t){let i=Date.now(),e=i-this._intervalTime;(!(e<50)||t)&&(this.velocity.x=this._getVelocity("x",e),this.velocity.y=this._getVelocity("y",e),this._intervalTime=i,s(this._intervalP1,this.p1),this._velocityCalculated=!0)}_finishTap(t){let{mainScroll:i}=this.pswp;if(i.isShifted()){i.moveIndexBy(0,!0);return}if(t.type.indexOf("cancel")>0)return;if("mouseup"===t.type||"mouse"===t.pointerType){this.tapHandler.click(this.startP1,t);return}let e=this.pswp.options.doubleTapAction?300:0;this._tapTimer?(this._clearTapTimer(),25>o(this._lastStartP1,this.startP1)&&this.tapHandler.doubleTap(this.startP1,t)):(s(this._lastStartP1,this.startP1),this._tapTimer=setTimeout(()=>{this.tapHandler.tap(this.startP1,t),this._clearTapTimer()},e))}_clearTapTimer(){this._tapTimer&&(clearTimeout(this._tapTimer),this._tapTimer=null)}_getVelocity(t,i){let e=this.p1[t]-this._intervalP1[t];return Math.abs(e)>1&&i>5?e/i:0}_rafStopLoop(){this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}_preventPointerEventBehaviour(t,i){this.pswp.applyFilters("preventPointerEvent",!0,t,i)&&t.preventDefault()}_updatePoints(t,i){if(this._pointerEventEnabled){let e=this._ongoingPointers.findIndex(i=>i.id===t.pointerId);"up"===i&&e>-1?this._ongoingPointers.splice(e,1):"down"===i&&-1===e?this._ongoingPointers.push(this._convertEventPosToPoint(t,{x:0,y:0})):e>-1&&this._convertEventPosToPoint(t,this._ongoingPointers[e]),this._numActivePoints=this._ongoingPointers.length,this._numActivePoints>0&&s(this.p1,this._ongoingPointers[0]),this._numActivePoints>1&&s(this.p2,this._ongoingPointers[1])}else this._numActivePoints=0,t.type.indexOf("touch")>-1?t.touches&&t.touches.length>0&&(this._convertEventPosToPoint(t.touches[0],this.p1),this._numActivePoints++,t.touches.length>1&&(this._convertEventPosToPoint(t.touches[1],this.p2),this._numActivePoints++)):(this._convertEventPosToPoint(t,this.p1),"up"===i?this._numActivePoints=0:this._numActivePoints++)}_updatePrevPoints(){s(this.prevP1,this.p1),s(this.prevP2,this.p2)}_updateStartPoints(){s(this.startP1,this.p1),s(this.startP2,this.p2),this._updatePrevPoints()}_calculateDragDirection(){if(this.pswp.mainScroll.isShifted())this.dragAxis="x";else{let t=Math.abs(this.p1.x-this.startP1.x)-Math.abs(this.p1.y-this.startP1.y);if(0!==t){let i=t>0?"x":"y";Math.abs(this.p1[i]-this.startP1[i])>=10&&(this.dragAxis=i)}}}_convertEventPosToPoint(t,i){return i.x=t.pageX-this.pswp.offset.x,i.y=t.pageY-this.pswp.offset.y,"pointerId"in t?i.id=t.pointerId:void 0!==t.identifier&&(i.id=t.identifier),i}_onClick(t){this.pswp.mainScroll.isShifted()&&(t.preventDefault(),t.stopPropagation())}}class A{constructor(t){this.pswp=t,this.x=0,this.slideWidth=0,this._currPositionIndex=0,this._prevPositionIndex=0,this._containerShiftIndex=-1,this.itemHolders=[]}resize(t){let{pswp:i}=this,e=Math.round(i.viewportSize.x+i.viewportSize.x*i.options.spacing),s=e!==this.slideWidth;s&&(this.slideWidth=e,this.moveTo(this.getCurrSlideX())),this.itemHolders.forEach((i,e)=>{s&&l(i.el,(e+this._containerShiftIndex)*this.slideWidth),t&&i.slide&&i.slide.resize()})}resetPosition(){this._currPositionIndex=0,this._prevPositionIndex=0,this.slideWidth=0,this._containerShiftIndex=-1}appendHolders(){this.itemHolders=[];for(let t=0;t<3;t++){let i=e("pswp__item","div",this.pswp.container);i.setAttribute("role","group"),i.setAttribute("aria-roledescription","slide"),i.setAttribute("aria-hidden","true"),i.style.display=1===t?"block":"none",this.itemHolders.push({el:i})}}canBeSwiped(){return this.pswp.getNumItems()>1}moveIndexBy(t,i,e){let{pswp:s}=this,n=s.potentialIndex+t,o=s.getNumItems();if(s.canLoop()){n=s.getLoopedIndex(n);let i=(t+o)%o;t=i<=o/2?i:i-o}else n<0?n=0:n>=o&&(n=o-1),t=n-s.potentialIndex;s.potentialIndex=n,this._currPositionIndex-=t,s.animations.stopMainScroll();let a=this.getCurrSlideX();if(i){s.animations.startSpring({isMainScroll:!0,start:this.x,end:a,velocity:e||0,naturalFrequency:30,dampingRatio:1,onUpdate:t=>{this.moveTo(t)},onComplete:()=>{this.updateCurrItem(),s.appendHeavy()}});let t=s.potentialIndex-s.currIndex;if(s.canLoop()){let i=(t+o)%o;t=i<=o/2?i:i-o}Math.abs(t)>1&&this.updateCurrItem()}else this.moveTo(a),this.updateCurrItem();return!!t}getCurrSlideX(){return this.slideWidth*this._currPositionIndex}isShifted(){return this.x!==this.getCurrSlideX()}updateCurrItem(){var t;let i;let{pswp:e}=this,s=this._prevPositionIndex-this._currPositionIndex;if(!s)return;this._prevPositionIndex=this._currPositionIndex,e.currIndex=e.potentialIndex;let n=Math.abs(s);n>=3&&(this._containerShiftIndex+=s+(s>0?-3:3),n=3,this.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.destroy(),t.slide=void 0}));for(let t=0;t0?(i=this.itemHolders.shift())&&(this.itemHolders[2]=i,this._containerShiftIndex++,l(i.el,(this._containerShiftIndex+2)*this.slideWidth),e.setContent(i,e.currIndex-n+t+2)):(i=this.itemHolders.pop())&&(this.itemHolders.unshift(i),this._containerShiftIndex--,l(i.el,this._containerShiftIndex*this.slideWidth),e.setContent(i,e.currIndex+n-t-2));Math.abs(this._containerShiftIndex)>50&&!this.isShifted()&&(this.resetPosition(),this.resize()),e.animations.stopAllPan(),this.itemHolders.forEach((t,i)=>{t.slide&&t.slide.setIsActive(1===i)}),e.currSlide=null===(t=this.itemHolders[1])||void 0===t?void 0:t.slide,e.contentLoader.updateLazy(s),e.currSlide&&e.currSlide.applyCurrentZoomPan(),e.dispatch("change")}moveTo(t,i){if(!this.pswp.canLoop()&&i){let i=(this.slideWidth*this._currPositionIndex-t)/this.slideWidth;i+=this.pswp.currIndex;let e=Math.round(t-this.x);(i<0&&e>0||i>=this.pswp.getNumItems()-1&&e<0)&&(t=this.x+.35*e)}this.x=t,this.pswp.container&&l(this.pswp.container,t),this.pswp.dispatch("moveMainScroll",{x:t,dragging:null!=i&&i})}}let C={Escape:27,z:90,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Tab:9},T=(t,i)=>i?t:C[t];class Z{constructor(t){this.pswp=t,this._wasFocused=!1,t.on("bindEvents",()=>{t.options.trapFocus&&(t.options.initialPointerPos||this._focusRoot(),t.events.add(document,"focusin",this._onFocusIn.bind(this))),t.events.add(document,"keydown",this._onKeyDown.bind(this))});let i=document.activeElement;t.on("destroy",()=>{t.options.returnFocus&&i&&this._wasFocused&&i.focus()})}_focusRoot(){!this._wasFocused&&this.pswp.element&&(this.pswp.element.focus(),this._wasFocused=!0)}_onKeyDown(t){let i,e;let{pswp:s}=this;if(s.dispatch("keydown",{originalEvent:t}).defaultPrevented||"button"in t&&1===t.button||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey)return;let n=!1,o="key"in t;switch(o?t.key:t.keyCode){case T("Escape",o):s.options.escKey&&(i="close");break;case T("z",o):i="toggleZoom";break;case T("ArrowLeft",o):e="x";break;case T("ArrowUp",o):e="y";break;case T("ArrowRight",o):e="x",n=!0;break;case T("ArrowDown",o):n=!0,e="y";break;case T("Tab",o):this._focusRoot()}if(e){t.preventDefault();let{currSlide:o}=s;s.options.arrowKeys&&"x"===e&&s.getNumItems()>1?i=n?"next":"prev":o&&o.currZoomLevel>o.zoomLevels.fit&&(o.pan[e]+=n?-80:80,o.panTo(o.pan.x,o.pan.y))}i&&(t.preventDefault(),s[i]())}_onFocusIn(t){let{template:i}=this.pswp;i&&document!==t.target&&i!==t.target&&!i.contains(t.target)&&i.focus()}}class O{constructor(t){var i;this.props=t;let{target:e,onComplete:s,transform:n,onFinish:o=()=>{},duration:a=333,easing:r="cubic-bezier(.4,0,.22,1)"}=t;this.onFinish=o;let h=n?"transform":"opacity",l=null!==(i=t[h])&&void 0!==i?i:"";this._target=e,this._onComplete=s,this._finished=!1,this._onTransitionEnd=this._onTransitionEnd.bind(this),this._helperTimeout=setTimeout(()=>{p(e,h,a,r),this._helperTimeout=setTimeout(()=>{e.addEventListener("transitionend",this._onTransitionEnd,!1),e.addEventListener("transitioncancel",this._onTransitionEnd,!1),this._helperTimeout=setTimeout(()=>{this._finalizeAnimation()},a+500),e.style[h]=l},30)},0)}_onTransitionEnd(t){t.target===this._target&&this._finalizeAnimation()}_finalizeAnimation(){!this._finished&&(this._finished=!0,this.onFinish(),this._onComplete&&this._onComplete())}destroy(){this._helperTimeout&&clearTimeout(this._helperTimeout),p(this._target),this._target.removeEventListener("transitionend",this._onTransitionEnd,!1),this._target.removeEventListener("transitioncancel",this._onTransitionEnd,!1),this._finished||this._finalizeAnimation()}}class D{constructor(t,i,e){this.velocity=1e3*t,this._dampingRatio=i||.75,this._naturalFrequency=e||12,this._dampedFrequency=this._naturalFrequency,this._dampingRatio<1&&(this._dampedFrequency*=Math.sqrt(1-this._dampingRatio*this._dampingRatio))}easeFrame(t,i){let e,s=0;i/=1e3;let n=Math.E**(-this._dampingRatio*this._naturalFrequency*i);if(1===this._dampingRatio)e=this.velocity+this._naturalFrequency*t,s=(t+e*i)*n,this.velocity=-(s*this._naturalFrequency)+e*n;else if(this._dampingRatio<1){e=1/this._dampedFrequency*(this._dampingRatio*this._naturalFrequency*t+this.velocity);let o=Math.cos(this._dampedFrequency*i),a=Math.sin(this._dampedFrequency*i);s=n*(t*o+e*a),this.velocity=-(s*this._naturalFrequency)*this._dampingRatio+n*(-this._dampedFrequency*t*a+this._dampedFrequency*e*o)}return s}}class E{constructor(t){this.props=t,this._raf=0;let{start:i,end:e,velocity:s,onUpdate:n,onComplete:o,onFinish:a=()=>{},dampingRatio:r,naturalFrequency:h}=t;this.onFinish=a;let l=new D(s,r,h),p=Date.now(),d=i-e,c=()=>{this._raf&&(1>Math.abs(d=l.easeFrame(d,Date.now()-p))&&50>Math.abs(l.velocity)?(n(e),o&&o(),this.onFinish()):(p=Date.now(),n(d+e),this._raf=requestAnimationFrame(c)))};this._raf=requestAnimationFrame(c)}destroy(){this._raf>=0&&cancelAnimationFrame(this._raf),this._raf=0}}class M{constructor(){this.activeAnimations=[]}startSpring(t){this._start(t,!0)}startTransition(t){this._start(t)}_start(t,i){let e=i?new E(t):new O(t);return this.activeAnimations.push(e),e.onFinish=()=>this.stop(e),e}stop(t){t.destroy();let i=this.activeAnimations.indexOf(t);i>-1&&this.activeAnimations.splice(i,1)}stopAll(){this.activeAnimations.forEach(t=>{t.destroy()}),this.activeAnimations=[]}stopAllPan(){this.activeAnimations=this.activeAnimations.filter(t=>!t.props.isPan||(t.destroy(),!1))}stopMainScroll(){this.activeAnimations=this.activeAnimations.filter(t=>!t.props.isMainScroll||(t.destroy(),!1))}isPanRunning(){return this.activeAnimations.some(t=>t.props.isPan)}}class F{constructor(t){this.pswp=t,t.events.add(t.element,"wheel",this._onWheel.bind(this))}_onWheel(t){t.preventDefault();let{currSlide:i}=this.pswp,{deltaX:e,deltaY:s}=t;if(i&&!this.pswp.dispatch("wheel",{originalEvent:t}).defaultPrevented){if(t.ctrlKey||this.pswp.options.wheelToZoom){if(i.isZoomable()){let e=-s;1===t.deltaMode?e*=.05:e*=t.deltaMode?1:.002,e=2**e;let n=i.currZoomLevel*e;i.zoomTo(n,{x:t.clientX,y:t.clientY})}}else i.isPannable()&&(1===t.deltaMode&&(e*=18,s*=18),i.panTo(i.pan.x-e,i.pan.y-s))}}}class R{constructor(t,i){var s;let n=i.name||i.className,o=i.html;if(!1===t.options[n])return;"string"==typeof t.options[n+"SVG"]&&(o=t.options[n+"SVG"]),t.dispatch("uiElementCreate",{data:i});let a="";i.isButton?(a+="pswp__button ",a+=i.className||`pswp__button--${i.name}`):a+=i.className||`pswp__${i.name}`;let r=i.isButton?i.tagName||"button":i.tagName||"div",h=e(a,r=r.toLowerCase());if(i.isButton){"button"===r&&(h.type="button");let{title:e}=i,{ariaLabel:s}=i;"string"==typeof t.options[n+"Title"]&&(e=t.options[n+"Title"]),e&&(h.title=e);let o=s||e;o&&h.setAttribute("aria-label",o)}h.innerHTML=function(t){if("string"==typeof t)return t;if(!t||!t.isCustomSVG)return"";let i='"}(o),i.onInit&&i.onInit(h,t),i.onClick&&(h.onclick=e=>{"string"==typeof i.onClick?t[i.onClick]():"function"==typeof i.onClick&&i.onClick(e,h,t)});let l=i.appendTo||"bar",p=t.element;"bar"===l?(t.topBar||(t.topBar=e("pswp__top-bar pswp__hide-on-close","div",t.scrollWrap)),p=t.topBar):(h.classList.add("pswp__hide-on-close"),"wrapper"===l&&(p=t.scrollWrap)),null===(s=p)||void 0===s||s.appendChild(t.applyFilters("uiElement",h,i))}}function B(t,i,e){t.classList.add("pswp__button--arrow"),t.setAttribute("aria-controls","pswp__items"),i.on("change",()=>{i.options.loop||(e?t.disabled=!(i.currIndex0))})}let H={name:"arrowPrev",className:"pswp__button--arrow--prev",title:"Previous",order:10,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"prev",onInit:B},k={name:"arrowNext",className:"pswp__button--arrow--next",title:"Next",order:11,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"next",onInit:(t,i)=>{B(t,i,!0)}},N={name:"close",title:"Close",order:20,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-close"},onClick:"close"},W={name:"zoom",title:"Zoom",order:10,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-zoom"},onClick:"toggleZoom"},V={name:"preloader",appendTo:"bar",order:7,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-loading"},onInit:(t,i)=>{let e;let s=null,n=(i,e)=>{t.classList.toggle("pswp__preloader--"+i,e)},o=t=>{e!==t&&(e=t,n("active",t))},a=()=>{var t;if(!(null!==(t=i.currSlide)&&void 0!==t&&t.content.isLoading())){o(!1),s&&(clearTimeout(s),s=null);return}s||(s=setTimeout(()=>{var t;o(!!(null===(t=i.currSlide)||void 0===t?void 0:t.content.isLoading())),s=null},i.options.preloaderDelay))};i.on("change",a),i.on("loadComplete",t=>{i.currSlide===t.slide&&a()}),i.ui&&(i.ui.updatePreloaderVisibility=a)}},q={name:"counter",order:5,onInit:(t,i)=>{i.on("change",()=>{t.innerText=i.currIndex+1+i.options.indexIndicatorSep+i.getNumItems()})}};function U(t,i){t.classList.toggle("pswp--zoomed-in",i)}class G{constructor(t){this.pswp=t,this.isRegistered=!1,this.uiElementsData=[],this.items=[],this.updatePreloaderVisibility=()=>{},this._lastUpdatedZoomLevel=void 0}init(){let{pswp:t}=this;this.isRegistered=!1,this.uiElementsData=[N,H,k,W,V,q],t.dispatch("uiRegister"),this.uiElementsData.sort((t,i)=>(t.order||0)-(i.order||0)),this.items=[],this.isRegistered=!0,this.uiElementsData.forEach(t=>{this.registerElement(t)}),t.on("change",()=>{var i;null===(i=t.element)||void 0===i||i.classList.toggle("pswp--one-slide",1===t.getNumItems())}),t.on("zoomPanUpdate",()=>this._onZoomPanUpdate())}registerElement(t){this.isRegistered?this.items.push(new R(this.pswp,t)):this.uiElementsData.push(t)}_onZoomPanUpdate(){let{template:t,currSlide:i,options:e}=this.pswp;if(this.pswp.opener.isClosing||!t||!i)return;let{currZoomLevel:s}=i;if(this.pswp.opener.isOpen||(s=i.zoomLevels.initial),s!==this._lastUpdatedZoomLevel){if(this._lastUpdatedZoomLevel=s,.01>Math.abs(i.zoomLevels.initial-i.zoomLevels.secondary)||!i.isZoomable()){U(t,!1),t.classList.remove("pswp--zoom-allowed");return}t.classList.add("pswp--zoom-allowed"),U(t,(s===i.zoomLevels.initial?i.zoomLevels.secondary:i.zoomLevels.initial)<=s),("zoom"===e.imageClickAction||"zoom-or-close"===e.imageClickAction)&&t.classList.add("pswp--click-to-zoom")}}}class K{constructor(t,i){this.type=t,this.defaultPrevented=!1,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class ${constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,i,e=100){var s,n,o;this._filters[t]||(this._filters[t]=[]),null===(s=this._filters[t])||void 0===s||s.push({fn:i,priority:e}),null===(n=this._filters[t])||void 0===n||n.sort((t,i)=>t.priority-i.priority),null===(o=this.pswp)||void 0===o||o.addFilter(t,i,e)}removeFilter(t,i){this._filters[t]&&(this._filters[t]=this._filters[t].filter(t=>t.fn!==i)),this.pswp&&this.pswp.removeFilter(t,i)}applyFilters(t,...i){var e;return null===(e=this._filters[t])||void 0===e||e.forEach(t=>{i[0]=t.fn.apply(this,i)}),i[0]}on(t,i){var e,s;this._listeners[t]||(this._listeners[t]=[]),null===(e=this._listeners[t])||void 0===e||e.push(i),null===(s=this.pswp)||void 0===s||s.on(t,i)}off(t,i){var e;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(t=>i!==t)),null===(e=this.pswp)||void 0===e||e.off(t,i)}dispatch(t,i){var e;if(this.pswp)return this.pswp.dispatch(t,i);let s=new K(t,i);return null===(e=this._listeners[t])||void 0===e||e.forEach(t=>{t.call(this,s)}),s}}class X{constructor(t,i){if(this.element=e("pswp__img pswp__img--placeholder",t?"img":"div",i),t){let i=this.element;i.decoding="async",i.alt="",i.src=t,i.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,i){this.element&&("IMG"===this.element.tagName?(d(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=h(0,0,t/250)):d(this.element,t,i))}destroy(){var t;null!==(t=this.element)&&void 0!==t&&t.parentNode&&this.element.remove(),this.element=null}}class Y{constructor(t,i,e){this.instance=i,this.data=t,this.index=e,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=c.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,i){if(this.slide&&this.usePlaceholder()){if(this.placeholder){let t=this.placeholder.element;t&&!t.parentElement&&this.slide.container.prepend(t)}else{let t=this.instance.applyFilters("placeholderSrc",!!this.data.msrc&&!!this.slide.isFirstSlide&&this.data.msrc,this);this.placeholder=new X(t,this.slide.container)}}(!this.element||i)&&!this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented&&(this.isImageContent()?(this.element=e("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=e("pswp__content","div"),this.element.innerHTML=this.data.html||""),i&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){var i,e;if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;let s=this.element;this.updateSrcsetSizes(),this.data.srcset&&(s.srcset=this.data.srcset),s.src=null!==(i=this.data.src)&&void 0!==i?i:"",s.alt=null!==(e=this.data.alt)&&void 0!==e?e:"",this.state=c.LOADING,s.complete?this.onLoaded():(s.onload=()=>{this.onLoaded()},s.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=c.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===c.LOADED||this.state===c.ERROR)&&this.removePlaceholder())}onError(){this.state=c.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===c.LOADING,this)}isError(){return this.state===c.ERROR}isImageContent(){return"image"===this.type}setDisplayedSize(t,i){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,i),!this.instance.dispatch("contentResize",{content:this,width:t,height:i}).defaultPrevented&&(d(this.element,t,i),this.isImageContent()&&!this.isError()))){let e=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=i,e?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:i,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==c.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;let t=this.element,i=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||i>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=i+"px",t.dataset.largestUsedSize=String(i))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){if(this.slide){var t,i;let s=e("pswp__error-msg","div");s.innerText=null!==(t=null===(i=this.instance.options)||void 0===i?void 0:i.errorMsg)&&void 0!==t?t:"",s=this.instance.applyFilters("contentErrorElement",s,this),this.element=e("pswp__content pswp__error-msg-container","div"),this.element.appendChild(s),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===c.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;let t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||m())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){!this.instance.dispatch("contentActivate",{content:this}).defaultPrevented&&this.slide&&(this.isImageContent()&&this.isDecoding&&!m()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===c.LOADED||this.state===c.ERROR)&&this.removePlaceholder()))}}function j(t,i,e){let s;let n=i.createContentFromData(t,e),{options:o}=i;if(o){let a;s=new w(o,t,-1),a=i.pswp?i.pswp.viewportSize:_(o,i);let r=y(o,a,t,e);s.update(n.width,n.height,r)}return n.lazyLoad(),s&&n.setDisplayedSize(Math.ceil(n.width*s.initial),Math.ceil(n.height*s.initial)),n}class Q{constructor(t){this.pswp=t,this.limit=Math.max(t.options.preload[0]+t.options.preload[1]+1,5),this._cachedItems=[]}updateLazy(t){let i;let{pswp:e}=this;if(e.dispatch("lazyLoad").defaultPrevented)return;let{preload:s}=e.options,n=void 0===t||t>=0;for(i=0;i<=s[1];i++)this.loadSlideByIndex(e.currIndex+(n?i:-i));for(i=1;i<=s[0];i++)this.loadSlideByIndex(e.currIndex+(n?-i:i))}loadSlideByIndex(t){let i=this.pswp.getLoopedIndex(t),e=this.getContentByIndex(i);!e&&(e=function(t,i){let e=i.getItemData(t);if(!i.dispatch("lazyLoadSlide",{index:t,itemData:e}).defaultPrevented)return j(e,i,t)}(i,this.pswp))&&this.addToCache(e)}getContentBySlide(t){let i=this.getContentByIndex(t.index);return i||(i=this.pswp.createContentFromData(t.data,t.index),this.addToCache(i)),i.setSlide(t),i}addToCache(t){if(this.removeByIndex(t.index),this._cachedItems.push(t),this._cachedItems.length>this.limit){let t=this._cachedItems.findIndex(t=>!t.isAttached&&!t.hasSlide);-1!==t&&this._cachedItems.splice(t,1)[0].destroy()}}removeByIndex(t){let i=this._cachedItems.findIndex(i=>i.index===t);-1!==i&&this._cachedItems.splice(i,1)}getContentByIndex(t){return this._cachedItems.find(i=>i.index===t)}destroy(){this._cachedItems.forEach(t=>t.destroy()),this._cachedItems=[]}}class J extends ${getNumItems(){var t;let i=0,e=null===(t=this.options)||void 0===t?void 0:t.dataSource;e&&"length"in e?i=e.length:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),e.items&&(i=e.items.length));let s=this.dispatch("numItems",{dataSource:e,numItems:i});return this.applyFilters("numItems",s.numItems,e)}createContentFromData(t,i){return new Y(t,this,i)}getItemData(t){var i;let e=null===(i=this.options)||void 0===i?void 0:i.dataSource,s={};Array.isArray(e)?s=e[t]:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),s=e.items[t]);let n=s;n instanceof Element&&(n=this._domElementToItemData(n));let o=this.dispatch("itemData",{itemData:n||{},index:t});return this.applyFilters("itemData",o.itemData,t)}_getGalleryDOMElements(t){var i,e;return null!==(i=this.options)&&void 0!==i&&i.children||null!==(e=this.options)&&void 0!==e&&e.childSelector?function(t,i,e=document){let s=[];if(t instanceof Element)s=[t];else if(t instanceof NodeList||Array.isArray(t))s=Array.from(t);else{let n="string"==typeof t?t:i;n&&(s=Array.from(e.querySelectorAll(n)))}return s}(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){let i={element:t},e="A"===t.tagName?t:t.querySelector("a");if(e){i.src=e.dataset.pswpSrc||e.href,e.dataset.pswpSrcset&&(i.srcset=e.dataset.pswpSrcset),i.width=e.dataset.pswpWidth?parseInt(e.dataset.pswpWidth,10):0,i.height=e.dataset.pswpHeight?parseInt(e.dataset.pswpHeight,10):0,i.w=i.width,i.h=i.height,e.dataset.pswpType&&(i.type=e.dataset.pswpType);let n=t.querySelector("img");if(n){var s;i.msrc=n.currentSrc||n.src,i.alt=null!==(s=n.getAttribute("alt"))&&void 0!==s?s:""}(e.dataset.pswpCropped||e.dataset.cropped)&&(i.thumbCropped=!0)}return this.applyFilters("domItemData",i,t,e)}lazyLoadData(t,i){return j(t,this,i)}}class tt{constructor(t){this.pswp=t,this.isClosed=!0,this.isOpen=!1,this.isClosing=!1,this.isOpening=!1,this._duration=void 0,this._useAnimation=!1,this._croppedZoom=!1,this._animateRootOpacity=!1,this._animateBgOpacity=!1,this._placeholder=void 0,this._opacityElement=void 0,this._cropContainer1=void 0,this._cropContainer2=void 0,this._thumbBounds=void 0,this._prepareOpen=this._prepareOpen.bind(this),t.on("firstZoomPan",this._prepareOpen)}open(){this._prepareOpen(),this._start()}close(){if(this.isClosed||this.isClosing||this.isOpening)return;let t=this.pswp.currSlide;this.isOpen=!1,this.isOpening=!1,this.isClosing=!0,this._duration=this.pswp.options.hideAnimationDuration,t&&t.currZoomLevel*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps(),setTimeout(()=>{this._start()},this._croppedZoom?30:0)}_prepareOpen(){if(this.pswp.off("firstZoomPan",this._prepareOpen),!this.isOpening){let t=this.pswp.currSlide;this.isOpening=!0,this.isClosing=!1,this._duration=this.pswp.options.showAnimationDuration,t&&t.zoomLevels.initial*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps()}}_applyStartProps(){var t,i;let{pswp:e}=this,s=this.pswp.currSlide,{options:n}=e;if("fade"===n.showHideAnimationType?(n.showHideOpacity=!0,this._thumbBounds=void 0):"none"===n.showHideAnimationType?(n.showHideOpacity=!1,this._duration=0,this._thumbBounds=void 0):this.isOpening&&e._initialThumbBounds?this._thumbBounds=e._initialThumbBounds:this._thumbBounds=this.pswp.getThumbBounds(),this._placeholder=null==s?void 0:s.getPlaceholderElement(),e.animations.stopAll(),this._useAnimation=!!(this._duration&&this._duration>50),this._animateZoom=!!this._thumbBounds&&(null==s?void 0:s.content.usePlaceholder())&&(!this.isClosing||!e.mainScroll.isShifted()),this._animateZoom?this._animateRootOpacity=null!==(t=n.showHideOpacity)&&void 0!==t&&t:(this._animateRootOpacity=!0,this.isOpening&&s&&(s.zoomAndPanToInitial(),s.applyCurrentZoomPan())),this._animateBgOpacity=!this._animateRootOpacity&&this.pswp.options.bgOpacity>.003,this._opacityElement=this._animateRootOpacity?e.element:e.bg,!this._useAnimation){this._duration=0,this._animateZoom=!1,this._animateBgOpacity=!1,this._animateRootOpacity=!0,this.isOpening&&(e.element&&(e.element.style.opacity=String(.003)),e.applyBgOpacity(1));return}this._animateZoom&&this._thumbBounds&&this._thumbBounds.innerRect?(this._croppedZoom=!0,this._cropContainer1=this.pswp.container,this._cropContainer2=null===(i=this.pswp.currSlide)||void 0===i?void 0:i.holderElement,e.container&&(e.container.style.overflow="hidden",e.container.style.width=e.viewportSize.x+"px")):this._croppedZoom=!1,this.isOpening?(this._animateRootOpacity?(e.element&&(e.element.style.opacity=String(.003)),e.applyBgOpacity(1)):(this._animateBgOpacity&&e.bg&&(e.bg.style.opacity=String(.003)),e.element&&(e.element.style.opacity="1")),this._animateZoom&&(this._setClosedStateZoomPan(),this._placeholder&&(this._placeholder.style.willChange="transform",this._placeholder.style.opacity=String(.003)))):this.isClosing&&(e.mainScroll.itemHolders[0]&&(e.mainScroll.itemHolders[0].el.style.display="none"),e.mainScroll.itemHolders[2]&&(e.mainScroll.itemHolders[2].el.style.display="none"),this._croppedZoom&&0!==e.mainScroll.x&&(e.mainScroll.resetPosition(),e.mainScroll.resize()))}_start(){this.isOpening&&this._useAnimation&&this._placeholder&&"IMG"===this._placeholder.tagName?new Promise(t=>{var i;let e=!1,s=!0;("decode"in(i=this._placeholder)?i.decode().catch(()=>{}):i.complete?Promise.resolve(i):new Promise((t,e)=>{i.onload=()=>t(i),i.onerror=e})).finally(()=>{e=!0,s||t(!0)}),setTimeout(()=>{s=!1,e&&t(!0)},50),setTimeout(t,250)}).finally(()=>this._initiate()):this._initiate()}_initiate(){var t,i;null===(t=this.pswp.element)||void 0===t||t.style.setProperty("--pswp-transition-duration",this._duration+"ms"),this.pswp.dispatch(this.isOpening?"openingAnimationStart":"closingAnimationStart"),this.pswp.dispatch("initialZoom"+(this.isOpening?"In":"Out")),null===(i=this.pswp.element)||void 0===i||i.classList.toggle("pswp--ui-visible",this.isOpening),this.isOpening?(this._placeholder&&(this._placeholder.style.opacity="1"),this._animateToOpenState()):this.isClosing&&this._animateToClosedState(),this._useAnimation||this._onAnimationComplete()}_onAnimationComplete(){let{pswp:t}=this;if(this.isOpen=this.isOpening,this.isClosed=this.isClosing,this.isOpening=!1,this.isClosing=!1,t.dispatch(this.isOpen?"openingAnimationEnd":"closingAnimationEnd"),t.dispatch("initialZoom"+(this.isOpen?"InEnd":"OutEnd")),this.isClosed)t.destroy();else if(this.isOpen){var i;this._animateZoom&&t.container&&(t.container.style.overflow="visible",t.container.style.width="100%"),null===(i=t.currSlide)||void 0===i||i.applyCurrentZoomPan()}}_animateToOpenState(){let{pswp:t}=this;this._animateZoom&&(this._croppedZoom&&this._cropContainer1&&this._cropContainer2&&(this._animateTo(this._cropContainer1,"transform","translate3d(0,0,0)"),this._animateTo(this._cropContainer2,"transform","none")),t.currSlide&&(t.currSlide.zoomAndPanToInitial(),this._animateTo(t.currSlide.container,"transform",t.currSlide.getCurrentTransform()))),this._animateBgOpacity&&t.bg&&this._animateTo(t.bg,"opacity",String(t.options.bgOpacity)),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","1")}_animateToClosedState(){let{pswp:t}=this;this._animateZoom&&this._setClosedStateZoomPan(!0),this._animateBgOpacity&&t.bgOpacity>.01&&t.bg&&this._animateTo(t.bg,"opacity","0"),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","0")}_setClosedStateZoomPan(t){if(!this._thumbBounds)return;let{pswp:i}=this,{innerRect:e}=this._thumbBounds,{currSlide:n,viewportSize:o}=i;if(this._croppedZoom&&e&&this._cropContainer1&&this._cropContainer2){let i=-o.x+(this._thumbBounds.x-e.x)+e.w,s=-o.y+(this._thumbBounds.y-e.y)+e.h,n=o.x-e.w,a=o.y-e.h;t?(this._animateTo(this._cropContainer1,"transform",h(i,s)),this._animateTo(this._cropContainer2,"transform",h(n,a))):(l(this._cropContainer1,i,s),l(this._cropContainer2,n,a))}n&&(s(n.pan,e||this._thumbBounds),n.currZoomLevel=this._thumbBounds.w/n.width,t?this._animateTo(n.container,"transform",n.getCurrentTransform()):n.applyCurrentZoomPan())}_animateTo(t,i,e){if(!this._duration){t.style[i]=e;return}let{animations:s}=this.pswp,n={duration:this._duration,easing:this.pswp.options.easing,onComplete:()=>{s.activeAnimations.length||this._onAnimationComplete()},target:t};n[i]=e,s.startTransition(n)}}let ti={allowPanToNext:!0,spacing:.1,loop:!0,pinchToClose:!0,closeOnVerticalDrag:!0,hideAnimationDuration:333,showAnimationDuration:333,zoomAnimationDuration:333,escKey:!0,arrowKeys:!0,trapFocus:!0,returnFocus:!0,maxWidthToAnimate:4e3,clickToCloseNonZoomable:!0,imageClickAction:"zoom-or-close",bgClickAction:"close",tapAction:"toggle-controls",doubleTapAction:"zoom",indexIndicatorSep:" / ",preloaderDelay:2e3,bgOpacity:.8,index:0,errorMsg:"The image cannot be loaded",preload:[1,2],easing:"cubic-bezier(.4,0,.22,1)"};class te extends J{constructor(t){super(),this.options=this._prepareOptions(t||{}),this.offset={x:0,y:0},this._prevViewportSize={x:0,y:0},this.viewportSize={x:0,y:0},this.bgOpacity=1,this.currIndex=0,this.potentialIndex=0,this.isOpen=!1,this.isDestroying=!1,this.hasMouse=!1,this._initialItemData={},this._initialThumbBounds=void 0,this.topBar=void 0,this.element=void 0,this.template=void 0,this.container=void 0,this.scrollWrap=void 0,this.currSlide=void 0,this.events=new v,this.animations=new M,this.mainScroll=new A(this),this.gestures=new I(this),this.opener=new tt(this),this.keyboard=new Z(this),this.contentLoader=new Q(this)}init(){if(this.isOpen||this.isDestroying)return!1;this.isOpen=!0,this.dispatch("init"),this.dispatch("beforeOpen"),this._createMainStructure();let t="pswp--open";return this.gestures.supportsTouch&&(t+=" pswp--touch"),this.options.mainClass&&(t+=" "+this.options.mainClass),this.element&&(this.element.className+=" "+t),this.currIndex=this.options.index||0,this.potentialIndex=this.currIndex,this.dispatch("firstUpdate"),this.scrollWheel=new F(this),(Number.isNaN(this.currIndex)||this.currIndex<0||this.currIndex>=this.getNumItems())&&(this.currIndex=0),this.gestures.supportsTouch||this.mouseDetected(),this.updateSize(),this.offset.y=window.pageYOffset,this._initialItemData=this.getItemData(this.currIndex),this.dispatch("gettingData",{index:this.currIndex,data:this._initialItemData,slide:void 0}),this._initialThumbBounds=this.getThumbBounds(),this.dispatch("initialLayout"),this.on("openingAnimationEnd",()=>{let{itemHolders:t}=this.mainScroll;t[0]&&(t[0].el.style.display="block",this.setContent(t[0],this.currIndex-1)),t[2]&&(t[2].el.style.display="block",this.setContent(t[2],this.currIndex+1)),this.appendHeavy(),this.contentLoader.updateLazy(),this.events.add(window,"resize",this._handlePageResize.bind(this)),this.events.add(window,"scroll",this._updatePageScrollOffset.bind(this)),this.dispatch("bindEvents")}),this.mainScroll.itemHolders[1]&&this.setContent(this.mainScroll.itemHolders[1],this.currIndex),this.dispatch("change"),this.opener.open(),this.dispatch("afterInit"),!0}getLoopedIndex(t){let i=this.getNumItems();return this.options.loop&&(t>i-1&&(t-=i),t<0&&(t+=i)),r(t,0,i-1)}appendHeavy(){this.mainScroll.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.appendHeavy()})}goTo(t){this.mainScroll.moveIndexBy(this.getLoopedIndex(t)-this.potentialIndex)}next(){this.goTo(this.potentialIndex+1)}prev(){this.goTo(this.potentialIndex-1)}zoomTo(...t){var i;null===(i=this.currSlide)||void 0===i||i.zoomTo(...t)}toggleZoom(){var t;null===(t=this.currSlide)||void 0===t||t.toggleZoom()}close(){this.opener.isOpen&&!this.isDestroying&&(this.isDestroying=!0,this.dispatch("close"),this.events.removeAll(),this.opener.close())}destroy(){var t;if(!this.isDestroying){this.options.showHideAnimationType="none",this.close();return}this.dispatch("destroy"),this._listeners={},this.scrollWrap&&(this.scrollWrap.ontouchmove=null,this.scrollWrap.ontouchend=null),null===(t=this.element)||void 0===t||t.remove(),this.mainScroll.itemHolders.forEach(t=>{var i;null===(i=t.slide)||void 0===i||i.destroy()}),this.contentLoader.destroy(),this.events.removeAll()}refreshSlideContent(t){this.contentLoader.removeByIndex(t),this.mainScroll.itemHolders.forEach((i,e)=>{var s,n,o;let a=(null!==(s=null===(n=this.currSlide)||void 0===n?void 0:n.index)&&void 0!==s?s:0)-1+e;this.canLoop()&&(a=this.getLoopedIndex(a)),a===t&&(this.setContent(i,t,!0),1===e&&(this.currSlide=i.slide,null===(o=i.slide)||void 0===o||o.setIsActive(!0)))}),this.dispatch("change")}setContent(t,i,e){if(this.canLoop()&&(i=this.getLoopedIndex(i)),t.slide){if(t.slide.index===i&&!e)return;t.slide.destroy(),t.slide=void 0}if(!this.canLoop()&&(i<0||i>=this.getNumItems()))return;let s=this.getItemData(i);t.slide=new x(s,i,this),i===this.currIndex&&(this.currSlide=t.slide),t.slide.append(t.el)}getViewportCenterPoint(){return{x:this.viewportSize.x/2,y:this.viewportSize.y/2}}updateSize(t){if(this.isDestroying)return;let i=_(this.options,this);!t&&a(i,this._prevViewportSize)||(s(this._prevViewportSize,i),this.dispatch("beforeResize"),s(this.viewportSize,this._prevViewportSize),this._updatePageScrollOffset(),this.dispatch("viewportSize"),this.mainScroll.resize(this.opener.isOpen),!this.hasMouse&&window.matchMedia("(any-hover: hover)").matches&&this.mouseDetected(),this.dispatch("resize"))}applyBgOpacity(t){this.bgOpacity=Math.max(t,0),this.bg&&(this.bg.style.opacity=String(this.bgOpacity*this.options.bgOpacity))}mouseDetected(){if(!this.hasMouse){var t;this.hasMouse=!0,null===(t=this.element)||void 0===t||t.classList.add("pswp--has_mouse")}}_handlePageResize(){this.updateSize(),/iPhone|iPad|iPod/i.test(window.navigator.userAgent)&&setTimeout(()=>{this.updateSize()},500)}_updatePageScrollOffset(){this.setScrollOffset(0,window.pageYOffset)}setScrollOffset(t,i){this.offset.x=t,this.offset.y=i,this.dispatch("updateScrollOffset")}_createMainStructure(){this.element=e("pswp","div"),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.template=this.element,this.bg=e("pswp__bg","div",this.element),this.scrollWrap=e("pswp__scroll-wrap","section",this.element),this.container=e("pswp__container","div",this.scrollWrap),this.scrollWrap.setAttribute("aria-roledescription","carousel"),this.container.setAttribute("aria-live","off"),this.container.setAttribute("id","pswp__items"),this.mainScroll.appendHolders(),this.ui=new G(this),this.ui.init(),(this.options.appendToEl||document.body).appendChild(this.element)}getThumbBounds(){return function(t,i,e){let s,n;let o=e.dispatch("thumbBounds",{index:t,itemData:i,instance:e});if(o.thumbBounds)return o.thumbBounds;let{element:a}=i;if(a&&!1!==e.options.thumbSelector){let t=e.options.thumbSelector||"img";n=a.matches(t)?a:a.querySelector(t)}return(n=e.applyFilters("thumbEl",n,i,t))&&(s=i.thumbCropped?function(t,i,e){let s=t.getBoundingClientRect(),n=s.width/i,o=s.height/e,a=n>o?n:o,r=(s.width-i*a)/2,h=(s.height-e*a)/2,l={x:s.left+r,y:s.top+h,w:i*a};return l.innerRect={w:s.width,h:s.height,x:r,y:h},l}(n,i.width||i.w||0,i.height||i.h||0):function(t){let i=t.getBoundingClientRect();return{x:i.left,y:i.top,w:i.width}}(n)),e.applyFilters("thumbBounds",s,i,t)}(this.currIndex,this.currSlide?this.currSlide.data:this._initialItemData,this)}canLoop(){return this.options.loop&&this.getNumItems()>2}_prepareOptions(t){return window.matchMedia("(prefers-reduced-motion), (update: slow)").matches&&(t.showHideAnimationType="none",t.zoomAnimationDuration=0),{...ti,...t}}}}); +//# sourceMappingURL=photoswipe.esm.b9f46f1c.js.map diff --git a/photoswipe.esm.b9f46f1c.js.map b/photoswipe.esm.b9f46f1c.js.map new file mode 100644 index 0000000..bde3684 --- /dev/null +++ b/photoswipe.esm.b9f46f1c.js.map @@ -0,0 +1 @@ +{"mappings":"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","sources":["","node_modules/photoswipe/dist/photoswipe.esm.js","src/js/util/util.js","src/js/util/dom-events.js","src/js/util/viewport-size.js","src/js/slide/pan-bounds.js","src/js/slide/zoom-level.js","src/js/slide/slide.js","src/js/gestures/drag-handler.js","src/js/gestures/zoom-handler.js","src/js/gestures/tap-handler.js","src/js/gestures/gestures.js","src/js/main-scroll.js","src/js/keyboard.js","src/js/util/css-animation.js","src/js/util/spring-easer.js","src/js/util/spring-animation.js","src/js/util/animations.js","src/js/scroll-wheel.js","src/js/ui/ui-element.js","src/js/ui/button-arrow.js","src/js/ui/button-close.js","src/js/ui/button-zoom.js","src/js/ui/loading-indicator.js","src/js/ui/counter-indicator.js","src/js/ui/ui.js","src/js/slide/get-thumb-bounds.js","src/js/core/eventable.js","src/js/slide/placeholder.js","src/js/slide/content.js","src/js/slide/loader.js","src/js/core/base.js","src/js/opener.js","src/js/photoswipe.js"],"sourcesContent":["\nfunction $parcel$defineInteropFlag(a) {\n Object.defineProperty(a, '__esModule', {value: true, configurable: true});\n}\n\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n var parcelRequire = $parcel$global[\"parcelRequire94c2\"];\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"lxZQh\", function(module, exports) {\n\n$parcel$defineInteropFlag(module.exports);\n\n$parcel$export(module.exports, \"default\", function () { return $fafca69a57f78827$export$2e2bcd8739ae039; });\n/*!\n * PhotoSwipe 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */ /** @typedef {import('../photoswipe.js').Point} Point */ /**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */ function $fafca69a57f78827$var$createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) el.className = className;\n if (appendToEl) appendToEl.appendChild(el);\n return el;\n}\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */ function $fafca69a57f78827$var$equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n if (p2.id !== undefined) p1.id = p2.id;\n return p1;\n}\n/**\r\n * @param {Point} p\r\n */ function $fafca69a57f78827$var$roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */ function $fafca69a57f78827$var$getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt(x * x + y * y);\n}\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */ function $fafca69a57f78827$var$pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */ function $fafca69a57f78827$var$clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */ function $fafca69a57f78827$var$toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n if (scale !== undefined) propValue += ` scale3d(${scale},${scale},1)`;\n return propValue;\n}\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */ function $fafca69a57f78827$var$setTransform(el, x, y, scale) {\n el.style.transform = $fafca69a57f78827$var$toTransformString(x, y, scale);\n}\nconst $fafca69a57f78827$var$defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */ function $fafca69a57f78827$var$setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop ? `${prop} ${duration}ms ${ease || $fafca69a57f78827$var$defaultCSSEasing}` : 'none';\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */ function $fafca69a57f78827$var$setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/**\r\n * @param {HTMLElement} el\r\n */ function $fafca69a57f78827$var$removeTransitionStyle(el) {\n $fafca69a57f78827$var$setTransitionStyle(el);\n}\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */ function $fafca69a57f78827$var$decodeImage(img) {\n if ('decode' in img) return img.decode().catch(()=>{});\n if (img.complete) return Promise.resolve(img);\n return new Promise((resolve, reject)=>{\n img.onload = ()=>resolve(img);\n img.onerror = reject;\n });\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ /** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ const $fafca69a57f78827$var$LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */ function $fafca69a57f78827$var$specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */ function $fafca69a57f78827$var$getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */ let elements = [];\n if (option instanceof Element) elements = [\n option\n ];\n else if (option instanceof NodeList || Array.isArray(option)) elements = Array.from(option);\n else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) elements = Array.from(parent.querySelectorAll(selector));\n }\n return elements;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */ function $fafca69a57f78827$var$isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n// Detect passive event listener support\nlet $fafca69a57f78827$var$supportsPassive = false;\n/* eslint-disable */ try {\n /* @ts-ignore */ window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\n get: ()=>{\n $fafca69a57f78827$var$supportsPassive = true;\n }\n }));\n} catch (e) {}\n/* eslint-enable */ /**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */ class $fafca69a57f78827$var$DOMEvents {\n constructor(){\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */ this._pool = [];\n }\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */ add(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive);\n }\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */ remove(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive, true);\n }\n /**\r\n * Removes all bound events\r\n */ removeAll() {\n this._pool.forEach((poolItem)=>{\n this._toggleListener(poolItem.target, poolItem.type, poolItem.listener, poolItem.passive, true, true);\n });\n this._pool = [];\n }\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */ _toggleListener(target, type, listener, passive, unbind, skipPool) {\n if (!target) return;\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\n const types = type.split(' ');\n types.forEach((eType)=>{\n if (eType) {\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\n // so developer doesn't need to do this manually\n if (!skipPool) {\n if (unbind) // Remove from the events pool\n this._pool = this._pool.filter((poolItem)=>{\n return poolItem.type !== eType || poolItem.listener !== listener || poolItem.target !== target;\n });\n else // Add to the events pool\n this._pool.push({\n target: target,\n type: eType,\n listener: listener,\n passive: passive\n });\n } // most PhotoSwipe events call preventDefault,\n // and we do not need browser to scroll the page\n const eventOptions = $fafca69a57f78827$var$supportsPassive ? {\n passive: passive || false\n } : false;\n target[methodName](eType, listener, eventOptions);\n }\n });\n }\n}\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */ function $fafca69a57f78827$var$getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) return newViewportSize;\n }\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */ function $fafca69a57f78827$var$parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n if (options.paddingFn) paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n else if (options.padding) paddingValue = options.padding[prop];\n else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n if (options[legacyPropName]) // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */ function $fafca69a57f78827$var$getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - $fafca69a57f78827$var$parsePaddingOption('left', options, viewportSize, itemData, index) - $fafca69a57f78827$var$parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - $fafca69a57f78827$var$parsePaddingOption('top', options, viewportSize, itemData, index) - $fafca69a57f78827$var$parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {Record} Point */ /** @typedef {'x' | 'y'} Axis */ /**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */ class $fafca69a57f78827$var$PanBounds {\n /**\r\n * @param {Slide} slide\r\n */ constructor(slide){\n this.slide = slide;\n this.currZoomLevel = 1;\n this.center = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n this.max = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n this.min = /** @type {Point} */ {\n x: 0,\n y: 0\n };\n }\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */ update(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n if (!this.slide.width) this.reset();\n else {\n this._updateAxis('x');\n this._updateAxis('y');\n this.slide.pswp.dispatch('calcBounds', {\n slide: this.slide\n });\n }\n }\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */ _updateAxis(axis) {\n const { pswp: pswp } = this.slide;\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\n const paddingProp = axis === 'x' ? 'left' : 'top';\n const padding = $fafca69a57f78827$var$parsePaddingOption(paddingProp, pswp.options, pswp.viewportSize, this.slide.data, this.slide.index);\n const panAreaSize = this.slide.panAreaSize[axis]; // Default position of element.\n // By default, it is center of viewport:\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding; // maximum pan position\n this.max[axis] = elSize > panAreaSize ? Math.round(panAreaSize - elSize) + padding : this.center[axis]; // minimum pan position\n this.min[axis] = elSize > panAreaSize ? padding : this.center[axis];\n }\n reset() {\n this.center.x = 0;\n this.center.y = 0;\n this.max.x = 0;\n this.max.y = 0;\n this.min.x = 0;\n this.min.y = 0;\n }\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */ correctPan(axis, panOffset) {\n // checkPanBounds\n return $fafca69a57f78827$var$clamp(panOffset, this.max[axis], this.min[axis]);\n }\n}\nconst $fafca69a57f78827$var$MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ /**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */ class $fafca69a57f78827$var$ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */ constructor(options, itemData, index, pswp){\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */ this.panAreaSize = null;\n /** @type { Point | null } */ this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */ update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */ const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n if (this.pswp) this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */ _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n if (!optionValue) return;\n if (typeof optionValue === 'function') return optionValue(this);\n if (optionValue === 'fill') return this.fill;\n if (optionValue === 'fit') return this.fit;\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n if (currZoomLevel) return currZoomLevel;\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n if (this.elementSize && currZoomLevel * this.elementSize.x > $fafca69a57f78827$var$MAX_IMAGE_WIDTH) currZoomLevel = $fafca69a57f78827$var$MAX_IMAGE_WIDTH / this.elementSize.x;\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n * Renders and allows to control a single slide\r\n */ class $fafca69a57f78827$var$Slide {\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(data, index, pswp){\n this.data = data;\n this.index = index;\n this.pswp = pswp;\n this.isActive = index === pswp.currIndex;\n this.currentResolution = 0;\n /** @type {Point} */ this.panAreaSize = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.pan = {\n x: 0,\n y: 0\n };\n this.isFirstSlide = this.isActive && !pswp.opener.isOpen;\n this.zoomLevels = new $fafca69a57f78827$var$ZoomLevel(pswp.options, data, index, pswp);\n this.pswp.dispatch('gettingData', {\n slide: this,\n data: this.data,\n index: index\n });\n this.content = this.pswp.contentLoader.getContentBySlide(this);\n this.container = $fafca69a57f78827$var$createElement('pswp__zoom-wrap', 'div');\n /** @type {HTMLElement | null} */ this.holderElement = null;\n this.currZoomLevel = 1;\n /** @type {number} */ this.width = this.content.width;\n /** @type {number} */ this.height = this.content.height;\n this.heavyAppended = false;\n this.bounds = new $fafca69a57f78827$var$PanBounds(this);\n this.prevDisplayedWidth = -1;\n this.prevDisplayedHeight = -1;\n this.pswp.dispatch('slideInit', {\n slide: this\n });\n }\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */ setIsActive(isActive) {\n if (isActive && !this.isActive) // slide just became active\n this.activate();\n else if (!isActive && this.isActive) // slide just became non-active\n this.deactivate();\n }\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */ append(holderElement) {\n this.holderElement = holderElement;\n this.container.style.transformOrigin = '0 0'; // Slide appended to DOM\n if (!this.data) return;\n this.calculateSize();\n this.load();\n this.updateContentSize();\n this.appendHeavy();\n this.holderElement.appendChild(this.container);\n this.zoomAndPanToInitial();\n this.pswp.dispatch('firstZoomPan', {\n slide: this\n });\n this.applyCurrentZoomPan();\n this.pswp.dispatch('afterSetContent', {\n slide: this\n });\n if (this.isActive) this.activate();\n }\n load() {\n this.content.load(false);\n this.pswp.dispatch('slideLoad', {\n slide: this\n });\n }\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */ appendHeavy() {\n const { pswp: pswp } = this;\n const appendHeavyNearby = true; // todo\n // Avoid appending heavy elements during animations\n if (this.heavyAppended || !pswp.opener.isOpen || pswp.mainScroll.isShifted() || !this.isActive && !appendHeavyNearby) return;\n if (this.pswp.dispatch('appendHeavy', {\n slide: this\n }).defaultPrevented) return;\n this.heavyAppended = true;\n this.content.append();\n this.pswp.dispatch('appendHeavyContent', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */ activate() {\n this.isActive = true;\n this.appendHeavy();\n this.content.activate();\n this.pswp.dispatch('slideActivate', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */ deactivate() {\n this.isActive = false;\n this.content.deactivate();\n if (this.currZoomLevel !== this.zoomLevels.initial) // allow filtering\n this.calculateSize();\n // reset zoom level\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n this.pswp.dispatch('slideDeactivate', {\n slide: this\n });\n }\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */ destroy() {\n this.content.hasSlide = false;\n this.content.remove();\n this.container.remove();\n this.pswp.dispatch('slideDestroy', {\n slide: this\n });\n }\n resize() {\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\n // Keep initial zoom level if it was before the resize,\n // as well as when this slide is not active\n // Reset position and scale to original state\n this.calculateSize();\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n } else {\n // readjust pan position if it's beyond the bounds\n this.calculateSize();\n this.bounds.update(this.currZoomLevel);\n this.panTo(this.pan.x, this.pan.y);\n }\n }\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */ updateContentSize(force) {\n // Use initial zoom level\n // if resolution is not defined (user didn't zoom yet)\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\n if (!scaleMultiplier) return;\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\n if (!this.sizeChanged(width, height) && !force) return;\n this.content.setDisplayedSize(width, height);\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ sizeChanged(width, height) {\n if (width !== this.prevDisplayedWidth || height !== this.prevDisplayedHeight) {\n this.prevDisplayedWidth = width;\n this.prevDisplayedHeight = height;\n return true;\n }\n return false;\n }\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */ getPlaceholderElement() {\n var _this$content$placeho;\n return (_this$content$placeho = this.content.placeholder) === null || _this$content$placeho === void 0 ? void 0 : _this$content$placeho.element;\n }\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */ zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\n const { pswp: pswp } = this;\n if (!this.isZoomable() || pswp.mainScroll.isShifted()) return;\n pswp.dispatch('beforeZoomTo', {\n destZoomLevel: destZoomLevel,\n centerPoint: centerPoint,\n transitionDuration: transitionDuration\n }); // stop all pan and zoom transitions\n pswp.animations.stopAllPan(); // if (!centerPoint) {\n // centerPoint = pswp.getViewportCenterPoint();\n // }\n const prevZoomLevel = this.currZoomLevel;\n if (!ignoreBounds) destZoomLevel = $fafca69a57f78827$var$clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\n // if (transitionDuration === undefined) {\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\n // }\n this.setZoomLevel(destZoomLevel);\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\n $fafca69a57f78827$var$roundPoint(this.pan);\n const finishTransition = ()=>{\n this._setResolution(destZoomLevel);\n this.applyCurrentZoomPan();\n };\n if (!transitionDuration) finishTransition();\n else pswp.animations.startTransition({\n isPan: true,\n name: 'zoomTo',\n target: this.container,\n transform: this.getCurrentTransform(),\n onComplete: finishTransition,\n duration: transitionDuration,\n easing: pswp.options.easing\n });\n }\n /**\r\n * @param {Point} [centerPoint]\r\n */ toggleZoom(centerPoint) {\n this.zoomTo(this.currZoomLevel === this.zoomLevels.initial ? this.zoomLevels.secondary : this.zoomLevels.initial, centerPoint, this.pswp.options.zoomAnimationDuration);\n }\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */ setZoomLevel(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n this.bounds.update(this.currZoomLevel);\n }\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */ calculateZoomToPanOffset(axis, point, prevZoomLevel) {\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\n if (totalPanDistance === 0) return this.bounds.center[axis];\n if (!point) point = this.pswp.getViewportCenterPoint();\n if (!prevZoomLevel) prevZoomLevel = this.zoomLevels.initial;\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\n return this.bounds.correctPan(axis, (this.pan[axis] - point[axis]) * zoomFactor + point[axis]);\n }\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */ panTo(panX, panY) {\n this.pan.x = this.bounds.correctPan('x', panX);\n this.pan.y = this.bounds.correctPan('y', panY);\n this.applyCurrentZoomPan();\n }\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */ isPannable() {\n return Boolean(this.width) && this.currZoomLevel > this.zoomLevels.fit;\n }\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */ isZoomable() {\n return Boolean(this.width) && this.content.isZoomable();\n }\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */ applyCurrentZoomPan() {\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\n if (this === this.pswp.currSlide) this.pswp.dispatch('zoomPanUpdate', {\n slide: this\n });\n }\n zoomAndPanToInitial() {\n this.currZoomLevel = this.zoomLevels.initial; // pan according to the zoom level\n this.bounds.update(this.currZoomLevel);\n $fafca69a57f78827$var$equalizePoints(this.pan, this.bounds.center);\n this.pswp.dispatch('initialZoomPan', {\n slide: this\n });\n }\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */ _applyZoomTransform(x, y, zoom) {\n zoom /= this.currentResolution || this.zoomLevels.initial;\n $fafca69a57f78827$var$setTransform(this.container, x, y, zoom);\n }\n calculateSize() {\n const { pswp: pswp } = this;\n $fafca69a57f78827$var$equalizePoints(this.panAreaSize, $fafca69a57f78827$var$getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index));\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\n pswp.dispatch('calcSlideSize', {\n slide: this\n });\n }\n /** @returns {string} */ getCurrentTransform() {\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\n return $fafca69a57f78827$var$toTransformString(this.pan.x, this.pan.y, scale);\n }\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */ _setResolution(newResolution) {\n if (newResolution === this.currentResolution) return;\n this.currentResolution = newResolution;\n this.updateContentSize();\n this.pswp.dispatch('resolutionChanged');\n }\n}\n/** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('./gestures.js').default} Gestures */ const $fafca69a57f78827$var$PAN_END_FRICTION = 0.35;\nconst $fafca69a57f78827$var$VERTICAL_DRAG_FRICTION = 0.6; // 1 corresponds to the third of viewport height\nconst $fafca69a57f78827$var$MIN_RATIO_TO_CLOSE = 0.4; // Minimum speed required to navigate\n// to next or previous slide\nconst $fafca69a57f78827$var$MIN_NEXT_SLIDE_SPEED = 0.5;\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */ function $fafca69a57f78827$var$project(initialVelocity, decelerationRate) {\n return initialVelocity * decelerationRate / (1 - decelerationRate);\n}\n/**\r\n * Handles single pointer dragging\r\n */ class $fafca69a57f78827$var$DragHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n this.pswp = gestures.pswp;\n /** @type {Point} */ this.startPan = {\n x: 0,\n y: 0\n };\n }\n start() {\n if (this.pswp.currSlide) $fafca69a57f78827$var$equalizePoints(this.startPan, this.pswp.currSlide.pan);\n this.pswp.animations.stopAll();\n }\n change() {\n const { p1: p1, prevP1: prevP1, dragAxis: dragAxis } = this.gestures;\n const { currSlide: currSlide } = this.pswp;\n if (dragAxis === 'y' && this.pswp.options.closeOnVerticalDrag && currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit && !this.gestures.isMultitouch) {\n // Handle vertical drag to close\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\n if (!this.pswp.dispatch('verticalDrag', {\n panY: panY\n }).defaultPrevented) {\n this._setPanWithFriction('y', panY, $fafca69a57f78827$var$VERTICAL_DRAG_FRICTION);\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\n this.pswp.applyBgOpacity(bgOpacity);\n currSlide.applyCurrentZoomPan();\n }\n } else {\n const mainScrollChanged = this._panOrMoveMainScroll('x');\n if (!mainScrollChanged) {\n this._panOrMoveMainScroll('y');\n if (currSlide) {\n $fafca69a57f78827$var$roundPoint(currSlide.pan);\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n }\n end() {\n const { velocity: velocity } = this.gestures;\n const { mainScroll: mainScroll, currSlide: currSlide } = this.pswp;\n let indexDiff = 0;\n this.pswp.animations.stopAll(); // Handle main scroll if it's shifted\n if (mainScroll.isShifted()) {\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX(); // Ratio between 0 and 1:\n // 0 - slide is not visible at all,\n // 0.5 - half of the slide is visible\n // 1 - slide is fully visible\n const currentSlideVisibilityRatio = mainScrollShiftDiff / this.pswp.viewportSize.x; // Go next slide.\n //\n // - if velocity and its direction is matched,\n // and we see at least tiny part of the next slide\n //\n // - or if we see less than 50% of the current slide\n // and velocity is close to 0\n //\n if (velocity.x < -$fafca69a57f78827$var$MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0 || velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5) {\n // Go to next slide\n indexDiff = 1;\n velocity.x = Math.min(velocity.x, 0);\n } else if (velocity.x > $fafca69a57f78827$var$MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0 || velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5) {\n // Go to prev slide\n indexDiff = -1;\n velocity.x = Math.max(velocity.x, 0);\n }\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\n } // Restore zoom level\n if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max || this.gestures.isMultitouch) this.gestures.zoomLevels.correctZoomPan(true);\n else {\n // we run two animations instead of one,\n // as each axis has own pan boundaries and thus different spring function\n // (correctZoomPan does not have this functionality,\n // it animates all properties with single timing function)\n this._finishPanGestureForAxis('x');\n this._finishPanGestureForAxis('y');\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */ _finishPanGestureForAxis(axis) {\n const { velocity: velocity } = this.gestures;\n const { currSlide: currSlide } = this.pswp;\n if (!currSlide) return;\n const { pan: pan, bounds: bounds } = currSlide;\n const panPos = pan[axis];\n const restoreBgOpacity = this.pswp.bgOpacity < 1 && axis === 'y'; // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\n // Increasing this number will reduce travel distance\n const decelerationRate = 0.995; // 0.99\n // Pan position if there is no bounds\n const projectedPosition = panPos + $fafca69a57f78827$var$project(velocity[axis], decelerationRate);\n if (restoreBgOpacity) {\n const vDragRatio = this._getVerticalDragRatio(panPos);\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition); // If we are above and moving upwards,\n // or if we are below and moving downwards\n if (vDragRatio < 0 && projectedVDragRatio < -$fafca69a57f78827$var$MIN_RATIO_TO_CLOSE || vDragRatio > 0 && projectedVDragRatio > $fafca69a57f78827$var$MIN_RATIO_TO_CLOSE) {\n this.pswp.close();\n return;\n }\n } // Pan position with corrected bounds\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition); // Exit if pan position should not be changed\n // or if speed it too low\n if (panPos === correctedPanPosition) return;\n // Overshoot if the final position is out of pan bounds\n const dampingRatio = correctedPanPosition === projectedPosition ? 1 : 0.82;\n const initialBgOpacity = this.pswp.bgOpacity;\n const totalPanDist = correctedPanPosition - panPos;\n this.pswp.animations.startSpring({\n name: 'panGesture' + axis,\n isPan: true,\n start: panPos,\n end: correctedPanPosition,\n velocity: velocity[axis],\n dampingRatio: dampingRatio,\n onUpdate: (pos)=>{\n // Animate opacity of background relative to Y pan position of an image\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\n // 0 - start of animation, 1 - end of animation\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist; // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n this.pswp.applyBgOpacity($fafca69a57f78827$var$clamp(initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio, 0, 1));\n }\n pan[axis] = Math.floor(pos);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */ _panOrMoveMainScroll(axis) {\n const { p1: p1, dragAxis: dragAxis, prevP1: prevP1, isMultitouch: isMultitouch } = this.gestures;\n const { currSlide: currSlide, mainScroll: mainScroll } = this.pswp;\n const delta = p1[axis] - prevP1[axis];\n const newMainScrollX = mainScroll.x + delta;\n if (!delta || !currSlide) return false;\n // Always move main scroll if image can not be panned\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\n mainScroll.moveTo(newMainScrollX, true);\n return true; // changed main scroll\n }\n const { bounds: bounds } = currSlide;\n const newPan = currSlide.pan[axis] + delta;\n if (this.pswp.options.allowPanToNext && dragAxis === 'x' && axis === 'x' && !isMultitouch) {\n const currSlideMainScrollX = mainScroll.getCurrSlideX(); // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\n const isLeftToRight = delta > 0;\n const isRightToLeft = !isLeftToRight;\n if (newPan > bounds.min[axis] && isLeftToRight) {\n // Panning from left to right, beyond the left edge\n // Wether the image was at minimum pan position (or less)\n // when this drag gesture started.\n // Minimum pan position refers to the left edge of the image.\n const wasAtMinPanPosition = bounds.min[axis] <= this.startPan[axis];\n if (wasAtMinPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\n // Paning from right to left, beyond the right edge\n // Maximum pan position refers to the right edge of the image.\n const wasAtMaxPanPosition = this.startPan[axis] <= bounds.max[axis];\n if (wasAtMaxPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n } else // If main scroll is shifted\n if (mainScrollShiftDiff !== 0) {\n // If main scroll is shifted right\n if (mainScrollShiftDiff > 0) {\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\n return true;\n } else if (mainScrollShiftDiff < 0) {\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\n return true;\n }\n } else // We are within pan bounds, so just pan\n this._setPanWithFriction(axis, newPan);\n } else {\n if (axis === 'y') // Do not pan vertically if main scroll is shifted o\n {\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) this._setPanWithFriction(axis, newPan);\n } else this._setPanWithFriction(axis, newPan);\n }\n return false;\n }\n // If we move below the ratio is positive\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */ _getVerticalDragRatio(panY) {\n var _this$pswp$currSlide$, _this$pswp$currSlide;\n return (panY - ((_this$pswp$currSlide$ = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.bounds.center.y) !== null && _this$pswp$currSlide$ !== void 0 ? _this$pswp$currSlide$ : 0)) / (this.pswp.viewportSize.y / 3);\n }\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */ _setPanWithFriction(axis, potentialPan, customFriction) {\n const { currSlide: currSlide } = this.pswp;\n if (!currSlide) return;\n const { pan: pan, bounds: bounds } = currSlide;\n const correctedPan = bounds.correctPan(axis, potentialPan); // If we are out of pan bounds\n if (correctedPan !== potentialPan || customFriction) {\n const delta = Math.round(potentialPan - pan[axis]);\n pan[axis] += delta * (customFriction || $fafca69a57f78827$var$PAN_END_FRICTION);\n } else pan[axis] = potentialPan;\n }\n}\n/** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('./gestures.js').default} Gestures */ const $fafca69a57f78827$var$UPPER_ZOOM_FRICTION = 0.05;\nconst $fafca69a57f78827$var$LOWER_ZOOM_FRICTION = 0.15;\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */ function $fafca69a57f78827$var$getZoomPointsCenter(p, p1, p2) {\n p.x = (p1.x + p2.x) / 2;\n p.y = (p1.y + p2.y) / 2;\n return p;\n}\nclass $fafca69a57f78827$var$ZoomHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._startPan = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._startZoomPoint = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */ this._zoomPoint = {\n x: 0,\n y: 0\n };\n /** @private */ this._wasOverFitZoomLevel = false;\n /** @private */ this._startZoomLevel = 1;\n }\n start() {\n const { currSlide: currSlide } = this.gestures.pswp;\n if (currSlide) {\n this._startZoomLevel = currSlide.currZoomLevel;\n $fafca69a57f78827$var$equalizePoints(this._startPan, currSlide.pan);\n }\n this.gestures.pswp.animations.stopAllPan();\n this._wasOverFitZoomLevel = false;\n }\n change() {\n const { p1: p1, startP1: startP1, p2: p2, startP2: startP2, pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if (!currSlide) return;\n const minZoomLevel = currSlide.zoomLevels.min;\n const maxZoomLevel = currSlide.zoomLevels.max;\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) return;\n $fafca69a57f78827$var$getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\n $fafca69a57f78827$var$getZoomPointsCenter(this._zoomPoint, p1, p2);\n let currZoomLevel = 1 / $fafca69a57f78827$var$getDistanceBetween(startP1, startP2) * $fafca69a57f78827$var$getDistanceBetween(p1, p2) * this._startZoomLevel; // slightly over the zoom.fit\n if (currZoomLevel > currSlide.zoomLevels.initial + currSlide.zoomLevels.initial / 15) this._wasOverFitZoomLevel = true;\n if (currZoomLevel < minZoomLevel) {\n if (pswp.options.pinchToClose && !this._wasOverFitZoomLevel && this._startZoomLevel <= currSlide.zoomLevels.initial) {\n // fade out background if zooming out\n const bgOpacity = 1 - (minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2);\n if (!pswp.dispatch('pinchClose', {\n bgOpacity: bgOpacity\n }).defaultPrevented) pswp.applyBgOpacity(bgOpacity);\n } else // Apply the friction if zoom level is below the min\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * $fafca69a57f78827$var$LOWER_ZOOM_FRICTION;\n } else if (currZoomLevel > maxZoomLevel) // Apply the friction if zoom level is above the max\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * $fafca69a57f78827$var$UPPER_ZOOM_FRICTION;\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\n currSlide.setZoomLevel(currZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n end() {\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial) && !this._wasOverFitZoomLevel && pswp.options.pinchToClose) pswp.close();\n else this.correctZoomPan();\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */ _calculatePanForZoomLevel(axis, currZoomLevel) {\n const zoomFactor = currZoomLevel / this._startZoomLevel;\n return this._zoomPoint[axis] - (this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor;\n }\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */ correctZoomPan(ignoreGesture) {\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n if (!(currSlide !== null && currSlide !== void 0 && currSlide.isZoomable())) return;\n if (this._zoomPoint.x === 0) ignoreGesture = true;\n const prevZoomLevel = currSlide.currZoomLevel;\n /** @type {number} */ let destinationZoomLevel;\n let currZoomLevelNeedsChange = true;\n if (prevZoomLevel < currSlide.zoomLevels.initial) destinationZoomLevel = currSlide.zoomLevels.initial; // zoom to min\n else if (prevZoomLevel > currSlide.zoomLevels.max) destinationZoomLevel = currSlide.zoomLevels.max; // zoom to max\n else {\n currZoomLevelNeedsChange = false;\n destinationZoomLevel = prevZoomLevel;\n }\n const initialBgOpacity = pswp.bgOpacity;\n const restoreBgOpacity = pswp.bgOpacity < 1;\n const initialPan = $fafca69a57f78827$var$equalizePoints({\n x: 0,\n y: 0\n }, currSlide.pan);\n let destinationPan = $fafca69a57f78827$var$equalizePoints({\n x: 0,\n y: 0\n }, initialPan);\n if (ignoreGesture) {\n this._zoomPoint.x = 0;\n this._zoomPoint.y = 0;\n this._startZoomPoint.x = 0;\n this._startZoomPoint.y = 0;\n this._startZoomLevel = prevZoomLevel;\n $fafca69a57f78827$var$equalizePoints(this._startPan, initialPan);\n }\n if (currZoomLevelNeedsChange) destinationPan = {\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\n };\n // set zoom level, so pan bounds are updated according to it\n currSlide.setZoomLevel(destinationZoomLevel);\n destinationPan = {\n x: currSlide.bounds.correctPan('x', destinationPan.x),\n y: currSlide.bounds.correctPan('y', destinationPan.y)\n }; // return zoom level and its bounds to initial\n currSlide.setZoomLevel(prevZoomLevel);\n const panNeedsChange = !$fafca69a57f78827$var$pointsEqual(destinationPan, initialPan);\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\n // update resolution after gesture\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan(); // nothing to animate\n return;\n }\n pswp.animations.stopAllPan();\n pswp.animations.startSpring({\n isPan: true,\n start: 0,\n end: 1000,\n velocity: 0,\n dampingRatio: 1,\n naturalFrequency: 40,\n onUpdate: (now)=>{\n now /= 1000; // 0 - start, 1 - end\n if (panNeedsChange || currZoomLevelNeedsChange) {\n if (panNeedsChange) {\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\n }\n if (currZoomLevelNeedsChange) {\n const newZoomLevel = prevZoomLevel + (destinationZoomLevel - prevZoomLevel) * now;\n currSlide.setZoomLevel(newZoomLevel);\n }\n currSlide.applyCurrentZoomPan();\n } // Restore background opacity\n if (restoreBgOpacity && pswp.bgOpacity < 1) // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n pswp.applyBgOpacity($fafca69a57f78827$var$clamp(initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1));\n },\n onComplete: ()=>{\n // update resolution after transition ends\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n}\n/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */ /** @typedef {import('./gestures.js').default} Gestures */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */ /**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */ function $fafca69a57f78827$var$didTapOnMainContent(event) {\n return !!/** @type {HTMLElement} */ event.target.closest('.pswp__container');\n}\n/**\r\n * Tap, double-tap handler.\r\n */ class $fafca69a57f78827$var$TapHandler {\n /**\r\n * @param {Gestures} gestures\r\n */ constructor(gestures){\n this.gestures = gestures;\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ click(point, originalEvent) {\n const targetClassList = /** @type {HTMLElement} */ originalEvent.target.classList;\n const isImageClick = targetClassList.contains('pswp__img');\n const isBackgroundClick = targetClassList.contains('pswp__item') || targetClassList.contains('pswp__zoom-wrap');\n if (isImageClick) this._doClickOrTapAction('imageClick', point, originalEvent);\n else if (isBackgroundClick) this._doClickOrTapAction('bgClick', point, originalEvent);\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ tap(point, originalEvent) {\n if ($fafca69a57f78827$var$didTapOnMainContent(originalEvent)) this._doClickOrTapAction('tap', point, originalEvent);\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ doubleTap(point, originalEvent) {\n if ($fafca69a57f78827$var$didTapOnMainContent(originalEvent)) this._doClickOrTapAction('doubleTap', point, originalEvent);\n }\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */ _doClickOrTapAction(actionName, point, originalEvent) {\n var _this$gestures$pswp$e;\n const { pswp: pswp } = this.gestures;\n const { currSlide: currSlide } = pswp;\n const actionFullName = /** @type {AddPostfix} */ actionName + 'Action';\n const optionValue = pswp.options[actionFullName];\n if (pswp.dispatch(actionFullName, {\n point: point,\n originalEvent: originalEvent\n }).defaultPrevented) return;\n if (typeof optionValue === 'function') {\n optionValue.call(pswp, point, originalEvent);\n return;\n }\n switch(optionValue){\n case 'close':\n case 'next':\n pswp[optionValue]();\n break;\n case 'zoom':\n currSlide === null || currSlide === void 0 || currSlide.toggleZoom(point);\n break;\n case 'zoom-or-close':\n // by default click zooms current image,\n // if it can not be zoomed - gallery will be closed\n if (currSlide !== null && currSlide !== void 0 && currSlide.isZoomable() && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) currSlide.toggleZoom(point);\n else if (pswp.options.clickToCloseNonZoomable) pswp.close();\n break;\n case 'toggle-controls':\n (_this$gestures$pswp$e = this.gestures.pswp.element) === null || _this$gestures$pswp$e === void 0 || _this$gestures$pswp$e.classList.toggle('pswp--ui-visible'); // if (_controlsVisible) {\n break;\n }\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').Point} Point */ // How far should user should drag\n// until we can determine that the gesture is swipe and its direction\nconst $fafca69a57f78827$var$AXIS_SWIPE_HYSTERISIS = 10; //const PAN_END_FRICTION = 0.35;\nconst $fafca69a57f78827$var$DOUBLE_TAP_DELAY = 300; // ms\nconst $fafca69a57f78827$var$MIN_TAP_DISTANCE = 25; // px\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */ class $fafca69a57f78827$var$Gestures {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n /** @type {'x' | 'y' | null} */ this.dragAxis = null; // point objects are defined once and reused\n // PhotoSwipe keeps track only of two pointers, others are ignored\n /** @type {Point} */ this.p1 = {\n x: 0,\n y: 0\n }; // the first pressed pointer\n /** @type {Point} */ this.p2 = {\n x: 0,\n y: 0\n }; // the second pressed pointer\n /** @type {Point} */ this.prevP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.prevP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.startP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.startP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */ this.velocity = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */ this._lastStartP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */ this._intervalP1 = {\n x: 0,\n y: 0\n };\n /** @private */ this._numActivePoints = 0;\n /** @type {Point[]}\r\n * @private\r\n */ this._ongoingPointers = [];\n /** @private */ this._touchEventEnabled = 'ontouchstart' in window;\n /** @private */ this._pointerEventEnabled = !!window.PointerEvent;\n this.supportsTouch = this._touchEventEnabled || this._pointerEventEnabled && navigator.maxTouchPoints > 1;\n /** @private */ this._numActivePoints = 0;\n /** @private */ this._intervalTime = 0;\n /** @private */ this._velocityCalculated = false;\n this.isMultitouch = false;\n this.isDragging = false;\n this.isZooming = false;\n /** @type {number | null} */ this.raf = null;\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */ this._tapTimer = null;\n if (!this.supportsTouch) // disable pan to next slide for non-touch devices\n pswp.options.allowPanToNext = false;\n this.drag = new $fafca69a57f78827$var$DragHandler(this);\n this.zoomLevels = new $fafca69a57f78827$var$ZoomHandler(this);\n this.tapHandler = new $fafca69a57f78827$var$TapHandler(this);\n pswp.on('bindEvents', ()=>{\n pswp.events.add(pswp.scrollWrap, 'click', /** @type EventListener */ this._onClick.bind(this));\n if (this._pointerEventEnabled) this._bindEvents('pointer', 'down', 'up', 'cancel');\n else if (this._touchEventEnabled) {\n this._bindEvents('touch', 'start', 'end', 'cancel'); // In previous versions we also bound mouse event here,\n // in case device supports both touch and mouse events,\n // but newer versions of browsers now support PointerEvent.\n // on iOS10 if you bind touchmove/end after touchstart,\n // and you don't preventDefault touchstart (which PhotoSwipe does),\n // preventDefault will have no effect on touchmove and touchend.\n // Unless you bind it previously.\n if (pswp.scrollWrap) {\n pswp.scrollWrap.ontouchmove = ()=>{};\n pswp.scrollWrap.ontouchend = ()=>{};\n }\n } else this._bindEvents('mouse', 'down', 'up');\n });\n }\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */ _bindEvents(pref, down, up, cancel) {\n const { pswp: pswp } = this;\n const { events: events } = pswp;\n const cancelEvent = cancel ? pref + cancel : '';\n events.add(pswp.scrollWrap, pref + down, /** @type EventListener */ this.onPointerDown.bind(this));\n events.add(window, pref + 'move', /** @type EventListener */ this.onPointerMove.bind(this));\n events.add(window, pref + up, /** @type EventListener */ this.onPointerUp.bind(this));\n if (cancelEvent) events.add(pswp.scrollWrap, cancelEvent, /** @type EventListener */ this.onPointerUp.bind(this));\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerDown(e) {\n // We do not call preventDefault for touch events\n // to allow browser to show native dialog on longpress\n // (the one that allows to save image or open it in new tab).\n //\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse'; // Allow dragging only via left mouse button.\n // http://www.quirksmode.org/js/events_properties.html\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\n if (isMousePointer && e.button > 0) return;\n const { pswp: pswp } = this; // if PhotoSwipe is opening or closing\n if (!pswp.opener.isOpen) {\n e.preventDefault();\n return;\n }\n if (pswp.dispatch('pointerDown', {\n originalEvent: e\n }).defaultPrevented) return;\n if (isMousePointer) {\n pswp.mouseDetected(); // preventDefault mouse event to prevent\n // browser image drag feature\n this._preventPointerEventBehaviour(e, 'down');\n }\n pswp.animations.stopAll();\n this._updatePoints(e, 'down');\n if (this._numActivePoints === 1) {\n this.dragAxis = null; // we need to store initial point to determine the main axis,\n // drag is activated only after the axis is determined\n $fafca69a57f78827$var$equalizePoints(this.startP1, this.p1);\n }\n if (this._numActivePoints > 1) {\n // Tap or double tap should not trigger if more than one pointer\n this._clearTapTimer();\n this.isMultitouch = true;\n } else this.isMultitouch = false;\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerMove(e) {\n this._preventPointerEventBehaviour(e, 'move');\n if (!this._numActivePoints) return;\n this._updatePoints(e, 'move');\n if (this.pswp.dispatch('pointerMove', {\n originalEvent: e\n }).defaultPrevented) return;\n if (this._numActivePoints === 1 && !this.isDragging) {\n if (!this.dragAxis) this._calculateDragDirection();\n // Drag axis was detected, emit drag.start\n if (this.dragAxis && !this.isDragging) {\n if (this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n }\n this.isDragging = true;\n this._clearTapTimer(); // Tap can not trigger after drag\n // Adjust starting point\n this._updateStartPoints();\n this._intervalTime = Date.now(); //this._startTime = this._intervalTime;\n this._velocityCalculated = false;\n $fafca69a57f78827$var$equalizePoints(this._intervalP1, this.p1);\n this.velocity.x = 0;\n this.velocity.y = 0;\n this.drag.start();\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n } else if (this._numActivePoints > 1 && !this.isZooming) {\n this._finishDrag();\n this.isZooming = true; // Adjust starting points\n this._updateStartPoints();\n this.zoomLevels.start();\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n }\n /**\r\n * @private\r\n */ _finishDrag() {\n if (this.isDragging) {\n this.isDragging = false; // Try to calculate velocity,\n // if it wasn't calculated yet in drag.change\n if (!this._velocityCalculated) this._updateVelocity(true);\n this.drag.end();\n this.dragAxis = null;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */ onPointerUp(e) {\n if (!this._numActivePoints) return;\n this._updatePoints(e, 'up');\n if (this.pswp.dispatch('pointerUp', {\n originalEvent: e\n }).defaultPrevented) return;\n if (this._numActivePoints === 0) {\n this._rafStopLoop();\n if (this.isDragging) this._finishDrag();\n else if (!this.isZooming && !this.isMultitouch) //this.zoomLevels.correctZoomPan();\n this._finishTap(e);\n }\n if (this._numActivePoints < 2 && this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n if (this._numActivePoints === 1) {\n // Since we have 1 point left, we need to reinitiate drag\n this.dragAxis = null;\n this._updateStartPoints();\n }\n }\n }\n /**\r\n * @private\r\n */ _rafRenderLoop() {\n if (this.isDragging || this.isZooming) {\n this._updateVelocity();\n if (this.isDragging) // make sure that pointer moved since the last update\n {\n if (!$fafca69a57f78827$var$pointsEqual(this.p1, this.prevP1)) this.drag.change();\n } else if (!$fafca69a57f78827$var$pointsEqual(this.p1, this.prevP1) || !$fafca69a57f78827$var$pointsEqual(this.p2, this.prevP2)) this.zoomLevels.change();\n this._updatePrevPoints();\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\n }\n }\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */ _updateVelocity(force) {\n const time = Date.now();\n const duration = time - this._intervalTime;\n if (duration < 50 && !force) return;\n this.velocity.x = this._getVelocity('x', duration);\n this.velocity.y = this._getVelocity('y', duration);\n this._intervalTime = time;\n $fafca69a57f78827$var$equalizePoints(this._intervalP1, this.p1);\n this._velocityCalculated = true;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */ _finishTap(e) {\n const { mainScroll: mainScroll } = this.pswp; // Do not trigger tap events if main scroll is shifted\n if (mainScroll.isShifted()) {\n // restore main scroll position\n // (usually happens if stopped in the middle of animation)\n mainScroll.moveIndexBy(0, true);\n return;\n } // Do not trigger tap for touchcancel or pointercancel\n if (e.type.indexOf('cancel') > 0) return;\n // Trigger click instead of tap for mouse events\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\n this.tapHandler.click(this.startP1, e);\n return;\n } // Disable delay if there is no doubleTapAction\n const tapDelay = this.pswp.options.doubleTapAction ? $fafca69a57f78827$var$DOUBLE_TAP_DELAY : 0; // If tapTimer is defined - we tapped recently,\n // check if the current tap is close to the previous one,\n // if yes - trigger double tap\n if (this._tapTimer) {\n this._clearTapTimer(); // Check if two taps were more or less on the same place\n if ($fafca69a57f78827$var$getDistanceBetween(this._lastStartP1, this.startP1) < $fafca69a57f78827$var$MIN_TAP_DISTANCE) this.tapHandler.doubleTap(this.startP1, e);\n } else {\n $fafca69a57f78827$var$equalizePoints(this._lastStartP1, this.startP1);\n this._tapTimer = setTimeout(()=>{\n this.tapHandler.tap(this.startP1, e);\n this._clearTapTimer();\n }, tapDelay);\n }\n }\n /**\r\n * @private\r\n */ _clearTapTimer() {\n if (this._tapTimer) {\n clearTimeout(this._tapTimer);\n this._tapTimer = null;\n }\n }\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */ _getVelocity(axis, duration) {\n // displacement is like distance, but can be negative.\n const displacement = this.p1[axis] - this._intervalP1[axis];\n if (Math.abs(displacement) > 1 && duration > 5) return displacement / duration;\n return 0;\n }\n /**\r\n * @private\r\n */ _rafStopLoop() {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = null;\n }\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */ _preventPointerEventBehaviour(e, pointerType) {\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\n if (preventPointerEvent) e.preventDefault();\n }\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */ _updatePoints(e, pointerType) {\n if (this._pointerEventEnabled) {\n const pointerEvent = /** @type {PointerEvent} */ e; // Try to find the current pointer in ongoing pointers by its ID\n const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer)=>{\n return ongoingPointer.id === pointerEvent.pointerId;\n });\n if (pointerType === 'up' && pointerIndex > -1) // release the pointer - remove it from ongoing\n this._ongoingPointers.splice(pointerIndex, 1);\n else if (pointerType === 'down' && pointerIndex === -1) // add new pointer\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, {\n x: 0,\n y: 0\n }));\n else if (pointerIndex > -1) // update existing pointer\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\n this._numActivePoints = this._ongoingPointers.length; // update points that PhotoSwipe uses\n // to calculate position and scale\n if (this._numActivePoints > 0) $fafca69a57f78827$var$equalizePoints(this.p1, this._ongoingPointers[0]);\n if (this._numActivePoints > 1) $fafca69a57f78827$var$equalizePoints(this.p2, this._ongoingPointers[1]);\n } else {\n const touchEvent = /** @type {TouchEvent} */ e;\n this._numActivePoints = 0;\n if (touchEvent.type.indexOf('touch') > -1) // Touch Event\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\n {\n if (touchEvent.touches && touchEvent.touches.length > 0) {\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\n this._numActivePoints++;\n if (touchEvent.touches.length > 1) {\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\n this._numActivePoints++;\n }\n }\n } else {\n // Mouse Event\n this._convertEventPosToPoint(/** @type {PointerEvent} */ e, this.p1);\n if (pointerType === 'up') // clear all points on mouseup\n this._numActivePoints = 0;\n else this._numActivePoints++;\n }\n }\n }\n /** update points that were used during previous rAF tick\r\n * @private\r\n */ _updatePrevPoints() {\n $fafca69a57f78827$var$equalizePoints(this.prevP1, this.p1);\n $fafca69a57f78827$var$equalizePoints(this.prevP2, this.p2);\n }\n /** update points at the start of gesture\r\n * @private\r\n */ _updateStartPoints() {\n $fafca69a57f78827$var$equalizePoints(this.startP1, this.p1);\n $fafca69a57f78827$var$equalizePoints(this.startP2, this.p2);\n this._updatePrevPoints();\n }\n /** @private */ _calculateDragDirection() {\n if (this.pswp.mainScroll.isShifted()) // if main scroll position is shifted – direction is always horizontal\n this.dragAxis = 'x';\n else {\n // calculate delta of the last touchmove tick\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\n if (diff !== 0) {\n // check if pointer was shifted horizontally or vertically\n const axisToCheck = diff > 0 ? 'x' : 'y';\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= $fafca69a57f78827$var$AXIS_SWIPE_HYSTERISIS) this.dragAxis = axisToCheck;\n }\n }\n }\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */ _convertEventPosToPoint(e, p) {\n p.x = e.pageX - this.pswp.offset.x;\n p.y = e.pageY - this.pswp.offset.y;\n if ('pointerId' in e) p.id = e.pointerId;\n else if (e.identifier !== undefined) p.id = e.identifier;\n return p;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */ _onClick(e) {\n // Do not allow click event to pass through after drag\n if (this.pswp.mainScroll.isShifted()) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./slide/slide.js').default} Slide */ /** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */ const $fafca69a57f78827$var$MAIN_SCROLL_END_FRICTION = 0.35; // const MIN_SWIPE_TRANSITION_DURATION = 250;\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */ class $fafca69a57f78827$var$MainScroll {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.x = 0;\n this.slideWidth = 0;\n /** @private */ this._currPositionIndex = 0;\n /** @private */ this._prevPositionIndex = 0;\n /** @private */ this._containerShiftIndex = -1;\n /** @type {ItemHolder[]} */ this.itemHolders = [];\n }\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */ resize(resizeSlides) {\n const { pswp: pswp } = this;\n const newSlideWidth = Math.round(pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing); // Mobile browsers might trigger a resize event during a gesture.\n // (due to toolbar appearing or hiding).\n // Avoid re-adjusting main scroll position if width wasn't changed\n const slideWidthChanged = newSlideWidth !== this.slideWidth;\n if (slideWidthChanged) {\n this.slideWidth = newSlideWidth;\n this.moveTo(this.getCurrSlideX());\n }\n this.itemHolders.forEach((itemHolder, index)=>{\n if (slideWidthChanged) $fafca69a57f78827$var$setTransform(itemHolder.el, (index + this._containerShiftIndex) * this.slideWidth);\n if (resizeSlides && itemHolder.slide) itemHolder.slide.resize();\n });\n }\n /**\r\n * Reset X position of the main scroller to zero\r\n */ resetPosition() {\n // Position on the main scroller (offset)\n // it is independent from slide index\n this._currPositionIndex = 0;\n this._prevPositionIndex = 0; // This will force recalculation of size on next resize()\n this.slideWidth = 0; // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\n this._containerShiftIndex = -1;\n }\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */ appendHolders() {\n this.itemHolders = []; // append our three slide holders -\n // previous, current, and next\n for(let i = 0; i < 3; i++){\n const el = $fafca69a57f78827$var$createElement('pswp__item', 'div', this.pswp.container);\n el.setAttribute('role', 'group');\n el.setAttribute('aria-roledescription', 'slide');\n el.setAttribute('aria-hidden', 'true'); // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\n el.style.display = i === 1 ? 'block' : 'none';\n this.itemHolders.push({\n el: el //index: -1\n });\n }\n }\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */ canBeSwiped() {\n return this.pswp.getNumItems() > 1;\n }\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */ moveIndexBy(diff, animate, velocityX) {\n const { pswp: pswp } = this;\n let newIndex = pswp.potentialIndex + diff;\n const numSlides = pswp.getNumItems();\n if (pswp.canLoop()) {\n newIndex = pswp.getLoopedIndex(newIndex);\n const distance = (diff + numSlides) % numSlides;\n if (distance <= numSlides / 2) // go forward\n diff = distance;\n else // go backwards\n diff = distance - numSlides;\n } else {\n if (newIndex < 0) newIndex = 0;\n else if (newIndex >= numSlides) newIndex = numSlides - 1;\n diff = newIndex - pswp.potentialIndex;\n }\n pswp.potentialIndex = newIndex;\n this._currPositionIndex -= diff;\n pswp.animations.stopMainScroll();\n const destinationX = this.getCurrSlideX();\n if (!animate) {\n this.moveTo(destinationX);\n this.updateCurrItem();\n } else {\n pswp.animations.startSpring({\n isMainScroll: true,\n start: this.x,\n end: destinationX,\n velocity: velocityX || 0,\n naturalFrequency: 30,\n dampingRatio: 1,\n //0.7,\n onUpdate: (x)=>{\n this.moveTo(x);\n },\n onComplete: ()=>{\n this.updateCurrItem();\n pswp.appendHeavy();\n }\n });\n let currDiff = pswp.potentialIndex - pswp.currIndex;\n if (pswp.canLoop()) {\n const currDistance = (currDiff + numSlides) % numSlides;\n if (currDistance <= numSlides / 2) // go forward\n currDiff = currDistance;\n else // go backwards\n currDiff = currDistance - numSlides;\n } // Force-append new slides during transition\n // if difference between slides is more than 1\n if (Math.abs(currDiff) > 1) this.updateCurrItem();\n }\n return Boolean(diff);\n }\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */ getCurrSlideX() {\n return this.slideWidth * this._currPositionIndex;\n }\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */ isShifted() {\n return this.x !== this.getCurrSlideX();\n }\n /**\r\n * Update slides X positions and set their content\r\n */ updateCurrItem() {\n var _this$itemHolders$;\n const { pswp: pswp } = this;\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\n if (!positionDifference) return;\n this._prevPositionIndex = this._currPositionIndex;\n pswp.currIndex = pswp.potentialIndex;\n let diffAbs = Math.abs(positionDifference);\n /** @type {ItemHolder | undefined} */ let tempHolder;\n if (diffAbs >= 3) {\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\n diffAbs = 3; // If slides are changed by 3 screens or more - clean up previous slides\n this.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide;\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.destroy();\n itemHolder.slide = undefined;\n });\n }\n for(let i = 0; i < diffAbs; i++)if (positionDifference > 0) {\n tempHolder = this.itemHolders.shift();\n if (tempHolder) {\n this.itemHolders[2] = tempHolder; // move first to last\n this._containerShiftIndex++;\n $fafca69a57f78827$var$setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex - diffAbs + i + 2);\n }\n } else {\n tempHolder = this.itemHolders.pop();\n if (tempHolder) {\n this.itemHolders.unshift(tempHolder); // move last to first\n this._containerShiftIndex--;\n $fafca69a57f78827$var$setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex + diffAbs - i - 2);\n }\n }\n // Reset transfrom every 50ish navigations in one direction.\n //\n // Otherwise transform will keep growing indefinitely,\n // which might cause issues as browsers have a maximum transform limit.\n // I wasn't able to reach it, but just to be safe.\n // This should not cause noticable lag.\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\n this.resetPosition();\n this.resize();\n } // Pan transition might be running (and consntantly updating pan position)\n pswp.animations.stopAllPan();\n this.itemHolders.forEach((itemHolder, i)=>{\n if (itemHolder.slide) // Slide in the 2nd holder is always active\n itemHolder.slide.setIsActive(i === 1);\n });\n pswp.currSlide = (_this$itemHolders$ = this.itemHolders[1]) === null || _this$itemHolders$ === void 0 ? void 0 : _this$itemHolders$.slide;\n pswp.contentLoader.updateLazy(positionDifference);\n if (pswp.currSlide) pswp.currSlide.applyCurrentZoomPan();\n pswp.dispatch('change');\n }\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */ moveTo(x, dragging) {\n if (!this.pswp.canLoop() && dragging) {\n // Apply friction\n let newSlideIndexOffset = (this.slideWidth * this._currPositionIndex - x) / this.slideWidth;\n newSlideIndexOffset += this.pswp.currIndex;\n const delta = Math.round(x - this.x);\n if (newSlideIndexOffset < 0 && delta > 0 || newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0) x = this.x + delta * $fafca69a57f78827$var$MAIN_SCROLL_END_FRICTION;\n }\n this.x = x;\n if (this.pswp.container) $fafca69a57f78827$var$setTransform(this.pswp.container, x);\n this.pswp.dispatch('moveMainScroll', {\n x: x,\n dragging: dragging !== null && dragging !== void 0 ? dragging : false\n });\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */ const $fafca69a57f78827$var$KeyboardKeyCodesMap = {\n Escape: 27,\n z: 90,\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n Tab: 9\n};\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */ const $fafca69a57f78827$var$getKeyboardEventKey = (key, isKeySupported)=>{\n return isKeySupported ? key : $fafca69a57f78827$var$KeyboardKeyCodesMap[key];\n};\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */ class $fafca69a57f78827$var$Keyboard {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n /** @private */ this._wasFocused = false;\n pswp.on('bindEvents', ()=>{\n if (pswp.options.trapFocus) {\n // Dialog was likely opened by keyboard if initial point is not defined\n if (!pswp.options.initialPointerPos) // focus causes layout,\n // which causes lag during the animation,\n // that's why we delay it until the opener transition ends\n this._focusRoot();\n pswp.events.add(document, 'focusin', /** @type EventListener */ this._onFocusIn.bind(this));\n }\n pswp.events.add(document, 'keydown', /** @type EventListener */ this._onKeyDown.bind(this));\n });\n const lastActiveElement = /** @type {HTMLElement} */ document.activeElement;\n pswp.on('destroy', ()=>{\n if (pswp.options.returnFocus && lastActiveElement && this._wasFocused) lastActiveElement.focus();\n });\n }\n /** @private */ _focusRoot() {\n if (!this._wasFocused && this.pswp.element) {\n this.pswp.element.focus();\n this._wasFocused = true;\n }\n }\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */ _onKeyDown(e) {\n const { pswp: pswp } = this;\n if (pswp.dispatch('keydown', {\n originalEvent: e\n }).defaultPrevented) return;\n if ($fafca69a57f78827$var$specialKeyUsed(e)) // don't do anything if special key pressed\n // to prevent from overriding default browser actions\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\n return;\n /** @type {Methods | undefined} */ let keydownAction;\n /** @type {'x' | 'y' | undefined} */ let axis;\n let isForward = false;\n const isKeySupported = 'key' in e;\n switch(isKeySupported ? e.key : e.keyCode){\n case $fafca69a57f78827$var$getKeyboardEventKey('Escape', isKeySupported):\n if (pswp.options.escKey) keydownAction = 'close';\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('z', isKeySupported):\n keydownAction = 'toggleZoom';\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('ArrowLeft', isKeySupported):\n axis = 'x';\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('ArrowUp', isKeySupported):\n axis = 'y';\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('ArrowRight', isKeySupported):\n axis = 'x';\n isForward = true;\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('ArrowDown', isKeySupported):\n isForward = true;\n axis = 'y';\n break;\n case $fafca69a57f78827$var$getKeyboardEventKey('Tab', isKeySupported):\n this._focusRoot();\n break;\n } // if left/right/top/bottom key\n if (axis) {\n // prevent page scroll\n e.preventDefault();\n const { currSlide: currSlide } = pswp;\n if (pswp.options.arrowKeys && axis === 'x' && pswp.getNumItems() > 1) keydownAction = isForward ? 'next' : 'prev';\n else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\n // up/down arrow keys pan the image vertically\n // left/right arrow keys pan horizontally.\n // Unless there is only one image,\n // or arrowKeys option is disabled\n currSlide.pan[axis] += isForward ? -80 : 80;\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\n }\n }\n if (keydownAction) {\n e.preventDefault(); // @ts-ignore\n pswp[keydownAction]();\n }\n }\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */ _onFocusIn(e) {\n const { template: template } = this.pswp;\n if (template && document !== e.target && template !== e.target && !template.contains(/** @type {Node} */ e.target)) // focus root element\n template.focus();\n }\n}\nconst $fafca69a57f78827$var$DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ /** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */ /** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */ /**\r\n * Runs CSS transition.\r\n */ class $fafca69a57f78827$var$CSSAnimation {\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */ constructor(props){\n var _props$prop;\n this.props = props;\n const { target: target, onComplete: onComplete, transform: transform, onFinish: onFinish = ()=>{}, duration: duration = 333, easing: easing = $fafca69a57f78827$var$DEFAULT_EASING } = props;\n this.onFinish = onFinish; // support only transform and opacity\n const prop = transform ? 'transform' : 'opacity';\n const propValue = (_props$prop = props[prop]) !== null && _props$prop !== void 0 ? _props$prop : '';\n /** @private */ this._target = target;\n /** @private */ this._onComplete = onComplete;\n /** @private */ this._finished = false;\n /** @private */ this._onTransitionEnd = this._onTransitionEnd.bind(this); // Using timeout hack to make sure that animation\n // starts even if the animated property was changed recently,\n // otherwise transitionend might not fire or transition won't start.\n // https://drafts.csswg.org/css-transitions/#starting\n //\n // ¯\\_(ツ)_/¯\n /** @private */ this._helperTimeout = setTimeout(()=>{\n $fafca69a57f78827$var$setTransitionStyle(target, prop, duration, easing);\n this._helperTimeout = setTimeout(()=>{\n target.addEventListener('transitionend', this._onTransitionEnd, false);\n target.addEventListener('transitioncancel', this._onTransitionEnd, false); // Safari occasionally does not emit transitionend event\n // if element property was modified during the transition,\n // which may be caused by resize or third party component,\n // using timeout as a safety fallback\n this._helperTimeout = setTimeout(()=>{\n this._finalizeAnimation();\n }, duration + 500);\n target.style[prop] = propValue;\n }, 30); // Do not reduce this number\n }, 0);\n }\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */ _onTransitionEnd(e) {\n if (e.target === this._target) this._finalizeAnimation();\n }\n /**\r\n * @private\r\n */ _finalizeAnimation() {\n if (!this._finished) {\n this._finished = true;\n this.onFinish();\n if (this._onComplete) this._onComplete();\n }\n }\n destroy() {\n if (this._helperTimeout) clearTimeout(this._helperTimeout);\n $fafca69a57f78827$var$removeTransitionStyle(this._target);\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\n if (!this._finished) this._finalizeAnimation();\n }\n}\nconst $fafca69a57f78827$var$DEFAULT_NATURAL_FREQUENCY = 12;\nconst $fafca69a57f78827$var$DEFAULT_DAMPING_RATIO = 0.75;\n/**\r\n * Spring easing helper\r\n */ class $fafca69a57f78827$var$SpringEaser {\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */ constructor(initialVelocity, dampingRatio, naturalFrequency){\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\n // https://en.wikipedia.org/wiki/Damping_ratio\n this._dampingRatio = dampingRatio || $fafca69a57f78827$var$DEFAULT_DAMPING_RATIO; // https://en.wikipedia.org/wiki/Natural_frequency\n this._naturalFrequency = naturalFrequency || $fafca69a57f78827$var$DEFAULT_NATURAL_FREQUENCY;\n this._dampedFrequency = this._naturalFrequency;\n if (this._dampingRatio < 1) this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\n }\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */ easeFrame(deltaPosition, deltaTime) {\n // Inspired by Apple Webkit and Android spring function implementation\n // https://en.wikipedia.org/wiki/Oscillation\n // https://en.wikipedia.org/wiki/Damping_ratio\n // we ignore mass (assume that it's 1kg)\n let displacement = 0;\n let coeff;\n deltaTime /= 1000;\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\n if (this._dampingRatio === 1) {\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\n this.velocity = displacement * -this._naturalFrequency + coeff * naturalDumpingPow;\n } else if (this._dampingRatio < 1) {\n coeff = 1 / this._dampedFrequency * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\n displacement = naturalDumpingPow * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\n this.velocity = displacement * -this._naturalFrequency * this._dampingRatio + naturalDumpingPow * (-this._dampedFrequency * deltaPosition * dumpedFSin + this._dampedFrequency * coeff * dumpedFCos);\n } // Overdamped (>1) damping ratio is not supported\n return displacement;\n }\n}\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ /**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */ /** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */ class $fafca69a57f78827$var$SpringAnimation {\n /**\r\n * @param {SpringAnimationProps} props\r\n */ constructor(props){\n this.props = props;\n this._raf = 0;\n const { start: start, end: end, velocity: velocity, onUpdate: onUpdate, onComplete: onComplete, onFinish: onFinish = ()=>{}, dampingRatio: dampingRatio, naturalFrequency: naturalFrequency } = props;\n this.onFinish = onFinish;\n const easer = new $fafca69a57f78827$var$SpringEaser(velocity, dampingRatio, naturalFrequency);\n let prevTime = Date.now();\n let deltaPosition = start - end;\n const animationLoop = ()=>{\n if (this._raf) {\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime); // Stop the animation if velocity is low and position is close to end\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\n // Finalize the animation\n onUpdate(end);\n if (onComplete) onComplete();\n this.onFinish();\n } else {\n prevTime = Date.now();\n onUpdate(deltaPosition + end);\n this._raf = requestAnimationFrame(animationLoop);\n }\n }\n };\n this._raf = requestAnimationFrame(animationLoop);\n }\n destroy() {\n if (this._raf >= 0) cancelAnimationFrame(this._raf);\n this._raf = 0;\n }\n}\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */ /** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */ /** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */ /** @typedef {SpringAnimation | CSSAnimation} Animation */ /** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */ /**\r\n * Manages animations\r\n */ class $fafca69a57f78827$var$Animations {\n constructor(){\n /** @type {Animation[]} */ this.activeAnimations = [];\n }\n /**\r\n * @param {SpringAnimationProps} props\r\n */ startSpring(props) {\n this._start(props, true);\n }\n /**\r\n * @param {CssAnimationProps} props\r\n */ startTransition(props) {\n this._start(props);\n }\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */ _start(props, isSpring) {\n const animation = isSpring ? new $fafca69a57f78827$var$SpringAnimation(/** @type SpringAnimationProps */ props) : new $fafca69a57f78827$var$CSSAnimation(/** @type CssAnimationProps */ props);\n this.activeAnimations.push(animation);\n animation.onFinish = ()=>this.stop(animation);\n return animation;\n }\n /**\r\n * @param {Animation} animation\r\n */ stop(animation) {\n animation.destroy();\n const index = this.activeAnimations.indexOf(animation);\n if (index > -1) this.activeAnimations.splice(index, 1);\n }\n stopAll() {\n // _stopAllAnimations\n this.activeAnimations.forEach((animation)=>{\n animation.destroy();\n });\n this.activeAnimations = [];\n }\n /**\r\n * Stop all pan or zoom transitions\r\n */ stopAllPan() {\n this.activeAnimations = this.activeAnimations.filter((animation)=>{\n if (animation.props.isPan) {\n animation.destroy();\n return false;\n }\n return true;\n });\n }\n stopMainScroll() {\n this.activeAnimations = this.activeAnimations.filter((animation)=>{\n if (animation.props.isMainScroll) {\n animation.destroy();\n return false;\n }\n return true;\n });\n }\n /**\r\n * Returns true if main scroll transition is running\r\n */ // isMainScrollRunning() {\n // return this.activeAnimations.some((animation) => {\n // return animation.props.isMainScroll;\n // });\n // }\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */ isPanRunning() {\n return this.activeAnimations.some((animation)=>{\n return animation.props.isPan;\n });\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */ class $fafca69a57f78827$var$ScrollWheel {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n pswp.events.add(pswp.element, 'wheel', /** @type EventListener */ this._onWheel.bind(this));\n }\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */ _onWheel(e) {\n e.preventDefault();\n const { currSlide: currSlide } = this.pswp;\n let { deltaX: deltaX, deltaY: deltaY } = e;\n if (!currSlide) return;\n if (this.pswp.dispatch('wheel', {\n originalEvent: e\n }).defaultPrevented) return;\n if (e.ctrlKey || this.pswp.options.wheelToZoom) // zoom\n {\n if (currSlide.isZoomable()) {\n let zoomFactor = -deltaY;\n if (e.deltaMode === 1) zoomFactor *= 0.05;\n else zoomFactor *= e.deltaMode ? 1 : 0.002;\n zoomFactor = 2 ** zoomFactor;\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\n currSlide.zoomTo(destZoomLevel, {\n x: e.clientX,\n y: e.clientY\n });\n }\n } else // pan\n if (currSlide.isPannable()) {\n if (e.deltaMode === 1) {\n // 18 - average line height\n deltaX *= 18;\n deltaY *= 18;\n }\n currSlide.panTo(currSlide.pan.x - deltaX, currSlide.pan.y - deltaY);\n }\n }\n}\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */ /**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */ /**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */ /** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */ /** @typedef {string | UIElementMarkupProps} UIElementMarkup */ /**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */ function $fafca69a57f78827$var$addElementHTML(htmlData) {\n if (typeof htmlData === 'string') // Allow developers to provide full svg,\n // For example:\n // \n // \n // \n // \n // Can also be any HTML string.\n return htmlData;\n if (!htmlData || !htmlData.isCustomSVG) return '';\n const svgData = htmlData;\n let out = ''; // replace all %d with size\n out = out.split('%d').join(/** @type {string} */ svgData.size || 32); // Icons may contain outline/shadow,\n // to make it we \"clone\" base icon shape and add border to it.\n // Icon itself and border are styled via CSS.\n //\n // Property shadowID defines ID of element that should be cloned.\n if (svgData.outlineID) out += '';\n out += svgData.inner;\n out += '';\n return out;\n}\nclass $fafca69a57f78827$var$UIElement {\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */ constructor(pswp, data){\n var _container;\n const name = data.name || data.className;\n let elementHTML = data.html; // @ts-expect-error lookup only by `data.name` maybe?\n if (pswp.options[name] === false) // exit if element is disabled from options\n return;\n // Allow to override SVG icons from options\n // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'SVG'] === 'string') // arrowPrevSVG\n // arrowNextSVG\n // closeSVG\n // zoomSVG\n // @ts-expect-error lookup only by `data.name` maybe?\n elementHTML = pswp.options[name + 'SVG'];\n pswp.dispatch('uiElementCreate', {\n data: data\n });\n let className = '';\n if (data.isButton) {\n className += 'pswp__button ';\n className += data.className || `pswp__button--${data.name}`;\n } else className += data.className || `pswp__${data.name}`;\n let tagName = data.isButton ? data.tagName || 'button' : data.tagName || 'div';\n tagName = /** @type {keyof HTMLElementTagNameMap} */ tagName.toLowerCase();\n /** @type {HTMLElement} */ const element = $fafca69a57f78827$var$createElement(className, tagName);\n if (data.isButton) {\n if (tagName === 'button') /** @type {HTMLButtonElement} */ element.type = 'button';\n let { title: title } = data;\n const { ariaLabel: ariaLabel } = data; // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'Title'] === 'string') // @ts-expect-error lookup only by `data.name` maybe?\n title = pswp.options[name + 'Title'];\n if (title) element.title = title;\n const ariaText = ariaLabel || title;\n if (ariaText) element.setAttribute('aria-label', ariaText);\n }\n element.innerHTML = $fafca69a57f78827$var$addElementHTML(elementHTML);\n if (data.onInit) data.onInit(element, pswp);\n if (data.onClick) element.onclick = (e)=>{\n if (typeof data.onClick === 'string') // @ts-ignore\n pswp[data.onClick]();\n else if (typeof data.onClick === 'function') data.onClick(e, element, pswp);\n };\n // Top bar is default position\n const appendTo = data.appendTo || 'bar';\n /** @type {HTMLElement | undefined} root element by default */ let container = pswp.element;\n if (appendTo === 'bar') {\n if (!pswp.topBar) pswp.topBar = $fafca69a57f78827$var$createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\n container = pswp.topBar;\n } else {\n // element outside of top bar gets a secondary class\n // that makes element fade out on close\n element.classList.add('pswp__hide-on-close');\n if (appendTo === 'wrapper') container = pswp.scrollWrap;\n }\n (_container = container) === null || _container === void 0 || _container.appendChild(pswp.applyFilters('uiElement', element, data));\n }\n}\n/*\r\n Backward and forward arrow buttons\r\n */ /** @typedef {import('./ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */ function $fafca69a57f78827$var$initArrowButton(element, pswp, isNextButton) {\n element.classList.add('pswp__button--arrow'); // TODO: this should point to a unique id for this instance\n element.setAttribute('aria-controls', 'pswp__items');\n pswp.on('change', ()=>{\n if (!pswp.options.loop) {\n if (isNextButton) /** @type {HTMLButtonElement} */ element.disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\n else /** @type {HTMLButtonElement} */ element.disabled = !(pswp.currIndex > 0);\n }\n });\n}\n/** @type {UIElementData} */ const $fafca69a57f78827$var$arrowPrev = {\n name: 'arrowPrev',\n className: 'pswp__button--arrow--prev',\n title: 'Previous',\n order: 10,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'prev',\n onInit: $fafca69a57f78827$var$initArrowButton\n};\n/** @type {UIElementData} */ const $fafca69a57f78827$var$arrowNext = {\n name: 'arrowNext',\n className: 'pswp__button--arrow--next',\n title: 'Next',\n order: 11,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'next',\n onInit: (el, pswp)=>{\n $fafca69a57f78827$var$initArrowButton(el, pswp, true);\n }\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $fafca69a57f78827$var$closeButton = {\n name: 'close',\n title: 'Close',\n order: 20,\n isButton: true,\n html: {\n isCustomSVG: true,\n inner: '',\n outlineID: 'pswp__icn-close'\n },\n onClick: 'close'\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $fafca69a57f78827$var$zoomButton = {\n name: 'zoom',\n title: 'Zoom',\n order: 10,\n isButton: true,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-zoom'\n },\n onClick: 'toggleZoom'\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $fafca69a57f78827$var$loadingIndicator = {\n name: 'preloader',\n appendTo: 'bar',\n order: 7,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-loading'\n },\n onInit: (indicatorElement, pswp)=>{\n /** @type {boolean | undefined} */ let isVisible;\n /** @type {NodeJS.Timeout | null} */ let delayTimeout = null;\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */ const toggleIndicatorClass = (className, add)=>{\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\n };\n /**\r\n * @param {boolean} visible\r\n */ const setIndicatorVisibility = (visible)=>{\n if (isVisible !== visible) {\n isVisible = visible;\n toggleIndicatorClass('active', visible);\n }\n };\n const updatePreloaderVisibility = ()=>{\n var _pswp$currSlide;\n if (!((_pswp$currSlide = pswp.currSlide) !== null && _pswp$currSlide !== void 0 && _pswp$currSlide.content.isLoading())) {\n setIndicatorVisibility(false);\n if (delayTimeout) {\n clearTimeout(delayTimeout);\n delayTimeout = null;\n }\n return;\n }\n if (!delayTimeout) // display loading indicator with delay\n delayTimeout = setTimeout(()=>{\n var _pswp$currSlide2;\n setIndicatorVisibility(Boolean((_pswp$currSlide2 = pswp.currSlide) === null || _pswp$currSlide2 === void 0 ? void 0 : _pswp$currSlide2.content.isLoading()));\n delayTimeout = null;\n }, pswp.options.preloaderDelay);\n };\n pswp.on('change', updatePreloaderVisibility);\n pswp.on('loadComplete', (e)=>{\n if (pswp.currSlide === e.slide) updatePreloaderVisibility();\n }); // expose the method\n if (pswp.ui) pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\n }\n};\n/** @type {import('./ui-element.js').UIElementData} UIElementData */ const $fafca69a57f78827$var$counterIndicator = {\n name: 'counter',\n order: 5,\n onInit: (counterElement, pswp)=>{\n pswp.on('change', ()=>{\n counterElement.innerText = pswp.currIndex + 1 + pswp.options.indexIndicatorSep + pswp.getNumItems();\n });\n }\n};\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./ui-element.js').UIElementData} UIElementData */ /**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */ function $fafca69a57f78827$var$setZoomedIn(el, isZoomedIn) {\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\n}\nclass $fafca69a57f78827$var$UI {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.isRegistered = false;\n /** @type {UIElementData[]} */ this.uiElementsData = [];\n /** @type {(UIElement | UIElementData)[]} */ this.items = [];\n /** @type {() => void} */ this.updatePreloaderVisibility = ()=>{};\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */ this._lastUpdatedZoomLevel = undefined;\n }\n init() {\n const { pswp: pswp } = this;\n this.isRegistered = false;\n this.uiElementsData = [\n $fafca69a57f78827$var$closeButton,\n $fafca69a57f78827$var$arrowPrev,\n $fafca69a57f78827$var$arrowNext,\n $fafca69a57f78827$var$zoomButton,\n $fafca69a57f78827$var$loadingIndicator,\n $fafca69a57f78827$var$counterIndicator\n ];\n pswp.dispatch('uiRegister'); // sort by order\n this.uiElementsData.sort((a, b)=>{\n // default order is 0\n return (a.order || 0) - (b.order || 0);\n });\n this.items = [];\n this.isRegistered = true;\n this.uiElementsData.forEach((uiElementData)=>{\n this.registerElement(uiElementData);\n });\n pswp.on('change', ()=>{\n var _pswp$element;\n (_pswp$element = pswp.element) === null || _pswp$element === void 0 || _pswp$element.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\n });\n pswp.on('zoomPanUpdate', ()=>this._onZoomPanUpdate());\n }\n /**\r\n * @param {UIElementData} elementData\r\n */ registerElement(elementData) {\n if (this.isRegistered) this.items.push(new $fafca69a57f78827$var$UIElement(this.pswp, elementData));\n else this.uiElementsData.push(elementData);\n }\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */ _onZoomPanUpdate() {\n const { template: template, currSlide: currSlide, options: options } = this.pswp;\n if (this.pswp.opener.isClosing || !template || !currSlide) return;\n let { currZoomLevel: currZoomLevel } = currSlide; // if not open yet - check against initial zoom level\n if (!this.pswp.opener.isOpen) currZoomLevel = currSlide.zoomLevels.initial;\n if (currZoomLevel === this._lastUpdatedZoomLevel) return;\n this._lastUpdatedZoomLevel = currZoomLevel;\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary; // Initial and secondary zoom levels are almost equal\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\n // disable zoom\n $fafca69a57f78827$var$setZoomedIn(template, false);\n template.classList.remove('pswp--zoom-allowed');\n return;\n }\n template.classList.add('pswp--zoom-allowed');\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\n $fafca69a57f78827$var$setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\n if (options.imageClickAction === 'zoom' || options.imageClickAction === 'zoom-or-close') template.classList.add('pswp--click-to-zoom');\n }\n}\n/** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */ /**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */ function $fafca69a57f78827$var$getBoundsByElement(el) {\n const thumbAreaRect = el.getBoundingClientRect();\n return {\n x: thumbAreaRect.left,\n y: thumbAreaRect.top,\n w: thumbAreaRect.width\n };\n}\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */ function $fafca69a57f78827$var$getCroppedBoundsByElement(el, imageWidth, imageHeight) {\n const thumbAreaRect = el.getBoundingClientRect(); // fill image into the area\n // (do they same as object-fit:cover does to retrieve coordinates)\n const hRatio = thumbAreaRect.width / imageWidth;\n const vRatio = thumbAreaRect.height / imageHeight;\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */ const bounds = {\n x: thumbAreaRect.left + offsetX,\n y: thumbAreaRect.top + offsetY,\n w: imageWidth * fillZoomLevel\n }; // Coordinates of inner crop area\n // relative to the image\n bounds.innerRect = {\n w: thumbAreaRect.width,\n h: thumbAreaRect.height,\n x: offsetX,\n y: offsetY\n };\n return bounds;\n}\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */ function $fafca69a57f78827$var$getThumbBounds(index, itemData, instance) {\n // legacy event, before filters were introduced\n const event = instance.dispatch('thumbBounds', {\n index: index,\n itemData: itemData,\n instance: instance\n }); // @ts-expect-error\n if (event.thumbBounds) // @ts-expect-error\n return event.thumbBounds;\n const { element: element } = itemData;\n /** @type {Bounds | undefined} */ let thumbBounds;\n /** @type {HTMLElement | null | undefined} */ let thumbnail;\n if (element && instance.options.thumbSelector !== false) {\n const thumbSelector = instance.options.thumbSelector || 'img';\n thumbnail = element.matches(thumbSelector) ? element : /** @type {HTMLElement | null} */ element.querySelector(thumbSelector);\n }\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\n if (thumbnail) {\n if (!itemData.thumbCropped) thumbBounds = $fafca69a57f78827$var$getBoundsByElement(thumbnail);\n else thumbBounds = $fafca69a57f78827$var$getCroppedBoundsByElement(thumbnail, itemData.width || itemData.w || 0, itemData.height || itemData.h || 0);\n }\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\n}\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../slide/content.js').default} ContentDefault */ /** @typedef {import('../slide/slide.js').default} Slide */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ /** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ /**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */ /** @typedef {{ x?: number; y?: number }} Point */ /**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */ /**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */ /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */ /**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */ class $fafca69a57f78827$var$PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */ constructor(type, details){\n this.type = type;\n this.defaultPrevented = false;\n if (details) Object.assign(this, details);\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */ class $fafca69a57f78827$var$Eventable {\n constructor(){\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */ this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */ this._filters = {};\n /** @type {PhotoSwipe | undefined} */ this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */ this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */ addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n if (!this._filters[name]) this._filters[name] = [];\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn: fn,\n priority: priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2)=>f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */ removeFilter(name, fn) {\n if (this._filters[name]) // @ts-expect-error\n this._filters[name] = this._filters[name].filter((filter)=>filter.fn !== fn);\n if (this.pswp) this.pswp.removeFilter(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */ applyFilters(name, ...args) {\n var _this$_filters$name3;\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach((filter)=>{\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n if (!this._listeners[name]) this._listeners[name] = [];\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ off(name, fn) {\n var _this$pswp3;\n if (this._listeners[name]) // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter((listener)=>fn !== listener);\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */ dispatch(name, details) {\n var _this$_listeners$name2;\n if (this.pswp) return this.pswp.dispatch(name, details);\n const event = /** @type {AugmentedEvent} */ new $fafca69a57f78827$var$PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach((listener)=>{\n listener.call(this, event);\n });\n return event;\n }\n}\nclass $fafca69a57f78827$var$Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */ constructor(imageSrc, container){\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */ this.element = $fafca69a57f78827$var$createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n $fafca69a57f78827$var$setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = $fafca69a57f78827$var$toTransformString(0, 0, width / 250);\n } else $fafca69a57f78827$var$setWidthHeight(this.element, width, height);\n }\n destroy() {\n var _this$element;\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) this.element.remove();\n this.element = null;\n }\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../util/util.js').LoadState} LoadState */ class $fafca69a57f78827$var$Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */ constructor(itemData, instance, index){\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {Placeholder | undefined} */ this.placeholder = undefined;\n /** @type {Slide | undefined} */ this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */ this.state = $fafca69a57f78827$var$LOAD_STATE.IDLE;\n if (this.data.type) this.type = this.data.type;\n else if (this.data.src) this.type = 'image';\n else this.type = 'html';\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) // With delay, as image might be loaded, but not rendered\n setTimeout(()=>{\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */ load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new $fafca69a57f78827$var$Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) this.slide.container.prepend(placeholderEl);\n }\n }\n if (this.element && !reload) return;\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n if (this.isImageContent()) {\n this.element = $fafca69a57f78827$var$createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) this.loadImage(isLazy);\n } else {\n this.element = $fafca69a57f78827$var$createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n if (reload && this.slide) this.slide.updateContentSize(true);\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */ loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n const imageElement = /** @type HTMLImageElement */ this.element;\n this.updateSrcsetSizes();\n if (this.data.srcset) imageElement.srcset = this.data.srcset;\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = $fafca69a57f78827$var$LOAD_STATE.LOADING;\n if (imageElement.complete) this.onLoaded();\n else {\n imageElement.onload = ()=>{\n this.onLoaded();\n };\n imageElement.onerror = ()=>{\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */ setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */ onLoaded() {\n this.state = $fafca69a57f78827$var$LOAD_STATE.LOADED;\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n if (this.state === $fafca69a57f78827$var$LOAD_STATE.LOADED || this.state === $fafca69a57f78827$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n }\n /**\r\n * Content load error handler\r\n */ onError() {\n this.state = $fafca69a57f78827$var$LOAD_STATE.ERROR;\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */ isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === $fafca69a57f78827$var$LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */ isError() {\n return this.state === $fafca69a57f78827$var$LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */ isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.placeholder) this.placeholder.setDisplayedSize(width, height);\n if (this.instance.dispatch('contentResize', {\n content: this,\n width: width,\n height: height\n }).defaultPrevented) return;\n $fafca69a57f78827$var$setWidthHeight(this.element, width, height);\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n if (isInitialSizeUpdate) this.loadImage(false);\n else this.updateSrcsetSizes();\n if (this.slide) this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width: width,\n height: height,\n content: this\n });\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */ isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== $fafca69a57f78827$var$LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */ updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) return;\n const image = /** @type HTMLImageElement */ this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */ usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */ lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) return;\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */ keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */ destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) return;\n this.remove();\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */ displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n let errorMsgEl = $fafca69a57f78827$var$createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl = /** @type {HTMLDivElement} */ this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = $fafca69a57f78827$var$createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */ append() {\n if (this.isAttached || !this.element) return;\n this.isAttached = true;\n if (this.state === $fafca69a57f78827$var$LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) return;\n const supportsDecode = 'decode' in this.element;\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || $fafca69a57f78827$var$isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */ this.element.decode().catch(()=>{}).finally(()=>{\n this.isDecoding = false;\n this.appendImage();\n });\n } else this.appendImage();\n } else if (this.slide && !this.element.parentNode) this.slide.container.appendChild(this.element);\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */ activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) return;\n if (this.isImageContent() && this.isDecoding && !$fafca69a57f78827$var$isSafari()) // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n else if (this.isError()) this.load(false, true); // try to reload\n if (this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n /**\r\n * Deactivate the content\r\n */ deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n if (this.slide && this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * Remove the content from DOM\r\n */ remove() {\n this.isAttached = false;\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) return;\n if (this.element && this.element.parentNode) this.element.remove();\n if (this.placeholder && this.placeholder.element) this.placeholder.element.remove();\n }\n /**\r\n * Append the image content to slide container\r\n */ appendImage() {\n if (!this.isAttached) return;\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) return;\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) this.slide.container.appendChild(this.element);\n if (this.state === $fafca69a57f78827$var$LOAD_STATE.LOADED || this.state === $fafca69a57f78827$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n}\n/** @typedef {import('./content.js').default} Content */ /** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ const $fafca69a57f78827$var$MIN_SLIDES_TO_CACHE = 5;\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ function $fafca69a57f78827$var$lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */ let zoomLevel;\n const { options: options } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new $fafca69a57f78827$var$ZoomLevel(options, itemData, -1);\n let viewportSize;\n if (instance.pswp) viewportSize = instance.pswp.viewportSize;\n else viewportSize = $fafca69a57f78827$var$getViewportSize(options, instance);\n const panAreaSize = $fafca69a57f78827$var$getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n content.lazyLoad();\n if (zoomLevel) content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */ function $fafca69a57f78827$var$lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n if (instance.dispatch('lazyLoadSlide', {\n index: index,\n itemData: itemData\n }).defaultPrevented) return;\n return $fafca69a57f78827$var$lazyLoadData(itemData, instance, index);\n}\nclass $fafca69a57f78827$var$ContentLoader {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp; // Total amount of cached images\n this.limit = Math.max(pswp.options.preload[0] + pswp.options.preload[1] + 1, $fafca69a57f78827$var$MIN_SLIDES_TO_CACHE);\n /** @type {Content[]} */ this._cachedItems = [];\n }\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */ updateLazy(diff) {\n const { pswp: pswp } = this;\n if (pswp.dispatch('lazyLoad').defaultPrevented) return;\n const { preload: preload } = pswp.options;\n const isForward = diff === undefined ? true : diff >= 0;\n let i; // preload[1] - num items to preload in forward direction\n for(i = 0; i <= preload[1]; i++)this.loadSlideByIndex(pswp.currIndex + (isForward ? i : -i));\n // preload[0] - num items to preload in backward direction\n for(i = 1; i <= preload[0]; i++)this.loadSlideByIndex(pswp.currIndex + (isForward ? -i : i));\n }\n /**\r\n * @param {number} initialIndex\r\n */ loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex); // try to get cached content\n let content = this.getContentByIndex(index);\n if (!content) {\n // no cached content, so try to load from scratch:\n content = $fafca69a57f78827$var$lazyLoadSlide(index, this.pswp); // if content can be loaded, add it to cache:\n if (content) this.addToCache(content);\n }\n }\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */ getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n } // assign slide to content\n content.setSlide(slide);\n return content;\n }\n /**\r\n * @param {Content} content\r\n */ addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n this._cachedItems.push(content);\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex((item)=>{\n return !item.isAttached && !item.hasSlide;\n });\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n removedItem.destroy();\n }\n }\n }\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */ removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex((item)=>item.index === index);\n if (indexToRemove !== -1) this._cachedItems.splice(indexToRemove, 1);\n }\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */ getContentByIndex(index) {\n return this._cachedItems.find((content)=>content.index === index);\n }\n destroy() {\n this._cachedItems.forEach((content)=>content.destroy());\n this._cachedItems = [];\n }\n}\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */ /** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */ /**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */ class $fafca69a57f78827$var$PhotoSwipeBase extends $fafca69a57f78827$var$Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */ getNumItems() {\n var _this$options;\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n if (dataSource && 'length' in dataSource) // may be an array or just object with length property\n numItems = dataSource.length;\n else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n if (dataSource.items) numItems = dataSource.items.length;\n } // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource: dataSource,\n numItems: numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */ createContentFromData(slideData, index) {\n return new $fafca69a57f78827$var$Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */ getItemData(index) {\n var _this$options2;\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */ let dataSourceItem = {};\n if (Array.isArray(dataSource)) // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n dataSourceItem = dataSource.items[index];\n }\n let itemData = dataSourceItem;\n if (itemData instanceof Element) itemData = this._domElementToItemData(itemData);\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index: index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */ _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) return $fafca69a57f78827$var$getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n return [\n galleryElement\n ];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */ _domElementToItemData(element) {\n /** @type {SlideData} */ const itemData = {\n element: element\n };\n const linkEl = /** @type {HTMLAnchorElement} */ element.tagName === 'A' ? element : element.querySelector('a');\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n if (linkEl.dataset.pswpSrcset) itemData.srcset = linkEl.dataset.pswpSrcset;\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n if (linkEl.dataset.pswpType) itemData.type = linkEl.dataset.pswpType;\n const thumbnailEl = element.querySelector('img');\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) itemData.thumbCropped = true;\n }\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ lazyLoadData(itemData, index) {\n return $fafca69a57f78827$var$lazyLoadData(itemData, this, index);\n }\n}\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ /** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */ /** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */ // some browsers do not paint\n// elements which opacity is set to 0,\n// since we need to pre-render elements for the animation -\n// we set it to the minimum amount\nconst $fafca69a57f78827$var$MIN_OPACITY = 0.003;\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */ class $fafca69a57f78827$var$Opener {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */ constructor(pswp){\n this.pswp = pswp;\n this.isClosed = true;\n this.isOpen = false;\n this.isClosing = false;\n this.isOpening = false;\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */ this._duration = undefined;\n /** @private */ this._useAnimation = false;\n /** @private */ this._croppedZoom = false;\n /** @private */ this._animateRootOpacity = false;\n /** @private */ this._animateBgOpacity = false;\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */ this._placeholder = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */ this._opacityElement = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */ this._cropContainer1 = undefined;\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */ this._cropContainer2 = undefined;\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */ this._thumbBounds = undefined;\n this._prepareOpen = this._prepareOpen.bind(this); // Override initial zoom and pan position\n pswp.on('firstZoomPan', this._prepareOpen);\n }\n open() {\n this._prepareOpen();\n this._start();\n }\n close() {\n if (this.isClosed || this.isClosing || this.isOpening) // if we close during opening animation\n // for now do nothing,\n // browsers aren't good at changing the direction of the CSS transition\n return;\n const slide = this.pswp.currSlide;\n this.isOpen = false;\n this.isOpening = false;\n this.isClosing = true;\n this._duration = this.pswp.options.hideAnimationDuration;\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) this._duration = 0;\n this._applyStartProps();\n setTimeout(()=>{\n this._start();\n }, this._croppedZoom ? 30 : 0);\n }\n /** @private */ _prepareOpen() {\n this.pswp.off('firstZoomPan', this._prepareOpen);\n if (!this.isOpening) {\n const slide = this.pswp.currSlide;\n this.isOpening = true;\n this.isClosing = false;\n this._duration = this.pswp.options.showAnimationDuration;\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) this._duration = 0;\n this._applyStartProps();\n }\n }\n /** @private */ _applyStartProps() {\n const { pswp: pswp } = this;\n const slide = this.pswp.currSlide;\n const { options: options } = pswp;\n if (options.showHideAnimationType === 'fade') {\n options.showHideOpacity = true;\n this._thumbBounds = undefined;\n } else if (options.showHideAnimationType === 'none') {\n options.showHideOpacity = false;\n this._duration = 0;\n this._thumbBounds = undefined;\n } else if (this.isOpening && pswp._initialThumbBounds) // Use initial bounds if defined\n this._thumbBounds = pswp._initialThumbBounds;\n else this._thumbBounds = this.pswp.getThumbBounds();\n this._placeholder = slide === null || slide === void 0 ? void 0 : slide.getPlaceholderElement();\n pswp.animations.stopAll(); // Discard animations when duration is less than 50ms\n this._useAnimation = Boolean(this._duration && this._duration > 50);\n this._animateZoom = Boolean(this._thumbBounds) && (slide === null || slide === void 0 ? void 0 : slide.content.usePlaceholder()) && (!this.isClosing || !pswp.mainScroll.isShifted());\n if (!this._animateZoom) {\n this._animateRootOpacity = true;\n if (this.isOpening && slide) {\n slide.zoomAndPanToInitial();\n slide.applyCurrentZoomPan();\n }\n } else {\n var _options$showHideOpac;\n this._animateRootOpacity = (_options$showHideOpac = options.showHideOpacity) !== null && _options$showHideOpac !== void 0 ? _options$showHideOpac : false;\n }\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > $fafca69a57f78827$var$MIN_OPACITY;\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\n if (!this._useAnimation) {\n this._duration = 0;\n this._animateZoom = false;\n this._animateBgOpacity = false;\n this._animateRootOpacity = true;\n if (this.isOpening) {\n if (pswp.element) pswp.element.style.opacity = String($fafca69a57f78827$var$MIN_OPACITY);\n pswp.applyBgOpacity(1);\n }\n return;\n }\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\n var _this$pswp$currSlide;\n // Properties are used when animation from cropped thumbnail\n this._croppedZoom = true;\n this._cropContainer1 = this.pswp.container;\n this._cropContainer2 = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.holderElement;\n if (pswp.container) {\n pswp.container.style.overflow = 'hidden';\n pswp.container.style.width = pswp.viewportSize.x + 'px';\n }\n } else this._croppedZoom = false;\n if (this.isOpening) {\n // Apply styles before opening transition\n if (this._animateRootOpacity) {\n if (pswp.element) pswp.element.style.opacity = String($fafca69a57f78827$var$MIN_OPACITY);\n pswp.applyBgOpacity(1);\n } else {\n if (this._animateBgOpacity && pswp.bg) pswp.bg.style.opacity = String($fafca69a57f78827$var$MIN_OPACITY);\n if (pswp.element) pswp.element.style.opacity = '1';\n }\n if (this._animateZoom) {\n this._setClosedStateZoomPan();\n if (this._placeholder) {\n // tell browser that we plan to animate the placeholder\n this._placeholder.style.willChange = 'transform'; // hide placeholder to allow hiding of\n // elements that overlap it (such as icons over the thumbnail)\n this._placeholder.style.opacity = String($fafca69a57f78827$var$MIN_OPACITY);\n }\n }\n } else if (this.isClosing) {\n // hide nearby slides to make sure that\n // they are not painted during the transition\n if (pswp.mainScroll.itemHolders[0]) pswp.mainScroll.itemHolders[0].el.style.display = 'none';\n if (pswp.mainScroll.itemHolders[2]) pswp.mainScroll.itemHolders[2].el.style.display = 'none';\n if (this._croppedZoom) {\n if (pswp.mainScroll.x !== 0) {\n // shift the main scroller to zero position\n pswp.mainScroll.resetPosition();\n pswp.mainScroll.resize();\n }\n }\n }\n }\n /** @private */ _start() {\n if (this.isOpening && this._useAnimation && this._placeholder && this._placeholder.tagName === 'IMG') // To ensure smooth animation\n // we wait till the current slide image placeholder is decoded,\n // but no longer than 250ms,\n // and no shorter than 50ms\n // (just using requestanimationframe is not enough in Firefox,\n // for some reason)\n new Promise((resolve)=>{\n let decoded = false;\n let isDelaying = true;\n $fafca69a57f78827$var$decodeImage(/** @type {HTMLImageElement} */ this._placeholder).finally(()=>{\n decoded = true;\n if (!isDelaying) resolve(true);\n });\n setTimeout(()=>{\n isDelaying = false;\n if (decoded) resolve(true);\n }, 50);\n setTimeout(resolve, 250);\n }).finally(()=>this._initiate());\n else this._initiate();\n }\n /** @private */ _initiate() {\n var _this$pswp$element, _this$pswp$element2;\n (_this$pswp$element = this.pswp.element) === null || _this$pswp$element === void 0 || _this$pswp$element.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\n this.pswp.dispatch(this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'); // legacy event\n this.pswp.dispatch(/** @type {'initialZoomIn' | 'initialZoomOut'} */ 'initialZoom' + (this.isOpening ? 'In' : 'Out'));\n (_this$pswp$element2 = this.pswp.element) === null || _this$pswp$element2 === void 0 || _this$pswp$element2.classList.toggle('pswp--ui-visible', this.isOpening);\n if (this.isOpening) {\n if (this._placeholder) // unhide the placeholder\n this._placeholder.style.opacity = '1';\n this._animateToOpenState();\n } else if (this.isClosing) this._animateToClosedState();\n if (!this._useAnimation) this._onAnimationComplete();\n }\n /** @private */ _onAnimationComplete() {\n const { pswp: pswp } = this;\n this.isOpen = this.isOpening;\n this.isClosed = this.isClosing;\n this.isOpening = false;\n this.isClosing = false;\n pswp.dispatch(this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'); // legacy event\n pswp.dispatch(/** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */ 'initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'));\n if (this.isClosed) pswp.destroy();\n else if (this.isOpen) {\n var _pswp$currSlide;\n if (this._animateZoom && pswp.container) {\n pswp.container.style.overflow = 'visible';\n pswp.container.style.width = '100%';\n }\n (_pswp$currSlide = pswp.currSlide) === null || _pswp$currSlide === void 0 || _pswp$currSlide.applyCurrentZoomPan();\n }\n }\n /** @private */ _animateToOpenState() {\n const { pswp: pswp } = this;\n if (this._animateZoom) {\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\n this._animateTo(this._cropContainer2, 'transform', 'none');\n }\n if (pswp.currSlide) {\n pswp.currSlide.zoomAndPanToInitial();\n this._animateTo(pswp.currSlide.container, 'transform', pswp.currSlide.getCurrentTransform());\n }\n }\n if (this._animateBgOpacity && pswp.bg) this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\n if (this._animateRootOpacity && pswp.element) this._animateTo(pswp.element, 'opacity', '1');\n }\n /** @private */ _animateToClosedState() {\n const { pswp: pswp } = this;\n if (this._animateZoom) this._setClosedStateZoomPan(true);\n // do not animate opacity if it's already at 0\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) this._animateTo(pswp.bg, 'opacity', '0');\n if (this._animateRootOpacity && pswp.element) this._animateTo(pswp.element, 'opacity', '0');\n }\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */ _setClosedStateZoomPan(animate) {\n if (!this._thumbBounds) return;\n const { pswp: pswp } = this;\n const { innerRect: innerRect } = this._thumbBounds;\n const { currSlide: currSlide, viewportSize: viewportSize } = pswp;\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\n const containerTwoPanX = viewportSize.x - innerRect.w;\n const containerTwoPanY = viewportSize.y - innerRect.h;\n if (animate) {\n this._animateTo(this._cropContainer1, 'transform', $fafca69a57f78827$var$toTransformString(containerOnePanX, containerOnePanY));\n this._animateTo(this._cropContainer2, 'transform', $fafca69a57f78827$var$toTransformString(containerTwoPanX, containerTwoPanY));\n } else {\n $fafca69a57f78827$var$setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\n $fafca69a57f78827$var$setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\n }\n }\n if (currSlide) {\n $fafca69a57f78827$var$equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\n if (animate) this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\n else currSlide.applyCurrentZoomPan();\n }\n }\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */ _animateTo(target, prop, propValue) {\n if (!this._duration) {\n target.style[prop] = propValue;\n return;\n }\n const { animations: animations } = this.pswp;\n /** @type {AnimationProps} */ const animProps = {\n duration: this._duration,\n easing: this.pswp.options.easing,\n onComplete: ()=>{\n if (!animations.activeAnimations.length) this._onAnimationComplete();\n },\n target: target\n };\n animProps[prop] = propValue;\n animations.startTransition(animProps);\n }\n}\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */ /** @typedef {import('./slide/slide.js').SlideData} SlideData */ /** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */ /** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */ /** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ /** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ /** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */ /** @typedef {{ x: number; y: number; id?: string | number }} Point */ /** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */ /** @typedef {SlideData[]} DataSourceArray */ /** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */ /** @typedef {DataSourceArray | DataSourceObject} DataSource */ /** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */ /** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */ /** @typedef {Type | { default: Type }} PhotoSwipeModule */ /** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */ /**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */ /** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */ /**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */ /** @type {PreparedPhotoSwipeOptions} */ const $fafca69a57f78827$var$defaultOptions = {\n allowPanToNext: true,\n spacing: 0.1,\n loop: true,\n pinchToClose: true,\n closeOnVerticalDrag: true,\n hideAnimationDuration: 333,\n showAnimationDuration: 333,\n zoomAnimationDuration: 333,\n escKey: true,\n arrowKeys: true,\n trapFocus: true,\n returnFocus: true,\n maxWidthToAnimate: 4000,\n clickToCloseNonZoomable: true,\n imageClickAction: 'zoom-or-close',\n bgClickAction: 'close',\n tapAction: 'toggle-controls',\n doubleTapAction: 'zoom',\n indexIndicatorSep: ' / ',\n preloaderDelay: 2000,\n bgOpacity: 0.8,\n index: 0,\n errorMsg: 'The image cannot be loaded',\n preload: [\n 1,\n 2\n ],\n easing: 'cubic-bezier(.4,0,.22,1)'\n};\n/**\r\n * PhotoSwipe Core\r\n */ class $fafca69a57f78827$export$2e2bcd8739ae039 extends $fafca69a57f78827$var$PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */ constructor(options){\n super();\n this.options = this._prepareOptions(options || {});\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */ this.offset = {\n x: 0,\n y: 0\n };\n /**\r\n * @type {Point}\r\n * @private\r\n */ this._prevViewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */ this.viewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * background (backdrop) opacity\r\n */ this.bgOpacity = 1;\n this.currIndex = 0;\n this.potentialIndex = 0;\n this.isOpen = false;\n this.isDestroying = false;\n this.hasMouse = false;\n /**\r\n * @private\r\n * @type {SlideData}\r\n */ this._initialItemData = {};\n /** @type {Bounds | undefined} */ this._initialThumbBounds = undefined;\n /** @type {HTMLDivElement | undefined} */ this.topBar = undefined;\n /** @type {HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {HTMLDivElement | undefined} */ this.template = undefined;\n /** @type {HTMLDivElement | undefined} */ this.container = undefined;\n /** @type {HTMLElement | undefined} */ this.scrollWrap = undefined;\n /** @type {Slide | undefined} */ this.currSlide = undefined;\n this.events = new $fafca69a57f78827$var$DOMEvents();\n this.animations = new $fafca69a57f78827$var$Animations();\n this.mainScroll = new $fafca69a57f78827$var$MainScroll(this);\n this.gestures = new $fafca69a57f78827$var$Gestures(this);\n this.opener = new $fafca69a57f78827$var$Opener(this);\n this.keyboard = new $fafca69a57f78827$var$Keyboard(this);\n this.contentLoader = new $fafca69a57f78827$var$ContentLoader(this);\n }\n /** @returns {boolean} */ init() {\n if (this.isOpen || this.isDestroying) return false;\n this.isOpen = true;\n this.dispatch('init'); // legacy\n this.dispatch('beforeOpen');\n this._createMainStructure(); // add classes to the root element of PhotoSwipe\n let rootClasses = 'pswp--open';\n if (this.gestures.supportsTouch) rootClasses += ' pswp--touch';\n if (this.options.mainClass) rootClasses += ' ' + this.options.mainClass;\n if (this.element) this.element.className += ' ' + rootClasses;\n this.currIndex = this.options.index || 0;\n this.potentialIndex = this.currIndex;\n this.dispatch('firstUpdate'); // starting index can be modified here\n // initialize scroll wheel handler to block the scroll\n this.scrollWheel = new $fafca69a57f78827$var$ScrollWheel(this); // sanitize index\n if (Number.isNaN(this.currIndex) || this.currIndex < 0 || this.currIndex >= this.getNumItems()) this.currIndex = 0;\n if (!this.gestures.supportsTouch) // enable mouse features if no touch support detected\n this.mouseDetected();\n // causes forced synchronous layout\n this.updateSize();\n this.offset.y = window.pageYOffset;\n this._initialItemData = this.getItemData(this.currIndex);\n this.dispatch('gettingData', {\n index: this.currIndex,\n data: this._initialItemData,\n slide: undefined\n }); // *Layout* - calculate size and position of elements here\n this._initialThumbBounds = this.getThumbBounds();\n this.dispatch('initialLayout');\n this.on('openingAnimationEnd', ()=>{\n const { itemHolders: itemHolders } = this.mainScroll; // Add content to the previous and next slide\n if (itemHolders[0]) {\n itemHolders[0].el.style.display = 'block';\n this.setContent(itemHolders[0], this.currIndex - 1);\n }\n if (itemHolders[2]) {\n itemHolders[2].el.style.display = 'block';\n this.setContent(itemHolders[2], this.currIndex + 1);\n }\n this.appendHeavy();\n this.contentLoader.updateLazy();\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\n this.dispatch('bindEvents');\n }); // set content for center slide (first time)\n if (this.mainScroll.itemHolders[1]) this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\n this.dispatch('change');\n this.opener.open();\n this.dispatch('afterInit');\n return true;\n }\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */ getLoopedIndex(index) {\n const numSlides = this.getNumItems();\n if (this.options.loop) {\n if (index > numSlides - 1) index -= numSlides;\n if (index < 0) index += numSlides;\n }\n return $fafca69a57f78827$var$clamp(index, 0, numSlides - 1);\n }\n appendHeavy() {\n this.mainScroll.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide;\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.appendHeavy();\n });\n }\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */ goTo(index) {\n this.mainScroll.moveIndexBy(this.getLoopedIndex(index) - this.potentialIndex);\n }\n /**\r\n * Go to the next slide.\r\n */ next() {\n this.goTo(this.potentialIndex + 1);\n }\n /**\r\n * Go to the previous slide.\r\n */ prev() {\n this.goTo(this.potentialIndex - 1);\n }\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */ zoomTo(...args) {\n var _this$currSlide;\n (_this$currSlide = this.currSlide) === null || _this$currSlide === void 0 || _this$currSlide.zoomTo(...args);\n }\n /**\r\n * @see slide/slide.js toggleZoom\r\n */ toggleZoom() {\n var _this$currSlide2;\n (_this$currSlide2 = this.currSlide) === null || _this$currSlide2 === void 0 || _this$currSlide2.toggleZoom();\n }\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */ close() {\n if (!this.opener.isOpen || this.isDestroying) return;\n this.isDestroying = true;\n this.dispatch('close');\n this.events.removeAll();\n this.opener.close();\n }\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */ destroy() {\n var _this$element;\n if (!this.isDestroying) {\n this.options.showHideAnimationType = 'none';\n this.close();\n return;\n }\n this.dispatch('destroy');\n this._listeners = {};\n if (this.scrollWrap) {\n this.scrollWrap.ontouchmove = null;\n this.scrollWrap.ontouchend = null;\n }\n (_this$element = this.element) === null || _this$element === void 0 || _this$element.remove();\n this.mainScroll.itemHolders.forEach((itemHolder)=>{\n var _itemHolder$slide2;\n (_itemHolder$slide2 = itemHolder.slide) === null || _itemHolder$slide2 === void 0 || _itemHolder$slide2.destroy();\n });\n this.contentLoader.destroy();\n this.events.removeAll();\n }\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */ refreshSlideContent(slideIndex) {\n this.contentLoader.removeByIndex(slideIndex);\n this.mainScroll.itemHolders.forEach((itemHolder, i)=>{\n var _this$currSlide$index, _this$currSlide3;\n let potentialHolderIndex = ((_this$currSlide$index = (_this$currSlide3 = this.currSlide) === null || _this$currSlide3 === void 0 ? void 0 : _this$currSlide3.index) !== null && _this$currSlide$index !== void 0 ? _this$currSlide$index : 0) - 1 + i;\n if (this.canLoop()) potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\n if (potentialHolderIndex === slideIndex) {\n // set the new slide content\n this.setContent(itemHolder, slideIndex, true); // activate the new slide if it's current\n if (i === 1) {\n var _itemHolder$slide3;\n this.currSlide = itemHolder.slide;\n (_itemHolder$slide3 = itemHolder.slide) === null || _itemHolder$slide3 === void 0 || _itemHolder$slide3.setIsActive(true);\n }\n }\n });\n this.dispatch('change');\n }\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */ setContent(holder, index, force) {\n if (this.canLoop()) index = this.getLoopedIndex(index);\n if (holder.slide) {\n if (holder.slide.index === index && !force) // exit if holder already contains this slide\n // this could be common when just three slides are used\n return;\n // destroy previous slide\n holder.slide.destroy();\n holder.slide = undefined;\n } // exit if no loop and index is out of bounds\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) return;\n const itemData = this.getItemData(index);\n holder.slide = new $fafca69a57f78827$var$Slide(itemData, index, this); // set current slide\n if (index === this.currIndex) this.currSlide = holder.slide;\n holder.slide.append(holder.el);\n }\n /** @returns {Point} */ getViewportCenterPoint() {\n return {\n x: this.viewportSize.x / 2,\n y: this.viewportSize.y / 2\n };\n }\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */ updateSize(force) {\n // let item;\n // let itemIndex;\n if (this.isDestroying) // exit if PhotoSwipe is closed or closing\n // (to avoid errors, as resize event might be delayed)\n return;\n //const newWidth = this.scrollWrap.clientWidth;\n //const newHeight = this.scrollWrap.clientHeight;\n const newViewportSize = $fafca69a57f78827$var$getViewportSize(this.options, this);\n if (!force && $fafca69a57f78827$var$pointsEqual(newViewportSize, this._prevViewportSize)) // Exit if dimensions were not changed\n return;\n //this._prevViewportSize.x = newWidth;\n //this._prevViewportSize.y = newHeight;\n $fafca69a57f78827$var$equalizePoints(this._prevViewportSize, newViewportSize);\n this.dispatch('beforeResize');\n $fafca69a57f78827$var$equalizePoints(this.viewportSize, this._prevViewportSize);\n this._updatePageScrollOffset();\n this.dispatch('viewportSize'); // Resize slides only after opener animation is finished\n // and don't re-calculate size on inital size update\n this.mainScroll.resize(this.opener.isOpen);\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) this.mouseDetected();\n this.dispatch('resize');\n }\n /**\r\n * @param {number} opacity\r\n */ applyBgOpacity(opacity) {\n this.bgOpacity = Math.max(opacity, 0);\n if (this.bg) this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\n }\n /**\r\n * Whether mouse is detected\r\n */ mouseDetected() {\n if (!this.hasMouse) {\n var _this$element2;\n this.hasMouse = true;\n (_this$element2 = this.element) === null || _this$element2 === void 0 || _this$element2.classList.add('pswp--has_mouse');\n }\n }\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */ _handlePageResize() {\n this.updateSize(); // In iOS webview, if element size depends on document size,\n // it'll be measured incorrectly in resize event\n //\n // https://bugs.webkit.org/show_bug.cgi?id=170595\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) setTimeout(()=>{\n this.updateSize();\n }, 500);\n }\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */ _updatePageScrollOffset() {\n this.setScrollOffset(0, window.pageYOffset);\n }\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */ setScrollOffset(x, y) {\n this.offset.x = x;\n this.offset.y = y;\n this.dispatch('updateScrollOffset');\n }\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */ _createMainStructure() {\n // root DOM element of PhotoSwipe (.pswp)\n this.element = $fafca69a57f78827$var$createElement('pswp', 'div');\n this.element.setAttribute('tabindex', '-1');\n this.element.setAttribute('role', 'dialog'); // template is legacy prop\n this.template = this.element; // Background is added as a separate element,\n // as animating opacity is faster than animating rgba()\n this.bg = $fafca69a57f78827$var$createElement('pswp__bg', 'div', this.element);\n this.scrollWrap = $fafca69a57f78827$var$createElement('pswp__scroll-wrap', 'section', this.element);\n this.container = $fafca69a57f78827$var$createElement('pswp__container', 'div', this.scrollWrap); // aria pattern: carousel\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\n this.container.setAttribute('aria-live', 'off');\n this.container.setAttribute('id', 'pswp__items');\n this.mainScroll.appendHolders();\n this.ui = new $fafca69a57f78827$var$UI(this);\n this.ui.init(); // append to DOM\n (this.options.appendToEl || document.body).appendChild(this.element);\n }\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */ getThumbBounds() {\n return $fafca69a57f78827$var$getThumbBounds(this.currIndex, this.currSlide ? this.currSlide.data : this._initialItemData, this);\n }\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */ canLoop() {\n return this.options.loop && this.getNumItems() > 2;\n }\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */ _prepareOptions(options) {\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\n options.showHideAnimationType = 'none';\n options.zoomAnimationDuration = 0;\n }\n /** @type {PreparedPhotoSwipeOptions} */ return {\n ...$fafca69a57f78827$var$defaultOptions,\n ...options\n };\n }\n}\n\n});\n\n\n//# sourceMappingURL=photoswipe.esm.b9f46f1c.js.map\n","/*!\n * PhotoSwipe 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\nfunction createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n\n if (className) {\n el.className = className;\n }\n\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n\n return el;\n}\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\n\nfunction equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n\n if (p2.id !== undefined) {\n p1.id = p2.id;\n }\n\n return p1;\n}\n/**\r\n * @param {Point} p\r\n */\n\nfunction roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\n\nfunction getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt(x * x + y * y);\n}\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\n\nfunction pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\n\nfunction clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\n\nfunction toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\n\nfunction setTransform(el, x, y, scale) {\n el.style.transform = toTransformString(x, y, scale);\n}\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\n\nfunction setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop ? `${prop} ${duration}ms ${ease || defaultCSSEasing}` : 'none';\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\n\nfunction setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/**\r\n * @param {HTMLElement} el\r\n */\n\nfunction removeTransitionStyle(el) {\n setTransitionStyle(el);\n}\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\n\nfunction decodeImage(img) {\n if ('decode' in img) {\n return img.decode().catch(() => {});\n }\n\n if (img.complete) {\n return Promise.resolve(img);\n }\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img);\n\n img.onerror = reject;\n });\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\n\nconst LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\n\nfunction specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\n\nfunction getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\n\nfunction isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n// Detect passive event listener support\nlet supportsPassive = false;\n/* eslint-disable */\n\ntry {\n /* @ts-ignore */\n window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\n get: () => {\n supportsPassive = true;\n }\n }));\n} catch (e) {}\n/* eslint-enable */\n\n/**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */\n\n\nclass DOMEvents {\n constructor() {\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */\n this._pool = [];\n }\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\n\n\n add(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive);\n }\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\n\n\n remove(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive, true);\n }\n /**\r\n * Removes all bound events\r\n */\n\n\n removeAll() {\n this._pool.forEach(poolItem => {\n this._toggleListener(poolItem.target, poolItem.type, poolItem.listener, poolItem.passive, true, true);\n });\n\n this._pool = [];\n }\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */\n\n\n _toggleListener(target, type, listener, passive, unbind, skipPool) {\n if (!target) {\n return;\n }\n\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\n const types = type.split(' ');\n types.forEach(eType => {\n if (eType) {\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\n // so developer doesn't need to do this manually\n if (!skipPool) {\n if (unbind) {\n // Remove from the events pool\n this._pool = this._pool.filter(poolItem => {\n return poolItem.type !== eType || poolItem.listener !== listener || poolItem.target !== target;\n });\n } else {\n // Add to the events pool\n this._pool.push({\n target,\n type: eType,\n listener,\n passive\n });\n }\n } // most PhotoSwipe events call preventDefault,\n // and we do not need browser to scroll the page\n\n\n const eventOptions = supportsPassive ? {\n passive: passive || false\n } : false;\n target[methodName](eType, listener, eventOptions);\n }\n });\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\nfunction getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\n\nfunction parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\n\nfunction getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - parsePaddingOption('left', options, viewportSize, itemData, index) - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - parsePaddingOption('top', options, viewportSize, itemData, index) - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {Record} Point */\n\n/** @typedef {'x' | 'y'} Axis */\n\n/**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */\n\nclass PanBounds {\n /**\r\n * @param {Slide} slide\r\n */\n constructor(slide) {\n this.slide = slide;\n this.currZoomLevel = 1;\n this.center =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n this.max =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n this.min =\n /** @type {Point} */\n {\n x: 0,\n y: 0\n };\n }\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */\n\n\n update(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n\n if (!this.slide.width) {\n this.reset();\n } else {\n this._updateAxis('x');\n\n this._updateAxis('y');\n\n this.slide.pswp.dispatch('calcBounds', {\n slide: this.slide\n });\n }\n }\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */\n\n\n _updateAxis(axis) {\n const {\n pswp\n } = this.slide;\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\n const paddingProp = axis === 'x' ? 'left' : 'top';\n const padding = parsePaddingOption(paddingProp, pswp.options, pswp.viewportSize, this.slide.data, this.slide.index);\n const panAreaSize = this.slide.panAreaSize[axis]; // Default position of element.\n // By default, it is center of viewport:\n\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding; // maximum pan position\n\n this.max[axis] = elSize > panAreaSize ? Math.round(panAreaSize - elSize) + padding : this.center[axis]; // minimum pan position\n\n this.min[axis] = elSize > panAreaSize ? padding : this.center[axis];\n } // _getZeroBounds\n\n\n reset() {\n this.center.x = 0;\n this.center.y = 0;\n this.max.x = 0;\n this.max.y = 0;\n this.min.x = 0;\n this.min.y = 0;\n }\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */\n\n\n correctPan(axis, panOffset) {\n // checkPanBounds\n return clamp(panOffset, this.max[axis], this.min[axis]);\n }\n\n}\n\nconst MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\n\nclass ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n\n this.panAreaSize = null;\n /** @type { Point | null } */\n\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\n\n\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\n\n\n _parseZoomLevelOption(optionPrefix) {\n const optionName =\n /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */\n optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n } // 3x of \"fit\" state, but not larger than original\n\n\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/**\r\n * Renders and allows to control a single slide\r\n */\n\nclass Slide {\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(data, index, pswp) {\n this.data = data;\n this.index = index;\n this.pswp = pswp;\n this.isActive = index === pswp.currIndex;\n this.currentResolution = 0;\n /** @type {Point} */\n\n this.panAreaSize = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.pan = {\n x: 0,\n y: 0\n };\n this.isFirstSlide = this.isActive && !pswp.opener.isOpen;\n this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp);\n this.pswp.dispatch('gettingData', {\n slide: this,\n data: this.data,\n index\n });\n this.content = this.pswp.contentLoader.getContentBySlide(this);\n this.container = createElement('pswp__zoom-wrap', 'div');\n /** @type {HTMLElement | null} */\n\n this.holderElement = null;\n this.currZoomLevel = 1;\n /** @type {number} */\n\n this.width = this.content.width;\n /** @type {number} */\n\n this.height = this.content.height;\n this.heavyAppended = false;\n this.bounds = new PanBounds(this);\n this.prevDisplayedWidth = -1;\n this.prevDisplayedHeight = -1;\n this.pswp.dispatch('slideInit', {\n slide: this\n });\n }\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */\n\n\n setIsActive(isActive) {\n if (isActive && !this.isActive) {\n // slide just became active\n this.activate();\n } else if (!isActive && this.isActive) {\n // slide just became non-active\n this.deactivate();\n }\n }\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */\n\n\n append(holderElement) {\n this.holderElement = holderElement;\n this.container.style.transformOrigin = '0 0'; // Slide appended to DOM\n\n if (!this.data) {\n return;\n }\n\n this.calculateSize();\n this.load();\n this.updateContentSize();\n this.appendHeavy();\n this.holderElement.appendChild(this.container);\n this.zoomAndPanToInitial();\n this.pswp.dispatch('firstZoomPan', {\n slide: this\n });\n this.applyCurrentZoomPan();\n this.pswp.dispatch('afterSetContent', {\n slide: this\n });\n\n if (this.isActive) {\n this.activate();\n }\n }\n\n load() {\n this.content.load(false);\n this.pswp.dispatch('slideLoad', {\n slide: this\n });\n }\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */\n\n\n appendHeavy() {\n const {\n pswp\n } = this;\n const appendHeavyNearby = true; // todo\n // Avoid appending heavy elements during animations\n\n if (this.heavyAppended || !pswp.opener.isOpen || pswp.mainScroll.isShifted() || !this.isActive && !appendHeavyNearby) {\n return;\n }\n\n if (this.pswp.dispatch('appendHeavy', {\n slide: this\n }).defaultPrevented) {\n return;\n }\n\n this.heavyAppended = true;\n this.content.append();\n this.pswp.dispatch('appendHeavyContent', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */\n\n\n activate() {\n this.isActive = true;\n this.appendHeavy();\n this.content.activate();\n this.pswp.dispatch('slideActivate', {\n slide: this\n });\n }\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */\n\n\n deactivate() {\n this.isActive = false;\n this.content.deactivate();\n\n if (this.currZoomLevel !== this.zoomLevels.initial) {\n // allow filtering\n this.calculateSize();\n } // reset zoom level\n\n\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n this.pswp.dispatch('slideDeactivate', {\n slide: this\n });\n }\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */\n\n\n destroy() {\n this.content.hasSlide = false;\n this.content.remove();\n this.container.remove();\n this.pswp.dispatch('slideDestroy', {\n slide: this\n });\n }\n\n resize() {\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\n // Keep initial zoom level if it was before the resize,\n // as well as when this slide is not active\n // Reset position and scale to original state\n this.calculateSize();\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n } else {\n // readjust pan position if it's beyond the bounds\n this.calculateSize();\n this.bounds.update(this.currZoomLevel);\n this.panTo(this.pan.x, this.pan.y);\n }\n }\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */\n\n\n updateContentSize(force) {\n // Use initial zoom level\n // if resolution is not defined (user didn't zoom yet)\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\n\n if (!scaleMultiplier) {\n return;\n }\n\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\n\n if (!this.sizeChanged(width, height) && !force) {\n return;\n }\n\n this.content.setDisplayedSize(width, height);\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n sizeChanged(width, height) {\n if (width !== this.prevDisplayedWidth || height !== this.prevDisplayedHeight) {\n this.prevDisplayedWidth = width;\n this.prevDisplayedHeight = height;\n return true;\n }\n\n return false;\n }\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */\n\n\n getPlaceholderElement() {\n var _this$content$placeho;\n\n return (_this$content$placeho = this.content.placeholder) === null || _this$content$placeho === void 0 ? void 0 : _this$content$placeho.element;\n }\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */\n\n\n zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\n const {\n pswp\n } = this;\n\n if (!this.isZoomable() || pswp.mainScroll.isShifted()) {\n return;\n }\n\n pswp.dispatch('beforeZoomTo', {\n destZoomLevel,\n centerPoint,\n transitionDuration\n }); // stop all pan and zoom transitions\n\n pswp.animations.stopAllPan(); // if (!centerPoint) {\n // centerPoint = pswp.getViewportCenterPoint();\n // }\n\n const prevZoomLevel = this.currZoomLevel;\n\n if (!ignoreBounds) {\n destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\n } // if (transitionDuration === undefined) {\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\n // }\n\n\n this.setZoomLevel(destZoomLevel);\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\n roundPoint(this.pan);\n\n const finishTransition = () => {\n this._setResolution(destZoomLevel);\n\n this.applyCurrentZoomPan();\n };\n\n if (!transitionDuration) {\n finishTransition();\n } else {\n pswp.animations.startTransition({\n isPan: true,\n name: 'zoomTo',\n target: this.container,\n transform: this.getCurrentTransform(),\n onComplete: finishTransition,\n duration: transitionDuration,\n easing: pswp.options.easing\n });\n }\n }\n /**\r\n * @param {Point} [centerPoint]\r\n */\n\n\n toggleZoom(centerPoint) {\n this.zoomTo(this.currZoomLevel === this.zoomLevels.initial ? this.zoomLevels.secondary : this.zoomLevels.initial, centerPoint, this.pswp.options.zoomAnimationDuration);\n }\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */\n\n\n setZoomLevel(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n this.bounds.update(this.currZoomLevel);\n }\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */\n\n\n calculateZoomToPanOffset(axis, point, prevZoomLevel) {\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\n\n if (totalPanDistance === 0) {\n return this.bounds.center[axis];\n }\n\n if (!point) {\n point = this.pswp.getViewportCenterPoint();\n }\n\n if (!prevZoomLevel) {\n prevZoomLevel = this.zoomLevels.initial;\n }\n\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\n return this.bounds.correctPan(axis, (this.pan[axis] - point[axis]) * zoomFactor + point[axis]);\n }\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */\n\n\n panTo(panX, panY) {\n this.pan.x = this.bounds.correctPan('x', panX);\n this.pan.y = this.bounds.correctPan('y', panY);\n this.applyCurrentZoomPan();\n }\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */\n\n\n isPannable() {\n return Boolean(this.width) && this.currZoomLevel > this.zoomLevels.fit;\n }\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */\n\n\n isZoomable() {\n return Boolean(this.width) && this.content.isZoomable();\n }\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */\n\n\n applyCurrentZoomPan() {\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\n\n if (this === this.pswp.currSlide) {\n this.pswp.dispatch('zoomPanUpdate', {\n slide: this\n });\n }\n }\n\n zoomAndPanToInitial() {\n this.currZoomLevel = this.zoomLevels.initial; // pan according to the zoom level\n\n this.bounds.update(this.currZoomLevel);\n equalizePoints(this.pan, this.bounds.center);\n this.pswp.dispatch('initialZoomPan', {\n slide: this\n });\n }\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */\n\n\n _applyZoomTransform(x, y, zoom) {\n zoom /= this.currentResolution || this.zoomLevels.initial;\n setTransform(this.container, x, y, zoom);\n }\n\n calculateSize() {\n const {\n pswp\n } = this;\n equalizePoints(this.panAreaSize, getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index));\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\n pswp.dispatch('calcSlideSize', {\n slide: this\n });\n }\n /** @returns {string} */\n\n\n getCurrentTransform() {\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\n return toTransformString(this.pan.x, this.pan.y, scale);\n }\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */\n\n\n _setResolution(newResolution) {\n if (newResolution === this.currentResolution) {\n return;\n }\n\n this.currentResolution = newResolution;\n this.updateContentSize();\n this.pswp.dispatch('resolutionChanged');\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst PAN_END_FRICTION = 0.35;\nconst VERTICAL_DRAG_FRICTION = 0.6; // 1 corresponds to the third of viewport height\n\nconst MIN_RATIO_TO_CLOSE = 0.4; // Minimum speed required to navigate\n// to next or previous slide\n\nconst MIN_NEXT_SLIDE_SPEED = 0.5;\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */\n\nfunction project(initialVelocity, decelerationRate) {\n return initialVelocity * decelerationRate / (1 - decelerationRate);\n}\n/**\r\n * Handles single pointer dragging\r\n */\n\n\nclass DragHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n this.pswp = gestures.pswp;\n /** @type {Point} */\n\n this.startPan = {\n x: 0,\n y: 0\n };\n }\n\n start() {\n if (this.pswp.currSlide) {\n equalizePoints(this.startPan, this.pswp.currSlide.pan);\n }\n\n this.pswp.animations.stopAll();\n }\n\n change() {\n const {\n p1,\n prevP1,\n dragAxis\n } = this.gestures;\n const {\n currSlide\n } = this.pswp;\n\n if (dragAxis === 'y' && this.pswp.options.closeOnVerticalDrag && currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit && !this.gestures.isMultitouch) {\n // Handle vertical drag to close\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\n\n if (!this.pswp.dispatch('verticalDrag', {\n panY\n }).defaultPrevented) {\n this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION);\n\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\n this.pswp.applyBgOpacity(bgOpacity);\n currSlide.applyCurrentZoomPan();\n }\n } else {\n const mainScrollChanged = this._panOrMoveMainScroll('x');\n\n if (!mainScrollChanged) {\n this._panOrMoveMainScroll('y');\n\n if (currSlide) {\n roundPoint(currSlide.pan);\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n }\n\n end() {\n const {\n velocity\n } = this.gestures;\n const {\n mainScroll,\n currSlide\n } = this.pswp;\n let indexDiff = 0;\n this.pswp.animations.stopAll(); // Handle main scroll if it's shifted\n\n if (mainScroll.isShifted()) {\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX(); // Ratio between 0 and 1:\n // 0 - slide is not visible at all,\n // 0.5 - half of the slide is visible\n // 1 - slide is fully visible\n\n const currentSlideVisibilityRatio = mainScrollShiftDiff / this.pswp.viewportSize.x; // Go next slide.\n //\n // - if velocity and its direction is matched,\n // and we see at least tiny part of the next slide\n //\n // - or if we see less than 50% of the current slide\n // and velocity is close to 0\n //\n\n if (velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0 || velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5) {\n // Go to next slide\n indexDiff = 1;\n velocity.x = Math.min(velocity.x, 0);\n } else if (velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0 || velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5) {\n // Go to prev slide\n indexDiff = -1;\n velocity.x = Math.max(velocity.x, 0);\n }\n\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\n } // Restore zoom level\n\n\n if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max || this.gestures.isMultitouch) {\n this.gestures.zoomLevels.correctZoomPan(true);\n } else {\n // we run two animations instead of one,\n // as each axis has own pan boundaries and thus different spring function\n // (correctZoomPan does not have this functionality,\n // it animates all properties with single timing function)\n this._finishPanGestureForAxis('x');\n\n this._finishPanGestureForAxis('y');\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */\n\n\n _finishPanGestureForAxis(axis) {\n const {\n velocity\n } = this.gestures;\n const {\n currSlide\n } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const {\n pan,\n bounds\n } = currSlide;\n const panPos = pan[axis];\n const restoreBgOpacity = this.pswp.bgOpacity < 1 && axis === 'y'; // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\n // Increasing this number will reduce travel distance\n\n const decelerationRate = 0.995; // 0.99\n // Pan position if there is no bounds\n\n const projectedPosition = panPos + project(velocity[axis], decelerationRate);\n\n if (restoreBgOpacity) {\n const vDragRatio = this._getVerticalDragRatio(panPos);\n\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition); // If we are above and moving upwards,\n // or if we are below and moving downwards\n\n\n if (vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE || vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE) {\n this.pswp.close();\n return;\n }\n } // Pan position with corrected bounds\n\n\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition); // Exit if pan position should not be changed\n // or if speed it too low\n\n if (panPos === correctedPanPosition) {\n return;\n } // Overshoot if the final position is out of pan bounds\n\n\n const dampingRatio = correctedPanPosition === projectedPosition ? 1 : 0.82;\n const initialBgOpacity = this.pswp.bgOpacity;\n const totalPanDist = correctedPanPosition - panPos;\n this.pswp.animations.startSpring({\n name: 'panGesture' + axis,\n isPan: true,\n start: panPos,\n end: correctedPanPosition,\n velocity: velocity[axis],\n dampingRatio,\n onUpdate: pos => {\n // Animate opacity of background relative to Y pan position of an image\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\n // 0 - start of animation, 1 - end of animation\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist; // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n\n this.pswp.applyBgOpacity(clamp(initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio, 0, 1));\n }\n\n pan[axis] = Math.floor(pos);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */\n\n\n _panOrMoveMainScroll(axis) {\n const {\n p1,\n dragAxis,\n prevP1,\n isMultitouch\n } = this.gestures;\n const {\n currSlide,\n mainScroll\n } = this.pswp;\n const delta = p1[axis] - prevP1[axis];\n const newMainScrollX = mainScroll.x + delta;\n\n if (!delta || !currSlide) {\n return false;\n } // Always move main scroll if image can not be panned\n\n\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\n mainScroll.moveTo(newMainScrollX, true);\n return true; // changed main scroll\n }\n\n const {\n bounds\n } = currSlide;\n const newPan = currSlide.pan[axis] + delta;\n\n if (this.pswp.options.allowPanToNext && dragAxis === 'x' && axis === 'x' && !isMultitouch) {\n const currSlideMainScrollX = mainScroll.getCurrSlideX(); // Position of the main scroll relative to the viewport\n\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\n const isLeftToRight = delta > 0;\n const isRightToLeft = !isLeftToRight;\n\n if (newPan > bounds.min[axis] && isLeftToRight) {\n // Panning from left to right, beyond the left edge\n // Wether the image was at minimum pan position (or less)\n // when this drag gesture started.\n // Minimum pan position refers to the left edge of the image.\n const wasAtMinPanPosition = bounds.min[axis] <= this.startPan[axis];\n\n if (wasAtMinPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n\n }\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\n // Paning from right to left, beyond the right edge\n // Maximum pan position refers to the right edge of the image.\n const wasAtMaxPanPosition = this.startPan[axis] <= bounds.max[axis];\n\n if (wasAtMaxPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan); //currSlide.pan[axis] = newPan;\n\n }\n } else {\n // If main scroll is shifted\n if (mainScrollShiftDiff !== 0) {\n // If main scroll is shifted right\n if (mainScrollShiftDiff > 0\n /*&& isRightToLeft*/\n ) {\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\n return true;\n } else if (mainScrollShiftDiff < 0\n /*&& isLeftToRight*/\n ) {\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\n return true;\n }\n } else {\n // We are within pan bounds, so just pan\n this._setPanWithFriction(axis, newPan);\n }\n }\n } else {\n if (axis === 'y') {\n // Do not pan vertically if main scroll is shifted o\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) {\n this._setPanWithFriction(axis, newPan);\n }\n } else {\n this._setPanWithFriction(axis, newPan);\n }\n }\n\n return false;\n } // If we move above - the ratio is negative\n // If we move below the ratio is positive\n\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */\n\n\n _getVerticalDragRatio(panY) {\n var _this$pswp$currSlide$, _this$pswp$currSlide;\n\n return (panY - ((_this$pswp$currSlide$ = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.bounds.center.y) !== null && _this$pswp$currSlide$ !== void 0 ? _this$pswp$currSlide$ : 0)) / (this.pswp.viewportSize.y / 3);\n }\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */\n\n\n _setPanWithFriction(axis, potentialPan, customFriction) {\n const {\n currSlide\n } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const {\n pan,\n bounds\n } = currSlide;\n const correctedPan = bounds.correctPan(axis, potentialPan); // If we are out of pan bounds\n\n if (correctedPan !== potentialPan || customFriction) {\n const delta = Math.round(potentialPan - pan[axis]);\n pan[axis] += delta * (customFriction || PAN_END_FRICTION);\n } else {\n pan[axis] = potentialPan;\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst UPPER_ZOOM_FRICTION = 0.05;\nconst LOWER_ZOOM_FRICTION = 0.15;\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\n\nfunction getZoomPointsCenter(p, p1, p2) {\n p.x = (p1.x + p2.x) / 2;\n p.y = (p1.y + p2.y) / 2;\n return p;\n}\n\nclass ZoomHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._startPan = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._startZoomPoint = {\n x: 0,\n y: 0\n };\n /**\r\n * @private\r\n * @type {Point}\r\n */\n\n this._zoomPoint = {\n x: 0,\n y: 0\n };\n /** @private */\n\n this._wasOverFitZoomLevel = false;\n /** @private */\n\n this._startZoomLevel = 1;\n }\n\n start() {\n const {\n currSlide\n } = this.gestures.pswp;\n\n if (currSlide) {\n this._startZoomLevel = currSlide.currZoomLevel;\n equalizePoints(this._startPan, currSlide.pan);\n }\n\n this.gestures.pswp.animations.stopAllPan();\n this._wasOverFitZoomLevel = false;\n }\n\n change() {\n const {\n p1,\n startP1,\n p2,\n startP2,\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if (!currSlide) {\n return;\n }\n\n const minZoomLevel = currSlide.zoomLevels.min;\n const maxZoomLevel = currSlide.zoomLevels.max;\n\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) {\n return;\n }\n\n getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\n getZoomPointsCenter(this._zoomPoint, p1, p2);\n\n let currZoomLevel = 1 / getDistanceBetween(startP1, startP2) * getDistanceBetween(p1, p2) * this._startZoomLevel; // slightly over the zoom.fit\n\n\n if (currZoomLevel > currSlide.zoomLevels.initial + currSlide.zoomLevels.initial / 15) {\n this._wasOverFitZoomLevel = true;\n }\n\n if (currZoomLevel < minZoomLevel) {\n if (pswp.options.pinchToClose && !this._wasOverFitZoomLevel && this._startZoomLevel <= currSlide.zoomLevels.initial) {\n // fade out background if zooming out\n const bgOpacity = 1 - (minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2);\n\n if (!pswp.dispatch('pinchClose', {\n bgOpacity\n }).defaultPrevented) {\n pswp.applyBgOpacity(bgOpacity);\n }\n } else {\n // Apply the friction if zoom level is below the min\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION;\n }\n } else if (currZoomLevel > maxZoomLevel) {\n // Apply the friction if zoom level is above the max\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION;\n }\n\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\n currSlide.setZoomLevel(currZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n\n end() {\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial) && !this._wasOverFitZoomLevel && pswp.options.pinchToClose) {\n pswp.close();\n } else {\n this.correctZoomPan();\n }\n }\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */\n\n\n _calculatePanForZoomLevel(axis, currZoomLevel) {\n const zoomFactor = currZoomLevel / this._startZoomLevel;\n return this._zoomPoint[axis] - (this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor;\n }\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */\n\n\n correctZoomPan(ignoreGesture) {\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n\n if (!(currSlide !== null && currSlide !== void 0 && currSlide.isZoomable())) {\n return;\n }\n\n if (this._zoomPoint.x === 0) {\n ignoreGesture = true;\n }\n\n const prevZoomLevel = currSlide.currZoomLevel;\n /** @type {number} */\n\n let destinationZoomLevel;\n let currZoomLevelNeedsChange = true;\n\n if (prevZoomLevel < currSlide.zoomLevels.initial) {\n destinationZoomLevel = currSlide.zoomLevels.initial; // zoom to min\n } else if (prevZoomLevel > currSlide.zoomLevels.max) {\n destinationZoomLevel = currSlide.zoomLevels.max; // zoom to max\n } else {\n currZoomLevelNeedsChange = false;\n destinationZoomLevel = prevZoomLevel;\n }\n\n const initialBgOpacity = pswp.bgOpacity;\n const restoreBgOpacity = pswp.bgOpacity < 1;\n const initialPan = equalizePoints({\n x: 0,\n y: 0\n }, currSlide.pan);\n let destinationPan = equalizePoints({\n x: 0,\n y: 0\n }, initialPan);\n\n if (ignoreGesture) {\n this._zoomPoint.x = 0;\n this._zoomPoint.y = 0;\n this._startZoomPoint.x = 0;\n this._startZoomPoint.y = 0;\n this._startZoomLevel = prevZoomLevel;\n equalizePoints(this._startPan, initialPan);\n }\n\n if (currZoomLevelNeedsChange) {\n destinationPan = {\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\n };\n } // set zoom level, so pan bounds are updated according to it\n\n\n currSlide.setZoomLevel(destinationZoomLevel);\n destinationPan = {\n x: currSlide.bounds.correctPan('x', destinationPan.x),\n y: currSlide.bounds.correctPan('y', destinationPan.y)\n }; // return zoom level and its bounds to initial\n\n currSlide.setZoomLevel(prevZoomLevel);\n const panNeedsChange = !pointsEqual(destinationPan, initialPan);\n\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\n // update resolution after gesture\n currSlide._setResolution(destinationZoomLevel);\n\n currSlide.applyCurrentZoomPan(); // nothing to animate\n\n return;\n }\n\n pswp.animations.stopAllPan();\n pswp.animations.startSpring({\n isPan: true,\n start: 0,\n end: 1000,\n velocity: 0,\n dampingRatio: 1,\n naturalFrequency: 40,\n onUpdate: now => {\n now /= 1000; // 0 - start, 1 - end\n\n if (panNeedsChange || currZoomLevelNeedsChange) {\n if (panNeedsChange) {\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\n }\n\n if (currZoomLevelNeedsChange) {\n const newZoomLevel = prevZoomLevel + (destinationZoomLevel - prevZoomLevel) * now;\n currSlide.setZoomLevel(newZoomLevel);\n }\n\n currSlide.applyCurrentZoomPan();\n } // Restore background opacity\n\n\n if (restoreBgOpacity && pswp.bgOpacity < 1) {\n // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n pswp.applyBgOpacity(clamp(initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1));\n }\n },\n onComplete: () => {\n // update resolution after transition ends\n currSlide._setResolution(destinationZoomLevel);\n\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n\n}\n\n/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */\n\n/**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */\nfunction didTapOnMainContent(event) {\n return !!\n /** @type {HTMLElement} */\n event.target.closest('.pswp__container');\n}\n/**\r\n * Tap, double-tap handler.\r\n */\n\n\nclass TapHandler {\n /**\r\n * @param {Gestures} gestures\r\n */\n constructor(gestures) {\n this.gestures = gestures;\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n click(point, originalEvent) {\n const targetClassList =\n /** @type {HTMLElement} */\n originalEvent.target.classList;\n const isImageClick = targetClassList.contains('pswp__img');\n const isBackgroundClick = targetClassList.contains('pswp__item') || targetClassList.contains('pswp__zoom-wrap');\n\n if (isImageClick) {\n this._doClickOrTapAction('imageClick', point, originalEvent);\n } else if (isBackgroundClick) {\n this._doClickOrTapAction('bgClick', point, originalEvent);\n }\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n tap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('tap', point, originalEvent);\n }\n }\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n doubleTap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('doubleTap', point, originalEvent);\n }\n }\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\n\n\n _doClickOrTapAction(actionName, point, originalEvent) {\n var _this$gestures$pswp$e;\n\n const {\n pswp\n } = this.gestures;\n const {\n currSlide\n } = pswp;\n const actionFullName =\n /** @type {AddPostfix} */\n actionName + 'Action';\n const optionValue = pswp.options[actionFullName];\n\n if (pswp.dispatch(actionFullName, {\n point,\n originalEvent\n }).defaultPrevented) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n optionValue.call(pswp, point, originalEvent);\n return;\n }\n\n switch (optionValue) {\n case 'close':\n case 'next':\n pswp[optionValue]();\n break;\n\n case 'zoom':\n currSlide === null || currSlide === void 0 || currSlide.toggleZoom(point);\n break;\n\n case 'zoom-or-close':\n // by default click zooms current image,\n // if it can not be zoomed - gallery will be closed\n if (currSlide !== null && currSlide !== void 0 && currSlide.isZoomable() && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) {\n currSlide.toggleZoom(point);\n } else if (pswp.options.clickToCloseNonZoomable) {\n pswp.close();\n }\n\n break;\n\n case 'toggle-controls':\n (_this$gestures$pswp$e = this.gestures.pswp.element) === null || _this$gestures$pswp$e === void 0 || _this$gestures$pswp$e.classList.toggle('pswp--ui-visible'); // if (_controlsVisible) {\n // _ui.hideControls();\n // } else {\n // _ui.showControls();\n // }\n\n break;\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n// How far should user should drag\n// until we can determine that the gesture is swipe and its direction\n\nconst AXIS_SWIPE_HYSTERISIS = 10; //const PAN_END_FRICTION = 0.35;\n\nconst DOUBLE_TAP_DELAY = 300; // ms\n\nconst MIN_TAP_DISTANCE = 25; // px\n\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */\n\nclass Gestures {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n /** @type {'x' | 'y' | null} */\n\n this.dragAxis = null; // point objects are defined once and reused\n // PhotoSwipe keeps track only of two pointers, others are ignored\n\n /** @type {Point} */\n\n this.p1 = {\n x: 0,\n y: 0\n }; // the first pressed pointer\n\n /** @type {Point} */\n\n this.p2 = {\n x: 0,\n y: 0\n }; // the second pressed pointer\n\n /** @type {Point} */\n\n this.prevP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.prevP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.startP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.startP2 = {\n x: 0,\n y: 0\n };\n /** @type {Point} */\n\n this.velocity = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */\n\n this._lastStartP1 = {\n x: 0,\n y: 0\n };\n /** @type {Point}\r\n * @private\r\n */\n\n this._intervalP1 = {\n x: 0,\n y: 0\n };\n /** @private */\n\n this._numActivePoints = 0;\n /** @type {Point[]}\r\n * @private\r\n */\n\n this._ongoingPointers = [];\n /** @private */\n\n this._touchEventEnabled = 'ontouchstart' in window;\n /** @private */\n\n this._pointerEventEnabled = !!window.PointerEvent;\n this.supportsTouch = this._touchEventEnabled || this._pointerEventEnabled && navigator.maxTouchPoints > 1;\n /** @private */\n\n this._numActivePoints = 0;\n /** @private */\n\n this._intervalTime = 0;\n /** @private */\n\n this._velocityCalculated = false;\n this.isMultitouch = false;\n this.isDragging = false;\n this.isZooming = false;\n /** @type {number | null} */\n\n this.raf = null;\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */\n\n this._tapTimer = null;\n\n if (!this.supportsTouch) {\n // disable pan to next slide for non-touch devices\n pswp.options.allowPanToNext = false;\n }\n\n this.drag = new DragHandler(this);\n this.zoomLevels = new ZoomHandler(this);\n this.tapHandler = new TapHandler(this);\n pswp.on('bindEvents', () => {\n pswp.events.add(pswp.scrollWrap, 'click',\n /** @type EventListener */\n this._onClick.bind(this));\n\n if (this._pointerEventEnabled) {\n this._bindEvents('pointer', 'down', 'up', 'cancel');\n } else if (this._touchEventEnabled) {\n this._bindEvents('touch', 'start', 'end', 'cancel'); // In previous versions we also bound mouse event here,\n // in case device supports both touch and mouse events,\n // but newer versions of browsers now support PointerEvent.\n // on iOS10 if you bind touchmove/end after touchstart,\n // and you don't preventDefault touchstart (which PhotoSwipe does),\n // preventDefault will have no effect on touchmove and touchend.\n // Unless you bind it previously.\n\n\n if (pswp.scrollWrap) {\n pswp.scrollWrap.ontouchmove = () => {};\n\n pswp.scrollWrap.ontouchend = () => {};\n }\n } else {\n this._bindEvents('mouse', 'down', 'up');\n }\n });\n }\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */\n\n\n _bindEvents(pref, down, up, cancel) {\n const {\n pswp\n } = this;\n const {\n events\n } = pswp;\n const cancelEvent = cancel ? pref + cancel : '';\n events.add(pswp.scrollWrap, pref + down,\n /** @type EventListener */\n this.onPointerDown.bind(this));\n events.add(window, pref + 'move',\n /** @type EventListener */\n this.onPointerMove.bind(this));\n events.add(window, pref + up,\n /** @type EventListener */\n this.onPointerUp.bind(this));\n\n if (cancelEvent) {\n events.add(pswp.scrollWrap, cancelEvent,\n /** @type EventListener */\n this.onPointerUp.bind(this));\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerDown(e) {\n // We do not call preventDefault for touch events\n // to allow browser to show native dialog on longpress\n // (the one that allows to save image or open it in new tab).\n //\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse'; // Allow dragging only via left mouse button.\n // http://www.quirksmode.org/js/events_properties.html\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\n\n if (isMousePointer && e.button > 0) {\n return;\n }\n\n const {\n pswp\n } = this; // if PhotoSwipe is opening or closing\n\n if (!pswp.opener.isOpen) {\n e.preventDefault();\n return;\n }\n\n if (pswp.dispatch('pointerDown', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (isMousePointer) {\n pswp.mouseDetected(); // preventDefault mouse event to prevent\n // browser image drag feature\n\n this._preventPointerEventBehaviour(e, 'down');\n }\n\n pswp.animations.stopAll();\n\n this._updatePoints(e, 'down');\n\n if (this._numActivePoints === 1) {\n this.dragAxis = null; // we need to store initial point to determine the main axis,\n // drag is activated only after the axis is determined\n\n equalizePoints(this.startP1, this.p1);\n }\n\n if (this._numActivePoints > 1) {\n // Tap or double tap should not trigger if more than one pointer\n this._clearTapTimer();\n\n this.isMultitouch = true;\n } else {\n this.isMultitouch = false;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerMove(e) {\n this._preventPointerEventBehaviour(e, 'move');\n\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'move');\n\n if (this.pswp.dispatch('pointerMove', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 1 && !this.isDragging) {\n if (!this.dragAxis) {\n this._calculateDragDirection();\n } // Drag axis was detected, emit drag.start\n\n\n if (this.dragAxis && !this.isDragging) {\n if (this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n }\n\n this.isDragging = true;\n\n this._clearTapTimer(); // Tap can not trigger after drag\n // Adjust starting point\n\n\n this._updateStartPoints();\n\n this._intervalTime = Date.now(); //this._startTime = this._intervalTime;\n\n this._velocityCalculated = false;\n equalizePoints(this._intervalP1, this.p1);\n this.velocity.x = 0;\n this.velocity.y = 0;\n this.drag.start();\n\n this._rafStopLoop();\n\n this._rafRenderLoop();\n }\n } else if (this._numActivePoints > 1 && !this.isZooming) {\n this._finishDrag();\n\n this.isZooming = true; // Adjust starting points\n\n this._updateStartPoints();\n\n this.zoomLevels.start();\n\n this._rafStopLoop();\n\n this._rafRenderLoop();\n }\n }\n /**\r\n * @private\r\n */\n\n\n _finishDrag() {\n if (this.isDragging) {\n this.isDragging = false; // Try to calculate velocity,\n // if it wasn't calculated yet in drag.change\n\n if (!this._velocityCalculated) {\n this._updateVelocity(true);\n }\n\n this.drag.end();\n this.dragAxis = null;\n }\n }\n /**\r\n * @param {PointerEvent} e\r\n */\n\n\n onPointerUp(e) {\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'up');\n\n if (this.pswp.dispatch('pointerUp', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 0) {\n this._rafStopLoop();\n\n if (this.isDragging) {\n this._finishDrag();\n } else if (!this.isZooming && !this.isMultitouch) {\n //this.zoomLevels.correctZoomPan();\n this._finishTap(e);\n }\n }\n\n if (this._numActivePoints < 2 && this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n\n if (this._numActivePoints === 1) {\n // Since we have 1 point left, we need to reinitiate drag\n this.dragAxis = null;\n\n this._updateStartPoints();\n }\n }\n }\n /**\r\n * @private\r\n */\n\n\n _rafRenderLoop() {\n if (this.isDragging || this.isZooming) {\n this._updateVelocity();\n\n if (this.isDragging) {\n // make sure that pointer moved since the last update\n if (!pointsEqual(this.p1, this.prevP1)) {\n this.drag.change();\n }\n } else\n /* if (this.isZooming) */\n {\n if (!pointsEqual(this.p1, this.prevP1) || !pointsEqual(this.p2, this.prevP2)) {\n this.zoomLevels.change();\n }\n }\n\n this._updatePrevPoints();\n\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\n }\n }\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */\n\n\n _updateVelocity(force) {\n const time = Date.now();\n const duration = time - this._intervalTime;\n\n if (duration < 50 && !force) {\n return;\n }\n\n this.velocity.x = this._getVelocity('x', duration);\n this.velocity.y = this._getVelocity('y', duration);\n this._intervalTime = time;\n equalizePoints(this._intervalP1, this.p1);\n this._velocityCalculated = true;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\n\n\n _finishTap(e) {\n const {\n mainScroll\n } = this.pswp; // Do not trigger tap events if main scroll is shifted\n\n if (mainScroll.isShifted()) {\n // restore main scroll position\n // (usually happens if stopped in the middle of animation)\n mainScroll.moveIndexBy(0, true);\n return;\n } // Do not trigger tap for touchcancel or pointercancel\n\n\n if (e.type.indexOf('cancel') > 0) {\n return;\n } // Trigger click instead of tap for mouse events\n\n\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\n this.tapHandler.click(this.startP1, e);\n return;\n } // Disable delay if there is no doubleTapAction\n\n\n const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0; // If tapTimer is defined - we tapped recently,\n // check if the current tap is close to the previous one,\n // if yes - trigger double tap\n\n if (this._tapTimer) {\n this._clearTapTimer(); // Check if two taps were more or less on the same place\n\n\n if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) {\n this.tapHandler.doubleTap(this.startP1, e);\n }\n } else {\n equalizePoints(this._lastStartP1, this.startP1);\n this._tapTimer = setTimeout(() => {\n this.tapHandler.tap(this.startP1, e);\n\n this._clearTapTimer();\n }, tapDelay);\n }\n }\n /**\r\n * @private\r\n */\n\n\n _clearTapTimer() {\n if (this._tapTimer) {\n clearTimeout(this._tapTimer);\n this._tapTimer = null;\n }\n }\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */\n\n\n _getVelocity(axis, duration) {\n // displacement is like distance, but can be negative.\n const displacement = this.p1[axis] - this._intervalP1[axis];\n\n if (Math.abs(displacement) > 1 && duration > 5) {\n return displacement / duration;\n }\n\n return 0;\n }\n /**\r\n * @private\r\n */\n\n\n _rafStopLoop() {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = null;\n }\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\n\n\n _preventPointerEventBehaviour(e, pointerType) {\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\n\n if (preventPointerEvent) {\n e.preventDefault();\n }\n }\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\n\n\n _updatePoints(e, pointerType) {\n if (this._pointerEventEnabled) {\n const pointerEvent =\n /** @type {PointerEvent} */\n e; // Try to find the current pointer in ongoing pointers by its ID\n\n const pointerIndex = this._ongoingPointers.findIndex(ongoingPointer => {\n return ongoingPointer.id === pointerEvent.pointerId;\n });\n\n if (pointerType === 'up' && pointerIndex > -1) {\n // release the pointer - remove it from ongoing\n this._ongoingPointers.splice(pointerIndex, 1);\n } else if (pointerType === 'down' && pointerIndex === -1) {\n // add new pointer\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, {\n x: 0,\n y: 0\n }));\n } else if (pointerIndex > -1) {\n // update existing pointer\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\n }\n\n this._numActivePoints = this._ongoingPointers.length; // update points that PhotoSwipe uses\n // to calculate position and scale\n\n if (this._numActivePoints > 0) {\n equalizePoints(this.p1, this._ongoingPointers[0]);\n }\n\n if (this._numActivePoints > 1) {\n equalizePoints(this.p2, this._ongoingPointers[1]);\n }\n } else {\n const touchEvent =\n /** @type {TouchEvent} */\n e;\n this._numActivePoints = 0;\n\n if (touchEvent.type.indexOf('touch') > -1) {\n // Touch Event\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\n if (touchEvent.touches && touchEvent.touches.length > 0) {\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\n\n this._numActivePoints++;\n\n if (touchEvent.touches.length > 1) {\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\n\n this._numActivePoints++;\n }\n }\n } else {\n // Mouse Event\n this._convertEventPosToPoint(\n /** @type {PointerEvent} */\n e, this.p1);\n\n if (pointerType === 'up') {\n // clear all points on mouseup\n this._numActivePoints = 0;\n } else {\n this._numActivePoints++;\n }\n }\n }\n }\n /** update points that were used during previous rAF tick\r\n * @private\r\n */\n\n\n _updatePrevPoints() {\n equalizePoints(this.prevP1, this.p1);\n equalizePoints(this.prevP2, this.p2);\n }\n /** update points at the start of gesture\r\n * @private\r\n */\n\n\n _updateStartPoints() {\n equalizePoints(this.startP1, this.p1);\n equalizePoints(this.startP2, this.p2);\n\n this._updatePrevPoints();\n }\n /** @private */\n\n\n _calculateDragDirection() {\n if (this.pswp.mainScroll.isShifted()) {\n // if main scroll position is shifted – direction is always horizontal\n this.dragAxis = 'x';\n } else {\n // calculate delta of the last touchmove tick\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\n\n if (diff !== 0) {\n // check if pointer was shifted horizontally or vertically\n const axisToCheck = diff > 0 ? 'x' : 'y';\n\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) {\n this.dragAxis = axisToCheck;\n }\n }\n }\n }\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */\n\n\n _convertEventPosToPoint(e, p) {\n p.x = e.pageX - this.pswp.offset.x;\n p.y = e.pageY - this.pswp.offset.y;\n\n if ('pointerId' in e) {\n p.id = e.pointerId;\n } else if (e.identifier !== undefined) {\n p.id = e.identifier;\n }\n\n return p;\n }\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\n\n\n _onClick(e) {\n // Do not allow click event to pass through after drag\n if (this.pswp.mainScroll.isShifted()) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./slide/slide.js').default} Slide */\n\n/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */\n\nconst MAIN_SCROLL_END_FRICTION = 0.35; // const MIN_SWIPE_TRANSITION_DURATION = 250;\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\n\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */\n\nclass MainScroll {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.x = 0;\n this.slideWidth = 0;\n /** @private */\n\n this._currPositionIndex = 0;\n /** @private */\n\n this._prevPositionIndex = 0;\n /** @private */\n\n this._containerShiftIndex = -1;\n /** @type {ItemHolder[]} */\n\n this.itemHolders = [];\n }\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */\n\n\n resize(resizeSlides) {\n const {\n pswp\n } = this;\n const newSlideWidth = Math.round(pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing); // Mobile browsers might trigger a resize event during a gesture.\n // (due to toolbar appearing or hiding).\n // Avoid re-adjusting main scroll position if width wasn't changed\n\n const slideWidthChanged = newSlideWidth !== this.slideWidth;\n\n if (slideWidthChanged) {\n this.slideWidth = newSlideWidth;\n this.moveTo(this.getCurrSlideX());\n }\n\n this.itemHolders.forEach((itemHolder, index) => {\n if (slideWidthChanged) {\n setTransform(itemHolder.el, (index + this._containerShiftIndex) * this.slideWidth);\n }\n\n if (resizeSlides && itemHolder.slide) {\n itemHolder.slide.resize();\n }\n });\n }\n /**\r\n * Reset X position of the main scroller to zero\r\n */\n\n\n resetPosition() {\n // Position on the main scroller (offset)\n // it is independent from slide index\n this._currPositionIndex = 0;\n this._prevPositionIndex = 0; // This will force recalculation of size on next resize()\n\n this.slideWidth = 0; // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\n\n this._containerShiftIndex = -1;\n }\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */\n\n\n appendHolders() {\n this.itemHolders = []; // append our three slide holders -\n // previous, current, and next\n\n for (let i = 0; i < 3; i++) {\n const el = createElement('pswp__item', 'div', this.pswp.container);\n el.setAttribute('role', 'group');\n el.setAttribute('aria-roledescription', 'slide');\n el.setAttribute('aria-hidden', 'true'); // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\n\n el.style.display = i === 1 ? 'block' : 'none';\n this.itemHolders.push({\n el //index: -1\n\n });\n }\n }\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */\n\n\n canBeSwiped() {\n return this.pswp.getNumItems() > 1;\n }\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */\n\n\n moveIndexBy(diff, animate, velocityX) {\n const {\n pswp\n } = this;\n let newIndex = pswp.potentialIndex + diff;\n const numSlides = pswp.getNumItems();\n\n if (pswp.canLoop()) {\n newIndex = pswp.getLoopedIndex(newIndex);\n const distance = (diff + numSlides) % numSlides;\n\n if (distance <= numSlides / 2) {\n // go forward\n diff = distance;\n } else {\n // go backwards\n diff = distance - numSlides;\n }\n } else {\n if (newIndex < 0) {\n newIndex = 0;\n } else if (newIndex >= numSlides) {\n newIndex = numSlides - 1;\n }\n\n diff = newIndex - pswp.potentialIndex;\n }\n\n pswp.potentialIndex = newIndex;\n this._currPositionIndex -= diff;\n pswp.animations.stopMainScroll();\n const destinationX = this.getCurrSlideX();\n\n if (!animate) {\n this.moveTo(destinationX);\n this.updateCurrItem();\n } else {\n pswp.animations.startSpring({\n isMainScroll: true,\n start: this.x,\n end: destinationX,\n velocity: velocityX || 0,\n naturalFrequency: 30,\n dampingRatio: 1,\n //0.7,\n onUpdate: x => {\n this.moveTo(x);\n },\n onComplete: () => {\n this.updateCurrItem();\n pswp.appendHeavy();\n }\n });\n let currDiff = pswp.potentialIndex - pswp.currIndex;\n\n if (pswp.canLoop()) {\n const currDistance = (currDiff + numSlides) % numSlides;\n\n if (currDistance <= numSlides / 2) {\n // go forward\n currDiff = currDistance;\n } else {\n // go backwards\n currDiff = currDistance - numSlides;\n }\n } // Force-append new slides during transition\n // if difference between slides is more than 1\n\n\n if (Math.abs(currDiff) > 1) {\n this.updateCurrItem();\n }\n }\n\n return Boolean(diff);\n }\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */\n\n\n getCurrSlideX() {\n return this.slideWidth * this._currPositionIndex;\n }\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */\n\n\n isShifted() {\n return this.x !== this.getCurrSlideX();\n }\n /**\r\n * Update slides X positions and set their content\r\n */\n\n\n updateCurrItem() {\n var _this$itemHolders$;\n\n const {\n pswp\n } = this;\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\n\n if (!positionDifference) {\n return;\n }\n\n this._prevPositionIndex = this._currPositionIndex;\n pswp.currIndex = pswp.potentialIndex;\n let diffAbs = Math.abs(positionDifference);\n /** @type {ItemHolder | undefined} */\n\n let tempHolder;\n\n if (diffAbs >= 3) {\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\n diffAbs = 3; // If slides are changed by 3 screens or more - clean up previous slides\n\n this.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide;\n\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.destroy();\n itemHolder.slide = undefined;\n });\n }\n\n for (let i = 0; i < diffAbs; i++) {\n if (positionDifference > 0) {\n tempHolder = this.itemHolders.shift();\n\n if (tempHolder) {\n this.itemHolders[2] = tempHolder; // move first to last\n\n this._containerShiftIndex++;\n setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex - diffAbs + i + 2);\n }\n } else {\n tempHolder = this.itemHolders.pop();\n\n if (tempHolder) {\n this.itemHolders.unshift(tempHolder); // move last to first\n\n this._containerShiftIndex--;\n setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\n pswp.setContent(tempHolder, pswp.currIndex + diffAbs - i - 2);\n }\n }\n } // Reset transfrom every 50ish navigations in one direction.\n //\n // Otherwise transform will keep growing indefinitely,\n // which might cause issues as browsers have a maximum transform limit.\n // I wasn't able to reach it, but just to be safe.\n // This should not cause noticable lag.\n\n\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\n this.resetPosition();\n this.resize();\n } // Pan transition might be running (and consntantly updating pan position)\n\n\n pswp.animations.stopAllPan();\n this.itemHolders.forEach((itemHolder, i) => {\n if (itemHolder.slide) {\n // Slide in the 2nd holder is always active\n itemHolder.slide.setIsActive(i === 1);\n }\n });\n pswp.currSlide = (_this$itemHolders$ = this.itemHolders[1]) === null || _this$itemHolders$ === void 0 ? void 0 : _this$itemHolders$.slide;\n pswp.contentLoader.updateLazy(positionDifference);\n\n if (pswp.currSlide) {\n pswp.currSlide.applyCurrentZoomPan();\n }\n\n pswp.dispatch('change');\n }\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */\n\n\n moveTo(x, dragging) {\n if (!this.pswp.canLoop() && dragging) {\n // Apply friction\n let newSlideIndexOffset = (this.slideWidth * this._currPositionIndex - x) / this.slideWidth;\n newSlideIndexOffset += this.pswp.currIndex;\n const delta = Math.round(x - this.x);\n\n if (newSlideIndexOffset < 0 && delta > 0 || newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0) {\n x = this.x + delta * MAIN_SCROLL_END_FRICTION;\n }\n }\n\n this.x = x;\n\n if (this.pswp.container) {\n setTransform(this.pswp.container, x);\n }\n\n this.pswp.dispatch('moveMainScroll', {\n x,\n dragging: dragging !== null && dragging !== void 0 ? dragging : false\n });\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */\n\nconst KeyboardKeyCodesMap = {\n Escape: 27,\n z: 90,\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n Tab: 9\n};\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */\n\nconst getKeyboardEventKey = (key, isKeySupported) => {\n return isKeySupported ? key : KeyboardKeyCodesMap[key];\n};\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */\n\n\nclass Keyboard {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n /** @private */\n\n this._wasFocused = false;\n pswp.on('bindEvents', () => {\n if (pswp.options.trapFocus) {\n // Dialog was likely opened by keyboard if initial point is not defined\n if (!pswp.options.initialPointerPos) {\n // focus causes layout,\n // which causes lag during the animation,\n // that's why we delay it until the opener transition ends\n this._focusRoot();\n }\n\n pswp.events.add(document, 'focusin',\n /** @type EventListener */\n this._onFocusIn.bind(this));\n }\n\n pswp.events.add(document, 'keydown',\n /** @type EventListener */\n this._onKeyDown.bind(this));\n });\n const lastActiveElement =\n /** @type {HTMLElement} */\n document.activeElement;\n pswp.on('destroy', () => {\n if (pswp.options.returnFocus && lastActiveElement && this._wasFocused) {\n lastActiveElement.focus();\n }\n });\n }\n /** @private */\n\n\n _focusRoot() {\n if (!this._wasFocused && this.pswp.element) {\n this.pswp.element.focus();\n this._wasFocused = true;\n }\n }\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */\n\n\n _onKeyDown(e) {\n const {\n pswp\n } = this;\n\n if (pswp.dispatch('keydown', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (specialKeyUsed(e)) {\n // don't do anything if special key pressed\n // to prevent from overriding default browser actions\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\n return;\n }\n /** @type {Methods | undefined} */\n\n\n let keydownAction;\n /** @type {'x' | 'y' | undefined} */\n\n let axis;\n let isForward = false;\n const isKeySupported = ('key' in e);\n\n switch (isKeySupported ? e.key : e.keyCode) {\n case getKeyboardEventKey('Escape', isKeySupported):\n if (pswp.options.escKey) {\n keydownAction = 'close';\n }\n\n break;\n\n case getKeyboardEventKey('z', isKeySupported):\n keydownAction = 'toggleZoom';\n break;\n\n case getKeyboardEventKey('ArrowLeft', isKeySupported):\n axis = 'x';\n break;\n\n case getKeyboardEventKey('ArrowUp', isKeySupported):\n axis = 'y';\n break;\n\n case getKeyboardEventKey('ArrowRight', isKeySupported):\n axis = 'x';\n isForward = true;\n break;\n\n case getKeyboardEventKey('ArrowDown', isKeySupported):\n isForward = true;\n axis = 'y';\n break;\n\n case getKeyboardEventKey('Tab', isKeySupported):\n this._focusRoot();\n\n break;\n } // if left/right/top/bottom key\n\n\n if (axis) {\n // prevent page scroll\n e.preventDefault();\n const {\n currSlide\n } = pswp;\n\n if (pswp.options.arrowKeys && axis === 'x' && pswp.getNumItems() > 1) {\n keydownAction = isForward ? 'next' : 'prev';\n } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\n // up/down arrow keys pan the image vertically\n // left/right arrow keys pan horizontally.\n // Unless there is only one image,\n // or arrowKeys option is disabled\n currSlide.pan[axis] += isForward ? -80 : 80;\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\n }\n }\n\n if (keydownAction) {\n e.preventDefault(); // @ts-ignore\n\n pswp[keydownAction]();\n }\n }\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */\n\n\n _onFocusIn(e) {\n const {\n template\n } = this.pswp;\n\n if (template && document !== e.target && template !== e.target && !template.contains(\n /** @type {Node} */\n e.target)) {\n // focus root element\n template.focus();\n }\n }\n\n}\n\nconst DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */\n\n/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */\n\n/**\r\n * Runs CSS transition.\r\n */\n\nclass CSSAnimation {\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */\n constructor(props) {\n var _props$prop;\n\n this.props = props;\n const {\n target,\n onComplete,\n transform,\n onFinish = () => {},\n duration = 333,\n easing = DEFAULT_EASING\n } = props;\n this.onFinish = onFinish; // support only transform and opacity\n\n const prop = transform ? 'transform' : 'opacity';\n const propValue = (_props$prop = props[prop]) !== null && _props$prop !== void 0 ? _props$prop : '';\n /** @private */\n\n this._target = target;\n /** @private */\n\n this._onComplete = onComplete;\n /** @private */\n\n this._finished = false;\n /** @private */\n\n this._onTransitionEnd = this._onTransitionEnd.bind(this); // Using timeout hack to make sure that animation\n // starts even if the animated property was changed recently,\n // otherwise transitionend might not fire or transition won't start.\n // https://drafts.csswg.org/css-transitions/#starting\n //\n // ¯\\_(ツ)_/¯\n\n /** @private */\n\n this._helperTimeout = setTimeout(() => {\n setTransitionStyle(target, prop, duration, easing);\n this._helperTimeout = setTimeout(() => {\n target.addEventListener('transitionend', this._onTransitionEnd, false);\n target.addEventListener('transitioncancel', this._onTransitionEnd, false); // Safari occasionally does not emit transitionend event\n // if element property was modified during the transition,\n // which may be caused by resize or third party component,\n // using timeout as a safety fallback\n\n this._helperTimeout = setTimeout(() => {\n this._finalizeAnimation();\n }, duration + 500);\n target.style[prop] = propValue;\n }, 30); // Do not reduce this number\n }, 0);\n }\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */\n\n\n _onTransitionEnd(e) {\n if (e.target === this._target) {\n this._finalizeAnimation();\n }\n }\n /**\r\n * @private\r\n */\n\n\n _finalizeAnimation() {\n if (!this._finished) {\n this._finished = true;\n this.onFinish();\n\n if (this._onComplete) {\n this._onComplete();\n }\n }\n } // Destroy is called automatically onFinish\n\n\n destroy() {\n if (this._helperTimeout) {\n clearTimeout(this._helperTimeout);\n }\n\n removeTransitionStyle(this._target);\n\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\n\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\n\n if (!this._finished) {\n this._finalizeAnimation();\n }\n }\n\n}\n\nconst DEFAULT_NATURAL_FREQUENCY = 12;\nconst DEFAULT_DAMPING_RATIO = 0.75;\n/**\r\n * Spring easing helper\r\n */\n\nclass SpringEaser {\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */\n constructor(initialVelocity, dampingRatio, naturalFrequency) {\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\n // https://en.wikipedia.org/wiki/Damping_ratio\n\n this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO; // https://en.wikipedia.org/wiki/Natural_frequency\n\n this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY;\n this._dampedFrequency = this._naturalFrequency;\n\n if (this._dampingRatio < 1) {\n this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\n }\n }\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */\n\n\n easeFrame(deltaPosition, deltaTime) {\n // Inspired by Apple Webkit and Android spring function implementation\n // https://en.wikipedia.org/wiki/Oscillation\n // https://en.wikipedia.org/wiki/Damping_ratio\n // we ignore mass (assume that it's 1kg)\n let displacement = 0;\n let coeff;\n deltaTime /= 1000;\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\n\n if (this._dampingRatio === 1) {\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\n this.velocity = displacement * -this._naturalFrequency + coeff * naturalDumpingPow;\n } else if (this._dampingRatio < 1) {\n coeff = 1 / this._dampedFrequency * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\n displacement = naturalDumpingPow * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\n this.velocity = displacement * -this._naturalFrequency * this._dampingRatio + naturalDumpingPow * (-this._dampedFrequency * deltaPosition * dumpedFSin + this._dampedFrequency * coeff * dumpedFCos);\n } // Overdamped (>1) damping ratio is not supported\n\n\n return displacement;\n }\n\n}\n\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */\n\n/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */\n\nclass SpringAnimation {\n /**\r\n * @param {SpringAnimationProps} props\r\n */\n constructor(props) {\n this.props = props;\n this._raf = 0;\n const {\n start,\n end,\n velocity,\n onUpdate,\n onComplete,\n onFinish = () => {},\n dampingRatio,\n naturalFrequency\n } = props;\n this.onFinish = onFinish;\n const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency);\n let prevTime = Date.now();\n let deltaPosition = start - end;\n\n const animationLoop = () => {\n if (this._raf) {\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime); // Stop the animation if velocity is low and position is close to end\n\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\n // Finalize the animation\n onUpdate(end);\n\n if (onComplete) {\n onComplete();\n }\n\n this.onFinish();\n } else {\n prevTime = Date.now();\n onUpdate(deltaPosition + end);\n this._raf = requestAnimationFrame(animationLoop);\n }\n }\n };\n\n this._raf = requestAnimationFrame(animationLoop);\n } // Destroy is called automatically onFinish\n\n\n destroy() {\n if (this._raf >= 0) {\n cancelAnimationFrame(this._raf);\n }\n\n this._raf = 0;\n }\n\n}\n\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */\n\n/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */\n\n/** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */\n\n/** @typedef {SpringAnimation | CSSAnimation} Animation */\n\n/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */\n\n/**\r\n * Manages animations\r\n */\n\nclass Animations {\n constructor() {\n /** @type {Animation[]} */\n this.activeAnimations = [];\n }\n /**\r\n * @param {SpringAnimationProps} props\r\n */\n\n\n startSpring(props) {\n this._start(props, true);\n }\n /**\r\n * @param {CssAnimationProps} props\r\n */\n\n\n startTransition(props) {\n this._start(props);\n }\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */\n\n\n _start(props, isSpring) {\n const animation = isSpring ? new SpringAnimation(\n /** @type SpringAnimationProps */\n props) : new CSSAnimation(\n /** @type CssAnimationProps */\n props);\n this.activeAnimations.push(animation);\n\n animation.onFinish = () => this.stop(animation);\n\n return animation;\n }\n /**\r\n * @param {Animation} animation\r\n */\n\n\n stop(animation) {\n animation.destroy();\n const index = this.activeAnimations.indexOf(animation);\n\n if (index > -1) {\n this.activeAnimations.splice(index, 1);\n }\n }\n\n stopAll() {\n // _stopAllAnimations\n this.activeAnimations.forEach(animation => {\n animation.destroy();\n });\n this.activeAnimations = [];\n }\n /**\r\n * Stop all pan or zoom transitions\r\n */\n\n\n stopAllPan() {\n this.activeAnimations = this.activeAnimations.filter(animation => {\n if (animation.props.isPan) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n\n stopMainScroll() {\n this.activeAnimations = this.activeAnimations.filter(animation => {\n if (animation.props.isMainScroll) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n /**\r\n * Returns true if main scroll transition is running\r\n */\n // isMainScrollRunning() {\n // return this.activeAnimations.some((animation) => {\n // return animation.props.isMainScroll;\n // });\n // }\n\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */\n\n\n isPanRunning() {\n return this.activeAnimations.some(animation => {\n return animation.props.isPan;\n });\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */\nclass ScrollWheel {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n pswp.events.add(pswp.element, 'wheel',\n /** @type EventListener */\n this._onWheel.bind(this));\n }\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */\n\n\n _onWheel(e) {\n e.preventDefault();\n const {\n currSlide\n } = this.pswp;\n let {\n deltaX,\n deltaY\n } = e;\n\n if (!currSlide) {\n return;\n }\n\n if (this.pswp.dispatch('wheel', {\n originalEvent: e\n }).defaultPrevented) {\n return;\n }\n\n if (e.ctrlKey || this.pswp.options.wheelToZoom) {\n // zoom\n if (currSlide.isZoomable()) {\n let zoomFactor = -deltaY;\n\n if (e.deltaMode === 1\n /* DOM_DELTA_LINE */\n ) {\n zoomFactor *= 0.05;\n } else {\n zoomFactor *= e.deltaMode ? 1 : 0.002;\n }\n\n zoomFactor = 2 ** zoomFactor;\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\n currSlide.zoomTo(destZoomLevel, {\n x: e.clientX,\n y: e.clientY\n });\n }\n } else {\n // pan\n if (currSlide.isPannable()) {\n if (e.deltaMode === 1\n /* DOM_DELTA_LINE */\n ) {\n // 18 - average line height\n deltaX *= 18;\n deltaY *= 18;\n }\n\n currSlide.panTo(currSlide.pan.x - deltaX, currSlide.pan.y - deltaY);\n }\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */\n\n/**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */\n\n/**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */\n\n/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */\n\n/** @typedef {string | UIElementMarkupProps} UIElementMarkup */\n\n/**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */\n\nfunction addElementHTML(htmlData) {\n if (typeof htmlData === 'string') {\n // Allow developers to provide full svg,\n // For example:\n // \n // \n // \n // \n // Can also be any HTML string.\n return htmlData;\n }\n\n if (!htmlData || !htmlData.isCustomSVG) {\n return '';\n }\n\n const svgData = htmlData;\n let out = ''; // replace all %d with size\n\n out = out.split('%d').join(\n /** @type {string} */\n svgData.size || 32); // Icons may contain outline/shadow,\n // to make it we \"clone\" base icon shape and add border to it.\n // Icon itself and border are styled via CSS.\n //\n // Property shadowID defines ID of element that should be cloned.\n\n if (svgData.outlineID) {\n out += '';\n }\n\n out += svgData.inner;\n out += '';\n return out;\n}\n\nclass UIElement {\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */\n constructor(pswp, data) {\n var _container;\n\n const name = data.name || data.className;\n let elementHTML = data.html; // @ts-expect-error lookup only by `data.name` maybe?\n\n if (pswp.options[name] === false) {\n // exit if element is disabled from options\n return;\n } // Allow to override SVG icons from options\n // @ts-expect-error lookup only by `data.name` maybe?\n\n\n if (typeof pswp.options[name + 'SVG'] === 'string') {\n // arrowPrevSVG\n // arrowNextSVG\n // closeSVG\n // zoomSVG\n // @ts-expect-error lookup only by `data.name` maybe?\n elementHTML = pswp.options[name + 'SVG'];\n }\n\n pswp.dispatch('uiElementCreate', {\n data\n });\n let className = '';\n\n if (data.isButton) {\n className += 'pswp__button ';\n className += data.className || `pswp__button--${data.name}`;\n } else {\n className += data.className || `pswp__${data.name}`;\n }\n\n let tagName = data.isButton ? data.tagName || 'button' : data.tagName || 'div';\n tagName =\n /** @type {keyof HTMLElementTagNameMap} */\n tagName.toLowerCase();\n /** @type {HTMLElement} */\n\n const element = createElement(className, tagName);\n\n if (data.isButton) {\n if (tagName === 'button') {\n /** @type {HTMLButtonElement} */\n element.type = 'button';\n }\n\n let {\n title\n } = data;\n const {\n ariaLabel\n } = data; // @ts-expect-error lookup only by `data.name` maybe?\n\n if (typeof pswp.options[name + 'Title'] === 'string') {\n // @ts-expect-error lookup only by `data.name` maybe?\n title = pswp.options[name + 'Title'];\n }\n\n if (title) {\n element.title = title;\n }\n\n const ariaText = ariaLabel || title;\n\n if (ariaText) {\n element.setAttribute('aria-label', ariaText);\n }\n }\n\n element.innerHTML = addElementHTML(elementHTML);\n\n if (data.onInit) {\n data.onInit(element, pswp);\n }\n\n if (data.onClick) {\n element.onclick = e => {\n if (typeof data.onClick === 'string') {\n // @ts-ignore\n pswp[data.onClick]();\n } else if (typeof data.onClick === 'function') {\n data.onClick(e, element, pswp);\n }\n };\n } // Top bar is default position\n\n\n const appendTo = data.appendTo || 'bar';\n /** @type {HTMLElement | undefined} root element by default */\n\n let container = pswp.element;\n\n if (appendTo === 'bar') {\n if (!pswp.topBar) {\n pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\n }\n\n container = pswp.topBar;\n } else {\n // element outside of top bar gets a secondary class\n // that makes element fade out on close\n element.classList.add('pswp__hide-on-close');\n\n if (appendTo === 'wrapper') {\n container = pswp.scrollWrap;\n }\n }\n\n (_container = container) === null || _container === void 0 || _container.appendChild(pswp.applyFilters('uiElement', element, data));\n }\n\n}\n\n/*\r\n Backward and forward arrow buttons\r\n */\n\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */\nfunction initArrowButton(element, pswp, isNextButton) {\n element.classList.add('pswp__button--arrow'); // TODO: this should point to a unique id for this instance\n\n element.setAttribute('aria-controls', 'pswp__items');\n pswp.on('change', () => {\n if (!pswp.options.loop) {\n if (isNextButton) {\n /** @type {HTMLButtonElement} */\n element.disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\n } else {\n /** @type {HTMLButtonElement} */\n element.disabled = !(pswp.currIndex > 0);\n }\n }\n });\n}\n/** @type {UIElementData} */\n\n\nconst arrowPrev = {\n name: 'arrowPrev',\n className: 'pswp__button--arrow--prev',\n title: 'Previous',\n order: 10,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'prev',\n onInit: initArrowButton\n};\n/** @type {UIElementData} */\n\nconst arrowNext = {\n name: 'arrowNext',\n className: 'pswp__button--arrow--next',\n title: 'Next',\n order: 11,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'next',\n onInit: (el, pswp) => {\n initArrowButton(el, pswp, true);\n }\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst closeButton = {\n name: 'close',\n title: 'Close',\n order: 20,\n isButton: true,\n html: {\n isCustomSVG: true,\n inner: '',\n outlineID: 'pswp__icn-close'\n },\n onClick: 'close'\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst zoomButton = {\n name: 'zoom',\n title: 'Zoom',\n order: 10,\n isButton: true,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '' + '' + '',\n outlineID: 'pswp__icn-zoom'\n },\n onClick: 'toggleZoom'\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst loadingIndicator = {\n name: 'preloader',\n appendTo: 'bar',\n order: 7,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-loading'\n },\n onInit: (indicatorElement, pswp) => {\n /** @type {boolean | undefined} */\n let isVisible;\n /** @type {NodeJS.Timeout | null} */\n\n let delayTimeout = null;\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */\n\n const toggleIndicatorClass = (className, add) => {\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\n };\n /**\r\n * @param {boolean} visible\r\n */\n\n\n const setIndicatorVisibility = visible => {\n if (isVisible !== visible) {\n isVisible = visible;\n toggleIndicatorClass('active', visible);\n }\n };\n\n const updatePreloaderVisibility = () => {\n var _pswp$currSlide;\n\n if (!((_pswp$currSlide = pswp.currSlide) !== null && _pswp$currSlide !== void 0 && _pswp$currSlide.content.isLoading())) {\n setIndicatorVisibility(false);\n\n if (delayTimeout) {\n clearTimeout(delayTimeout);\n delayTimeout = null;\n }\n\n return;\n }\n\n if (!delayTimeout) {\n // display loading indicator with delay\n delayTimeout = setTimeout(() => {\n var _pswp$currSlide2;\n\n setIndicatorVisibility(Boolean((_pswp$currSlide2 = pswp.currSlide) === null || _pswp$currSlide2 === void 0 ? void 0 : _pswp$currSlide2.content.isLoading()));\n delayTimeout = null;\n }, pswp.options.preloaderDelay);\n }\n };\n\n pswp.on('change', updatePreloaderVisibility);\n pswp.on('loadComplete', e => {\n if (pswp.currSlide === e.slide) {\n updatePreloaderVisibility();\n }\n }); // expose the method\n\n if (pswp.ui) {\n pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\n }\n }\n};\n\n/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst counterIndicator = {\n name: 'counter',\n order: 5,\n onInit: (counterElement, pswp) => {\n pswp.on('change', () => {\n counterElement.innerText = pswp.currIndex + 1 + pswp.options.indexIndicatorSep + pswp.getNumItems();\n });\n }\n};\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n\n/**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */\n\nfunction setZoomedIn(el, isZoomedIn) {\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\n}\n\nclass UI {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isRegistered = false;\n /** @type {UIElementData[]} */\n\n this.uiElementsData = [];\n /** @type {(UIElement | UIElementData)[]} */\n\n this.items = [];\n /** @type {() => void} */\n\n this.updatePreloaderVisibility = () => {};\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */\n\n\n this._lastUpdatedZoomLevel = undefined;\n }\n\n init() {\n const {\n pswp\n } = this;\n this.isRegistered = false;\n this.uiElementsData = [closeButton, arrowPrev, arrowNext, zoomButton, loadingIndicator, counterIndicator];\n pswp.dispatch('uiRegister'); // sort by order\n\n this.uiElementsData.sort((a, b) => {\n // default order is 0\n return (a.order || 0) - (b.order || 0);\n });\n this.items = [];\n this.isRegistered = true;\n this.uiElementsData.forEach(uiElementData => {\n this.registerElement(uiElementData);\n });\n pswp.on('change', () => {\n var _pswp$element;\n\n (_pswp$element = pswp.element) === null || _pswp$element === void 0 || _pswp$element.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\n });\n pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate());\n }\n /**\r\n * @param {UIElementData} elementData\r\n */\n\n\n registerElement(elementData) {\n if (this.isRegistered) {\n this.items.push(new UIElement(this.pswp, elementData));\n } else {\n this.uiElementsData.push(elementData);\n }\n }\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */\n\n\n _onZoomPanUpdate() {\n const {\n template,\n currSlide,\n options\n } = this.pswp;\n\n if (this.pswp.opener.isClosing || !template || !currSlide) {\n return;\n }\n\n let {\n currZoomLevel\n } = currSlide; // if not open yet - check against initial zoom level\n\n if (!this.pswp.opener.isOpen) {\n currZoomLevel = currSlide.zoomLevels.initial;\n }\n\n if (currZoomLevel === this._lastUpdatedZoomLevel) {\n return;\n }\n\n this._lastUpdatedZoomLevel = currZoomLevel;\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary; // Initial and secondary zoom levels are almost equal\n\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\n // disable zoom\n setZoomedIn(template, false);\n template.classList.remove('pswp--zoom-allowed');\n return;\n }\n\n template.classList.add('pswp--zoom-allowed');\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\n setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\n\n if (options.imageClickAction === 'zoom' || options.imageClickAction === 'zoom-or-close') {\n template.classList.add('pswp--click-to-zoom');\n }\n }\n\n}\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */\n\n/**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */\nfunction getBoundsByElement(el) {\n const thumbAreaRect = el.getBoundingClientRect();\n return {\n x: thumbAreaRect.left,\n y: thumbAreaRect.top,\n w: thumbAreaRect.width\n };\n}\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */\n\n\nfunction getCroppedBoundsByElement(el, imageWidth, imageHeight) {\n const thumbAreaRect = el.getBoundingClientRect(); // fill image into the area\n // (do they same as object-fit:cover does to retrieve coordinates)\n\n const hRatio = thumbAreaRect.width / imageWidth;\n const vRatio = thumbAreaRect.height / imageHeight;\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */\n\n const bounds = {\n x: thumbAreaRect.left + offsetX,\n y: thumbAreaRect.top + offsetY,\n w: imageWidth * fillZoomLevel\n }; // Coordinates of inner crop area\n // relative to the image\n\n bounds.innerRect = {\n w: thumbAreaRect.width,\n h: thumbAreaRect.height,\n x: offsetX,\n y: offsetY\n };\n return bounds;\n}\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */\n\n\nfunction getThumbBounds(index, itemData, instance) {\n // legacy event, before filters were introduced\n const event = instance.dispatch('thumbBounds', {\n index,\n itemData,\n instance\n }); // @ts-expect-error\n\n if (event.thumbBounds) {\n // @ts-expect-error\n return event.thumbBounds;\n }\n\n const {\n element\n } = itemData;\n /** @type {Bounds | undefined} */\n\n let thumbBounds;\n /** @type {HTMLElement | null | undefined} */\n\n let thumbnail;\n\n if (element && instance.options.thumbSelector !== false) {\n const thumbSelector = instance.options.thumbSelector || 'img';\n thumbnail = element.matches(thumbSelector) ? element :\n /** @type {HTMLElement | null} */\n element.querySelector(thumbSelector);\n }\n\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\n\n if (thumbnail) {\n if (!itemData.thumbCropped) {\n thumbBounds = getBoundsByElement(thumbnail);\n } else {\n thumbBounds = getCroppedBoundsByElement(thumbnail, itemData.width || itemData.w || 0, itemData.height || itemData.h || 0);\n }\n }\n\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\n}\n\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n\n/** @typedef {import('../slide/slide.js').default} Slide */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\n\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\n\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\n\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\nclass PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\n\n\nclass Eventable {\n constructor() {\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\n this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\n\n this._filters = {};\n /** @type {PhotoSwipe | undefined} */\n\n this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */\n\n this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\n\n\n addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn,\n priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2) => f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\n\n\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => filter.fn !== fn);\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\n\n\n applyFilters(name, ...args) {\n var _this$_filters$name3;\n\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach(filter => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n off(name, fn) {\n var _this$pswp3;\n\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => fn !== listener);\n }\n\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\n\n\n dispatch(name, details) {\n var _this$_listeners$name2;\n\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event =\n /** @type {AugmentedEvent} */\n new PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach(listener => {\n listener.call(this, event);\n });\n return event;\n }\n\n}\n\nclass Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n\n if (imageSrc) {\n const imgEl =\n /** @type {HTMLImageElement} */\n this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n var _this$element;\n\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) {\n this.element.remove();\n }\n\n this.element = null;\n }\n\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n\n this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\n\n\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\n\n\n loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n const imageElement =\n /** @type HTMLImageElement */\n this.element;\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\n\n\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */\n\n\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n /**\r\n * Content load error handler\r\n */\n\n\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\n\n\n isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\n\n\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */\n\n\n isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch('contentResize', {\n content: this,\n width,\n height\n }).defaultPrevented) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width,\n height,\n content: this\n });\n }\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\n\n\n isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\n\n\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image =\n /** @type HTMLImageElement */\n this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\n\n\n usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */\n\n\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\n\n\n keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */\n\n\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */\n\n\n displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl =\n /** @type {HTMLDivElement} */\n this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */\n\n\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n\n /** @type {HTMLImageElement} */\n\n this.element.decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\n\n\n activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n /**\r\n * Deactivate the content\r\n */\n\n\n deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n /**\r\n * Remove the content from DOM\r\n */\n\n\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n /**\r\n * Append the image content to slide container\r\n */\n\n\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) {\n return;\n } // ensure that element exists and is not already appended\n\n\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n\n}\n\n/** @typedef {import('./content.js').default} Content */\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\nconst MIN_SLIDES_TO_CACHE = 5;\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\nfunction lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n\n let zoomLevel;\n const {\n options\n } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n let viewportSize;\n\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n }\n\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\n\nfunction lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', {\n index,\n itemData\n }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\nclass ContentLoader {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp; // Total amount of cached images\n\n this.limit = Math.max(pswp.options.preload[0] + pswp.options.preload[1] + 1, MIN_SLIDES_TO_CACHE);\n /** @type {Content[]} */\n\n this._cachedItems = [];\n }\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\n\n\n updateLazy(diff) {\n const {\n pswp\n } = this;\n\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\n return;\n }\n\n const {\n preload\n } = pswp.options;\n const isForward = diff === undefined ? true : diff >= 0;\n let i; // preload[1] - num items to preload in forward direction\n\n for (i = 0; i <= preload[1]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : -i));\n } // preload[0] - num items to preload in backward direction\n\n\n for (i = 1; i <= preload[0]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? -i : i));\n }\n }\n /**\r\n * @param {number} initialIndex\r\n */\n\n\n loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex); // try to get cached content\n\n let content = this.getContentByIndex(index);\n\n if (!content) {\n // no cached content, so try to load from scratch:\n content = lazyLoadSlide(index, this.pswp); // if content can be loaded, add it to cache:\n\n if (content) {\n this.addToCache(content);\n }\n }\n }\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\n\n\n getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n } // assign slide to content\n\n\n content.setSlide(slide);\n return content;\n }\n /**\r\n * @param {Content} content\r\n */\n\n\n addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n\n this._cachedItems.push(content);\n\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex(item => {\n return !item.isAttached && !item.hasSlide;\n });\n\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n\n removedItem.destroy();\n }\n }\n }\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\n\n\n removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\n\n if (indexToRemove !== -1) {\n this._cachedItems.splice(indexToRemove, 1);\n }\n }\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\n\n\n getContentByIndex(index) {\n return this._cachedItems.find(content => content.index === index);\n }\n\n destroy() {\n this._cachedItems.forEach(content => content.destroy());\n\n this._cachedItems = [];\n }\n\n}\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\n\nclass PhotoSwipeBase extends Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\n getNumItems() {\n var _this$options;\n\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n } // legacy event, before filters were introduced\n\n\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\n\n\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\n\n\n getItemData(index) {\n var _this$options2;\n\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */\n\n let dataSourceItem = {};\n\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n } // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n\n\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\n\n\n _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) {\n return getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n }\n\n return [galleryElement];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\n\n\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n const linkEl =\n /** @type {HTMLAnchorElement} */\n element.tagName === 'A' ? element : element.querySelector('a');\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\n\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n\n}\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */\n// some browsers do not paint\n// elements which opacity is set to 0,\n// since we need to pre-render elements for the animation -\n// we set it to the minimum amount\n\nconst MIN_OPACITY = 0.003;\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */\n\nclass Opener {\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isClosed = true;\n this.isOpen = false;\n this.isClosing = false;\n this.isOpening = false;\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */\n\n this._duration = undefined;\n /** @private */\n\n this._useAnimation = false;\n /** @private */\n\n this._croppedZoom = false;\n /** @private */\n\n this._animateRootOpacity = false;\n /** @private */\n\n this._animateBgOpacity = false;\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */\n\n this._placeholder = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\n\n this._opacityElement = undefined;\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\n\n this._cropContainer1 = undefined;\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */\n\n this._cropContainer2 = undefined;\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */\n\n this._thumbBounds = undefined;\n this._prepareOpen = this._prepareOpen.bind(this); // Override initial zoom and pan position\n\n pswp.on('firstZoomPan', this._prepareOpen);\n }\n\n open() {\n this._prepareOpen();\n\n this._start();\n }\n\n close() {\n if (this.isClosed || this.isClosing || this.isOpening) {\n // if we close during opening animation\n // for now do nothing,\n // browsers aren't good at changing the direction of the CSS transition\n return;\n }\n\n const slide = this.pswp.currSlide;\n this.isOpen = false;\n this.isOpening = false;\n this.isClosing = true;\n this._duration = this.pswp.options.hideAnimationDuration;\n\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n\n this._applyStartProps();\n\n setTimeout(() => {\n this._start();\n }, this._croppedZoom ? 30 : 0);\n }\n /** @private */\n\n\n _prepareOpen() {\n this.pswp.off('firstZoomPan', this._prepareOpen);\n\n if (!this.isOpening) {\n const slide = this.pswp.currSlide;\n this.isOpening = true;\n this.isClosing = false;\n this._duration = this.pswp.options.showAnimationDuration;\n\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n\n this._applyStartProps();\n }\n }\n /** @private */\n\n\n _applyStartProps() {\n const {\n pswp\n } = this;\n const slide = this.pswp.currSlide;\n const {\n options\n } = pswp;\n\n if (options.showHideAnimationType === 'fade') {\n options.showHideOpacity = true;\n this._thumbBounds = undefined;\n } else if (options.showHideAnimationType === 'none') {\n options.showHideOpacity = false;\n this._duration = 0;\n this._thumbBounds = undefined;\n } else if (this.isOpening && pswp._initialThumbBounds) {\n // Use initial bounds if defined\n this._thumbBounds = pswp._initialThumbBounds;\n } else {\n this._thumbBounds = this.pswp.getThumbBounds();\n }\n\n this._placeholder = slide === null || slide === void 0 ? void 0 : slide.getPlaceholderElement();\n pswp.animations.stopAll(); // Discard animations when duration is less than 50ms\n\n this._useAnimation = Boolean(this._duration && this._duration > 50);\n this._animateZoom = Boolean(this._thumbBounds) && (slide === null || slide === void 0 ? void 0 : slide.content.usePlaceholder()) && (!this.isClosing || !pswp.mainScroll.isShifted());\n\n if (!this._animateZoom) {\n this._animateRootOpacity = true;\n\n if (this.isOpening && slide) {\n slide.zoomAndPanToInitial();\n slide.applyCurrentZoomPan();\n }\n } else {\n var _options$showHideOpac;\n\n this._animateRootOpacity = (_options$showHideOpac = options.showHideOpacity) !== null && _options$showHideOpac !== void 0 ? _options$showHideOpac : false;\n }\n\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY;\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\n\n if (!this._useAnimation) {\n this._duration = 0;\n this._animateZoom = false;\n this._animateBgOpacity = false;\n this._animateRootOpacity = true;\n\n if (this.isOpening) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n\n pswp.applyBgOpacity(1);\n }\n\n return;\n }\n\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\n var _this$pswp$currSlide;\n\n // Properties are used when animation from cropped thumbnail\n this._croppedZoom = true;\n this._cropContainer1 = this.pswp.container;\n this._cropContainer2 = (_this$pswp$currSlide = this.pswp.currSlide) === null || _this$pswp$currSlide === void 0 ? void 0 : _this$pswp$currSlide.holderElement;\n\n if (pswp.container) {\n pswp.container.style.overflow = 'hidden';\n pswp.container.style.width = pswp.viewportSize.x + 'px';\n }\n } else {\n this._croppedZoom = false;\n }\n\n if (this.isOpening) {\n // Apply styles before opening transition\n if (this._animateRootOpacity) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n\n pswp.applyBgOpacity(1);\n } else {\n if (this._animateBgOpacity && pswp.bg) {\n pswp.bg.style.opacity = String(MIN_OPACITY);\n }\n\n if (pswp.element) {\n pswp.element.style.opacity = '1';\n }\n }\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan();\n\n if (this._placeholder) {\n // tell browser that we plan to animate the placeholder\n this._placeholder.style.willChange = 'transform'; // hide placeholder to allow hiding of\n // elements that overlap it (such as icons over the thumbnail)\n\n this._placeholder.style.opacity = String(MIN_OPACITY);\n }\n }\n } else if (this.isClosing) {\n // hide nearby slides to make sure that\n // they are not painted during the transition\n if (pswp.mainScroll.itemHolders[0]) {\n pswp.mainScroll.itemHolders[0].el.style.display = 'none';\n }\n\n if (pswp.mainScroll.itemHolders[2]) {\n pswp.mainScroll.itemHolders[2].el.style.display = 'none';\n }\n\n if (this._croppedZoom) {\n if (pswp.mainScroll.x !== 0) {\n // shift the main scroller to zero position\n pswp.mainScroll.resetPosition();\n pswp.mainScroll.resize();\n }\n }\n }\n }\n /** @private */\n\n\n _start() {\n if (this.isOpening && this._useAnimation && this._placeholder && this._placeholder.tagName === 'IMG') {\n // To ensure smooth animation\n // we wait till the current slide image placeholder is decoded,\n // but no longer than 250ms,\n // and no shorter than 50ms\n // (just using requestanimationframe is not enough in Firefox,\n // for some reason)\n new Promise(resolve => {\n let decoded = false;\n let isDelaying = true;\n decodeImage(\n /** @type {HTMLImageElement} */\n this._placeholder).finally(() => {\n decoded = true;\n\n if (!isDelaying) {\n resolve(true);\n }\n });\n setTimeout(() => {\n isDelaying = false;\n\n if (decoded) {\n resolve(true);\n }\n }, 50);\n setTimeout(resolve, 250);\n }).finally(() => this._initiate());\n } else {\n this._initiate();\n }\n }\n /** @private */\n\n\n _initiate() {\n var _this$pswp$element, _this$pswp$element2;\n\n (_this$pswp$element = this.pswp.element) === null || _this$pswp$element === void 0 || _this$pswp$element.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\n this.pswp.dispatch(this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'); // legacy event\n\n this.pswp.dispatch(\n /** @type {'initialZoomIn' | 'initialZoomOut'} */\n 'initialZoom' + (this.isOpening ? 'In' : 'Out'));\n (_this$pswp$element2 = this.pswp.element) === null || _this$pswp$element2 === void 0 || _this$pswp$element2.classList.toggle('pswp--ui-visible', this.isOpening);\n\n if (this.isOpening) {\n if (this._placeholder) {\n // unhide the placeholder\n this._placeholder.style.opacity = '1';\n }\n\n this._animateToOpenState();\n } else if (this.isClosing) {\n this._animateToClosedState();\n }\n\n if (!this._useAnimation) {\n this._onAnimationComplete();\n }\n }\n /** @private */\n\n\n _onAnimationComplete() {\n const {\n pswp\n } = this;\n this.isOpen = this.isOpening;\n this.isClosed = this.isClosing;\n this.isOpening = false;\n this.isClosing = false;\n pswp.dispatch(this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'); // legacy event\n\n pswp.dispatch(\n /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */\n 'initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'));\n\n if (this.isClosed) {\n pswp.destroy();\n } else if (this.isOpen) {\n var _pswp$currSlide;\n\n if (this._animateZoom && pswp.container) {\n pswp.container.style.overflow = 'visible';\n pswp.container.style.width = '100%';\n }\n\n (_pswp$currSlide = pswp.currSlide) === null || _pswp$currSlide === void 0 || _pswp$currSlide.applyCurrentZoomPan();\n }\n }\n /** @private */\n\n\n _animateToOpenState() {\n const {\n pswp\n } = this;\n\n if (this._animateZoom) {\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\n\n this._animateTo(this._cropContainer2, 'transform', 'none');\n }\n\n if (pswp.currSlide) {\n pswp.currSlide.zoomAndPanToInitial();\n\n this._animateTo(pswp.currSlide.container, 'transform', pswp.currSlide.getCurrentTransform());\n }\n }\n\n if (this._animateBgOpacity && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '1');\n }\n }\n /** @private */\n\n\n _animateToClosedState() {\n const {\n pswp\n } = this;\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan(true);\n } // do not animate opacity if it's already at 0\n\n\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', '0');\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '0');\n }\n }\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */\n\n\n _setClosedStateZoomPan(animate) {\n if (!this._thumbBounds) return;\n const {\n pswp\n } = this;\n const {\n innerRect\n } = this._thumbBounds;\n const {\n currSlide,\n viewportSize\n } = pswp;\n\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\n const containerTwoPanX = viewportSize.x - innerRect.w;\n const containerTwoPanY = viewportSize.y - innerRect.h;\n\n if (animate) {\n this._animateTo(this._cropContainer1, 'transform', toTransformString(containerOnePanX, containerOnePanY));\n\n this._animateTo(this._cropContainer2, 'transform', toTransformString(containerTwoPanX, containerTwoPanY));\n } else {\n setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\n setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\n }\n }\n\n if (currSlide) {\n equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\n\n if (animate) {\n this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\n } else {\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */\n\n\n _animateTo(target, prop, propValue) {\n if (!this._duration) {\n target.style[prop] = propValue;\n return;\n }\n\n const {\n animations\n } = this.pswp;\n /** @type {AnimationProps} */\n\n const animProps = {\n duration: this._duration,\n easing: this.pswp.options.easing,\n onComplete: () => {\n if (!animations.activeAnimations.length) {\n this._onAnimationComplete();\n }\n },\n target\n };\n animProps[prop] = propValue;\n animations.startTransition(animProps);\n }\n\n}\n\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */\n\n/** @typedef {import('./slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */\n\n/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */\n\n/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n\n/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */\n\n/** @typedef {{ x: number; y: number; id?: string | number }} Point */\n\n/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */\n\n/** @typedef {SlideData[]} DataSourceArray */\n\n/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */\n\n/** @typedef {DataSourceArray | DataSourceObject} DataSource */\n\n/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */\n\n/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */\n\n/** @typedef {Type | { default: Type }} PhotoSwipeModule */\n\n/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */\n\n/**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */\n\n/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */\n\n/**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */\n\n/** @type {PreparedPhotoSwipeOptions} */\n\nconst defaultOptions = {\n allowPanToNext: true,\n spacing: 0.1,\n loop: true,\n pinchToClose: true,\n closeOnVerticalDrag: true,\n hideAnimationDuration: 333,\n showAnimationDuration: 333,\n zoomAnimationDuration: 333,\n escKey: true,\n arrowKeys: true,\n trapFocus: true,\n returnFocus: true,\n maxWidthToAnimate: 4000,\n clickToCloseNonZoomable: true,\n imageClickAction: 'zoom-or-close',\n bgClickAction: 'close',\n tapAction: 'toggle-controls',\n doubleTapAction: 'zoom',\n indexIndicatorSep: ' / ',\n preloaderDelay: 2000,\n bgOpacity: 0.8,\n index: 0,\n errorMsg: 'The image cannot be loaded',\n preload: [1, 2],\n easing: 'cubic-bezier(.4,0,.22,1)'\n};\n/**\r\n * PhotoSwipe Core\r\n */\n\nclass PhotoSwipe extends PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\n constructor(options) {\n super();\n this.options = this._prepareOptions(options || {});\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */\n\n this.offset = {\n x: 0,\n y: 0\n };\n /**\r\n * @type {Point}\r\n * @private\r\n */\n\n this._prevViewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */\n\n this.viewportSize = {\n x: 0,\n y: 0\n };\n /**\r\n * background (backdrop) opacity\r\n */\n\n this.bgOpacity = 1;\n this.currIndex = 0;\n this.potentialIndex = 0;\n this.isOpen = false;\n this.isDestroying = false;\n this.hasMouse = false;\n /**\r\n * @private\r\n * @type {SlideData}\r\n */\n\n this._initialItemData = {};\n /** @type {Bounds | undefined} */\n\n this._initialThumbBounds = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.topBar = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.template = undefined;\n /** @type {HTMLDivElement | undefined} */\n\n this.container = undefined;\n /** @type {HTMLElement | undefined} */\n\n this.scrollWrap = undefined;\n /** @type {Slide | undefined} */\n\n this.currSlide = undefined;\n this.events = new DOMEvents();\n this.animations = new Animations();\n this.mainScroll = new MainScroll(this);\n this.gestures = new Gestures(this);\n this.opener = new Opener(this);\n this.keyboard = new Keyboard(this);\n this.contentLoader = new ContentLoader(this);\n }\n /** @returns {boolean} */\n\n\n init() {\n if (this.isOpen || this.isDestroying) {\n return false;\n }\n\n this.isOpen = true;\n this.dispatch('init'); // legacy\n\n this.dispatch('beforeOpen');\n\n this._createMainStructure(); // add classes to the root element of PhotoSwipe\n\n\n let rootClasses = 'pswp--open';\n\n if (this.gestures.supportsTouch) {\n rootClasses += ' pswp--touch';\n }\n\n if (this.options.mainClass) {\n rootClasses += ' ' + this.options.mainClass;\n }\n\n if (this.element) {\n this.element.className += ' ' + rootClasses;\n }\n\n this.currIndex = this.options.index || 0;\n this.potentialIndex = this.currIndex;\n this.dispatch('firstUpdate'); // starting index can be modified here\n // initialize scroll wheel handler to block the scroll\n\n this.scrollWheel = new ScrollWheel(this); // sanitize index\n\n if (Number.isNaN(this.currIndex) || this.currIndex < 0 || this.currIndex >= this.getNumItems()) {\n this.currIndex = 0;\n }\n\n if (!this.gestures.supportsTouch) {\n // enable mouse features if no touch support detected\n this.mouseDetected();\n } // causes forced synchronous layout\n\n\n this.updateSize();\n this.offset.y = window.pageYOffset;\n this._initialItemData = this.getItemData(this.currIndex);\n this.dispatch('gettingData', {\n index: this.currIndex,\n data: this._initialItemData,\n slide: undefined\n }); // *Layout* - calculate size and position of elements here\n\n this._initialThumbBounds = this.getThumbBounds();\n this.dispatch('initialLayout');\n this.on('openingAnimationEnd', () => {\n const {\n itemHolders\n } = this.mainScroll; // Add content to the previous and next slide\n\n if (itemHolders[0]) {\n itemHolders[0].el.style.display = 'block';\n this.setContent(itemHolders[0], this.currIndex - 1);\n }\n\n if (itemHolders[2]) {\n itemHolders[2].el.style.display = 'block';\n this.setContent(itemHolders[2], this.currIndex + 1);\n }\n\n this.appendHeavy();\n this.contentLoader.updateLazy();\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\n this.dispatch('bindEvents');\n }); // set content for center slide (first time)\n\n if (this.mainScroll.itemHolders[1]) {\n this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\n }\n\n this.dispatch('change');\n this.opener.open();\n this.dispatch('afterInit');\n return true;\n }\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */\n\n\n getLoopedIndex(index) {\n const numSlides = this.getNumItems();\n\n if (this.options.loop) {\n if (index > numSlides - 1) {\n index -= numSlides;\n }\n\n if (index < 0) {\n index += numSlides;\n }\n }\n\n return clamp(index, 0, numSlides - 1);\n }\n\n appendHeavy() {\n this.mainScroll.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide;\n\n (_itemHolder$slide = itemHolder.slide) === null || _itemHolder$slide === void 0 || _itemHolder$slide.appendHeavy();\n });\n }\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */\n\n\n goTo(index) {\n this.mainScroll.moveIndexBy(this.getLoopedIndex(index) - this.potentialIndex);\n }\n /**\r\n * Go to the next slide.\r\n */\n\n\n next() {\n this.goTo(this.potentialIndex + 1);\n }\n /**\r\n * Go to the previous slide.\r\n */\n\n\n prev() {\n this.goTo(this.potentialIndex - 1);\n }\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */\n\n\n zoomTo(...args) {\n var _this$currSlide;\n\n (_this$currSlide = this.currSlide) === null || _this$currSlide === void 0 || _this$currSlide.zoomTo(...args);\n }\n /**\r\n * @see slide/slide.js toggleZoom\r\n */\n\n\n toggleZoom() {\n var _this$currSlide2;\n\n (_this$currSlide2 = this.currSlide) === null || _this$currSlide2 === void 0 || _this$currSlide2.toggleZoom();\n }\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */\n\n\n close() {\n if (!this.opener.isOpen || this.isDestroying) {\n return;\n }\n\n this.isDestroying = true;\n this.dispatch('close');\n this.events.removeAll();\n this.opener.close();\n }\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */\n\n\n destroy() {\n var _this$element;\n\n if (!this.isDestroying) {\n this.options.showHideAnimationType = 'none';\n this.close();\n return;\n }\n\n this.dispatch('destroy');\n this._listeners = {};\n\n if (this.scrollWrap) {\n this.scrollWrap.ontouchmove = null;\n this.scrollWrap.ontouchend = null;\n }\n\n (_this$element = this.element) === null || _this$element === void 0 || _this$element.remove();\n this.mainScroll.itemHolders.forEach(itemHolder => {\n var _itemHolder$slide2;\n\n (_itemHolder$slide2 = itemHolder.slide) === null || _itemHolder$slide2 === void 0 || _itemHolder$slide2.destroy();\n });\n this.contentLoader.destroy();\n this.events.removeAll();\n }\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */\n\n\n refreshSlideContent(slideIndex) {\n this.contentLoader.removeByIndex(slideIndex);\n this.mainScroll.itemHolders.forEach((itemHolder, i) => {\n var _this$currSlide$index, _this$currSlide3;\n\n let potentialHolderIndex = ((_this$currSlide$index = (_this$currSlide3 = this.currSlide) === null || _this$currSlide3 === void 0 ? void 0 : _this$currSlide3.index) !== null && _this$currSlide$index !== void 0 ? _this$currSlide$index : 0) - 1 + i;\n\n if (this.canLoop()) {\n potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\n }\n\n if (potentialHolderIndex === slideIndex) {\n // set the new slide content\n this.setContent(itemHolder, slideIndex, true); // activate the new slide if it's current\n\n if (i === 1) {\n var _itemHolder$slide3;\n\n this.currSlide = itemHolder.slide;\n (_itemHolder$slide3 = itemHolder.slide) === null || _itemHolder$slide3 === void 0 || _itemHolder$slide3.setIsActive(true);\n }\n }\n });\n this.dispatch('change');\n }\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */\n\n\n setContent(holder, index, force) {\n if (this.canLoop()) {\n index = this.getLoopedIndex(index);\n }\n\n if (holder.slide) {\n if (holder.slide.index === index && !force) {\n // exit if holder already contains this slide\n // this could be common when just three slides are used\n return;\n } // destroy previous slide\n\n\n holder.slide.destroy();\n holder.slide = undefined;\n } // exit if no loop and index is out of bounds\n\n\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) {\n return;\n }\n\n const itemData = this.getItemData(index);\n holder.slide = new Slide(itemData, index, this); // set current slide\n\n if (index === this.currIndex) {\n this.currSlide = holder.slide;\n }\n\n holder.slide.append(holder.el);\n }\n /** @returns {Point} */\n\n\n getViewportCenterPoint() {\n return {\n x: this.viewportSize.x / 2,\n y: this.viewportSize.y / 2\n };\n }\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */\n\n\n updateSize(force) {\n // let item;\n // let itemIndex;\n if (this.isDestroying) {\n // exit if PhotoSwipe is closed or closing\n // (to avoid errors, as resize event might be delayed)\n return;\n } //const newWidth = this.scrollWrap.clientWidth;\n //const newHeight = this.scrollWrap.clientHeight;\n\n\n const newViewportSize = getViewportSize(this.options, this);\n\n if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) {\n // Exit if dimensions were not changed\n return;\n } //this._prevViewportSize.x = newWidth;\n //this._prevViewportSize.y = newHeight;\n\n\n equalizePoints(this._prevViewportSize, newViewportSize);\n this.dispatch('beforeResize');\n equalizePoints(this.viewportSize, this._prevViewportSize);\n\n this._updatePageScrollOffset();\n\n this.dispatch('viewportSize'); // Resize slides only after opener animation is finished\n // and don't re-calculate size on inital size update\n\n this.mainScroll.resize(this.opener.isOpen);\n\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) {\n this.mouseDetected();\n }\n\n this.dispatch('resize');\n }\n /**\r\n * @param {number} opacity\r\n */\n\n\n applyBgOpacity(opacity) {\n this.bgOpacity = Math.max(opacity, 0);\n\n if (this.bg) {\n this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\n }\n }\n /**\r\n * Whether mouse is detected\r\n */\n\n\n mouseDetected() {\n if (!this.hasMouse) {\n var _this$element2;\n\n this.hasMouse = true;\n (_this$element2 = this.element) === null || _this$element2 === void 0 || _this$element2.classList.add('pswp--has_mouse');\n }\n }\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */\n\n\n _handlePageResize() {\n this.updateSize(); // In iOS webview, if element size depends on document size,\n // it'll be measured incorrectly in resize event\n //\n // https://bugs.webkit.org/show_bug.cgi?id=170595\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\n\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) {\n setTimeout(() => {\n this.updateSize();\n }, 500);\n }\n }\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */\n\n\n _updatePageScrollOffset() {\n this.setScrollOffset(0, window.pageYOffset);\n }\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */\n\n\n setScrollOffset(x, y) {\n this.offset.x = x;\n this.offset.y = y;\n this.dispatch('updateScrollOffset');\n }\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */\n\n\n _createMainStructure() {\n // root DOM element of PhotoSwipe (.pswp)\n this.element = createElement('pswp', 'div');\n this.element.setAttribute('tabindex', '-1');\n this.element.setAttribute('role', 'dialog'); // template is legacy prop\n\n this.template = this.element; // Background is added as a separate element,\n // as animating opacity is faster than animating rgba()\n\n this.bg = createElement('pswp__bg', 'div', this.element);\n this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element);\n this.container = createElement('pswp__container', 'div', this.scrollWrap); // aria pattern: carousel\n\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\n this.container.setAttribute('aria-live', 'off');\n this.container.setAttribute('id', 'pswp__items');\n this.mainScroll.appendHolders();\n this.ui = new UI(this);\n this.ui.init(); // append to DOM\n\n (this.options.appendToEl || document.body).appendChild(this.element);\n }\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */\n\n\n getThumbBounds() {\n return getThumbBounds(this.currIndex, this.currSlide ? this.currSlide.data : this._initialItemData, this);\n }\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */\n\n\n canLoop() {\n return this.options.loop && this.getNumItems() > 2;\n }\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */\n\n\n _prepareOptions(options) {\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\n options.showHideAnimationType = 'none';\n options.zoomAnimationDuration = 0;\n }\n /** @type {PreparedPhotoSwipeOptions} */\n\n\n return { ...defaultOptions,\n ...options\n };\n }\n\n}\n\nexport { PhotoSwipe as default };\n//# sourceMappingURL=photoswipe.esm.js.map\n","/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\r\nexport function createElement(className, tagName, appendToEl) {\r\n const el = document.createElement(tagName);\r\n if (className) {\r\n el.className = className;\r\n }\r\n if (appendToEl) {\r\n appendToEl.appendChild(el);\r\n }\r\n return el;\r\n}\r\n\r\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nexport function equalizePoints(p1, p2) {\r\n p1.x = p2.x;\r\n p1.y = p2.y;\r\n if (p2.id !== undefined) {\r\n p1.id = p2.id;\r\n }\r\n return p1;\r\n}\r\n\r\n/**\r\n * @param {Point} p\r\n */\r\nexport function roundPoint(p) {\r\n p.x = Math.round(p.x);\r\n p.y = Math.round(p.y);\r\n}\r\n\r\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\r\nexport function getDistanceBetween(p1, p2) {\r\n const x = Math.abs(p1.x - p2.x);\r\n const y = Math.abs(p1.y - p2.y);\r\n return Math.sqrt((x * x) + (y * y));\r\n}\r\n\r\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\r\nexport function pointsEqual(p1, p2) {\r\n return p1.x === p2.x && p1.y === p2.y;\r\n}\r\n\r\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\r\nexport function clamp(val, min, max) {\r\n return Math.min(Math.max(val, min), max);\r\n}\r\n\r\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\r\nexport function toTransformString(x, y, scale) {\r\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\r\n\r\n if (scale !== undefined) {\r\n propValue += ` scale3d(${scale},${scale},1)`;\r\n }\r\n\r\n return propValue;\r\n}\r\n\r\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\r\nexport function setTransform(el, x, y, scale) {\r\n el.style.transform = toTransformString(x, y, scale);\r\n}\r\n\r\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\r\nexport function setTransitionStyle(el, prop, duration, ease) {\r\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\r\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\r\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\r\n el.style.transition = prop\r\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\r\n : 'none';\r\n}\r\n\r\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\r\nexport function setWidthHeight(el, w, h) {\r\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\r\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n */\r\nexport function removeTransitionStyle(el) {\r\n setTransitionStyle(el);\r\n}\r\n\r\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\r\nexport function decodeImage(img) {\r\n if ('decode' in img) {\r\n return img.decode().catch(() => {});\r\n }\r\n\r\n if (img.complete) {\r\n return Promise.resolve(img);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n img.onload = () => resolve(img);\r\n img.onerror = reject;\r\n });\r\n}\r\n\r\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\r\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\r\nexport const LOAD_STATE = {\r\n IDLE: 'idle',\r\n LOADING: 'loading',\r\n LOADED: 'loaded',\r\n ERROR: 'error',\r\n};\r\n\r\n\r\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\r\nexport function specialKeyUsed(e) {\r\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\r\n}\r\n\r\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\r\nexport function getElementsFromOption(option, legacySelector, parent = document) {\r\n /** @type {HTMLElement[]} */\r\n let elements = [];\r\n\r\n if (option instanceof Element) {\r\n elements = [option];\r\n } else if (option instanceof NodeList || Array.isArray(option)) {\r\n elements = Array.from(option);\r\n } else {\r\n const selector = typeof option === 'string' ? option : legacySelector;\r\n if (selector) {\r\n elements = Array.from(parent.querySelectorAll(selector));\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\r\nexport function isPswpClass(fn) {\r\n return typeof fn === 'function'\r\n && fn.prototype\r\n && fn.prototype.goTo;\r\n}\r\n\r\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\r\nexport function isSafari() {\r\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\r\n}\r\n\r\n","// Detect passive event listener support\r\nlet supportsPassive = false;\r\n/* eslint-disable */\r\ntry {\r\n /* @ts-ignore */\r\n window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\r\n get: () => {\r\n supportsPassive = true;\r\n }\r\n }));\r\n} catch (e) {}\r\n/* eslint-enable */\r\n\r\n/**\r\n * @typedef {Object} PoolItem\r\n * @prop {HTMLElement | Window | Document | undefined | null} target\r\n * @prop {string} type\r\n * @prop {EventListenerOrEventListenerObject} listener\r\n * @prop {boolean} [passive]\r\n */\r\n\r\nclass DOMEvents {\r\n constructor() {\r\n /**\r\n * @type {PoolItem[]}\r\n * @private\r\n */\r\n this._pool = [];\r\n }\r\n\r\n /**\r\n * Adds event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type Can be multiple, separated by space.\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\r\n add(target, type, listener, passive) {\r\n this._toggleListener(target, type, listener, passive);\r\n }\r\n\r\n /**\r\n * Removes event listeners\r\n *\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n */\r\n remove(target, type, listener, passive) {\r\n this._toggleListener(target, type, listener, passive, true);\r\n }\r\n\r\n /**\r\n * Removes all bound events\r\n */\r\n removeAll() {\r\n this._pool.forEach((poolItem) => {\r\n this._toggleListener(\r\n poolItem.target,\r\n poolItem.type,\r\n poolItem.listener,\r\n poolItem.passive,\r\n true,\r\n true\r\n );\r\n });\r\n this._pool = [];\r\n }\r\n\r\n /**\r\n * Adds or removes event\r\n *\r\n * @private\r\n * @param {PoolItem['target']} target\r\n * @param {PoolItem['type']} type\r\n * @param {PoolItem['listener']} listener\r\n * @param {PoolItem['passive']} [passive]\r\n * @param {boolean} [unbind] Whether the event should be added or removed\r\n * @param {boolean} [skipPool] Whether events pool should be skipped\r\n */\r\n _toggleListener(target, type, listener, passive, unbind, skipPool) {\r\n if (!target) {\r\n return;\r\n }\r\n\r\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\r\n const types = type.split(' ');\r\n types.forEach((eType) => {\r\n if (eType) {\r\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\r\n // so developer doesn't need to do this manually\r\n if (!skipPool) {\r\n if (unbind) {\r\n // Remove from the events pool\r\n this._pool = this._pool.filter((poolItem) => {\r\n return poolItem.type !== eType\r\n || poolItem.listener !== listener\r\n || poolItem.target !== target;\r\n });\r\n } else {\r\n // Add to the events pool\r\n this._pool.push({\r\n target,\r\n type: eType,\r\n listener,\r\n passive\r\n });\r\n }\r\n }\r\n\r\n // most PhotoSwipe events call preventDefault,\r\n // and we do not need browser to scroll the page\r\n const eventOptions = supportsPassive ? { passive: (passive || false) } : false;\r\n\r\n target[methodName](\r\n eType,\r\n listener,\r\n eventOptions\r\n );\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport default DOMEvents;\r\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\r\nexport function getViewportSize(options, pswp) {\r\n if (options.getViewportSizeFn) {\r\n const newViewportSize = options.getViewportSizeFn(options, pswp);\r\n if (newViewportSize) {\r\n return newViewportSize;\r\n }\r\n }\r\n\r\n return {\r\n x: document.documentElement.clientWidth,\r\n\r\n // TODO: height on mobile is very incosistent due to toolbar\r\n // find a way to improve this\r\n //\r\n // document.documentElement.clientHeight - doesn't seem to work well\r\n y: window.innerHeight\r\n };\r\n}\r\n\r\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\r\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\r\n let paddingValue = 0;\r\n\r\n if (options.paddingFn) {\r\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\r\n } else if (options.padding) {\r\n paddingValue = options.padding[prop];\r\n } else {\r\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\r\n // @ts-expect-error\r\n if (options[legacyPropName]) {\r\n // @ts-expect-error\r\n paddingValue = options[legacyPropName];\r\n }\r\n }\r\n\r\n return Number(paddingValue) || 0;\r\n}\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\r\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\r\n return {\r\n x: viewportSize.x\r\n - parsePaddingOption('left', options, viewportSize, itemData, index)\r\n - parsePaddingOption('right', options, viewportSize, itemData, index),\r\n y: viewportSize.y\r\n - parsePaddingOption('top', options, viewportSize, itemData, index)\r\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\r\n };\r\n}\r\n","import { clamp } from '../util/util.js';\r\nimport { parsePaddingOption } from '../util/viewport-size.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {Record} Point */\r\n/** @typedef {'x' | 'y'} Axis */\r\n\r\n/**\r\n * Calculates minimum, maximum and initial (center) bounds of a slide\r\n */\r\nclass PanBounds {\r\n /**\r\n * @param {Slide} slide\r\n */\r\n constructor(slide) {\r\n this.slide = slide;\r\n this.currZoomLevel = 1;\r\n this.center = /** @type {Point} */ { x: 0, y: 0 };\r\n this.max = /** @type {Point} */ { x: 0, y: 0 };\r\n this.min = /** @type {Point} */ { x: 0, y: 0 };\r\n }\r\n\r\n /**\r\n * _getItemBounds\r\n *\r\n * @param {number} currZoomLevel\r\n */\r\n update(currZoomLevel) {\r\n this.currZoomLevel = currZoomLevel;\r\n\r\n if (!this.slide.width) {\r\n this.reset();\r\n } else {\r\n this._updateAxis('x');\r\n this._updateAxis('y');\r\n this.slide.pswp.dispatch('calcBounds', { slide: this.slide });\r\n }\r\n }\r\n\r\n /**\r\n * _calculateItemBoundsForAxis\r\n *\r\n * @param {Axis} axis\r\n */\r\n _updateAxis(axis) {\r\n const { pswp } = this.slide;\r\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\r\n const paddingProp = axis === 'x' ? 'left' : 'top';\r\n const padding = parsePaddingOption(\r\n paddingProp,\r\n pswp.options,\r\n pswp.viewportSize,\r\n this.slide.data,\r\n this.slide.index\r\n );\r\n\r\n const panAreaSize = this.slide.panAreaSize[axis];\r\n\r\n // Default position of element.\r\n // By default, it is center of viewport:\r\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding;\r\n\r\n // maximum pan position\r\n this.max[axis] = (elSize > panAreaSize)\r\n ? Math.round(panAreaSize - elSize) + padding\r\n : this.center[axis];\r\n\r\n // minimum pan position\r\n this.min[axis] = (elSize > panAreaSize)\r\n ? padding\r\n : this.center[axis];\r\n }\r\n\r\n // _getZeroBounds\r\n reset() {\r\n this.center.x = 0;\r\n this.center.y = 0;\r\n this.max.x = 0;\r\n this.max.y = 0;\r\n this.min.x = 0;\r\n this.min.y = 0;\r\n }\r\n\r\n /**\r\n * Correct pan position if it's beyond the bounds\r\n *\r\n * @param {Axis} axis x or y\r\n * @param {number} panOffset\r\n * @returns {number}\r\n */\r\n correctPan(axis, panOffset) { // checkPanBounds\r\n return clamp(panOffset, this.max[axis], this.min[axis]);\r\n }\r\n}\r\n\r\nexport default PanBounds;\r\n","const MAX_IMAGE_WIDTH = 4000;\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\r\n\r\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\r\nclass ZoomLevel {\r\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\r\n constructor(options, itemData, index, pswp) {\r\n this.pswp = pswp;\r\n this.options = options;\r\n this.itemData = itemData;\r\n this.index = index;\r\n /** @type { Point | null } */\r\n this.panAreaSize = null;\r\n /** @type { Point | null } */\r\n this.elementSize = null;\r\n this.fit = 1;\r\n this.fill = 1;\r\n this.vFill = 1;\r\n this.initial = 1;\r\n this.secondary = 1;\r\n this.max = 1;\r\n this.min = 1;\r\n }\r\n\r\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\r\n update(maxWidth, maxHeight, panAreaSize) {\r\n /** @type {Point} */\r\n const elementSize = { x: maxWidth, y: maxHeight };\r\n this.elementSize = elementSize;\r\n this.panAreaSize = panAreaSize;\r\n\r\n const hRatio = panAreaSize.x / elementSize.x;\r\n const vRatio = panAreaSize.y / elementSize.y;\r\n\r\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\r\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\r\n\r\n // zoom.vFill defines zoom level of the image\r\n // when it has 100% of viewport vertical space (height)\r\n this.vFill = Math.min(1, vRatio);\r\n\r\n this.initial = this._getInitial();\r\n this.secondary = this._getSecondary();\r\n this.max = Math.max(\r\n this.initial,\r\n this.secondary,\r\n this._getMax()\r\n );\r\n\r\n this.min = Math.min(\r\n this.fit,\r\n this.initial,\r\n this.secondary\r\n );\r\n\r\n if (this.pswp) {\r\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\r\n }\r\n }\r\n\r\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\r\n _parseZoomLevelOption(optionPrefix) {\r\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\r\n optionPrefix + 'ZoomLevel'\r\n );\r\n const optionValue = this.options[optionName];\r\n\r\n if (!optionValue) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n return optionValue(this);\r\n }\r\n\r\n if (optionValue === 'fill') {\r\n return this.fill;\r\n }\r\n\r\n if (optionValue === 'fit') {\r\n return this.fit;\r\n }\r\n\r\n return Number(optionValue);\r\n }\r\n\r\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getSecondary() {\r\n let currZoomLevel = this._parseZoomLevelOption('secondary');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // 3x of \"fit\" state, but not larger than original\r\n currZoomLevel = Math.min(1, this.fit * 3);\r\n\r\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\r\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\r\n }\r\n\r\n return currZoomLevel;\r\n }\r\n\r\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getInitial() {\r\n return this._parseZoomLevelOption('initial') || this.fit;\r\n }\r\n\r\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getMax() {\r\n // max zoom level is x4 from \"fit state\",\r\n // used for zoom gesture and ctrl/trackpad zoom\r\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\r\n }\r\n}\r\n\r\nexport default ZoomLevel;\r\n","/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @typedef {_SlideData & Record} SlideData\r\n * @typedef {Object} _SlideData\r\n * @prop {HTMLElement} [element] thumbnail element\r\n * @prop {string} [src] image URL\r\n * @prop {string} [srcset] image srcset\r\n * @prop {number} [w] image width (deprecated)\r\n * @prop {number} [h] image height (deprecated)\r\n * @prop {number} [width] image width\r\n * @prop {number} [height] image height\r\n * @prop {string} [msrc] placeholder image URL that's displayed before large image is loaded\r\n * @prop {string} [alt] image alt text\r\n * @prop {boolean} [thumbCropped] whether thumbnail is cropped client-side or not\r\n * @prop {string} [html] html content of a slide\r\n * @prop {'image' | 'html' | string} [type] slide type\r\n */\r\n\r\nimport {\r\n createElement,\r\n setTransform,\r\n equalizePoints,\r\n roundPoint,\r\n toTransformString,\r\n clamp,\r\n} from '../util/util.js';\r\n\r\nimport PanBounds from './pan-bounds.js';\r\nimport ZoomLevel from './zoom-level.js';\r\nimport { getPanAreaSize } from '../util/viewport-size.js';\r\n\r\n/**\r\n * Renders and allows to control a single slide\r\n */\r\nclass Slide {\r\n /**\r\n * @param {SlideData} data\r\n * @param {number} index\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(data, index, pswp) {\r\n this.data = data;\r\n this.index = index;\r\n this.pswp = pswp;\r\n this.isActive = (index === pswp.currIndex);\r\n this.currentResolution = 0;\r\n /** @type {Point} */\r\n this.panAreaSize = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.pan = { x: 0, y: 0 };\r\n\r\n this.isFirstSlide = (this.isActive && !pswp.opener.isOpen);\r\n\r\n this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp);\r\n\r\n this.pswp.dispatch('gettingData', {\r\n slide: this,\r\n data: this.data,\r\n index\r\n });\r\n\r\n this.content = this.pswp.contentLoader.getContentBySlide(this);\r\n this.container = createElement('pswp__zoom-wrap', 'div');\r\n /** @type {HTMLElement | null} */\r\n this.holderElement = null;\r\n\r\n this.currZoomLevel = 1;\r\n /** @type {number} */\r\n this.width = this.content.width;\r\n /** @type {number} */\r\n this.height = this.content.height;\r\n this.heavyAppended = false;\r\n this.bounds = new PanBounds(this);\r\n\r\n this.prevDisplayedWidth = -1;\r\n this.prevDisplayedHeight = -1;\r\n\r\n this.pswp.dispatch('slideInit', { slide: this });\r\n }\r\n\r\n /**\r\n * If this slide is active/current/visible\r\n *\r\n * @param {boolean} isActive\r\n */\r\n setIsActive(isActive) {\r\n if (isActive && !this.isActive) {\r\n // slide just became active\r\n this.activate();\r\n } else if (!isActive && this.isActive) {\r\n // slide just became non-active\r\n this.deactivate();\r\n }\r\n }\r\n\r\n /**\r\n * Appends slide content to DOM\r\n *\r\n * @param {HTMLElement} holderElement\r\n */\r\n append(holderElement) {\r\n this.holderElement = holderElement;\r\n\r\n this.container.style.transformOrigin = '0 0';\r\n\r\n // Slide appended to DOM\r\n if (!this.data) {\r\n return;\r\n }\r\n\r\n this.calculateSize();\r\n\r\n this.load();\r\n this.updateContentSize();\r\n this.appendHeavy();\r\n\r\n this.holderElement.appendChild(this.container);\r\n\r\n this.zoomAndPanToInitial();\r\n\r\n this.pswp.dispatch('firstZoomPan', { slide: this });\r\n\r\n this.applyCurrentZoomPan();\r\n\r\n this.pswp.dispatch('afterSetContent', { slide: this });\r\n\r\n if (this.isActive) {\r\n this.activate();\r\n }\r\n }\r\n\r\n load() {\r\n this.content.load(false);\r\n this.pswp.dispatch('slideLoad', { slide: this });\r\n }\r\n\r\n /**\r\n * Append \"heavy\" DOM elements\r\n *\r\n * This may depend on a type of slide,\r\n * but generally these are large images.\r\n */\r\n appendHeavy() {\r\n const { pswp } = this;\r\n const appendHeavyNearby = true; // todo\r\n\r\n // Avoid appending heavy elements during animations\r\n if (this.heavyAppended\r\n || !pswp.opener.isOpen\r\n || pswp.mainScroll.isShifted()\r\n || (!this.isActive && !appendHeavyNearby)) {\r\n return;\r\n }\r\n\r\n if (this.pswp.dispatch('appendHeavy', { slide: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.heavyAppended = true;\r\n\r\n this.content.append();\r\n\r\n this.pswp.dispatch('appendHeavyContent', { slide: this });\r\n }\r\n\r\n /**\r\n * Triggered when this slide is active (selected).\r\n *\r\n * If it's part of opening/closing transition -\r\n * activate() will trigger after the transition is ended.\r\n */\r\n activate() {\r\n this.isActive = true;\r\n this.appendHeavy();\r\n this.content.activate();\r\n this.pswp.dispatch('slideActivate', { slide: this });\r\n }\r\n\r\n /**\r\n * Triggered when this slide becomes inactive.\r\n *\r\n * Slide can become inactive only after it was active.\r\n */\r\n deactivate() {\r\n this.isActive = false;\r\n this.content.deactivate();\r\n\r\n if (this.currZoomLevel !== this.zoomLevels.initial) {\r\n // allow filtering\r\n this.calculateSize();\r\n }\r\n\r\n // reset zoom level\r\n this.currentResolution = 0;\r\n this.zoomAndPanToInitial();\r\n this.applyCurrentZoomPan();\r\n this.updateContentSize();\r\n\r\n this.pswp.dispatch('slideDeactivate', { slide: this });\r\n }\r\n\r\n /**\r\n * The slide should destroy itself, it will never be used again.\r\n * (unbind all events and destroy internal components)\r\n */\r\n destroy() {\r\n this.content.hasSlide = false;\r\n this.content.remove();\r\n this.container.remove();\r\n this.pswp.dispatch('slideDestroy', { slide: this });\r\n }\r\n\r\n resize() {\r\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\r\n // Keep initial zoom level if it was before the resize,\r\n // as well as when this slide is not active\r\n\r\n // Reset position and scale to original state\r\n this.calculateSize();\r\n this.currentResolution = 0;\r\n this.zoomAndPanToInitial();\r\n this.applyCurrentZoomPan();\r\n this.updateContentSize();\r\n } else {\r\n // readjust pan position if it's beyond the bounds\r\n this.calculateSize();\r\n this.bounds.update(this.currZoomLevel);\r\n this.panTo(this.pan.x, this.pan.y);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Apply size to current slide content,\r\n * based on the current resolution and scale.\r\n *\r\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\r\n */\r\n updateContentSize(force) {\r\n // Use initial zoom level\r\n // if resolution is not defined (user didn't zoom yet)\r\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\r\n\r\n if (!scaleMultiplier) {\r\n return;\r\n }\r\n\r\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\r\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\r\n\r\n if (!this.sizeChanged(width, height) && !force) {\r\n return;\r\n }\r\n this.content.setDisplayedSize(width, height);\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n sizeChanged(width, height) {\r\n if (width !== this.prevDisplayedWidth\r\n || height !== this.prevDisplayedHeight) {\r\n this.prevDisplayedWidth = width;\r\n this.prevDisplayedHeight = height;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */\r\n getPlaceholderElement() {\r\n return this.content.placeholder?.element;\r\n }\r\n\r\n /**\r\n * Zoom current slide image to...\r\n *\r\n * @param {number} destZoomLevel Destination zoom level.\r\n * @param {Point} [centerPoint]\r\n * Transform origin center point, or false if viewport center should be used.\r\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\r\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\r\n */\r\n zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\r\n const { pswp } = this;\r\n if (!this.isZoomable()\r\n || pswp.mainScroll.isShifted()) {\r\n return;\r\n }\r\n\r\n pswp.dispatch('beforeZoomTo', {\r\n destZoomLevel, centerPoint, transitionDuration\r\n });\r\n\r\n // stop all pan and zoom transitions\r\n pswp.animations.stopAllPan();\r\n\r\n // if (!centerPoint) {\r\n // centerPoint = pswp.getViewportCenterPoint();\r\n // }\r\n\r\n const prevZoomLevel = this.currZoomLevel;\r\n\r\n if (!ignoreBounds) {\r\n destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\r\n }\r\n\r\n // if (transitionDuration === undefined) {\r\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\r\n // }\r\n\r\n this.setZoomLevel(destZoomLevel);\r\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\r\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\r\n roundPoint(this.pan);\r\n\r\n const finishTransition = () => {\r\n this._setResolution(destZoomLevel);\r\n this.applyCurrentZoomPan();\r\n };\r\n\r\n if (!transitionDuration) {\r\n finishTransition();\r\n } else {\r\n pswp.animations.startTransition({\r\n isPan: true,\r\n name: 'zoomTo',\r\n target: this.container,\r\n transform: this.getCurrentTransform(),\r\n onComplete: finishTransition,\r\n duration: transitionDuration,\r\n easing: pswp.options.easing\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} [centerPoint]\r\n */\r\n toggleZoom(centerPoint) {\r\n this.zoomTo(\r\n this.currZoomLevel === this.zoomLevels.initial\r\n ? this.zoomLevels.secondary : this.zoomLevels.initial,\r\n centerPoint,\r\n this.pswp.options.zoomAnimationDuration\r\n );\r\n }\r\n\r\n /**\r\n * Updates zoom level property and recalculates new pan bounds,\r\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\r\n *\r\n * @param {number} currZoomLevel\r\n */\r\n setZoomLevel(currZoomLevel) {\r\n this.currZoomLevel = currZoomLevel;\r\n this.bounds.update(this.currZoomLevel);\r\n }\r\n\r\n /**\r\n * Get pan position after zoom at a given `point`.\r\n *\r\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\r\n * pan bounds according to the new zoom level.\r\n *\r\n * @param {'x' | 'y'} axis\r\n * @param {Point} [point]\r\n * point based on which zoom is performed, usually refers to the current mouse position,\r\n * if false - viewport center will be used.\r\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\r\n * @returns {number}\r\n */\r\n calculateZoomToPanOffset(axis, point, prevZoomLevel) {\r\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\r\n if (totalPanDistance === 0) {\r\n return this.bounds.center[axis];\r\n }\r\n\r\n if (!point) {\r\n point = this.pswp.getViewportCenterPoint();\r\n }\r\n\r\n if (!prevZoomLevel) {\r\n prevZoomLevel = this.zoomLevels.initial;\r\n }\r\n\r\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\r\n return this.bounds.correctPan(\r\n axis,\r\n (this.pan[axis] - point[axis]) * zoomFactor + point[axis]\r\n );\r\n }\r\n\r\n /**\r\n * Apply pan and keep it within bounds.\r\n *\r\n * @param {number} panX\r\n * @param {number} panY\r\n */\r\n panTo(panX, panY) {\r\n this.pan.x = this.bounds.correctPan('x', panX);\r\n this.pan.y = this.bounds.correctPan('y', panY);\r\n this.applyCurrentZoomPan();\r\n }\r\n\r\n /**\r\n * If the slide in the current state can be panned by the user\r\n * @returns {boolean}\r\n */\r\n isPannable() {\r\n return Boolean(this.width) && (this.currZoomLevel > this.zoomLevels.fit);\r\n }\r\n\r\n /**\r\n * If the slide can be zoomed\r\n * @returns {boolean}\r\n */\r\n isZoomable() {\r\n return Boolean(this.width) && this.content.isZoomable();\r\n }\r\n\r\n /**\r\n * Apply transform and scale based on\r\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\r\n */\r\n applyCurrentZoomPan() {\r\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\r\n if (this === this.pswp.currSlide) {\r\n this.pswp.dispatch('zoomPanUpdate', { slide: this });\r\n }\r\n }\r\n\r\n zoomAndPanToInitial() {\r\n this.currZoomLevel = this.zoomLevels.initial;\r\n\r\n // pan according to the zoom level\r\n this.bounds.update(this.currZoomLevel);\r\n equalizePoints(this.pan, this.bounds.center);\r\n this.pswp.dispatch('initialZoomPan', { slide: this });\r\n }\r\n\r\n /**\r\n * Set translate and scale based on current resolution\r\n *\r\n * @param {number} x\r\n * @param {number} y\r\n * @param {number} zoom\r\n * @private\r\n */\r\n _applyZoomTransform(x, y, zoom) {\r\n zoom /= this.currentResolution || this.zoomLevels.initial;\r\n setTransform(this.container, x, y, zoom);\r\n }\r\n\r\n calculateSize() {\r\n const { pswp } = this;\r\n\r\n equalizePoints(\r\n this.panAreaSize,\r\n getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index)\r\n );\r\n\r\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\r\n\r\n pswp.dispatch('calcSlideSize', {\r\n slide: this\r\n });\r\n }\r\n\r\n /** @returns {string} */\r\n getCurrentTransform() {\r\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\r\n return toTransformString(this.pan.x, this.pan.y, scale);\r\n }\r\n\r\n /**\r\n * Set resolution and re-render the image.\r\n *\r\n * For example, if the real image size is 2000x1500,\r\n * and resolution is 0.5 - it will be rendered as 1000x750.\r\n *\r\n * Image with zoom level 2 and resolution 0.5 is\r\n * the same as image with zoom level 1 and resolution 1.\r\n *\r\n * Used to optimize animations and make\r\n * sure that browser renders image in the highest quality.\r\n * Also used by responsive images to load the correct one.\r\n *\r\n * @param {number} newResolution\r\n */\r\n _setResolution(newResolution) {\r\n if (newResolution === this.currentResolution) {\r\n return;\r\n }\r\n\r\n this.currentResolution = newResolution;\r\n this.updateContentSize();\r\n\r\n this.pswp.dispatch('resolutionChanged');\r\n }\r\n}\r\n\r\nexport default Slide;\r\n","import {\r\n equalizePoints, roundPoint, clamp\r\n} from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n\r\nconst PAN_END_FRICTION = 0.35;\r\nconst VERTICAL_DRAG_FRICTION = 0.6;\r\n\r\n// 1 corresponds to the third of viewport height\r\nconst MIN_RATIO_TO_CLOSE = 0.4;\r\n\r\n// Minimum speed required to navigate\r\n// to next or previous slide\r\nconst MIN_NEXT_SLIDE_SPEED = 0.5;\r\n\r\n/**\r\n * @param {number} initialVelocity\r\n * @param {number} decelerationRate\r\n * @returns {number}\r\n */\r\nfunction project(initialVelocity, decelerationRate) {\r\n return initialVelocity * decelerationRate / (1 - decelerationRate);\r\n}\r\n\r\n/**\r\n * Handles single pointer dragging\r\n */\r\nclass DragHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n this.pswp = gestures.pswp;\r\n /** @type {Point} */\r\n this.startPan = { x: 0, y: 0 };\r\n }\r\n\r\n start() {\r\n if (this.pswp.currSlide) {\r\n equalizePoints(this.startPan, this.pswp.currSlide.pan);\r\n }\r\n this.pswp.animations.stopAll();\r\n }\r\n\r\n change() {\r\n const { p1, prevP1, dragAxis } = this.gestures;\r\n const { currSlide } = this.pswp;\r\n\r\n if (dragAxis === 'y'\r\n && this.pswp.options.closeOnVerticalDrag\r\n && (currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit)\r\n && !this.gestures.isMultitouch) {\r\n // Handle vertical drag to close\r\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\r\n if (!this.pswp.dispatch('verticalDrag', { panY }).defaultPrevented) {\r\n this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION);\r\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\r\n this.pswp.applyBgOpacity(bgOpacity);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n } else {\r\n const mainScrollChanged = this._panOrMoveMainScroll('x');\r\n if (!mainScrollChanged) {\r\n this._panOrMoveMainScroll('y');\r\n\r\n if (currSlide) {\r\n roundPoint(currSlide.pan);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n }\r\n }\r\n }\r\n\r\n end() {\r\n const { velocity } = this.gestures;\r\n const { mainScroll, currSlide } = this.pswp;\r\n let indexDiff = 0;\r\n\r\n this.pswp.animations.stopAll();\r\n\r\n // Handle main scroll if it's shifted\r\n if (mainScroll.isShifted()) {\r\n // Position of the main scroll relative to the viewport\r\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX();\r\n\r\n // Ratio between 0 and 1:\r\n // 0 - slide is not visible at all,\r\n // 0.5 - half of the slide is visible\r\n // 1 - slide is fully visible\r\n const currentSlideVisibilityRatio = (mainScrollShiftDiff / this.pswp.viewportSize.x);\r\n\r\n // Go next slide.\r\n //\r\n // - if velocity and its direction is matched,\r\n // and we see at least tiny part of the next slide\r\n //\r\n // - or if we see less than 50% of the current slide\r\n // and velocity is close to 0\r\n //\r\n if ((velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0)\r\n || (velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5)) {\r\n // Go to next slide\r\n indexDiff = 1;\r\n velocity.x = Math.min(velocity.x, 0);\r\n } else if ((velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0)\r\n || (velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5)) {\r\n // Go to prev slide\r\n indexDiff = -1;\r\n velocity.x = Math.max(velocity.x, 0);\r\n }\r\n\r\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\r\n }\r\n\r\n // Restore zoom level\r\n if ((currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max)\r\n || this.gestures.isMultitouch) {\r\n this.gestures.zoomLevels.correctZoomPan(true);\r\n } else {\r\n // we run two animations instead of one,\r\n // as each axis has own pan boundaries and thus different spring function\r\n // (correctZoomPan does not have this functionality,\r\n // it animates all properties with single timing function)\r\n this._finishPanGestureForAxis('x');\r\n this._finishPanGestureForAxis('y');\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n */\r\n _finishPanGestureForAxis(axis) {\r\n const { velocity } = this.gestures;\r\n const { currSlide } = this.pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const { pan, bounds } = currSlide;\r\n const panPos = pan[axis];\r\n const restoreBgOpacity = (this.pswp.bgOpacity < 1 && axis === 'y');\r\n\r\n // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\r\n // Increasing this number will reduce travel distance\r\n const decelerationRate = 0.995; // 0.99\r\n\r\n // Pan position if there is no bounds\r\n const projectedPosition = panPos + project(velocity[axis], decelerationRate);\r\n\r\n if (restoreBgOpacity) {\r\n const vDragRatio = this._getVerticalDragRatio(panPos);\r\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition);\r\n\r\n // If we are above and moving upwards,\r\n // or if we are below and moving downwards\r\n if ((vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE)\r\n || (vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE)) {\r\n this.pswp.close();\r\n return;\r\n }\r\n }\r\n\r\n // Pan position with corrected bounds\r\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition);\r\n\r\n // Exit if pan position should not be changed\r\n // or if speed it too low\r\n if (panPos === correctedPanPosition) {\r\n return;\r\n }\r\n\r\n // Overshoot if the final position is out of pan bounds\r\n const dampingRatio = (correctedPanPosition === projectedPosition) ? 1 : 0.82;\r\n\r\n const initialBgOpacity = this.pswp.bgOpacity;\r\n const totalPanDist = correctedPanPosition - panPos;\r\n\r\n this.pswp.animations.startSpring({\r\n name: 'panGesture' + axis,\r\n isPan: true,\r\n start: panPos,\r\n end: correctedPanPosition,\r\n velocity: velocity[axis],\r\n dampingRatio,\r\n onUpdate: (pos) => {\r\n // Animate opacity of background relative to Y pan position of an image\r\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\r\n // 0 - start of animation, 1 - end of animation\r\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist;\r\n\r\n // We clamp opacity to keep it between 0 and 1.\r\n // As progress ratio can be larger than 1 due to overshoot,\r\n // and we do not want to bounce opacity.\r\n this.pswp.applyBgOpacity(clamp(\r\n initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio,\r\n 0,\r\n 1\r\n ));\r\n }\r\n\r\n pan[axis] = Math.floor(pos);\r\n currSlide.applyCurrentZoomPan();\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Update position of the main scroll,\r\n * or/and update pan position of the current slide.\r\n *\r\n * Should return true if it changes (or can change) main scroll.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @returns {boolean}\r\n */\r\n _panOrMoveMainScroll(axis) {\r\n const { p1, dragAxis, prevP1, isMultitouch } = this.gestures;\r\n const { currSlide, mainScroll } = this.pswp;\r\n const delta = (p1[axis] - prevP1[axis]);\r\n const newMainScrollX = mainScroll.x + delta;\r\n\r\n if (!delta || !currSlide) {\r\n return false;\r\n }\r\n\r\n // Always move main scroll if image can not be panned\r\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true; // changed main scroll\r\n }\r\n\r\n const { bounds } = currSlide;\r\n const newPan = currSlide.pan[axis] + delta;\r\n\r\n if (this.pswp.options.allowPanToNext\r\n && dragAxis === 'x'\r\n && axis === 'x'\r\n && !isMultitouch) {\r\n const currSlideMainScrollX = mainScroll.getCurrSlideX();\r\n\r\n // Position of the main scroll relative to the viewport\r\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\r\n\r\n const isLeftToRight = delta > 0;\r\n const isRightToLeft = !isLeftToRight;\r\n\r\n if (newPan > bounds.min[axis] && isLeftToRight) {\r\n // Panning from left to right, beyond the left edge\r\n\r\n // Wether the image was at minimum pan position (or less)\r\n // when this drag gesture started.\r\n // Minimum pan position refers to the left edge of the image.\r\n const wasAtMinPanPosition = (bounds.min[axis] <= this.startPan[axis]);\r\n\r\n if (wasAtMinPanPosition) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true;\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n //currSlide.pan[axis] = newPan;\r\n }\r\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\r\n // Paning from right to left, beyond the right edge\r\n\r\n // Maximum pan position refers to the right edge of the image.\r\n const wasAtMaxPanPosition = (this.startPan[axis] <= bounds.max[axis]);\r\n\r\n if (wasAtMaxPanPosition) {\r\n mainScroll.moveTo(newMainScrollX, true);\r\n return true;\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n //currSlide.pan[axis] = newPan;\r\n }\r\n } else {\r\n // If main scroll is shifted\r\n if (mainScrollShiftDiff !== 0) {\r\n // If main scroll is shifted right\r\n if (mainScrollShiftDiff > 0 /*&& isRightToLeft*/) {\r\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\r\n return true;\r\n } else if (mainScrollShiftDiff < 0 /*&& isLeftToRight*/) {\r\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\r\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\r\n return true;\r\n }\r\n } else {\r\n // We are within pan bounds, so just pan\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n }\r\n } else {\r\n if (axis === 'y') {\r\n // Do not pan vertically if main scroll is shifted o\r\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) {\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n } else {\r\n this._setPanWithFriction(axis, newPan);\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n // If we move above - the ratio is negative\r\n // If we move below the ratio is positive\r\n\r\n /**\r\n * Relation between pan Y position and third of viewport height.\r\n *\r\n * When we are at initial position (center bounds) - the ratio is 0,\r\n * if position is shifted upwards - the ratio is negative,\r\n * if position is shifted downwards - the ratio is positive.\r\n *\r\n * @private\r\n * @param {number} panY The current pan Y position.\r\n * @returns {number}\r\n */\r\n _getVerticalDragRatio(panY) {\r\n return (panY - (this.pswp.currSlide?.bounds.center.y ?? 0)) / (this.pswp.viewportSize.y / 3);\r\n }\r\n\r\n /**\r\n * Set pan position of the current slide.\r\n * Apply friction if the position is beyond the pan bounds,\r\n * or if custom friction is defined.\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} potentialPan\r\n * @param {number} [customFriction] (0.1 - 1)\r\n */\r\n _setPanWithFriction(axis, potentialPan, customFriction) {\r\n const { currSlide } = this.pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const { pan, bounds } = currSlide;\r\n const correctedPan = bounds.correctPan(axis, potentialPan);\r\n // If we are out of pan bounds\r\n if (correctedPan !== potentialPan || customFriction) {\r\n const delta = Math.round(potentialPan - pan[axis]);\r\n pan[axis] += delta * (customFriction || PAN_END_FRICTION);\r\n } else {\r\n pan[axis] = potentialPan;\r\n }\r\n }\r\n}\r\n\r\nexport default DragHandler;\r\n","import {\r\n equalizePoints, getDistanceBetween, clamp, pointsEqual\r\n} from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n\r\nconst UPPER_ZOOM_FRICTION = 0.05;\r\nconst LOWER_ZOOM_FRICTION = 0.15;\r\n\r\n\r\n/**\r\n * Get center point between two points\r\n *\r\n * @param {Point} p\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nfunction getZoomPointsCenter(p, p1, p2) {\r\n p.x = (p1.x + p2.x) / 2;\r\n p.y = (p1.y + p2.y) / 2;\r\n return p;\r\n}\r\n\r\nclass ZoomHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._startPan = { x: 0, y: 0 };\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._startZoomPoint = { x: 0, y: 0 };\r\n /**\r\n * @private\r\n * @type {Point}\r\n */\r\n this._zoomPoint = { x: 0, y: 0 };\r\n /** @private */\r\n this._wasOverFitZoomLevel = false;\r\n /** @private */\r\n this._startZoomLevel = 1;\r\n }\r\n\r\n start() {\r\n const { currSlide } = this.gestures.pswp;\r\n if (currSlide) {\r\n this._startZoomLevel = currSlide.currZoomLevel;\r\n equalizePoints(this._startPan, currSlide.pan);\r\n }\r\n\r\n this.gestures.pswp.animations.stopAllPan();\r\n this._wasOverFitZoomLevel = false;\r\n }\r\n\r\n change() {\r\n const { p1, startP1, p2, startP2, pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n const minZoomLevel = currSlide.zoomLevels.min;\r\n const maxZoomLevel = currSlide.zoomLevels.max;\r\n\r\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) {\r\n return;\r\n }\r\n\r\n getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\r\n getZoomPointsCenter(this._zoomPoint, p1, p2);\r\n\r\n let currZoomLevel = (1 / getDistanceBetween(startP1, startP2))\r\n * getDistanceBetween(p1, p2)\r\n * this._startZoomLevel;\r\n\r\n // slightly over the zoom.fit\r\n if (currZoomLevel > currSlide.zoomLevels.initial + (currSlide.zoomLevels.initial / 15)) {\r\n this._wasOverFitZoomLevel = true;\r\n }\r\n\r\n if (currZoomLevel < minZoomLevel) {\r\n if (pswp.options.pinchToClose\r\n && !this._wasOverFitZoomLevel\r\n && this._startZoomLevel <= currSlide.zoomLevels.initial) {\r\n // fade out background if zooming out\r\n const bgOpacity = 1 - ((minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2));\r\n if (!pswp.dispatch('pinchClose', { bgOpacity }).defaultPrevented) {\r\n pswp.applyBgOpacity(bgOpacity);\r\n }\r\n } else {\r\n // Apply the friction if zoom level is below the min\r\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION;\r\n }\r\n } else if (currZoomLevel > maxZoomLevel) {\r\n // Apply the friction if zoom level is above the max\r\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION;\r\n }\r\n\r\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\r\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\r\n\r\n currSlide.setZoomLevel(currZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n end() {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial)\r\n && !this._wasOverFitZoomLevel\r\n && pswp.options.pinchToClose) {\r\n pswp.close();\r\n } else {\r\n this.correctZoomPan();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} currZoomLevel\r\n * @returns {number}\r\n */\r\n _calculatePanForZoomLevel(axis, currZoomLevel) {\r\n const zoomFactor = currZoomLevel / this._startZoomLevel;\r\n return this._zoomPoint[axis]\r\n - ((this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor);\r\n }\r\n\r\n /**\r\n * Correct currZoomLevel and pan if they are\r\n * beyond minimum or maximum values.\r\n * With animation.\r\n *\r\n * @param {boolean} [ignoreGesture]\r\n * Wether gesture coordinates should be ignored when calculating destination pan position.\r\n */\r\n correctZoomPan(ignoreGesture) {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n\r\n if (!currSlide?.isZoomable()) {\r\n return;\r\n }\r\n\r\n if (this._zoomPoint.x === 0) {\r\n ignoreGesture = true;\r\n }\r\n\r\n const prevZoomLevel = currSlide.currZoomLevel;\r\n\r\n /** @type {number} */\r\n let destinationZoomLevel;\r\n let currZoomLevelNeedsChange = true;\r\n\r\n if (prevZoomLevel < currSlide.zoomLevels.initial) {\r\n destinationZoomLevel = currSlide.zoomLevels.initial;\r\n // zoom to min\r\n } else if (prevZoomLevel > currSlide.zoomLevels.max) {\r\n destinationZoomLevel = currSlide.zoomLevels.max;\r\n // zoom to max\r\n } else {\r\n currZoomLevelNeedsChange = false;\r\n destinationZoomLevel = prevZoomLevel;\r\n }\r\n\r\n const initialBgOpacity = pswp.bgOpacity;\r\n const restoreBgOpacity = pswp.bgOpacity < 1;\r\n\r\n const initialPan = equalizePoints({ x: 0, y: 0 }, currSlide.pan);\r\n let destinationPan = equalizePoints({ x: 0, y: 0 }, initialPan);\r\n\r\n if (ignoreGesture) {\r\n this._zoomPoint.x = 0;\r\n this._zoomPoint.y = 0;\r\n this._startZoomPoint.x = 0;\r\n this._startZoomPoint.y = 0;\r\n this._startZoomLevel = prevZoomLevel;\r\n equalizePoints(this._startPan, initialPan);\r\n }\r\n\r\n if (currZoomLevelNeedsChange) {\r\n destinationPan = {\r\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\r\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\r\n };\r\n }\r\n\r\n // set zoom level, so pan bounds are updated according to it\r\n currSlide.setZoomLevel(destinationZoomLevel);\r\n\r\n destinationPan = {\r\n x: currSlide.bounds.correctPan('x', destinationPan.x),\r\n y: currSlide.bounds.correctPan('y', destinationPan.y)\r\n };\r\n\r\n // return zoom level and its bounds to initial\r\n currSlide.setZoomLevel(prevZoomLevel);\r\n\r\n const panNeedsChange = !pointsEqual(destinationPan, initialPan);\r\n\r\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\r\n // update resolution after gesture\r\n currSlide._setResolution(destinationZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n\r\n // nothing to animate\r\n return;\r\n }\r\n\r\n pswp.animations.stopAllPan();\r\n\r\n pswp.animations.startSpring({\r\n isPan: true,\r\n start: 0,\r\n end: 1000,\r\n velocity: 0,\r\n dampingRatio: 1,\r\n naturalFrequency: 40,\r\n onUpdate: (now) => {\r\n now /= 1000; // 0 - start, 1 - end\r\n\r\n if (panNeedsChange || currZoomLevelNeedsChange) {\r\n if (panNeedsChange) {\r\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\r\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\r\n }\r\n\r\n if (currZoomLevelNeedsChange) {\r\n const newZoomLevel = prevZoomLevel\r\n + (destinationZoomLevel - prevZoomLevel) * now;\r\n currSlide.setZoomLevel(newZoomLevel);\r\n }\r\n\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n // Restore background opacity\r\n if (restoreBgOpacity && pswp.bgOpacity < 1) {\r\n // We clamp opacity to keep it between 0 and 1.\r\n // As progress ratio can be larger than 1 due to overshoot,\r\n // and we do not want to bounce opacity.\r\n pswp.applyBgOpacity(clamp(\r\n initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1\r\n ));\r\n }\r\n },\r\n onComplete: () => {\r\n // update resolution after transition ends\r\n currSlide._setResolution(destinationZoomLevel);\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport default ZoomHandler;\r\n","/**\r\n * @template {string} T\r\n * @template {string} P\r\n * @typedef {import('../types.js').AddPostfix} AddPostfix\r\n */\r\n\r\n/** @typedef {import('./gestures.js').default} Gestures */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */\r\n\r\n/**\r\n * Whether the tap was performed on the main slide\r\n * (rather than controls or caption).\r\n *\r\n * @param {PointerEvent} event\r\n * @returns {boolean}\r\n */\r\nfunction didTapOnMainContent(event) {\r\n return !!(/** @type {HTMLElement} */ (event.target).closest('.pswp__container'));\r\n}\r\n\r\n/**\r\n * Tap, double-tap handler.\r\n */\r\nclass TapHandler {\r\n /**\r\n * @param {Gestures} gestures\r\n */\r\n constructor(gestures) {\r\n this.gestures = gestures;\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n click(point, originalEvent) {\r\n const targetClassList = /** @type {HTMLElement} */ (originalEvent.target).classList;\r\n const isImageClick = targetClassList.contains('pswp__img');\r\n const isBackgroundClick = targetClassList.contains('pswp__item')\r\n || targetClassList.contains('pswp__zoom-wrap');\r\n\r\n if (isImageClick) {\r\n this._doClickOrTapAction('imageClick', point, originalEvent);\r\n } else if (isBackgroundClick) {\r\n this._doClickOrTapAction('bgClick', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n tap(point, originalEvent) {\r\n if (didTapOnMainContent(originalEvent)) {\r\n this._doClickOrTapAction('tap', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n doubleTap(point, originalEvent) {\r\n if (didTapOnMainContent(originalEvent)) {\r\n this._doClickOrTapAction('doubleTap', point, originalEvent);\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {Actions} actionName\r\n * @param {Point} point\r\n * @param {PointerEvent} originalEvent\r\n */\r\n _doClickOrTapAction(actionName, point, originalEvent) {\r\n const { pswp } = this.gestures;\r\n const { currSlide } = pswp;\r\n const actionFullName = /** @type {AddPostfix} */ (actionName + 'Action');\r\n const optionValue = pswp.options[actionFullName];\r\n\r\n if (pswp.dispatch(actionFullName, { point, originalEvent }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n optionValue.call(pswp, point, originalEvent);\r\n return;\r\n }\r\n\r\n switch (optionValue) {\r\n case 'close':\r\n case 'next':\r\n pswp[optionValue]();\r\n break;\r\n case 'zoom':\r\n currSlide?.toggleZoom(point);\r\n break;\r\n case 'zoom-or-close':\r\n // by default click zooms current image,\r\n // if it can not be zoomed - gallery will be closed\r\n if (currSlide?.isZoomable()\r\n && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) {\r\n currSlide.toggleZoom(point);\r\n } else if (pswp.options.clickToCloseNonZoomable) {\r\n pswp.close();\r\n }\r\n break;\r\n case 'toggle-controls':\r\n this.gestures.pswp.element?.classList.toggle('pswp--ui-visible');\r\n // if (_controlsVisible) {\r\n // _ui.hideControls();\r\n // } else {\r\n // _ui.showControls();\r\n // }\r\n break;\r\n }\r\n }\r\n}\r\n\r\nexport default TapHandler;\r\n","import {\r\n equalizePoints, pointsEqual, getDistanceBetween\r\n} from '../util/util.js';\r\n\r\nimport DragHandler from './drag-handler.js';\r\nimport ZoomHandler from './zoom-handler.js';\r\nimport TapHandler from './tap-handler.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n// How far should user should drag\r\n// until we can determine that the gesture is swipe and its direction\r\nconst AXIS_SWIPE_HYSTERISIS = 10;\r\n//const PAN_END_FRICTION = 0.35;\r\n\r\nconst DOUBLE_TAP_DELAY = 300; // ms\r\nconst MIN_TAP_DISTANCE = 25; // px\r\n\r\n/**\r\n * Gestures class bind touch, pointer or mouse events\r\n * and emits drag to drag-handler and zoom events zoom-handler.\r\n *\r\n * Drag and zoom events are emited in requestAnimationFrame,\r\n * and only when one of pointers was actually changed.\r\n */\r\nclass Gestures {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n\r\n /** @type {'x' | 'y' | null} */\r\n this.dragAxis = null;\r\n\r\n // point objects are defined once and reused\r\n // PhotoSwipe keeps track only of two pointers, others are ignored\r\n /** @type {Point} */\r\n this.p1 = { x: 0, y: 0 }; // the first pressed pointer\r\n /** @type {Point} */\r\n this.p2 = { x: 0, y: 0 }; // the second pressed pointer\r\n /** @type {Point} */\r\n this.prevP1 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.prevP2 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.startP1 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.startP2 = { x: 0, y: 0 };\r\n /** @type {Point} */\r\n this.velocity = { x: 0, y: 0 };\r\n\r\n /** @type {Point}\r\n * @private\r\n */\r\n this._lastStartP1 = { x: 0, y: 0 };\r\n /** @type {Point}\r\n * @private\r\n */\r\n this._intervalP1 = { x: 0, y: 0 };\r\n /** @private */\r\n this._numActivePoints = 0;\r\n /** @type {Point[]}\r\n * @private\r\n */\r\n this._ongoingPointers = [];\r\n /** @private */\r\n this._touchEventEnabled = 'ontouchstart' in window;\r\n /** @private */\r\n this._pointerEventEnabled = !!(window.PointerEvent);\r\n this.supportsTouch = this._touchEventEnabled\r\n || (this._pointerEventEnabled && navigator.maxTouchPoints > 1);\r\n /** @private */\r\n this._numActivePoints = 0;\r\n /** @private */\r\n this._intervalTime = 0;\r\n /** @private */\r\n this._velocityCalculated = false;\r\n this.isMultitouch = false;\r\n this.isDragging = false;\r\n this.isZooming = false;\r\n /** @type {number | null} */\r\n this.raf = null;\r\n /** @type {NodeJS.Timeout | null}\r\n * @private\r\n */\r\n this._tapTimer = null;\r\n\r\n if (!this.supportsTouch) {\r\n // disable pan to next slide for non-touch devices\r\n pswp.options.allowPanToNext = false;\r\n }\r\n\r\n this.drag = new DragHandler(this);\r\n this.zoomLevels = new ZoomHandler(this);\r\n this.tapHandler = new TapHandler(this);\r\n\r\n pswp.on('bindEvents', () => {\r\n pswp.events.add(\r\n pswp.scrollWrap,\r\n 'click',\r\n /** @type EventListener */(this._onClick.bind(this))\r\n );\r\n\r\n if (this._pointerEventEnabled) {\r\n this._bindEvents('pointer', 'down', 'up', 'cancel');\r\n } else if (this._touchEventEnabled) {\r\n this._bindEvents('touch', 'start', 'end', 'cancel');\r\n\r\n // In previous versions we also bound mouse event here,\r\n // in case device supports both touch and mouse events,\r\n // but newer versions of browsers now support PointerEvent.\r\n\r\n // on iOS10 if you bind touchmove/end after touchstart,\r\n // and you don't preventDefault touchstart (which PhotoSwipe does),\r\n // preventDefault will have no effect on touchmove and touchend.\r\n // Unless you bind it previously.\r\n if (pswp.scrollWrap) {\r\n pswp.scrollWrap.ontouchmove = () => {};\r\n pswp.scrollWrap.ontouchend = () => {};\r\n }\r\n } else {\r\n this._bindEvents('mouse', 'down', 'up');\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {'mouse' | 'touch' | 'pointer'} pref\r\n * @param {'down' | 'start'} down\r\n * @param {'up' | 'end'} up\r\n * @param {'cancel'} [cancel]\r\n */\r\n _bindEvents(pref, down, up, cancel) {\r\n const { pswp } = this;\r\n const { events } = pswp;\r\n\r\n const cancelEvent = cancel ? pref + cancel : '';\r\n\r\n events.add(\r\n pswp.scrollWrap,\r\n pref + down,\r\n /** @type EventListener */(this.onPointerDown.bind(this))\r\n );\r\n events.add(window, pref + 'move', /** @type EventListener */(this.onPointerMove.bind(this)));\r\n events.add(window, pref + up, /** @type EventListener */(this.onPointerUp.bind(this)));\r\n if (cancelEvent) {\r\n events.add(\r\n pswp.scrollWrap,\r\n cancelEvent,\r\n /** @type EventListener */(this.onPointerUp.bind(this))\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerDown(e) {\r\n // We do not call preventDefault for touch events\r\n // to allow browser to show native dialog on longpress\r\n // (the one that allows to save image or open it in new tab).\r\n //\r\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\r\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\r\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse';\r\n\r\n // Allow dragging only via left mouse button.\r\n // http://www.quirksmode.org/js/events_properties.html\r\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\r\n if (isMousePointer && e.button > 0) {\r\n return;\r\n }\r\n\r\n const { pswp } = this;\r\n\r\n // if PhotoSwipe is opening or closing\r\n if (!pswp.opener.isOpen) {\r\n e.preventDefault();\r\n return;\r\n }\r\n\r\n if (pswp.dispatch('pointerDown', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (isMousePointer) {\r\n pswp.mouseDetected();\r\n\r\n // preventDefault mouse event to prevent\r\n // browser image drag feature\r\n this._preventPointerEventBehaviour(e, 'down');\r\n }\r\n\r\n pswp.animations.stopAll();\r\n\r\n this._updatePoints(e, 'down');\r\n\r\n if (this._numActivePoints === 1) {\r\n this.dragAxis = null;\r\n // we need to store initial point to determine the main axis,\r\n // drag is activated only after the axis is determined\r\n equalizePoints(this.startP1, this.p1);\r\n }\r\n\r\n if (this._numActivePoints > 1) {\r\n // Tap or double tap should not trigger if more than one pointer\r\n this._clearTapTimer();\r\n this.isMultitouch = true;\r\n } else {\r\n this.isMultitouch = false;\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerMove(e) {\r\n this._preventPointerEventBehaviour(e, 'move');\r\n\r\n if (!this._numActivePoints) {\r\n return;\r\n }\r\n\r\n this._updatePoints(e, 'move');\r\n\r\n if (this.pswp.dispatch('pointerMove', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this._numActivePoints === 1 && !this.isDragging) {\r\n if (!this.dragAxis) {\r\n this._calculateDragDirection();\r\n }\r\n\r\n // Drag axis was detected, emit drag.start\r\n if (this.dragAxis && !this.isDragging) {\r\n if (this.isZooming) {\r\n this.isZooming = false;\r\n this.zoomLevels.end();\r\n }\r\n\r\n this.isDragging = true;\r\n this._clearTapTimer(); // Tap can not trigger after drag\r\n\r\n // Adjust starting point\r\n this._updateStartPoints();\r\n this._intervalTime = Date.now();\r\n //this._startTime = this._intervalTime;\r\n this._velocityCalculated = false;\r\n equalizePoints(this._intervalP1, this.p1);\r\n this.velocity.x = 0;\r\n this.velocity.y = 0;\r\n this.drag.start();\r\n\r\n this._rafStopLoop();\r\n this._rafRenderLoop();\r\n }\r\n } else if (this._numActivePoints > 1 && !this.isZooming) {\r\n this._finishDrag();\r\n\r\n this.isZooming = true;\r\n\r\n // Adjust starting points\r\n this._updateStartPoints();\r\n\r\n this.zoomLevels.start();\r\n\r\n this._rafStopLoop();\r\n this._rafRenderLoop();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _finishDrag() {\r\n if (this.isDragging) {\r\n this.isDragging = false;\r\n\r\n // Try to calculate velocity,\r\n // if it wasn't calculated yet in drag.change\r\n if (!this._velocityCalculated) {\r\n this._updateVelocity(true);\r\n }\r\n\r\n this.drag.end();\r\n this.dragAxis = null;\r\n }\r\n }\r\n\r\n /**\r\n * @param {PointerEvent} e\r\n */\r\n onPointerUp(e) {\r\n if (!this._numActivePoints) {\r\n return;\r\n }\r\n\r\n this._updatePoints(e, 'up');\r\n\r\n if (this.pswp.dispatch('pointerUp', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this._numActivePoints === 0) {\r\n this._rafStopLoop();\r\n\r\n if (this.isDragging) {\r\n this._finishDrag();\r\n } else if (!this.isZooming && !this.isMultitouch) {\r\n //this.zoomLevels.correctZoomPan();\r\n this._finishTap(e);\r\n }\r\n }\r\n\r\n if (this._numActivePoints < 2 && this.isZooming) {\r\n this.isZooming = false;\r\n this.zoomLevels.end();\r\n\r\n if (this._numActivePoints === 1) {\r\n // Since we have 1 point left, we need to reinitiate drag\r\n this.dragAxis = null;\r\n this._updateStartPoints();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _rafRenderLoop() {\r\n if (this.isDragging || this.isZooming) {\r\n this._updateVelocity();\r\n\r\n if (this.isDragging) {\r\n // make sure that pointer moved since the last update\r\n if (!pointsEqual(this.p1, this.prevP1)) {\r\n this.drag.change();\r\n }\r\n } else /* if (this.isZooming) */ {\r\n if (!pointsEqual(this.p1, this.prevP1)\r\n || !pointsEqual(this.p2, this.prevP2)) {\r\n this.zoomLevels.change();\r\n }\r\n }\r\n\r\n this._updatePrevPoints();\r\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\r\n }\r\n }\r\n\r\n /**\r\n * Update velocity at 50ms interval\r\n *\r\n * @private\r\n * @param {boolean} [force]\r\n */\r\n _updateVelocity(force) {\r\n const time = Date.now();\r\n const duration = time - this._intervalTime;\r\n\r\n if (duration < 50 && !force) {\r\n return;\r\n }\r\n\r\n\r\n this.velocity.x = this._getVelocity('x', duration);\r\n this.velocity.y = this._getVelocity('y', duration);\r\n\r\n this._intervalTime = time;\r\n equalizePoints(this._intervalP1, this.p1);\r\n this._velocityCalculated = true;\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\r\n _finishTap(e) {\r\n const { mainScroll } = this.pswp;\r\n\r\n // Do not trigger tap events if main scroll is shifted\r\n if (mainScroll.isShifted()) {\r\n // restore main scroll position\r\n // (usually happens if stopped in the middle of animation)\r\n mainScroll.moveIndexBy(0, true);\r\n return;\r\n }\r\n\r\n // Do not trigger tap for touchcancel or pointercancel\r\n if (e.type.indexOf('cancel') > 0) {\r\n return;\r\n }\r\n\r\n // Trigger click instead of tap for mouse events\r\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\r\n this.tapHandler.click(this.startP1, e);\r\n return;\r\n }\r\n\r\n // Disable delay if there is no doubleTapAction\r\n const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0;\r\n\r\n // If tapTimer is defined - we tapped recently,\r\n // check if the current tap is close to the previous one,\r\n // if yes - trigger double tap\r\n if (this._tapTimer) {\r\n this._clearTapTimer();\r\n // Check if two taps were more or less on the same place\r\n if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) {\r\n this.tapHandler.doubleTap(this.startP1, e);\r\n }\r\n } else {\r\n equalizePoints(this._lastStartP1, this.startP1);\r\n this._tapTimer = setTimeout(() => {\r\n this.tapHandler.tap(this.startP1, e);\r\n this._clearTapTimer();\r\n }, tapDelay);\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _clearTapTimer() {\r\n if (this._tapTimer) {\r\n clearTimeout(this._tapTimer);\r\n this._tapTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get velocity for axis\r\n *\r\n * @private\r\n * @param {'x' | 'y'} axis\r\n * @param {number} duration\r\n * @returns {number}\r\n */\r\n _getVelocity(axis, duration) {\r\n // displacement is like distance, but can be negative.\r\n const displacement = this.p1[axis] - this._intervalP1[axis];\r\n\r\n if (Math.abs(displacement) > 1 && duration > 5) {\r\n return displacement / duration;\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _rafStopLoop() {\r\n if (this.raf) {\r\n cancelAnimationFrame(this.raf);\r\n this.raf = null;\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\r\n _preventPointerEventBehaviour(e, pointerType) {\r\n const preventPointerEvent = this.pswp.applyFilters('preventPointerEvent', true, e, pointerType);\r\n if (preventPointerEvent) {\r\n e.preventDefault();\r\n }\r\n }\r\n\r\n /**\r\n * Parses and normalizes points from the touch, mouse or pointer event.\r\n * Updates p1 and p2.\r\n *\r\n * @private\r\n * @param {PointerEvent | TouchEvent} e\r\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\r\n */\r\n _updatePoints(e, pointerType) {\r\n if (this._pointerEventEnabled) {\r\n const pointerEvent = /** @type {PointerEvent} */ (e);\r\n // Try to find the current pointer in ongoing pointers by its ID\r\n const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer) => {\r\n return ongoingPointer.id === pointerEvent.pointerId;\r\n });\r\n\r\n if (pointerType === 'up' && pointerIndex > -1) {\r\n // release the pointer - remove it from ongoing\r\n this._ongoingPointers.splice(pointerIndex, 1);\r\n } else if (pointerType === 'down' && pointerIndex === -1) {\r\n // add new pointer\r\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, { x: 0, y: 0 }));\r\n } else if (pointerIndex > -1) {\r\n // update existing pointer\r\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\r\n }\r\n\r\n this._numActivePoints = this._ongoingPointers.length;\r\n\r\n // update points that PhotoSwipe uses\r\n // to calculate position and scale\r\n if (this._numActivePoints > 0) {\r\n equalizePoints(this.p1, this._ongoingPointers[0]);\r\n }\r\n\r\n if (this._numActivePoints > 1) {\r\n equalizePoints(this.p2, this._ongoingPointers[1]);\r\n }\r\n } else {\r\n const touchEvent = /** @type {TouchEvent} */ (e);\r\n\r\n this._numActivePoints = 0;\r\n if (touchEvent.type.indexOf('touch') > -1) {\r\n // Touch Event\r\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\r\n if (touchEvent.touches && touchEvent.touches.length > 0) {\r\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\r\n this._numActivePoints++;\r\n if (touchEvent.touches.length > 1) {\r\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\r\n this._numActivePoints++;\r\n }\r\n }\r\n } else {\r\n // Mouse Event\r\n this._convertEventPosToPoint(/** @type {PointerEvent} */ (e), this.p1);\r\n if (pointerType === 'up') {\r\n // clear all points on mouseup\r\n this._numActivePoints = 0;\r\n } else {\r\n this._numActivePoints++;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** update points that were used during previous rAF tick\r\n * @private\r\n */\r\n _updatePrevPoints() {\r\n equalizePoints(this.prevP1, this.p1);\r\n equalizePoints(this.prevP2, this.p2);\r\n }\r\n\r\n /** update points at the start of gesture\r\n * @private\r\n */\r\n _updateStartPoints() {\r\n equalizePoints(this.startP1, this.p1);\r\n equalizePoints(this.startP2, this.p2);\r\n this._updatePrevPoints();\r\n }\r\n\r\n /** @private */\r\n _calculateDragDirection() {\r\n if (this.pswp.mainScroll.isShifted()) {\r\n // if main scroll position is shifted – direction is always horizontal\r\n this.dragAxis = 'x';\r\n } else {\r\n // calculate delta of the last touchmove tick\r\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\r\n\r\n if (diff !== 0) {\r\n // check if pointer was shifted horizontally or vertically\r\n const axisToCheck = diff > 0 ? 'x' : 'y';\r\n\r\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) {\r\n this.dragAxis = axisToCheck;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Converts touch, pointer or mouse event\r\n * to PhotoSwipe point.\r\n *\r\n * @private\r\n * @param {Touch | PointerEvent} e\r\n * @param {Point} p\r\n * @returns {Point}\r\n */\r\n _convertEventPosToPoint(e, p) {\r\n p.x = e.pageX - this.pswp.offset.x;\r\n p.y = e.pageY - this.pswp.offset.y;\r\n\r\n if ('pointerId' in e) {\r\n p.id = e.pointerId;\r\n } else if (e.identifier !== undefined) {\r\n p.id = e.identifier;\r\n }\r\n\r\n return p;\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PointerEvent} e\r\n */\r\n _onClick(e) {\r\n // Do not allow click event to pass through after drag\r\n if (this.pswp.mainScroll.isShifted()) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n }\r\n}\r\n\r\nexport default Gestures;\r\n","import {\r\n setTransform,\r\n createElement,\r\n} from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./slide/slide.js').default} Slide */\r\n\r\n/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */\r\n\r\nconst MAIN_SCROLL_END_FRICTION = 0.35;\r\n\r\n\r\n// const MIN_SWIPE_TRANSITION_DURATION = 250;\r\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\r\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\r\n\r\n/**\r\n * Handles movement of the main scrolling container\r\n * (for example, it repositions when user swipes left or right).\r\n *\r\n * Also stores its state.\r\n */\r\nclass MainScroll {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.x = 0;\r\n this.slideWidth = 0;\r\n /** @private */\r\n this._currPositionIndex = 0;\r\n /** @private */\r\n this._prevPositionIndex = 0;\r\n /** @private */\r\n this._containerShiftIndex = -1;\r\n\r\n /** @type {ItemHolder[]} */\r\n this.itemHolders = [];\r\n }\r\n\r\n /**\r\n * Position the scroller and slide containers\r\n * according to viewport size.\r\n *\r\n * @param {boolean} [resizeSlides] Whether slides content should resized\r\n */\r\n resize(resizeSlides) {\r\n const { pswp } = this;\r\n const newSlideWidth = Math.round(\r\n pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing\r\n );\r\n // Mobile browsers might trigger a resize event during a gesture.\r\n // (due to toolbar appearing or hiding).\r\n // Avoid re-adjusting main scroll position if width wasn't changed\r\n const slideWidthChanged = (newSlideWidth !== this.slideWidth);\r\n\r\n if (slideWidthChanged) {\r\n this.slideWidth = newSlideWidth;\r\n this.moveTo(this.getCurrSlideX());\r\n }\r\n\r\n this.itemHolders.forEach((itemHolder, index) => {\r\n if (slideWidthChanged) {\r\n setTransform(itemHolder.el, (index + this._containerShiftIndex)\r\n * this.slideWidth);\r\n }\r\n\r\n if (resizeSlides && itemHolder.slide) {\r\n itemHolder.slide.resize();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Reset X position of the main scroller to zero\r\n */\r\n resetPosition() {\r\n // Position on the main scroller (offset)\r\n // it is independent from slide index\r\n this._currPositionIndex = 0;\r\n this._prevPositionIndex = 0;\r\n\r\n // This will force recalculation of size on next resize()\r\n this.slideWidth = 0;\r\n\r\n // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\r\n this._containerShiftIndex = -1;\r\n }\r\n\r\n /**\r\n * Create and append array of three items\r\n * that hold data about slides in DOM\r\n */\r\n appendHolders() {\r\n this.itemHolders = [];\r\n\r\n // append our three slide holders -\r\n // previous, current, and next\r\n for (let i = 0; i < 3; i++) {\r\n const el = createElement('pswp__item', 'div', this.pswp.container);\r\n el.setAttribute('role', 'group');\r\n el.setAttribute('aria-roledescription', 'slide');\r\n el.setAttribute('aria-hidden', 'true');\r\n\r\n // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\r\n el.style.display = (i === 1) ? 'block' : 'none';\r\n\r\n this.itemHolders.push({\r\n el,\r\n //index: -1\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\r\n * @returns {boolean}\r\n */\r\n canBeSwiped() {\r\n return this.pswp.getNumItems() > 1;\r\n }\r\n\r\n /**\r\n * Move main scroll by X amount of slides.\r\n * For example:\r\n * `-1` will move to the previous slide,\r\n * `0` will reset the scroll position of the current slide,\r\n * `3` will move three slides forward\r\n *\r\n * If loop option is enabled - index will be automatically looped too,\r\n * (for example `-1` will move to the last slide of the gallery).\r\n *\r\n * @param {number} diff\r\n * @param {boolean} [animate]\r\n * @param {number} [velocityX]\r\n * @returns {boolean} whether index was changed or not\r\n */\r\n moveIndexBy(diff, animate, velocityX) {\r\n const { pswp } = this;\r\n let newIndex = pswp.potentialIndex + diff;\r\n const numSlides = pswp.getNumItems();\r\n\r\n if (pswp.canLoop()) {\r\n newIndex = pswp.getLoopedIndex(newIndex);\r\n const distance = (diff + numSlides) % numSlides;\r\n if (distance <= numSlides / 2) {\r\n // go forward\r\n diff = distance;\r\n } else {\r\n // go backwards\r\n diff = distance - numSlides;\r\n }\r\n } else {\r\n if (newIndex < 0) {\r\n newIndex = 0;\r\n } else if (newIndex >= numSlides) {\r\n newIndex = numSlides - 1;\r\n }\r\n diff = newIndex - pswp.potentialIndex;\r\n }\r\n\r\n pswp.potentialIndex = newIndex;\r\n this._currPositionIndex -= diff;\r\n\r\n pswp.animations.stopMainScroll();\r\n\r\n const destinationX = this.getCurrSlideX();\r\n if (!animate) {\r\n this.moveTo(destinationX);\r\n this.updateCurrItem();\r\n } else {\r\n pswp.animations.startSpring({\r\n isMainScroll: true,\r\n start: this.x,\r\n end: destinationX,\r\n velocity: velocityX || 0,\r\n naturalFrequency: 30,\r\n dampingRatio: 1, //0.7,\r\n onUpdate: (x) => {\r\n this.moveTo(x);\r\n },\r\n onComplete: () => {\r\n this.updateCurrItem();\r\n pswp.appendHeavy();\r\n }\r\n });\r\n\r\n let currDiff = pswp.potentialIndex - pswp.currIndex;\r\n if (pswp.canLoop()) {\r\n const currDistance = (currDiff + numSlides) % numSlides;\r\n if (currDistance <= numSlides / 2) {\r\n // go forward\r\n currDiff = currDistance;\r\n } else {\r\n // go backwards\r\n currDiff = currDistance - numSlides;\r\n }\r\n }\r\n\r\n // Force-append new slides during transition\r\n // if difference between slides is more than 1\r\n if (Math.abs(currDiff) > 1) {\r\n this.updateCurrItem();\r\n }\r\n }\r\n\r\n return Boolean(diff);\r\n }\r\n\r\n /**\r\n * X position of the main scroll for the current slide\r\n * (ignores position during dragging)\r\n * @returns {number}\r\n */\r\n getCurrSlideX() {\r\n return this.slideWidth * this._currPositionIndex;\r\n }\r\n\r\n /**\r\n * Whether scroll position is shifted.\r\n * For example, it will return true if the scroll is being dragged or animated.\r\n * @returns {boolean}\r\n */\r\n isShifted() {\r\n return this.x !== this.getCurrSlideX();\r\n }\r\n\r\n /**\r\n * Update slides X positions and set their content\r\n */\r\n updateCurrItem() {\r\n const { pswp } = this;\r\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\r\n\r\n if (!positionDifference) {\r\n return;\r\n }\r\n\r\n this._prevPositionIndex = this._currPositionIndex;\r\n\r\n pswp.currIndex = pswp.potentialIndex;\r\n\r\n let diffAbs = Math.abs(positionDifference);\r\n /** @type {ItemHolder | undefined} */\r\n let tempHolder;\r\n\r\n if (diffAbs >= 3) {\r\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\r\n diffAbs = 3;\r\n\r\n // If slides are changed by 3 screens or more - clean up previous slides\r\n this.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.destroy();\r\n itemHolder.slide = undefined;\r\n });\r\n }\r\n\r\n for (let i = 0; i < diffAbs; i++) {\r\n if (positionDifference > 0) {\r\n tempHolder = this.itemHolders.shift();\r\n if (tempHolder) {\r\n this.itemHolders[2] = tempHolder; // move first to last\r\n\r\n this._containerShiftIndex++;\r\n\r\n setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\r\n\r\n pswp.setContent(tempHolder, (pswp.currIndex - diffAbs) + i + 2);\r\n }\r\n } else {\r\n tempHolder = this.itemHolders.pop();\r\n if (tempHolder) {\r\n this.itemHolders.unshift(tempHolder); // move last to first\r\n\r\n this._containerShiftIndex--;\r\n\r\n setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\r\n\r\n pswp.setContent(tempHolder, (pswp.currIndex + diffAbs) - i - 2);\r\n }\r\n }\r\n }\r\n\r\n // Reset transfrom every 50ish navigations in one direction.\r\n //\r\n // Otherwise transform will keep growing indefinitely,\r\n // which might cause issues as browsers have a maximum transform limit.\r\n // I wasn't able to reach it, but just to be safe.\r\n // This should not cause noticable lag.\r\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\r\n this.resetPosition();\r\n this.resize();\r\n }\r\n\r\n // Pan transition might be running (and consntantly updating pan position)\r\n pswp.animations.stopAllPan();\r\n\r\n this.itemHolders.forEach((itemHolder, i) => {\r\n if (itemHolder.slide) {\r\n // Slide in the 2nd holder is always active\r\n itemHolder.slide.setIsActive(i === 1);\r\n }\r\n });\r\n\r\n pswp.currSlide = this.itemHolders[1]?.slide;\r\n pswp.contentLoader.updateLazy(positionDifference);\r\n\r\n if (pswp.currSlide) {\r\n pswp.currSlide.applyCurrentZoomPan();\r\n }\r\n\r\n pswp.dispatch('change');\r\n }\r\n\r\n /**\r\n * Move the X position of the main scroll container\r\n *\r\n * @param {number} x\r\n * @param {boolean} [dragging]\r\n */\r\n moveTo(x, dragging) {\r\n if (!this.pswp.canLoop() && dragging) {\r\n // Apply friction\r\n let newSlideIndexOffset = ((this.slideWidth * this._currPositionIndex) - x) / this.slideWidth;\r\n newSlideIndexOffset += this.pswp.currIndex;\r\n const delta = Math.round(x - this.x);\r\n\r\n if ((newSlideIndexOffset < 0 && delta > 0)\r\n || (newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0)) {\r\n x = this.x + (delta * MAIN_SCROLL_END_FRICTION);\r\n }\r\n }\r\n\r\n this.x = x;\r\n\r\n if (this.pswp.container) {\r\n setTransform(this.pswp.container, x);\r\n }\r\n\r\n this.pswp.dispatch('moveMainScroll', { x, dragging: dragging ?? false });\r\n }\r\n}\r\n\r\nexport default MainScroll;\r\n","import { specialKeyUsed } from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Methods} Methods\r\n */\r\n\r\nconst KeyboardKeyCodesMap = {\r\n Escape: 27,\r\n z: 90,\r\n ArrowLeft: 37,\r\n ArrowUp: 38,\r\n ArrowRight: 39,\r\n ArrowDown: 40,\r\n Tab: 9,\r\n};\r\n\r\n/**\r\n * @template {keyof KeyboardKeyCodesMap} T\r\n * @param {T} key\r\n * @param {boolean} isKeySupported\r\n * @returns {T | number | undefined}\r\n */\r\nconst getKeyboardEventKey = (key, isKeySupported) => {\r\n return isKeySupported ? key : KeyboardKeyCodesMap[key];\r\n};\r\n\r\n/**\r\n * - Manages keyboard shortcuts.\r\n * - Helps trap focus within photoswipe.\r\n */\r\nclass Keyboard {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n /** @private */\r\n this._wasFocused = false;\r\n\r\n pswp.on('bindEvents', () => {\r\n if (pswp.options.trapFocus) {\r\n // Dialog was likely opened by keyboard if initial point is not defined\r\n if (!pswp.options.initialPointerPos) {\r\n // focus causes layout,\r\n // which causes lag during the animation,\r\n // that's why we delay it until the opener transition ends\r\n this._focusRoot();\r\n }\r\n\r\n pswp.events.add(\r\n document,\r\n 'focusin',\r\n /** @type EventListener */(this._onFocusIn.bind(this))\r\n );\r\n }\r\n\r\n pswp.events.add(document, 'keydown', /** @type EventListener */(this._onKeyDown.bind(this)));\r\n });\r\n\r\n const lastActiveElement = /** @type {HTMLElement} */ (document.activeElement);\r\n pswp.on('destroy', () => {\r\n if (pswp.options.returnFocus\r\n && lastActiveElement\r\n && this._wasFocused) {\r\n lastActiveElement.focus();\r\n }\r\n });\r\n }\r\n\r\n /** @private */\r\n _focusRoot() {\r\n if (!this._wasFocused && this.pswp.element) {\r\n this.pswp.element.focus();\r\n this._wasFocused = true;\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {KeyboardEvent} e\r\n */\r\n _onKeyDown(e) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('keydown', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (specialKeyUsed(e)) {\r\n // don't do anything if special key pressed\r\n // to prevent from overriding default browser actions\r\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\r\n return;\r\n }\r\n\r\n /** @type {Methods | undefined} */\r\n let keydownAction;\r\n /** @type {'x' | 'y' | undefined} */\r\n let axis;\r\n let isForward = false;\r\n const isKeySupported = 'key' in e;\r\n\r\n switch (isKeySupported ? e.key : e.keyCode) {\r\n case getKeyboardEventKey('Escape', isKeySupported):\r\n if (pswp.options.escKey) {\r\n keydownAction = 'close';\r\n }\r\n break;\r\n case getKeyboardEventKey('z', isKeySupported):\r\n keydownAction = 'toggleZoom';\r\n break;\r\n case getKeyboardEventKey('ArrowLeft', isKeySupported):\r\n axis = 'x';\r\n break;\r\n case getKeyboardEventKey('ArrowUp', isKeySupported):\r\n axis = 'y';\r\n break;\r\n case getKeyboardEventKey('ArrowRight', isKeySupported):\r\n axis = 'x';\r\n isForward = true;\r\n break;\r\n case getKeyboardEventKey('ArrowDown', isKeySupported):\r\n isForward = true;\r\n axis = 'y';\r\n break;\r\n case getKeyboardEventKey('Tab', isKeySupported):\r\n this._focusRoot();\r\n break;\r\n default:\r\n }\r\n\r\n // if left/right/top/bottom key\r\n if (axis) {\r\n // prevent page scroll\r\n e.preventDefault();\r\n\r\n const { currSlide } = pswp;\r\n\r\n if (pswp.options.arrowKeys\r\n && axis === 'x'\r\n && pswp.getNumItems() > 1) {\r\n keydownAction = isForward ? 'next' : 'prev';\r\n } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\r\n // up/down arrow keys pan the image vertically\r\n // left/right arrow keys pan horizontally.\r\n // Unless there is only one image,\r\n // or arrowKeys option is disabled\r\n currSlide.pan[axis] += isForward ? -80 : 80;\r\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\r\n }\r\n }\r\n\r\n if (keydownAction) {\r\n e.preventDefault();\r\n // @ts-ignore\r\n pswp[keydownAction]();\r\n }\r\n }\r\n\r\n /**\r\n * Trap focus inside photoswipe\r\n *\r\n * @private\r\n * @param {FocusEvent} e\r\n */\r\n _onFocusIn(e) {\r\n const { template } = this.pswp;\r\n if (template\r\n && document !== e.target\r\n && template !== e.target\r\n && !template.contains(/** @type {Node} */ (e.target))) {\r\n // focus root element\r\n template.focus();\r\n }\r\n }\r\n}\r\n\r\nexport default Keyboard;\r\n","import { setTransitionStyle, removeTransitionStyle } from './util.js';\r\n\r\nconst DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\r\n\r\n/** @typedef {Object} DefaultCssAnimationProps\r\n *\r\n * @prop {HTMLElement} target\r\n * @prop {number} [duration]\r\n * @prop {string} [easing]\r\n * @prop {string} [transform]\r\n * @prop {string} [opacity]\r\n * */\r\n\r\n/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */\r\n\r\n/**\r\n * Runs CSS transition.\r\n */\r\nclass CSSAnimation {\r\n /**\r\n * onComplete can be unpredictable, be careful about current state\r\n *\r\n * @param {CssAnimationProps} props\r\n */\r\n constructor(props) {\r\n this.props = props;\r\n const {\r\n target,\r\n onComplete,\r\n transform,\r\n onFinish = () => {},\r\n duration = 333,\r\n easing = DEFAULT_EASING,\r\n } = props;\r\n\r\n this.onFinish = onFinish;\r\n\r\n // support only transform and opacity\r\n const prop = transform ? 'transform' : 'opacity';\r\n const propValue = props[prop] ?? '';\r\n\r\n /** @private */\r\n this._target = target;\r\n /** @private */\r\n this._onComplete = onComplete;\r\n /** @private */\r\n this._finished = false;\r\n\r\n /** @private */\r\n this._onTransitionEnd = this._onTransitionEnd.bind(this);\r\n\r\n // Using timeout hack to make sure that animation\r\n // starts even if the animated property was changed recently,\r\n // otherwise transitionend might not fire or transition won't start.\r\n // https://drafts.csswg.org/css-transitions/#starting\r\n //\r\n // ¯\\_(ツ)_/¯\r\n /** @private */\r\n this._helperTimeout = setTimeout(() => {\r\n setTransitionStyle(target, prop, duration, easing);\r\n this._helperTimeout = setTimeout(() => {\r\n target.addEventListener('transitionend', this._onTransitionEnd, false);\r\n target.addEventListener('transitioncancel', this._onTransitionEnd, false);\r\n\r\n // Safari occasionally does not emit transitionend event\r\n // if element property was modified during the transition,\r\n // which may be caused by resize or third party component,\r\n // using timeout as a safety fallback\r\n this._helperTimeout = setTimeout(() => {\r\n this._finalizeAnimation();\r\n }, duration + 500);\r\n target.style[prop] = propValue;\r\n }, 30); // Do not reduce this number\r\n }, 0);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {TransitionEvent} e\r\n */\r\n _onTransitionEnd(e) {\r\n if (e.target === this._target) {\r\n this._finalizeAnimation();\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n */\r\n _finalizeAnimation() {\r\n if (!this._finished) {\r\n this._finished = true;\r\n this.onFinish();\r\n if (this._onComplete) {\r\n this._onComplete();\r\n }\r\n }\r\n }\r\n\r\n // Destroy is called automatically onFinish\r\n destroy() {\r\n if (this._helperTimeout) {\r\n clearTimeout(this._helperTimeout);\r\n }\r\n removeTransitionStyle(this._target);\r\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\r\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\r\n if (!this._finished) {\r\n this._finalizeAnimation();\r\n }\r\n }\r\n}\r\n\r\nexport default CSSAnimation;\r\n","const DEFAULT_NATURAL_FREQUENCY = 12;\r\nconst DEFAULT_DAMPING_RATIO = 0.75;\r\n\r\n/**\r\n * Spring easing helper\r\n */\r\nclass SpringEaser {\r\n /**\r\n * @param {number} initialVelocity Initial velocity, px per ms.\r\n *\r\n * @param {number} [dampingRatio]\r\n * Determines how bouncy animation will be.\r\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\r\n * \"overshoot\" refers to part of animation that\r\n * goes beyond the final value.\r\n *\r\n * @param {number} [naturalFrequency]\r\n * Determines how fast animation will slow down.\r\n * The higher value - the stiffer the transition will be,\r\n * and the faster it will slow down.\r\n * Recommended value from 10 to 50\r\n */\r\n constructor(initialVelocity, dampingRatio, naturalFrequency) {\r\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\r\n\r\n // https://en.wikipedia.org/wiki/Damping_ratio\r\n this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO;\r\n\r\n // https://en.wikipedia.org/wiki/Natural_frequency\r\n this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY;\r\n\r\n this._dampedFrequency = this._naturalFrequency;\r\n\r\n if (this._dampingRatio < 1) {\r\n this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} deltaPosition Difference between current and end position of the animation\r\n * @param {number} deltaTime Frame duration in milliseconds\r\n *\r\n * @returns {number} Displacement, relative to the end position.\r\n */\r\n easeFrame(deltaPosition, deltaTime) {\r\n // Inspired by Apple Webkit and Android spring function implementation\r\n // https://en.wikipedia.org/wiki/Oscillation\r\n // https://en.wikipedia.org/wiki/Damping_ratio\r\n // we ignore mass (assume that it's 1kg)\r\n\r\n let displacement = 0;\r\n let coeff;\r\n\r\n deltaTime /= 1000;\r\n\r\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\r\n\r\n if (this._dampingRatio === 1) {\r\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\r\n\r\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\r\n\r\n this.velocity = displacement\r\n * (-this._naturalFrequency) + coeff\r\n * naturalDumpingPow;\r\n } else if (this._dampingRatio < 1) {\r\n coeff = (1 / this._dampedFrequency)\r\n * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\r\n\r\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\r\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\r\n\r\n displacement = naturalDumpingPow\r\n * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\r\n\r\n this.velocity = displacement\r\n * (-this._naturalFrequency)\r\n * this._dampingRatio\r\n + naturalDumpingPow\r\n * (-this._dampedFrequency * deltaPosition * dumpedFSin\r\n + this._dampedFrequency * coeff * dumpedFCos);\r\n }\r\n\r\n // Overdamped (>1) damping ratio is not supported\r\n\r\n return displacement;\r\n }\r\n}\r\n\r\nexport default SpringEaser;\r\n","import SpringEaser from './spring-easer.js';\r\n\r\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\r\n\r\n/**\r\n * @typedef {Object} DefaultSpringAnimationProps\r\n *\r\n * @prop {number} start\r\n * @prop {number} end\r\n * @prop {number} velocity\r\n * @prop {number} [dampingRatio]\r\n * @prop {number} [naturalFrequency]\r\n * @prop {(end: number) => void} onUpdate\r\n */\r\n\r\n/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */\r\n\r\nclass SpringAnimation {\r\n /**\r\n * @param {SpringAnimationProps} props\r\n */\r\n constructor(props) {\r\n this.props = props;\r\n this._raf = 0;\r\n\r\n const {\r\n start,\r\n end,\r\n velocity,\r\n onUpdate,\r\n onComplete,\r\n onFinish = () => {},\r\n dampingRatio,\r\n naturalFrequency\r\n } = props;\r\n\r\n this.onFinish = onFinish;\r\n\r\n const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency);\r\n let prevTime = Date.now();\r\n let deltaPosition = start - end;\r\n\r\n const animationLoop = () => {\r\n if (this._raf) {\r\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime);\r\n\r\n // Stop the animation if velocity is low and position is close to end\r\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\r\n // Finalize the animation\r\n onUpdate(end);\r\n if (onComplete) {\r\n onComplete();\r\n }\r\n this.onFinish();\r\n } else {\r\n prevTime = Date.now();\r\n onUpdate(deltaPosition + end);\r\n this._raf = requestAnimationFrame(animationLoop);\r\n }\r\n }\r\n };\r\n\r\n this._raf = requestAnimationFrame(animationLoop);\r\n }\r\n\r\n // Destroy is called automatically onFinish\r\n destroy() {\r\n if (this._raf >= 0) {\r\n cancelAnimationFrame(this._raf);\r\n }\r\n this._raf = 0;\r\n }\r\n}\r\n\r\nexport default SpringAnimation;\r\n","import CSSAnimation from './css-animation.js';\r\nimport SpringAnimation from './spring-animation.js';\r\n\r\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */\r\n/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */\r\n\r\n/** @typedef {Object} SharedAnimationProps\r\n * @prop {string} [name]\r\n * @prop {boolean} [isPan]\r\n * @prop {boolean} [isMainScroll]\r\n * @prop {VoidFunction} [onComplete]\r\n * @prop {VoidFunction} [onFinish]\r\n */\r\n\r\n/** @typedef {SpringAnimation | CSSAnimation} Animation */\r\n/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */\r\n\r\n/**\r\n * Manages animations\r\n */\r\nclass Animations {\r\n constructor() {\r\n /** @type {Animation[]} */\r\n this.activeAnimations = [];\r\n }\r\n\r\n /**\r\n * @param {SpringAnimationProps} props\r\n */\r\n startSpring(props) {\r\n this._start(props, true);\r\n }\r\n\r\n /**\r\n * @param {CssAnimationProps} props\r\n */\r\n startTransition(props) {\r\n this._start(props);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {AnimationProps} props\r\n * @param {boolean} [isSpring]\r\n * @returns {Animation}\r\n */\r\n _start(props, isSpring) {\r\n const animation = isSpring\r\n ? new SpringAnimation(/** @type SpringAnimationProps */ (props))\r\n : new CSSAnimation(/** @type CssAnimationProps */ (props));\r\n\r\n this.activeAnimations.push(animation);\r\n animation.onFinish = () => this.stop(animation);\r\n\r\n return animation;\r\n }\r\n\r\n /**\r\n * @param {Animation} animation\r\n */\r\n stop(animation) {\r\n animation.destroy();\r\n const index = this.activeAnimations.indexOf(animation);\r\n if (index > -1) {\r\n this.activeAnimations.splice(index, 1);\r\n }\r\n }\r\n\r\n stopAll() { // _stopAllAnimations\r\n this.activeAnimations.forEach((animation) => {\r\n animation.destroy();\r\n });\r\n this.activeAnimations = [];\r\n }\r\n\r\n /**\r\n * Stop all pan or zoom transitions\r\n */\r\n stopAllPan() {\r\n this.activeAnimations = this.activeAnimations.filter((animation) => {\r\n if (animation.props.isPan) {\r\n animation.destroy();\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n stopMainScroll() {\r\n this.activeAnimations = this.activeAnimations.filter((animation) => {\r\n if (animation.props.isMainScroll) {\r\n animation.destroy();\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n /**\r\n * Returns true if main scroll transition is running\r\n */\r\n // isMainScrollRunning() {\r\n // return this.activeAnimations.some((animation) => {\r\n // return animation.props.isMainScroll;\r\n // });\r\n // }\r\n\r\n /**\r\n * Returns true if any pan or zoom transition is running\r\n */\r\n isPanRunning() {\r\n return this.activeAnimations.some((animation) => {\r\n return animation.props.isPan;\r\n });\r\n }\r\n}\r\n\r\nexport default Animations;\r\n","/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * Handles scroll wheel.\r\n * Can pan and zoom current slide image.\r\n */\r\nclass ScrollWheel {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n pswp.events.add(pswp.element, 'wheel', /** @type EventListener */(this._onWheel.bind(this)));\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {WheelEvent} e\r\n */\r\n _onWheel(e) {\r\n e.preventDefault();\r\n const { currSlide } = this.pswp;\r\n let { deltaX, deltaY } = e;\r\n\r\n if (!currSlide) {\r\n return;\r\n }\r\n\r\n if (this.pswp.dispatch('wheel', { originalEvent: e }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (e.ctrlKey || this.pswp.options.wheelToZoom) {\r\n // zoom\r\n if (currSlide.isZoomable()) {\r\n let zoomFactor = -deltaY;\r\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\r\n zoomFactor *= 0.05;\r\n } else {\r\n zoomFactor *= e.deltaMode ? 1 : 0.002;\r\n }\r\n zoomFactor = 2 ** zoomFactor;\r\n\r\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\r\n currSlide.zoomTo(destZoomLevel, {\r\n x: e.clientX,\r\n y: e.clientY\r\n });\r\n }\r\n } else {\r\n // pan\r\n if (currSlide.isPannable()) {\r\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\r\n // 18 - average line height\r\n deltaX *= 18;\r\n deltaY *= 18;\r\n }\r\n\r\n currSlide.panTo(\r\n currSlide.pan.x - deltaX,\r\n currSlide.pan.y - deltaY\r\n );\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport default ScrollWheel;\r\n","import { createElement } from '../util/util.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Methods} Methods\r\n */\r\n\r\n/**\r\n * @typedef {Object} UIElementMarkupProps\r\n * @prop {boolean} [isCustomSVG]\r\n * @prop {string} inner\r\n * @prop {string} [outlineID]\r\n * @prop {number | string} [size]\r\n */\r\n\r\n/**\r\n * @typedef {Object} UIElementData\r\n * @prop {DefaultUIElements | string} [name]\r\n * @prop {string} [className]\r\n * @prop {UIElementMarkup} [html]\r\n * @prop {boolean} [isButton]\r\n * @prop {keyof HTMLElementTagNameMap} [tagName]\r\n * @prop {string} [title]\r\n * @prop {string} [ariaLabel]\r\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\r\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\r\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\r\n * @prop {number} [order]\r\n */\r\n\r\n/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */\r\n\r\n/** @typedef {string | UIElementMarkupProps} UIElementMarkup */\r\n\r\n/**\r\n * @param {UIElementMarkup} [htmlData]\r\n * @returns {string}\r\n */\r\nfunction addElementHTML(htmlData) {\r\n if (typeof htmlData === 'string') {\r\n // Allow developers to provide full svg,\r\n // For example:\r\n // \r\n // \r\n // \r\n // \r\n // Can also be any HTML string.\r\n return htmlData;\r\n }\r\n\r\n if (!htmlData || !htmlData.isCustomSVG) {\r\n return '';\r\n }\r\n\r\n const svgData = htmlData;\r\n let out = '';\r\n // replace all %d with size\r\n out = out.split('%d').join(/** @type {string} */ (svgData.size || 32));\r\n\r\n // Icons may contain outline/shadow,\r\n // to make it we \"clone\" base icon shape and add border to it.\r\n // Icon itself and border are styled via CSS.\r\n //\r\n // Property shadowID defines ID of element that should be cloned.\r\n if (svgData.outlineID) {\r\n out += '';\r\n }\r\n\r\n out += svgData.inner;\r\n\r\n out += '';\r\n\r\n return out;\r\n}\r\n\r\nclass UIElement {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n * @param {UIElementData} data\r\n */\r\n constructor(pswp, data) {\r\n const name = data.name || data.className;\r\n let elementHTML = data.html;\r\n\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (pswp.options[name] === false) {\r\n // exit if element is disabled from options\r\n return;\r\n }\r\n\r\n // Allow to override SVG icons from options\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (typeof pswp.options[name + 'SVG'] === 'string') {\r\n // arrowPrevSVG\r\n // arrowNextSVG\r\n // closeSVG\r\n // zoomSVG\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n elementHTML = pswp.options[name + 'SVG'];\r\n }\r\n\r\n pswp.dispatch('uiElementCreate', { data });\r\n\r\n let className = '';\r\n if (data.isButton) {\r\n className += 'pswp__button ';\r\n className += (data.className || `pswp__button--${data.name}`);\r\n } else {\r\n className += (data.className || `pswp__${data.name}`);\r\n }\r\n\r\n let tagName = data.isButton ? (data.tagName || 'button') : (data.tagName || 'div');\r\n tagName = /** @type {keyof HTMLElementTagNameMap} */ (tagName.toLowerCase());\r\n /** @type {HTMLElement} */\r\n const element = createElement(className, tagName);\r\n\r\n if (data.isButton) {\r\n if (tagName === 'button') {\r\n /** @type {HTMLButtonElement} */ (element).type = 'button';\r\n }\r\n\r\n let { title } = data;\r\n const { ariaLabel } = data;\r\n\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n if (typeof pswp.options[name + 'Title'] === 'string') {\r\n // @ts-expect-error lookup only by `data.name` maybe?\r\n title = pswp.options[name + 'Title'];\r\n }\r\n\r\n if (title) {\r\n element.title = title;\r\n }\r\n\r\n const ariaText = ariaLabel || title;\r\n if (ariaText) {\r\n element.setAttribute('aria-label', ariaText);\r\n }\r\n }\r\n\r\n element.innerHTML = addElementHTML(elementHTML);\r\n\r\n if (data.onInit) {\r\n data.onInit(element, pswp);\r\n }\r\n\r\n if (data.onClick) {\r\n element.onclick = (e) => {\r\n if (typeof data.onClick === 'string') {\r\n // @ts-ignore\r\n pswp[data.onClick]();\r\n } else if (typeof data.onClick === 'function') {\r\n data.onClick(e, element, pswp);\r\n }\r\n };\r\n }\r\n\r\n // Top bar is default position\r\n const appendTo = data.appendTo || 'bar';\r\n /** @type {HTMLElement | undefined} root element by default */\r\n let container = pswp.element;\r\n if (appendTo === 'bar') {\r\n if (!pswp.topBar) {\r\n pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\r\n }\r\n container = pswp.topBar;\r\n } else {\r\n // element outside of top bar gets a secondary class\r\n // that makes element fade out on close\r\n element.classList.add('pswp__hide-on-close');\r\n\r\n if (appendTo === 'wrapper') {\r\n container = pswp.scrollWrap;\r\n }\r\n }\r\n\r\n container?.appendChild(pswp.applyFilters('uiElement', element, data));\r\n }\r\n}\r\n\r\nexport default UIElement;\r\n","/*\r\n Backward and forward arrow buttons\r\n */\r\n\r\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/**\r\n *\r\n * @param {HTMLElement} element\r\n * @param {PhotoSwipe} pswp\r\n * @param {boolean} [isNextButton]\r\n */\r\nfunction initArrowButton(element, pswp, isNextButton) {\r\n element.classList.add('pswp__button--arrow');\r\n // TODO: this should point to a unique id for this instance\r\n element.setAttribute('aria-controls', 'pswp__items');\r\n pswp.on('change', () => {\r\n if (!pswp.options.loop) {\r\n if (isNextButton) {\r\n /** @type {HTMLButtonElement} */\r\n (element).disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\r\n } else {\r\n /** @type {HTMLButtonElement} */\r\n (element).disabled = !(pswp.currIndex > 0);\r\n }\r\n }\r\n });\r\n}\r\n\r\n/** @type {UIElementData} */\r\nexport const arrowPrev = {\r\n name: 'arrowPrev',\r\n className: 'pswp__button--arrow--prev',\r\n title: 'Previous',\r\n order: 10,\r\n isButton: true,\r\n appendTo: 'wrapper',\r\n html: {\r\n isCustomSVG: true,\r\n size: 60,\r\n inner: '',\r\n outlineID: 'pswp__icn-arrow'\r\n },\r\n onClick: 'prev',\r\n onInit: initArrowButton\r\n};\r\n\r\n/** @type {UIElementData} */\r\nexport const arrowNext = {\r\n name: 'arrowNext',\r\n className: 'pswp__button--arrow--next',\r\n title: 'Next',\r\n order: 11,\r\n isButton: true,\r\n appendTo: 'wrapper',\r\n html: {\r\n isCustomSVG: true,\r\n size: 60,\r\n inner: '',\r\n outlineID: 'pswp__icn-arrow'\r\n },\r\n onClick: 'next',\r\n onInit: (el, pswp) => {\r\n initArrowButton(el, pswp, true);\r\n }\r\n};\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nconst closeButton = {\r\n name: 'close',\r\n title: 'Close',\r\n order: 20,\r\n isButton: true,\r\n html: {\r\n isCustomSVG: true,\r\n inner: '',\r\n outlineID: 'pswp__icn-close'\r\n },\r\n onClick: 'close'\r\n};\r\n\r\nexport default closeButton;\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nconst zoomButton = {\r\n name: 'zoom',\r\n title: 'Zoom',\r\n order: 10,\r\n isButton: true,\r\n html: {\r\n isCustomSVG: true,\r\n // eslint-disable-next-line max-len\r\n inner: ''\r\n + ''\r\n + '',\r\n outlineID: 'pswp__icn-zoom'\r\n },\r\n onClick: 'toggleZoom'\r\n};\r\n\r\nexport default zoomButton;\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nexport const loadingIndicator = {\r\n name: 'preloader',\r\n appendTo: 'bar',\r\n order: 7,\r\n html: {\r\n isCustomSVG: true,\r\n // eslint-disable-next-line max-len\r\n inner: '',\r\n outlineID: 'pswp__icn-loading'\r\n },\r\n onInit: (indicatorElement, pswp) => {\r\n /** @type {boolean | undefined} */\r\n let isVisible;\r\n /** @type {NodeJS.Timeout | null} */\r\n let delayTimeout = null;\r\n\r\n /**\r\n * @param {string} className\r\n * @param {boolean} add\r\n */\r\n const toggleIndicatorClass = (className, add) => {\r\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\r\n };\r\n\r\n /**\r\n * @param {boolean} visible\r\n */\r\n const setIndicatorVisibility = (visible) => {\r\n if (isVisible !== visible) {\r\n isVisible = visible;\r\n toggleIndicatorClass('active', visible);\r\n }\r\n };\r\n\r\n const updatePreloaderVisibility = () => {\r\n if (!pswp.currSlide?.content.isLoading()) {\r\n setIndicatorVisibility(false);\r\n if (delayTimeout) {\r\n clearTimeout(delayTimeout);\r\n delayTimeout = null;\r\n }\r\n return;\r\n }\r\n\r\n if (!delayTimeout) {\r\n // display loading indicator with delay\r\n delayTimeout = setTimeout(() => {\r\n setIndicatorVisibility(Boolean(pswp.currSlide?.content.isLoading()));\r\n delayTimeout = null;\r\n }, pswp.options.preloaderDelay);\r\n }\r\n };\r\n\r\n pswp.on('change', updatePreloaderVisibility);\r\n\r\n pswp.on('loadComplete', (e) => {\r\n if (pswp.currSlide === e.slide) {\r\n updatePreloaderVisibility();\r\n }\r\n });\r\n\r\n // expose the method\r\n if (pswp.ui) {\r\n pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\r\n }\r\n }\r\n};\r\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\r\nexport const counterIndicator = {\r\n name: 'counter',\r\n order: 5,\r\n onInit: (counterElement, pswp) => {\r\n pswp.on('change', () => {\r\n counterElement.innerText = (pswp.currIndex + 1)\r\n + pswp.options.indexIndicatorSep\r\n + pswp.getNumItems();\r\n });\r\n }\r\n};\r\n","import UIElement from './ui-element.js';\r\nimport { arrowPrev, arrowNext } from './button-arrow.js';\r\nimport closeButton from './button-close.js';\r\nimport zoomButton from './button-zoom.js';\r\nimport { loadingIndicator } from './loading-indicator.js';\r\nimport { counterIndicator } from './counter-indicator.js';\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\r\n\r\n/**\r\n * Set special class on element when image is zoomed.\r\n *\r\n * By default, it is used to adjust\r\n * zoom icon and zoom cursor via CSS.\r\n *\r\n * @param {HTMLElement} el\r\n * @param {boolean} isZoomedIn\r\n */\r\nfunction setZoomedIn(el, isZoomedIn) {\r\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\r\n}\r\n\r\nclass UI {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.isRegistered = false;\r\n /** @type {UIElementData[]} */\r\n this.uiElementsData = [];\r\n /** @type {(UIElement | UIElementData)[]} */\r\n this.items = [];\r\n /** @type {() => void} */\r\n this.updatePreloaderVisibility = () => {};\r\n\r\n /**\r\n * @private\r\n * @type {number | undefined}\r\n */\r\n this._lastUpdatedZoomLevel = undefined;\r\n }\r\n\r\n init() {\r\n const { pswp } = this;\r\n this.isRegistered = false;\r\n this.uiElementsData = [\r\n closeButton,\r\n arrowPrev,\r\n arrowNext,\r\n zoomButton,\r\n loadingIndicator,\r\n counterIndicator\r\n ];\r\n\r\n pswp.dispatch('uiRegister');\r\n\r\n // sort by order\r\n this.uiElementsData.sort((a, b) => {\r\n // default order is 0\r\n return (a.order || 0) - (b.order || 0);\r\n });\r\n\r\n this.items = [];\r\n\r\n this.isRegistered = true;\r\n this.uiElementsData.forEach((uiElementData) => {\r\n this.registerElement(uiElementData);\r\n });\r\n\r\n pswp.on('change', () => {\r\n pswp.element?.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\r\n });\r\n\r\n pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate());\r\n }\r\n\r\n /**\r\n * @param {UIElementData} elementData\r\n */\r\n registerElement(elementData) {\r\n if (this.isRegistered) {\r\n this.items.push(\r\n new UIElement(this.pswp, elementData)\r\n );\r\n } else {\r\n this.uiElementsData.push(elementData);\r\n }\r\n }\r\n\r\n /**\r\n * Fired each time zoom or pan position is changed.\r\n * Update classes that control visibility of zoom button and cursor icon.\r\n *\r\n * @private\r\n */\r\n _onZoomPanUpdate() {\r\n const { template, currSlide, options } = this.pswp;\r\n\r\n if (this.pswp.opener.isClosing || !template || !currSlide) {\r\n return;\r\n }\r\n\r\n let { currZoomLevel } = currSlide;\r\n\r\n // if not open yet - check against initial zoom level\r\n if (!this.pswp.opener.isOpen) {\r\n currZoomLevel = currSlide.zoomLevels.initial;\r\n }\r\n\r\n if (currZoomLevel === this._lastUpdatedZoomLevel) {\r\n return;\r\n }\r\n this._lastUpdatedZoomLevel = currZoomLevel;\r\n\r\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary;\r\n\r\n // Initial and secondary zoom levels are almost equal\r\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\r\n // disable zoom\r\n setZoomedIn(template, false);\r\n template.classList.remove('pswp--zoom-allowed');\r\n return;\r\n }\r\n\r\n template.classList.add('pswp--zoom-allowed');\r\n\r\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial\r\n ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\r\n\r\n setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\r\n\r\n if (options.imageClickAction === 'zoom'\r\n || options.imageClickAction === 'zoom-or-close') {\r\n template.classList.add('pswp--click-to-zoom');\r\n }\r\n }\r\n}\r\n\r\nexport default UI;\r\n","/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\n/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n * @returns Bounds\r\n */\r\nfunction getBoundsByElement(el) {\r\n const thumbAreaRect = el.getBoundingClientRect();\r\n return {\r\n x: thumbAreaRect.left,\r\n y: thumbAreaRect.top,\r\n w: thumbAreaRect.width\r\n };\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n * @param {number} imageWidth\r\n * @param {number} imageHeight\r\n * @returns Bounds\r\n */\r\nfunction getCroppedBoundsByElement(el, imageWidth, imageHeight) {\r\n const thumbAreaRect = el.getBoundingClientRect();\r\n\r\n // fill image into the area\r\n // (do they same as object-fit:cover does to retrieve coordinates)\r\n const hRatio = thumbAreaRect.width / imageWidth;\r\n const vRatio = thumbAreaRect.height / imageHeight;\r\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\r\n\r\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\r\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\r\n\r\n /**\r\n * Coordinates of the image,\r\n * as if it was not cropped,\r\n * height is calculated automatically\r\n *\r\n * @type {Bounds}\r\n */\r\n const bounds = {\r\n x: thumbAreaRect.left + offsetX,\r\n y: thumbAreaRect.top + offsetY,\r\n w: imageWidth * fillZoomLevel\r\n };\r\n\r\n // Coordinates of inner crop area\r\n // relative to the image\r\n bounds.innerRect = {\r\n w: thumbAreaRect.width,\r\n h: thumbAreaRect.height,\r\n x: offsetX,\r\n y: offsetY\r\n };\r\n\r\n return bounds;\r\n}\r\n\r\n/**\r\n * Get dimensions of thumbnail image\r\n * (click on which opens photoswipe or closes photoswipe to)\r\n *\r\n * @param {number} index\r\n * @param {SlideData} itemData\r\n * @param {PhotoSwipe} instance PhotoSwipe instance\r\n * @returns {Bounds | undefined}\r\n */\r\nexport function getThumbBounds(index, itemData, instance) {\r\n // legacy event, before filters were introduced\r\n const event = instance.dispatch('thumbBounds', {\r\n index,\r\n itemData,\r\n instance\r\n });\r\n // @ts-expect-error\r\n if (event.thumbBounds) {\r\n // @ts-expect-error\r\n return event.thumbBounds;\r\n }\r\n\r\n const { element } = itemData;\r\n /** @type {Bounds | undefined} */\r\n let thumbBounds;\r\n /** @type {HTMLElement | null | undefined} */\r\n let thumbnail;\r\n\r\n if (element && instance.options.thumbSelector !== false) {\r\n const thumbSelector = instance.options.thumbSelector || 'img';\r\n thumbnail = element.matches(thumbSelector)\r\n ? element : /** @type {HTMLElement | null} */ (element.querySelector(thumbSelector));\r\n }\r\n\r\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\r\n\r\n if (thumbnail) {\r\n if (!itemData.thumbCropped) {\r\n thumbBounds = getBoundsByElement(thumbnail);\r\n } else {\r\n thumbBounds = getCroppedBoundsByElement(\r\n thumbnail,\r\n itemData.width || itemData.w || 0,\r\n itemData.height || itemData.h || 0\r\n );\r\n }\r\n }\r\n\r\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\r\n}\r\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../slide/content.js').default} ContentDefault */\r\n/** @typedef {import('../slide/slide.js').default} Slide */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\r\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\r\n\r\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\r\n/** @typedef {{ x?: number; y?: number }} Point */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\r\n\r\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\r\nclass PhotoSwipeEvent {\r\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\r\n constructor(type, details) {\r\n this.type = type;\r\n this.defaultPrevented = false;\r\n if (details) {\r\n Object.assign(this, details);\r\n }\r\n }\r\n\r\n preventDefault() {\r\n this.defaultPrevented = true;\r\n }\r\n}\r\n\r\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\r\nclass Eventable {\r\n constructor() {\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\r\n this._listeners = {};\r\n\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\r\n this._filters = {};\r\n\r\n /** @type {PhotoSwipe | undefined} */\r\n this.pswp = undefined;\r\n\r\n /** @type {PhotoSwipeOptions | undefined} */\r\n this.options = undefined;\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\r\n addFilter(name, fn, priority = 100) {\r\n if (!this._filters[name]) {\r\n this._filters[name] = [];\r\n }\r\n\r\n this._filters[name]?.push({ fn, priority });\r\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\r\n\r\n this.pswp?.addFilter(name, fn, priority);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\r\n removeFilter(name, fn) {\r\n if (this._filters[name]) {\r\n // @ts-expect-error\r\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\r\n }\r\n\r\n if (this.pswp) {\r\n this.pswp.removeFilter(name, fn);\r\n }\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\r\n applyFilters(name, ...args) {\r\n this._filters[name]?.forEach((filter) => {\r\n // @ts-expect-error\r\n args[0] = filter.fn.apply(this, args);\r\n });\r\n return args[0];\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n on(name, fn) {\r\n if (!this._listeners[name]) {\r\n this._listeners[name] = [];\r\n }\r\n this._listeners[name]?.push(fn);\r\n\r\n // When binding events to lightbox,\r\n // also bind events to PhotoSwipe Core,\r\n // if it's open.\r\n this.pswp?.on(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n off(name, fn) {\r\n if (this._listeners[name]) {\r\n // @ts-expect-error\r\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\r\n }\r\n\r\n this.pswp?.off(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\r\n dispatch(name, details) {\r\n if (this.pswp) {\r\n return this.pswp.dispatch(name, details);\r\n }\r\n\r\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\r\n\r\n this._listeners[name]?.forEach((listener) => {\r\n listener.call(this, event);\r\n });\r\n\r\n return event;\r\n }\r\n}\r\n\r\nexport default Eventable;\r\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\r\n\r\nclass Placeholder {\r\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\r\n constructor(imageSrc, container) {\r\n // Create placeholder\r\n // (stretched thumbnail or simple div behind the main image)\r\n /** @type {HTMLImageElement | HTMLDivElement | null} */\r\n this.element = createElement(\r\n 'pswp__img pswp__img--placeholder',\r\n imageSrc ? 'img' : 'div',\r\n container\r\n );\r\n\r\n if (imageSrc) {\r\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\r\n imgEl.decoding = 'async';\r\n imgEl.alt = '';\r\n imgEl.src = imageSrc;\r\n imgEl.setAttribute('role', 'presentation');\r\n }\r\n\r\n this.element.setAttribute('aria-hidden', 'true');\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.element.tagName === 'IMG') {\r\n // Use transform scale() to modify img placeholder size\r\n // (instead of changing width/height directly).\r\n // This helps with performance, specifically in iOS15 Safari.\r\n setWidthHeight(this.element, 250, 'auto');\r\n this.element.style.transformOrigin = '0 0';\r\n this.element.style.transform = toTransformString(0, 0, width / 250);\r\n } else {\r\n setWidthHeight(this.element, width, height);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.element?.parentNode) {\r\n this.element.remove();\r\n }\r\n this.element = null;\r\n }\r\n}\r\n\r\nexport default Placeholder;\r\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\r\nimport Placeholder from './placeholder.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../util/util.js').LoadState} LoadState */\r\n\r\nclass Content {\r\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\r\n constructor(itemData, instance, index) {\r\n this.instance = instance;\r\n this.data = itemData;\r\n this.index = index;\r\n\r\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {Placeholder | undefined} */\r\n this.placeholder = undefined;\r\n /** @type {Slide | undefined} */\r\n this.slide = undefined;\r\n\r\n this.displayedImageWidth = 0;\r\n this.displayedImageHeight = 0;\r\n\r\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\r\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\r\n\r\n this.isAttached = false;\r\n this.hasSlide = false;\r\n this.isDecoding = false;\r\n /** @type {LoadState} */\r\n this.state = LOAD_STATE.IDLE;\r\n\r\n if (this.data.type) {\r\n this.type = this.data.type;\r\n } else if (this.data.src) {\r\n this.type = 'image';\r\n } else {\r\n this.type = 'html';\r\n }\r\n\r\n this.instance.dispatch('contentInit', { content: this });\r\n }\r\n\r\n removePlaceholder() {\r\n if (this.placeholder && !this.keepPlaceholder()) {\r\n // With delay, as image might be loaded, but not rendered\r\n setTimeout(() => {\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\r\n load(isLazy, reload) {\r\n if (this.slide && this.usePlaceholder()) {\r\n if (!this.placeholder) {\r\n const placeholderSrc = this.instance.applyFilters(\r\n 'placeholderSrc',\r\n // use image-based placeholder only for the first slide,\r\n // as rendering (even small stretched thumbnail) is an expensive operation\r\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\r\n this\r\n );\r\n this.placeholder = new Placeholder(\r\n placeholderSrc,\r\n this.slide.container\r\n );\r\n } else {\r\n const placeholderEl = this.placeholder.element;\r\n // Add placeholder to DOM if it was already created\r\n if (placeholderEl && !placeholderEl.parentElement) {\r\n this.slide.container.prepend(placeholderEl);\r\n }\r\n }\r\n }\r\n\r\n if (this.element && !reload) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent()) {\r\n this.element = createElement('pswp__img', 'img');\r\n // Start loading only after width is defined, as sizes might depend on it.\r\n // Due to Safari feature, we must define sizes before srcset.\r\n if (this.displayedImageWidth) {\r\n this.loadImage(isLazy);\r\n }\r\n } else {\r\n this.element = createElement('pswp__content', 'div');\r\n this.element.innerHTML = this.data.html || '';\r\n }\r\n\r\n if (reload && this.slide) {\r\n this.slide.updateContentSize(true);\r\n }\r\n }\r\n\r\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\r\n loadImage(isLazy) {\r\n if (!this.isImageContent()\r\n || !this.element\r\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const imageElement = /** @type HTMLImageElement */ (this.element);\r\n\r\n this.updateSrcsetSizes();\r\n\r\n if (this.data.srcset) {\r\n imageElement.srcset = this.data.srcset;\r\n }\r\n\r\n imageElement.src = this.data.src ?? '';\r\n imageElement.alt = this.data.alt ?? '';\r\n\r\n this.state = LOAD_STATE.LOADING;\r\n\r\n if (imageElement.complete) {\r\n this.onLoaded();\r\n } else {\r\n imageElement.onload = () => {\r\n this.onLoaded();\r\n };\r\n\r\n imageElement.onerror = () => {\r\n this.onError();\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\r\n setSlide(slide) {\r\n this.slide = slide;\r\n this.hasSlide = true;\r\n this.instance = slide.pswp;\r\n\r\n // todo: do we need to unset slide?\r\n }\r\n\r\n /**\r\n * Content load success handler\r\n */\r\n onLoaded() {\r\n this.state = LOAD_STATE.LOADED;\r\n\r\n if (this.slide && this.element) {\r\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\r\n\r\n // if content is reloaded\r\n if (this.slide.isActive\r\n && this.slide.heavyAppended\r\n && !this.element.parentNode) {\r\n this.append();\r\n this.slide.updateContentSize(true);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Content load error handler\r\n */\r\n onError() {\r\n this.state = LOAD_STATE.ERROR;\r\n\r\n if (this.slide) {\r\n this.displayError();\r\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\r\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\r\n }\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\r\n isLoading() {\r\n return this.instance.applyFilters(\r\n 'isContentLoading',\r\n this.state === LOAD_STATE.LOADING,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\r\n isError() {\r\n return this.state === LOAD_STATE.ERROR;\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content is image\r\n */\r\n isImageContent() {\r\n return this.type === 'image';\r\n }\r\n\r\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.placeholder) {\r\n this.placeholder.setDisplayedSize(width, height);\r\n }\r\n\r\n if (this.instance.dispatch(\r\n 'contentResize',\r\n { content: this, width, height }).defaultPrevented\r\n ) {\r\n return;\r\n }\r\n\r\n setWidthHeight(this.element, width, height);\r\n\r\n if (this.isImageContent() && !this.isError()) {\r\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\r\n\r\n this.displayedImageWidth = width;\r\n this.displayedImageHeight = height;\r\n\r\n if (isInitialSizeUpdate) {\r\n this.loadImage(false);\r\n } else {\r\n this.updateSrcsetSizes();\r\n }\r\n\r\n if (this.slide) {\r\n this.instance.dispatch(\r\n 'imageSizeChange',\r\n { slide: this.slide, width, height, content: this }\r\n );\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\r\n isZoomable() {\r\n return this.instance.applyFilters(\r\n 'isContentZoomable',\r\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\r\n updateSrcsetSizes() {\r\n // Handle srcset sizes attribute.\r\n //\r\n // Never lower quality, if it was increased previously.\r\n // Chrome does this automatically, Firefox and Safari do not,\r\n // so we store largest used size in dataset.\r\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\r\n return;\r\n }\r\n\r\n const image = /** @type HTMLImageElement */ (this.element);\r\n const sizesWidth = this.instance.applyFilters(\r\n 'srcsetSizesWidth',\r\n this.displayedImageWidth,\r\n this\r\n );\r\n\r\n if (\r\n !image.dataset.largestUsedSize\r\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\r\n ) {\r\n image.sizes = sizesWidth + 'px';\r\n image.dataset.largestUsedSize = String(sizesWidth);\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\r\n usePlaceholder() {\r\n return this.instance.applyFilters(\r\n 'useContentPlaceholder',\r\n this.isImageContent(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Preload content with lazy-loading param\r\n */\r\n lazyLoad() {\r\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.load(true);\r\n }\r\n\r\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\r\n keepPlaceholder() {\r\n return this.instance.applyFilters(\r\n 'isKeepingPlaceholder',\r\n this.isLoading(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Destroy the content\r\n */\r\n destroy() {\r\n this.hasSlide = false;\r\n this.slide = undefined;\r\n\r\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.remove();\r\n\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n\r\n if (this.isImageContent() && this.element) {\r\n this.element.onload = null;\r\n this.element.onerror = null;\r\n this.element = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * Display error message\r\n */\r\n displayError() {\r\n if (this.slide) {\r\n let errorMsgEl = createElement('pswp__error-msg', 'div');\r\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\r\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\r\n 'contentErrorElement',\r\n errorMsgEl,\r\n this\r\n ));\r\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\r\n this.element.appendChild(errorMsgEl);\r\n this.slide.container.innerText = '';\r\n this.slide.container.appendChild(this.element);\r\n this.slide.updateContentSize(true);\r\n this.removePlaceholder();\r\n }\r\n }\r\n\r\n /**\r\n * Append the content\r\n */\r\n append() {\r\n if (this.isAttached || !this.element) {\r\n return;\r\n }\r\n\r\n this.isAttached = true;\r\n\r\n if (this.state === LOAD_STATE.ERROR) {\r\n this.displayError();\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const supportsDecode = ('decode' in this.element);\r\n\r\n if (this.isImageContent()) {\r\n // Use decode() on nearby slides\r\n //\r\n // Nearby slide images are in DOM and not hidden via display:none.\r\n // However, they are placed offscreen (to the left and right side).\r\n //\r\n // Some browsers do not composite the image until it's actually visible,\r\n // using decode() helps.\r\n //\r\n // You might ask \"why dont you just decode() and then append all images\",\r\n // that's because I want to show image before it's fully loaded,\r\n // as browser can render parts of image while it is loading.\r\n // We do not do this in Safari due to partial loading bug.\r\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\r\n this.isDecoding = true;\r\n // purposefully using finally instead of then,\r\n // as if srcset sizes changes dynamically - it may cause decode error\r\n /** @type {HTMLImageElement} */\r\n (this.element).decode().catch(() => {}).finally(() => {\r\n this.isDecoding = false;\r\n this.appendImage();\r\n });\r\n } else {\r\n this.appendImage();\r\n }\r\n } else if (this.slide && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n }\r\n\r\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\r\n activate() {\r\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\r\n || !this.slide) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\r\n // add image to slide when it becomes active,\r\n // even if it's not finished decoding\r\n this.appendImage();\r\n } else if (this.isError()) {\r\n this.load(false, true); // try to reload\r\n }\r\n\r\n if (this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\r\n }\r\n }\r\n\r\n /**\r\n * Deactivate the content\r\n */\r\n deactivate() {\r\n this.instance.dispatch('contentDeactivate', { content: this });\r\n if (this.slide && this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Remove the content from DOM\r\n */\r\n remove() {\r\n this.isAttached = false;\r\n\r\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.element && this.element.parentNode) {\r\n this.element.remove();\r\n }\r\n\r\n if (this.placeholder && this.placeholder.element) {\r\n this.placeholder.element.remove();\r\n }\r\n }\r\n\r\n /**\r\n * Append the image content to slide container\r\n */\r\n appendImage() {\r\n if (!this.isAttached) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n // ensure that element exists and is not already appended\r\n if (this.slide && this.element && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n}\r\n\r\nexport default Content;\r\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\r\nimport ZoomLevel from './zoom-level.js';\r\n\r\n/** @typedef {import('./content.js').default} Content */\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\nconst MIN_SLIDES_TO_CACHE = 5;\r\n\r\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\nexport function lazyLoadData(itemData, instance, index) {\r\n const content = instance.createContentFromData(itemData, index);\r\n /** @type {ZoomLevel | undefined} */\r\n let zoomLevel;\r\n\r\n const { options } = instance;\r\n\r\n // We need to know dimensions of the image to preload it,\r\n // as it might use srcset, and we need to define sizes\r\n if (options) {\r\n zoomLevel = new ZoomLevel(options, itemData, -1);\r\n\r\n let viewportSize;\r\n if (instance.pswp) {\r\n viewportSize = instance.pswp.viewportSize;\r\n } else {\r\n viewportSize = getViewportSize(options, instance);\r\n }\r\n\r\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\r\n zoomLevel.update(content.width, content.height, panAreaSize);\r\n }\r\n\r\n content.lazyLoad();\r\n\r\n if (zoomLevel) {\r\n content.setDisplayedSize(\r\n Math.ceil(content.width * zoomLevel.initial),\r\n Math.ceil(content.height * zoomLevel.initial)\r\n );\r\n }\r\n\r\n return content;\r\n}\r\n\r\n\r\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\r\nexport function lazyLoadSlide(index, instance) {\r\n const itemData = instance.getItemData(index);\r\n\r\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n return lazyLoadData(itemData, instance, index);\r\n}\r\n\r\nclass ContentLoader {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n // Total amount of cached images\r\n this.limit = Math.max(\r\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\r\n MIN_SLIDES_TO_CACHE\r\n );\r\n /** @type {Content[]} */\r\n this._cachedItems = [];\r\n }\r\n\r\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\r\n updateLazy(diff) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\r\n return;\r\n }\r\n\r\n const { preload } = pswp.options;\r\n const isForward = diff === undefined ? true : (diff >= 0);\r\n let i;\r\n\r\n // preload[1] - num items to preload in forward direction\r\n for (i = 0; i <= preload[1]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\r\n }\r\n\r\n // preload[0] - num items to preload in backward direction\r\n for (i = 1; i <= preload[0]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} initialIndex\r\n */\r\n loadSlideByIndex(initialIndex) {\r\n const index = this.pswp.getLoopedIndex(initialIndex);\r\n // try to get cached content\r\n let content = this.getContentByIndex(index);\r\n if (!content) {\r\n // no cached content, so try to load from scratch:\r\n content = lazyLoadSlide(index, this.pswp);\r\n // if content can be loaded, add it to cache:\r\n if (content) {\r\n this.addToCache(content);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\r\n getContentBySlide(slide) {\r\n let content = this.getContentByIndex(slide.index);\r\n if (!content) {\r\n // create content if not found in cache\r\n content = this.pswp.createContentFromData(slide.data, slide.index);\r\n this.addToCache(content);\r\n }\r\n\r\n // assign slide to content\r\n content.setSlide(slide);\r\n\r\n return content;\r\n }\r\n\r\n /**\r\n * @param {Content} content\r\n */\r\n addToCache(content) {\r\n // move to the end of array\r\n this.removeByIndex(content.index);\r\n this._cachedItems.push(content);\r\n\r\n if (this._cachedItems.length > this.limit) {\r\n // Destroy the first content that's not attached\r\n const indexToRemove = this._cachedItems.findIndex((item) => {\r\n return !item.isAttached && !item.hasSlide;\r\n });\r\n if (indexToRemove !== -1) {\r\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\r\n removedItem.destroy();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\r\n removeByIndex(index) {\r\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\r\n if (indexToRemove !== -1) {\r\n this._cachedItems.splice(indexToRemove, 1);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\r\n getContentByIndex(index) {\r\n return this._cachedItems.find(content => content.index === index);\r\n }\r\n\r\n destroy() {\r\n this._cachedItems.forEach(content => content.destroy());\r\n this._cachedItems = [];\r\n }\r\n}\r\n\r\nexport default ContentLoader;\r\n","import Eventable from './eventable.js';\r\nimport { getElementsFromOption } from '../util/util.js';\r\nimport Content from '../slide/content.js';\r\nimport { lazyLoadData } from '../slide/loader.js';\r\n\r\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\r\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\r\n\r\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\r\nclass PhotoSwipeBase extends Eventable {\r\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\r\n getNumItems() {\r\n let numItems = 0;\r\n const dataSource = this.options?.dataSource;\r\n\r\n if (dataSource && 'length' in dataSource) {\r\n // may be an array or just object with length property\r\n numItems = dataSource.length;\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n if (dataSource.items) {\r\n numItems = dataSource.items.length;\r\n }\r\n }\r\n\r\n // legacy event, before filters were introduced\r\n const event = this.dispatch('numItems', {\r\n dataSource,\r\n numItems\r\n });\r\n return this.applyFilters('numItems', event.numItems, dataSource);\r\n }\r\n\r\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\r\n createContentFromData(slideData, index) {\r\n return new Content(slideData, this, index);\r\n }\r\n\r\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\r\n getItemData(index) {\r\n const dataSource = this.options?.dataSource;\r\n /** @type {SlideData | HTMLElement} */\r\n let dataSourceItem = {};\r\n if (Array.isArray(dataSource)) {\r\n // Datasource is an array of elements\r\n dataSourceItem = dataSource[index];\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // dataSource has gallery property,\r\n // thus it was created by Lightbox, based on\r\n // gallery and children options\r\n\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n dataSourceItem = dataSource.items[index];\r\n }\r\n\r\n let itemData = dataSourceItem;\r\n\r\n if (itemData instanceof Element) {\r\n itemData = this._domElementToItemData(itemData);\r\n }\r\n\r\n // Dispatching the itemData event,\r\n // it's a legacy verion before filters were introduced\r\n const event = this.dispatch('itemData', {\r\n itemData: itemData || {},\r\n index\r\n });\r\n\r\n return this.applyFilters('itemData', event.itemData, index);\r\n }\r\n\r\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\r\n _getGalleryDOMElements(galleryElement) {\r\n if (this.options?.children || this.options?.childSelector) {\r\n return getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n galleryElement\r\n ) || [];\r\n }\r\n\r\n return [galleryElement];\r\n }\r\n\r\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\r\n _domElementToItemData(element) {\r\n /** @type {SlideData} */\r\n const itemData = {\r\n element\r\n };\r\n\r\n const linkEl = /** @type {HTMLAnchorElement} */ (\r\n element.tagName === 'A'\r\n ? element\r\n : element.querySelector('a')\r\n );\r\n\r\n if (linkEl) {\r\n // src comes from data-pswp-src attribute,\r\n // if it's empty link href is used\r\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\r\n\r\n if (linkEl.dataset.pswpSrcset) {\r\n itemData.srcset = linkEl.dataset.pswpSrcset;\r\n }\r\n\r\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\r\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\r\n\r\n // support legacy w & h properties\r\n itemData.w = itemData.width;\r\n itemData.h = itemData.height;\r\n\r\n if (linkEl.dataset.pswpType) {\r\n itemData.type = linkEl.dataset.pswpType;\r\n }\r\n\r\n const thumbnailEl = element.querySelector('img');\r\n\r\n if (thumbnailEl) {\r\n // msrc is URL to placeholder image that's displayed before large image is loaded\r\n // by default it's displayed only for the first slide\r\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\r\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\r\n }\r\n\r\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\r\n itemData.thumbCropped = true;\r\n }\r\n }\r\n\r\n return this.applyFilters('domItemData', itemData, element, linkEl);\r\n }\r\n\r\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\n lazyLoadData(itemData, index) {\r\n return lazyLoadData(itemData, this, index);\r\n }\r\n}\r\n\r\nexport default PhotoSwipeBase;\r\n","import {\r\n setTransform,\r\n equalizePoints,\r\n decodeImage,\r\n toTransformString\r\n} from './util/util.js';\r\n\r\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */\r\n/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */\r\n\r\n// some browsers do not paint\r\n// elements which opacity is set to 0,\r\n// since we need to pre-render elements for the animation -\r\n// we set it to the minimum amount\r\nconst MIN_OPACITY = 0.003;\r\n\r\n/**\r\n * Manages opening and closing transitions of the PhotoSwipe.\r\n *\r\n * It can perform zoom, fade or no transition.\r\n */\r\nclass Opener {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.isClosed = true;\r\n this.isOpen = false;\r\n this.isClosing = false;\r\n this.isOpening = false;\r\n /**\r\n * @private\r\n * @type {number | false | undefined}\r\n */\r\n this._duration = undefined;\r\n /** @private */\r\n this._useAnimation = false;\r\n /** @private */\r\n this._croppedZoom = false;\r\n /** @private */\r\n this._animateRootOpacity = false;\r\n /** @private */\r\n this._animateBgOpacity = false;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\r\n */\r\n this._placeholder = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\r\n this._opacityElement = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLDivElement | undefined }\r\n */\r\n this._cropContainer1 = undefined;\r\n /**\r\n * @private\r\n * @type { HTMLElement | null | undefined }\r\n */\r\n this._cropContainer2 = undefined;\r\n\r\n /**\r\n * @private\r\n * @type {Bounds | undefined}\r\n */\r\n this._thumbBounds = undefined;\r\n\r\n\r\n this._prepareOpen = this._prepareOpen.bind(this);\r\n\r\n // Override initial zoom and pan position\r\n pswp.on('firstZoomPan', this._prepareOpen);\r\n }\r\n\r\n open() {\r\n this._prepareOpen();\r\n this._start();\r\n }\r\n\r\n close() {\r\n if (this.isClosed || this.isClosing || this.isOpening) {\r\n // if we close during opening animation\r\n // for now do nothing,\r\n // browsers aren't good at changing the direction of the CSS transition\r\n return;\r\n }\r\n\r\n const slide = this.pswp.currSlide;\r\n\r\n this.isOpen = false;\r\n this.isOpening = false;\r\n this.isClosing = true;\r\n this._duration = this.pswp.options.hideAnimationDuration;\r\n\r\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) {\r\n this._duration = 0;\r\n }\r\n\r\n this._applyStartProps();\r\n setTimeout(() => {\r\n this._start();\r\n }, this._croppedZoom ? 30 : 0);\r\n }\r\n\r\n /** @private */\r\n _prepareOpen() {\r\n this.pswp.off('firstZoomPan', this._prepareOpen);\r\n if (!this.isOpening) {\r\n const slide = this.pswp.currSlide;\r\n this.isOpening = true;\r\n this.isClosing = false;\r\n this._duration = this.pswp.options.showAnimationDuration;\r\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) {\r\n this._duration = 0;\r\n }\r\n this._applyStartProps();\r\n }\r\n }\r\n\r\n /** @private */\r\n _applyStartProps() {\r\n const { pswp } = this;\r\n const slide = this.pswp.currSlide;\r\n const { options } = pswp;\r\n\r\n if (options.showHideAnimationType === 'fade') {\r\n options.showHideOpacity = true;\r\n this._thumbBounds = undefined;\r\n } else if (options.showHideAnimationType === 'none') {\r\n options.showHideOpacity = false;\r\n this._duration = 0;\r\n this._thumbBounds = undefined;\r\n } else if (this.isOpening && pswp._initialThumbBounds) {\r\n // Use initial bounds if defined\r\n this._thumbBounds = pswp._initialThumbBounds;\r\n } else {\r\n this._thumbBounds = this.pswp.getThumbBounds();\r\n }\r\n\r\n this._placeholder = slide?.getPlaceholderElement();\r\n\r\n pswp.animations.stopAll();\r\n\r\n // Discard animations when duration is less than 50ms\r\n this._useAnimation = Boolean(this._duration && this._duration > 50);\r\n this._animateZoom = Boolean(this._thumbBounds)\r\n && slide?.content.usePlaceholder()\r\n && (!this.isClosing || !pswp.mainScroll.isShifted());\r\n if (!this._animateZoom) {\r\n this._animateRootOpacity = true;\r\n\r\n if (this.isOpening && slide) {\r\n slide.zoomAndPanToInitial();\r\n slide.applyCurrentZoomPan();\r\n }\r\n } else {\r\n this._animateRootOpacity = options.showHideOpacity ?? false;\r\n }\r\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY;\r\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\r\n\r\n if (!this._useAnimation) {\r\n this._duration = 0;\r\n this._animateZoom = false;\r\n this._animateBgOpacity = false;\r\n this._animateRootOpacity = true;\r\n if (this.isOpening) {\r\n if (pswp.element) {\r\n pswp.element.style.opacity = String(MIN_OPACITY);\r\n }\r\n pswp.applyBgOpacity(1);\r\n }\r\n return;\r\n }\r\n\r\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\r\n // Properties are used when animation from cropped thumbnail\r\n this._croppedZoom = true;\r\n this._cropContainer1 = this.pswp.container;\r\n this._cropContainer2 = this.pswp.currSlide?.holderElement;\r\n\r\n if (pswp.container) {\r\n pswp.container.style.overflow = 'hidden';\r\n pswp.container.style.width = pswp.viewportSize.x + 'px';\r\n }\r\n } else {\r\n this._croppedZoom = false;\r\n }\r\n\r\n if (this.isOpening) {\r\n // Apply styles before opening transition\r\n if (this._animateRootOpacity) {\r\n if (pswp.element) {\r\n pswp.element.style.opacity = String(MIN_OPACITY);\r\n }\r\n pswp.applyBgOpacity(1);\r\n } else {\r\n if (this._animateBgOpacity && pswp.bg) {\r\n pswp.bg.style.opacity = String(MIN_OPACITY);\r\n }\r\n if (pswp.element) {\r\n pswp.element.style.opacity = '1';\r\n }\r\n }\r\n\r\n if (this._animateZoom) {\r\n this._setClosedStateZoomPan();\r\n if (this._placeholder) {\r\n // tell browser that we plan to animate the placeholder\r\n this._placeholder.style.willChange = 'transform';\r\n\r\n // hide placeholder to allow hiding of\r\n // elements that overlap it (such as icons over the thumbnail)\r\n this._placeholder.style.opacity = String(MIN_OPACITY);\r\n }\r\n }\r\n } else if (this.isClosing) {\r\n // hide nearby slides to make sure that\r\n // they are not painted during the transition\r\n if (pswp.mainScroll.itemHolders[0]) {\r\n pswp.mainScroll.itemHolders[0].el.style.display = 'none';\r\n }\r\n if (pswp.mainScroll.itemHolders[2]) {\r\n pswp.mainScroll.itemHolders[2].el.style.display = 'none';\r\n }\r\n\r\n if (this._croppedZoom) {\r\n if (pswp.mainScroll.x !== 0) {\r\n // shift the main scroller to zero position\r\n pswp.mainScroll.resetPosition();\r\n pswp.mainScroll.resize();\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** @private */\r\n _start() {\r\n if (this.isOpening\r\n && this._useAnimation\r\n && this._placeholder\r\n && this._placeholder.tagName === 'IMG') {\r\n // To ensure smooth animation\r\n // we wait till the current slide image placeholder is decoded,\r\n // but no longer than 250ms,\r\n // and no shorter than 50ms\r\n // (just using requestanimationframe is not enough in Firefox,\r\n // for some reason)\r\n new Promise((resolve) => {\r\n let decoded = false;\r\n let isDelaying = true;\r\n decodeImage(/** @type {HTMLImageElement} */ (this._placeholder)).finally(() => {\r\n decoded = true;\r\n if (!isDelaying) {\r\n resolve(true);\r\n }\r\n });\r\n setTimeout(() => {\r\n isDelaying = false;\r\n if (decoded) {\r\n resolve(true);\r\n }\r\n }, 50);\r\n setTimeout(resolve, 250);\r\n }).finally(() => this._initiate());\r\n } else {\r\n this._initiate();\r\n }\r\n }\r\n\r\n /** @private */\r\n _initiate() {\r\n this.pswp.element?.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\r\n\r\n this.pswp.dispatch(\r\n this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'\r\n );\r\n\r\n // legacy event\r\n this.pswp.dispatch(\r\n /** @type {'initialZoomIn' | 'initialZoomOut'} */\r\n ('initialZoom' + (this.isOpening ? 'In' : 'Out'))\r\n );\r\n\r\n this.pswp.element?.classList.toggle('pswp--ui-visible', this.isOpening);\r\n\r\n if (this.isOpening) {\r\n if (this._placeholder) {\r\n // unhide the placeholder\r\n this._placeholder.style.opacity = '1';\r\n }\r\n this._animateToOpenState();\r\n } else if (this.isClosing) {\r\n this._animateToClosedState();\r\n }\r\n\r\n if (!this._useAnimation) {\r\n this._onAnimationComplete();\r\n }\r\n }\r\n\r\n /** @private */\r\n _onAnimationComplete() {\r\n const { pswp } = this;\r\n this.isOpen = this.isOpening;\r\n this.isClosed = this.isClosing;\r\n this.isOpening = false;\r\n this.isClosing = false;\r\n\r\n pswp.dispatch(\r\n this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'\r\n );\r\n\r\n // legacy event\r\n pswp.dispatch(\r\n /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */\r\n ('initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'))\r\n );\r\n\r\n if (this.isClosed) {\r\n pswp.destroy();\r\n } else if (this.isOpen) {\r\n if (this._animateZoom && pswp.container) {\r\n pswp.container.style.overflow = 'visible';\r\n pswp.container.style.width = '100%';\r\n }\r\n pswp.currSlide?.applyCurrentZoomPan();\r\n }\r\n }\r\n\r\n /** @private */\r\n _animateToOpenState() {\r\n const { pswp } = this;\r\n if (this._animateZoom) {\r\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\r\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\r\n this._animateTo(this._cropContainer2, 'transform', 'none');\r\n }\r\n\r\n if (pswp.currSlide) {\r\n pswp.currSlide.zoomAndPanToInitial();\r\n this._animateTo(\r\n pswp.currSlide.container,\r\n 'transform',\r\n pswp.currSlide.getCurrentTransform()\r\n );\r\n }\r\n }\r\n\r\n if (this._animateBgOpacity && pswp.bg) {\r\n this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\r\n }\r\n\r\n if (this._animateRootOpacity && pswp.element) {\r\n this._animateTo(pswp.element, 'opacity', '1');\r\n }\r\n }\r\n\r\n /** @private */\r\n _animateToClosedState() {\r\n const { pswp } = this;\r\n\r\n if (this._animateZoom) {\r\n this._setClosedStateZoomPan(true);\r\n }\r\n\r\n // do not animate opacity if it's already at 0\r\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) {\r\n this._animateTo(pswp.bg, 'opacity', '0');\r\n }\r\n\r\n if (this._animateRootOpacity && pswp.element) {\r\n this._animateTo(pswp.element, 'opacity', '0');\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {boolean} [animate]\r\n */\r\n _setClosedStateZoomPan(animate) {\r\n if (!this._thumbBounds) return;\r\n\r\n const { pswp } = this;\r\n const { innerRect } = this._thumbBounds;\r\n const { currSlide, viewportSize } = pswp;\r\n\r\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\r\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\r\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\r\n const containerTwoPanX = viewportSize.x - innerRect.w;\r\n const containerTwoPanY = viewportSize.y - innerRect.h;\r\n\r\n\r\n if (animate) {\r\n this._animateTo(\r\n this._cropContainer1,\r\n 'transform',\r\n toTransformString(containerOnePanX, containerOnePanY)\r\n );\r\n\r\n this._animateTo(\r\n this._cropContainer2,\r\n 'transform',\r\n toTransformString(containerTwoPanX, containerTwoPanY)\r\n );\r\n } else {\r\n setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\r\n setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\r\n }\r\n }\r\n\r\n if (currSlide) {\r\n equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\r\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\r\n if (animate) {\r\n this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\r\n } else {\r\n currSlide.applyCurrentZoomPan();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {HTMLElement} target\r\n * @param {'transform' | 'opacity'} prop\r\n * @param {string} propValue\r\n */\r\n _animateTo(target, prop, propValue) {\r\n if (!this._duration) {\r\n target.style[prop] = propValue;\r\n return;\r\n }\r\n\r\n const { animations } = this.pswp;\r\n /** @type {AnimationProps} */\r\n const animProps = {\r\n duration: this._duration,\r\n easing: this.pswp.options.easing,\r\n onComplete: () => {\r\n if (!animations.activeAnimations.length) {\r\n this._onAnimationComplete();\r\n }\r\n },\r\n target,\r\n };\r\n animProps[prop] = propValue;\r\n animations.startTransition(animProps);\r\n }\r\n}\r\n\r\nexport default Opener;\r\n","import {\r\n createElement,\r\n equalizePoints,\r\n pointsEqual,\r\n clamp,\r\n} from './util/util.js';\r\n\r\nimport DOMEvents from './util/dom-events.js';\r\nimport Slide from './slide/slide.js';\r\nimport Gestures from './gestures/gestures.js';\r\nimport MainScroll from './main-scroll.js';\r\n\r\nimport Keyboard from './keyboard.js';\r\nimport Animations from './util/animations.js';\r\nimport ScrollWheel from './scroll-wheel.js';\r\nimport UI from './ui/ui.js';\r\nimport { getViewportSize } from './util/viewport-size.js';\r\nimport { getThumbBounds } from './slide/get-thumb-bounds.js';\r\nimport PhotoSwipeBase from './core/base.js';\r\nimport Opener from './opener.js';\r\nimport ContentLoader from './slide/loader.js';\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('./types.js').Type} Type\r\n */\r\n\r\n/** @typedef {import('./slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */\r\n/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */\r\n/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\r\n/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\r\n/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\r\n */\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\r\n */\r\n\r\n/** @typedef {{ x: number; y: number; id?: string | number }} Point */\r\n/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */\r\n/** @typedef {SlideData[]} DataSourceArray */\r\n/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */\r\n/** @typedef {DataSourceArray | DataSourceObject} DataSource */\r\n/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */\r\n/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */\r\n/** @typedef {Type | { default: Type }} PhotoSwipeModule */\r\n/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */\r\n\r\n/**\r\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\r\n */\r\n\r\n/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */\r\n/**\r\n * @typedef {Object} PreparedPhotoSwipeOptions\r\n *\r\n * @prop {DataSource} [dataSource]\r\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\r\n * (which may be modified further from numItems event).\r\n *\r\n * Each item should contain data that you need to generate slide\r\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\r\n *\r\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\r\n *\r\n * @prop {number} bgOpacity\r\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\r\n *\r\n * @prop {number} spacing\r\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\r\n *\r\n * @prop {boolean} allowPanToNext\r\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\r\n *\r\n * @prop {boolean} loop\r\n * If set to true you'll be able to swipe from the last to the first image.\r\n * Option is always false when there are less than 3 slides.\r\n *\r\n * @prop {boolean} [wheelToZoom]\r\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\r\n *\r\n * @prop {boolean} pinchToClose\r\n * Pinch touch gesture to close the gallery.\r\n *\r\n * @prop {boolean} closeOnVerticalDrag\r\n * Vertical drag gesture to close the PhotoSwipe.\r\n *\r\n * @prop {Padding} [padding]\r\n * Slide area padding (in pixels).\r\n *\r\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\r\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\r\n *\r\n * @prop {number | false} hideAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} showAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {number | false} zoomAnimationDuration\r\n * Transition duration in milliseconds, can be 0.\r\n *\r\n * @prop {string} easing\r\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\r\n *\r\n * @prop {boolean} escKey\r\n * Esc key to close.\r\n *\r\n * @prop {boolean} arrowKeys\r\n * Left/right arrow keys for navigation.\r\n *\r\n * @prop {boolean} trapFocus\r\n * Trap focus within PhotoSwipe element while it's open.\r\n *\r\n * @prop {boolean} returnFocus\r\n * Restore focus the last active element after PhotoSwipe is closed.\r\n *\r\n * @prop {boolean} clickToCloseNonZoomable\r\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\r\n *\r\n * @prop {ActionType | ActionFn | false} imageClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} bgClickAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} tapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {ActionType | ActionFn | false} doubleTapAction\r\n * Refer to click and tap actions page.\r\n *\r\n * @prop {number} preloaderDelay\r\n * Delay before the loading indicator will be displayed,\r\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\r\n *\r\n * @prop {string} indexIndicatorSep\r\n * Used for slide count indicator (\"1 of 10 \").\r\n *\r\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\r\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\r\n *\r\n * @prop {string} errorMsg\r\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\r\n *\r\n * @prop {[number, number]} preload\r\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\r\n * first one - number of items to preload before the current image, second one - after the current image.\r\n * Two nearby images are always loaded.\r\n *\r\n * @prop {string} [mainClass]\r\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\r\n * Example on Styling page.\r\n *\r\n * @prop {HTMLElement} [appendToEl]\r\n * Element to which PhotoSwipe dialog will be appended when it opens.\r\n *\r\n * @prop {number} maxWidthToAnimate\r\n * Maximum width of image to animate, if initial rendered image width\r\n * is larger than this value - the opening/closing transition will be automatically disabled.\r\n *\r\n * @prop {string} [closeTitle]\r\n * Translating\r\n *\r\n * @prop {string} [zoomTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * Translating\r\n *\r\n * @prop {string} [arrowNextTitle]\r\n * Translating\r\n *\r\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\r\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\r\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\r\n *\r\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\r\n *\r\n * @prop {number} index\r\n * Defines start slide index.\r\n *\r\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\r\n *\r\n * @prop {boolean} [arrowPrev]\r\n * @prop {boolean} [arrowNext]\r\n * @prop {boolean} [zoom]\r\n * @prop {boolean} [close]\r\n * @prop {boolean} [counter]\r\n *\r\n * @prop {string} [arrowPrevSVG]\r\n * @prop {string} [arrowNextSVG]\r\n * @prop {string} [zoomSVG]\r\n * @prop {string} [closeSVG]\r\n * @prop {string} [counterSVG]\r\n *\r\n * @prop {string} [arrowPrevTitle]\r\n * @prop {string} [arrowNextTitle]\r\n * @prop {string} [zoomTitle]\r\n * @prop {string} [closeTitle]\r\n * @prop {string} [counterTitle]\r\n *\r\n * @prop {ZoomLevelOption} [initialZoomLevel]\r\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\r\n * @prop {ZoomLevelOption} [maxZoomLevel]\r\n *\r\n * @prop {boolean} [mouseMovePan]\r\n * @prop {Point | null} [initialPointerPos]\r\n * @prop {boolean} [showHideOpacity]\r\n *\r\n * @prop {PhotoSwipeModuleOption} [pswpModule]\r\n * @prop {() => Promise} [openPromise]\r\n * @prop {boolean} [preloadFirstSlide]\r\n * @prop {ElementProvider} [gallery]\r\n * @prop {string} [gallerySelector]\r\n * @prop {ElementProvider} [children]\r\n * @prop {string} [childSelector]\r\n * @prop {string | false} [thumbSelector]\r\n */\r\n\r\n/** @type {PreparedPhotoSwipeOptions} */\r\nconst defaultOptions = {\r\n allowPanToNext: true,\r\n spacing: 0.1,\r\n loop: true,\r\n pinchToClose: true,\r\n closeOnVerticalDrag: true,\r\n hideAnimationDuration: 333,\r\n showAnimationDuration: 333,\r\n zoomAnimationDuration: 333,\r\n escKey: true,\r\n arrowKeys: true,\r\n trapFocus: true,\r\n returnFocus: true,\r\n maxWidthToAnimate: 4000,\r\n clickToCloseNonZoomable: true,\r\n imageClickAction: 'zoom-or-close',\r\n bgClickAction: 'close',\r\n tapAction: 'toggle-controls',\r\n doubleTapAction: 'zoom',\r\n indexIndicatorSep: ' / ',\r\n preloaderDelay: 2000,\r\n bgOpacity: 0.8,\r\n\r\n index: 0,\r\n errorMsg: 'The image cannot be loaded',\r\n preload: [1, 2],\r\n easing: 'cubic-bezier(.4,0,.22,1)'\r\n};\r\n\r\n/**\r\n * PhotoSwipe Core\r\n */\r\nclass PhotoSwipe extends PhotoSwipeBase {\r\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\r\n constructor(options) {\r\n super();\r\n\r\n this.options = this._prepareOptions(options || {});\r\n\r\n /**\r\n * offset of viewport relative to document\r\n *\r\n * @type {Point}\r\n */\r\n this.offset = { x: 0, y: 0 };\r\n\r\n /**\r\n * @type {Point}\r\n * @private\r\n */\r\n this._prevViewportSize = { x: 0, y: 0 };\r\n\r\n /**\r\n * Size of scrollable PhotoSwipe viewport\r\n *\r\n * @type {Point}\r\n */\r\n this.viewportSize = { x: 0, y: 0 };\r\n\r\n /**\r\n * background (backdrop) opacity\r\n */\r\n this.bgOpacity = 1;\r\n this.currIndex = 0;\r\n this.potentialIndex = 0;\r\n this.isOpen = false;\r\n this.isDestroying = false;\r\n this.hasMouse = false;\r\n\r\n /**\r\n * @private\r\n * @type {SlideData}\r\n */\r\n this._initialItemData = {};\r\n /** @type {Bounds | undefined} */\r\n this._initialThumbBounds = undefined;\r\n\r\n /** @type {HTMLDivElement | undefined} */\r\n this.topBar = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.template = undefined;\r\n /** @type {HTMLDivElement | undefined} */\r\n this.container = undefined;\r\n /** @type {HTMLElement | undefined} */\r\n this.scrollWrap = undefined;\r\n /** @type {Slide | undefined} */\r\n this.currSlide = undefined;\r\n\r\n this.events = new DOMEvents();\r\n this.animations = new Animations();\r\n this.mainScroll = new MainScroll(this);\r\n this.gestures = new Gestures(this);\r\n this.opener = new Opener(this);\r\n this.keyboard = new Keyboard(this);\r\n this.contentLoader = new ContentLoader(this);\r\n }\r\n\r\n /** @returns {boolean} */\r\n init() {\r\n if (this.isOpen || this.isDestroying) {\r\n return false;\r\n }\r\n\r\n this.isOpen = true;\r\n this.dispatch('init'); // legacy\r\n this.dispatch('beforeOpen');\r\n\r\n this._createMainStructure();\r\n\r\n // add classes to the root element of PhotoSwipe\r\n let rootClasses = 'pswp--open';\r\n if (this.gestures.supportsTouch) {\r\n rootClasses += ' pswp--touch';\r\n }\r\n if (this.options.mainClass) {\r\n rootClasses += ' ' + this.options.mainClass;\r\n }\r\n if (this.element) {\r\n this.element.className += ' ' + rootClasses;\r\n }\r\n\r\n this.currIndex = this.options.index || 0;\r\n this.potentialIndex = this.currIndex;\r\n this.dispatch('firstUpdate'); // starting index can be modified here\r\n\r\n // initialize scroll wheel handler to block the scroll\r\n this.scrollWheel = new ScrollWheel(this);\r\n\r\n // sanitize index\r\n if (Number.isNaN(this.currIndex)\r\n || this.currIndex < 0\r\n || this.currIndex >= this.getNumItems()) {\r\n this.currIndex = 0;\r\n }\r\n\r\n if (!this.gestures.supportsTouch) {\r\n // enable mouse features if no touch support detected\r\n this.mouseDetected();\r\n }\r\n\r\n // causes forced synchronous layout\r\n this.updateSize();\r\n\r\n this.offset.y = window.pageYOffset;\r\n\r\n this._initialItemData = this.getItemData(this.currIndex);\r\n this.dispatch('gettingData', {\r\n index: this.currIndex,\r\n data: this._initialItemData,\r\n slide: undefined\r\n });\r\n\r\n // *Layout* - calculate size and position of elements here\r\n this._initialThumbBounds = this.getThumbBounds();\r\n this.dispatch('initialLayout');\r\n\r\n this.on('openingAnimationEnd', () => {\r\n const { itemHolders } = this.mainScroll;\r\n\r\n // Add content to the previous and next slide\r\n if (itemHolders[0]) {\r\n itemHolders[0].el.style.display = 'block';\r\n this.setContent(itemHolders[0], this.currIndex - 1);\r\n }\r\n if (itemHolders[2]) {\r\n itemHolders[2].el.style.display = 'block';\r\n this.setContent(itemHolders[2], this.currIndex + 1);\r\n }\r\n\r\n this.appendHeavy();\r\n\r\n this.contentLoader.updateLazy();\r\n\r\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\r\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\r\n this.dispatch('bindEvents');\r\n });\r\n\r\n // set content for center slide (first time)\r\n if (this.mainScroll.itemHolders[1]) {\r\n this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\r\n }\r\n this.dispatch('change');\r\n\r\n this.opener.open();\r\n\r\n this.dispatch('afterInit');\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Get looped slide index\r\n * (for example, -1 will return the last slide)\r\n *\r\n * @param {number} index\r\n * @returns {number}\r\n */\r\n getLoopedIndex(index) {\r\n const numSlides = this.getNumItems();\r\n\r\n if (this.options.loop) {\r\n if (index > numSlides - 1) {\r\n index -= numSlides;\r\n }\r\n\r\n if (index < 0) {\r\n index += numSlides;\r\n }\r\n }\r\n\r\n return clamp(index, 0, numSlides - 1);\r\n }\r\n\r\n appendHeavy() {\r\n this.mainScroll.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.appendHeavy();\r\n });\r\n }\r\n\r\n /**\r\n * Change the slide\r\n * @param {number} index New index\r\n */\r\n goTo(index) {\r\n this.mainScroll.moveIndexBy(\r\n this.getLoopedIndex(index) - this.potentialIndex\r\n );\r\n }\r\n\r\n /**\r\n * Go to the next slide.\r\n */\r\n next() {\r\n this.goTo(this.potentialIndex + 1);\r\n }\r\n\r\n /**\r\n * Go to the previous slide.\r\n */\r\n prev() {\r\n this.goTo(this.potentialIndex - 1);\r\n }\r\n\r\n /**\r\n * @see slide/slide.js zoomTo\r\n *\r\n * @param {Parameters} args\r\n */\r\n zoomTo(...args) {\r\n this.currSlide?.zoomTo(...args);\r\n }\r\n\r\n /**\r\n * @see slide/slide.js toggleZoom\r\n */\r\n toggleZoom() {\r\n this.currSlide?.toggleZoom();\r\n }\r\n\r\n /**\r\n * Close the gallery.\r\n * After closing transition ends - destroy it\r\n */\r\n close() {\r\n if (!this.opener.isOpen || this.isDestroying) {\r\n return;\r\n }\r\n\r\n this.isDestroying = true;\r\n\r\n this.dispatch('close');\r\n\r\n this.events.removeAll();\r\n this.opener.close();\r\n }\r\n\r\n /**\r\n * Destroys the gallery:\r\n * - instantly closes the gallery\r\n * - unbinds events,\r\n * - cleans intervals and timeouts\r\n * - removes elements from DOM\r\n */\r\n destroy() {\r\n if (!this.isDestroying) {\r\n this.options.showHideAnimationType = 'none';\r\n this.close();\r\n return;\r\n }\r\n\r\n this.dispatch('destroy');\r\n\r\n this._listeners = {};\r\n\r\n if (this.scrollWrap) {\r\n this.scrollWrap.ontouchmove = null;\r\n this.scrollWrap.ontouchend = null;\r\n }\r\n\r\n this.element?.remove();\r\n\r\n this.mainScroll.itemHolders.forEach((itemHolder) => {\r\n itemHolder.slide?.destroy();\r\n });\r\n\r\n this.contentLoader.destroy();\r\n this.events.removeAll();\r\n }\r\n\r\n /**\r\n * Refresh/reload content of a slide by its index\r\n *\r\n * @param {number} slideIndex\r\n */\r\n refreshSlideContent(slideIndex) {\r\n this.contentLoader.removeByIndex(slideIndex);\r\n this.mainScroll.itemHolders.forEach((itemHolder, i) => {\r\n let potentialHolderIndex = (this.currSlide?.index ?? 0) - 1 + i;\r\n if (this.canLoop()) {\r\n potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\r\n }\r\n if (potentialHolderIndex === slideIndex) {\r\n // set the new slide content\r\n this.setContent(itemHolder, slideIndex, true);\r\n\r\n // activate the new slide if it's current\r\n if (i === 1) {\r\n this.currSlide = itemHolder.slide;\r\n itemHolder.slide?.setIsActive(true);\r\n }\r\n }\r\n });\r\n\r\n this.dispatch('change');\r\n }\r\n\r\n\r\n /**\r\n * Set slide content\r\n *\r\n * @param {ItemHolder} holder mainScroll.itemHolders array item\r\n * @param {number} index Slide index\r\n * @param {boolean} [force] If content should be set even if index wasn't changed\r\n */\r\n setContent(holder, index, force) {\r\n if (this.canLoop()) {\r\n index = this.getLoopedIndex(index);\r\n }\r\n\r\n if (holder.slide) {\r\n if (holder.slide.index === index && !force) {\r\n // exit if holder already contains this slide\r\n // this could be common when just three slides are used\r\n return;\r\n }\r\n\r\n // destroy previous slide\r\n holder.slide.destroy();\r\n holder.slide = undefined;\r\n }\r\n\r\n // exit if no loop and index is out of bounds\r\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) {\r\n return;\r\n }\r\n\r\n const itemData = this.getItemData(index);\r\n holder.slide = new Slide(itemData, index, this);\r\n\r\n // set current slide\r\n if (index === this.currIndex) {\r\n this.currSlide = holder.slide;\r\n }\r\n\r\n holder.slide.append(holder.el);\r\n }\r\n\r\n /** @returns {Point} */\r\n getViewportCenterPoint() {\r\n return {\r\n x: this.viewportSize.x / 2,\r\n y: this.viewportSize.y / 2\r\n };\r\n }\r\n\r\n /**\r\n * Update size of all elements.\r\n * Executed on init and on page resize.\r\n *\r\n * @param {boolean} [force] Update size even if size of viewport was not changed.\r\n */\r\n updateSize(force) {\r\n // let item;\r\n // let itemIndex;\r\n\r\n if (this.isDestroying) {\r\n // exit if PhotoSwipe is closed or closing\r\n // (to avoid errors, as resize event might be delayed)\r\n return;\r\n }\r\n\r\n //const newWidth = this.scrollWrap.clientWidth;\r\n //const newHeight = this.scrollWrap.clientHeight;\r\n\r\n const newViewportSize = getViewportSize(this.options, this);\r\n\r\n if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) {\r\n // Exit if dimensions were not changed\r\n return;\r\n }\r\n\r\n //this._prevViewportSize.x = newWidth;\r\n //this._prevViewportSize.y = newHeight;\r\n equalizePoints(this._prevViewportSize, newViewportSize);\r\n\r\n this.dispatch('beforeResize');\r\n\r\n equalizePoints(this.viewportSize, this._prevViewportSize);\r\n\r\n this._updatePageScrollOffset();\r\n\r\n this.dispatch('viewportSize');\r\n\r\n // Resize slides only after opener animation is finished\r\n // and don't re-calculate size on inital size update\r\n this.mainScroll.resize(this.opener.isOpen);\r\n\r\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) {\r\n this.mouseDetected();\r\n }\r\n\r\n this.dispatch('resize');\r\n }\r\n\r\n /**\r\n * @param {number} opacity\r\n */\r\n applyBgOpacity(opacity) {\r\n this.bgOpacity = Math.max(opacity, 0);\r\n if (this.bg) {\r\n this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\r\n }\r\n }\r\n\r\n /**\r\n * Whether mouse is detected\r\n */\r\n mouseDetected() {\r\n if (!this.hasMouse) {\r\n this.hasMouse = true;\r\n this.element?.classList.add('pswp--has_mouse');\r\n }\r\n }\r\n\r\n /**\r\n * Page resize event handler\r\n *\r\n * @private\r\n */\r\n _handlePageResize() {\r\n this.updateSize();\r\n\r\n // In iOS webview, if element size depends on document size,\r\n // it'll be measured incorrectly in resize event\r\n //\r\n // https://bugs.webkit.org/show_bug.cgi?id=170595\r\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\r\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) {\r\n setTimeout(() => {\r\n this.updateSize();\r\n }, 500);\r\n }\r\n }\r\n\r\n /**\r\n * Page scroll offset is used\r\n * to get correct coordinates\r\n * relative to PhotoSwipe viewport.\r\n *\r\n * @private\r\n */\r\n _updatePageScrollOffset() {\r\n this.setScrollOffset(0, window.pageYOffset);\r\n }\r\n\r\n /**\r\n * @param {number} x\r\n * @param {number} y\r\n */\r\n setScrollOffset(x, y) {\r\n this.offset.x = x;\r\n this.offset.y = y;\r\n this.dispatch('updateScrollOffset');\r\n }\r\n\r\n /**\r\n * Create main HTML structure of PhotoSwipe,\r\n * and add it to DOM\r\n *\r\n * @private\r\n */\r\n _createMainStructure() {\r\n // root DOM element of PhotoSwipe (.pswp)\r\n this.element = createElement('pswp', 'div');\r\n this.element.setAttribute('tabindex', '-1');\r\n this.element.setAttribute('role', 'dialog');\r\n\r\n // template is legacy prop\r\n this.template = this.element;\r\n\r\n // Background is added as a separate element,\r\n // as animating opacity is faster than animating rgba()\r\n this.bg = createElement('pswp__bg', 'div', this.element);\r\n this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element);\r\n this.container = createElement('pswp__container', 'div', this.scrollWrap);\r\n\r\n // aria pattern: carousel\r\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\r\n this.container.setAttribute('aria-live', 'off');\r\n this.container.setAttribute('id', 'pswp__items');\r\n\r\n this.mainScroll.appendHolders();\r\n\r\n this.ui = new UI(this);\r\n this.ui.init();\r\n\r\n // append to DOM\r\n (this.options.appendToEl || document.body).appendChild(this.element);\r\n }\r\n\r\n\r\n /**\r\n * Get position and dimensions of small thumbnail\r\n * {x:,y:,w:}\r\n *\r\n * Height is optional (calculated based on the large image)\r\n *\r\n * @returns {Bounds | undefined}\r\n */\r\n getThumbBounds() {\r\n return getThumbBounds(\r\n this.currIndex,\r\n this.currSlide ? this.currSlide.data : this._initialItemData,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * If the PhotoSwipe can have continuous loop\r\n * @returns Boolean\r\n */\r\n canLoop() {\r\n return (this.options.loop && this.getNumItems() > 2);\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {PhotoSwipeOptions} options\r\n * @returns {PreparedPhotoSwipeOptions}\r\n */\r\n _prepareOptions(options) {\r\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\r\n options.showHideAnimationType = 'none';\r\n options.zoomAnimationDuration = 0;\r\n }\r\n\r\n /** @type {PreparedPhotoSwipeOptions} */\r\n return {\r\n ...defaultOptions,\r\n ...options\r\n };\r\n }\r\n}\r\n\r\nexport default PhotoSwipe;\r\n"],"names":["parcelRequire","$parcel$global","globalThis","self","window","global","register","module","exports","$fafca69a57f78827$var$createElement","className","tagName","appendToEl","el","document","createElement","appendChild","$fafca69a57f78827$var$equalizePoints","p1","p2","x","y","undefined","id","$fafca69a57f78827$var$roundPoint","p","Math","round","$fafca69a57f78827$var$getDistanceBetween","abs","sqrt","$fafca69a57f78827$var$pointsEqual","$fafca69a57f78827$var$clamp","val","min","max","$fafca69a57f78827$var$toTransformString","scale","propValue","$fafca69a57f78827$var$setTransform","style","transform","$fafca69a57f78827$var$setTransitionStyle","prop","duration","ease","transition","$fafca69a57f78827$var$setWidthHeight","w","h","width","height","Object","defineProperty","value","configurable","get","$fafca69a57f78827$export$2e2bcd8739ae039","set","s","enumerable","$fafca69a57f78827$var$LOAD_STATE","IDLE","LOADING","LOADED","ERROR","$fafca69a57f78827$var$isSafari","navigator","vendor","match","$fafca69a57f78827$var$supportsPassive","addEventListener","e","$fafca69a57f78827$var$DOMEvents","constructor","_pool","add","target","type","listener","passive","_toggleListener","remove","removeAll","forEach","poolItem","unbind","skipPool","methodName","types","split","eType","filter","push","eventOptions","$fafca69a57f78827$var$getViewportSize","options","pswp","getViewportSizeFn","newViewportSize","documentElement","clientWidth","innerHeight","$fafca69a57f78827$var$parsePaddingOption","viewportSize","itemData","index","paddingValue","paddingFn","padding","legacyPropName","toUpperCase","slice","Number","$fafca69a57f78827$var$getPanAreaSize","$fafca69a57f78827$var$PanBounds","slide","currZoomLevel","center","update","_updateAxis","dispatch","reset","axis","elSize","data","panAreaSize","correctPan","panOffset","$fafca69a57f78827$var$ZoomLevel","elementSize","fit","fill","vFill","initial","secondary","maxWidth","maxHeight","hRatio","vRatio","_getInitial","_getSecondary","_getMax","zoomLevels","slideData","_parseZoomLevelOption","optionPrefix","optionValue","$fafca69a57f78827$var$MAX_IMAGE_WIDTH","$fafca69a57f78827$var$Slide","isActive","currIndex","currentResolution","pan","isFirstSlide","opener","isOpen","content","contentLoader","getContentBySlide","container","holderElement","heavyAppended","bounds","prevDisplayedWidth","prevDisplayedHeight","setIsActive","activate","deactivate","append","transformOrigin","calculateSize","load","updateContentSize","appendHeavy","zoomAndPanToInitial","applyCurrentZoomPan","mainScroll","isShifted","defaultPrevented","destroy","hasSlide","resize","panTo","force","scaleMultiplier","sizeChanged","setDisplayedSize","getPlaceholderElement","_this$content$placeho","placeholder","element","zoomTo","destZoomLevel","centerPoint","transitionDuration","ignoreBounds","isZoomable","animations","stopAllPan","prevZoomLevel","setZoomLevel","calculateZoomToPanOffset","finishTransition","_setResolution","startTransition","isPan","name","getCurrentTransform","onComplete","easing","toggleZoom","zoomAnimationDuration","point","totalPanDistance","getViewportCenterPoint","zoomFactor","panX","panY","isPannable","Boolean","_applyZoomTransform","currSlide","zoom","newResolution","$fafca69a57f78827$var$DragHandler","gestures","startPan","start","stopAll","change","prevP1","dragAxis","closeOnVerticalDrag","isMultitouch","_setPanWithFriction","bgOpacity","_getVerticalDragRatio","applyBgOpacity","_panOrMoveMainScroll","end","velocity","indexDiff","currentSlideVisibilityRatio","mainScrollShiftDiff","getCurrSlideX","moveIndexBy","correctZoomPan","_finishPanGestureForAxis","panPos","restoreBgOpacity","projectedPosition","vDragRatio","projectedVDragRatio","close","correctedPanPosition","dampingRatio","initialBgOpacity","totalPanDist","startSpring","onUpdate","pos","animationProgressRatio","floor","delta","newMainScrollX","moveTo","newPan","allowPanToNext","currSlideMainScrollX","isLeftToRight","_this$pswp$currSlide$","_this$pswp$currSlide","potentialPan","customFriction","correctedPan","$fafca69a57f78827$var$getZoomPointsCenter","$fafca69a57f78827$var$ZoomHandler","_startPan","_startZoomPoint","_zoomPoint","_wasOverFitZoomLevel","_startZoomLevel","startP1","startP2","minZoomLevel","maxZoomLevel","pinchToClose","_calculatePanForZoomLevel","ignoreGesture","destinationZoomLevel","currZoomLevelNeedsChange","initialPan","destinationPan","panNeedsChange","naturalFrequency","now","newZoomLevel","$fafca69a57f78827$var$didTapOnMainContent","event","closest","$fafca69a57f78827$var$TapHandler","click","originalEvent","targetClassList","classList","isImageClick","contains","isBackgroundClick","_doClickOrTapAction","tap","doubleTap","actionName","_this$gestures$pswp$e","actionFullName","call","clickToCloseNonZoomable","toggle","$fafca69a57f78827$var$Gestures","prevP2","_lastStartP1","_intervalP1","_numActivePoints","_ongoingPointers","_touchEventEnabled","_pointerEventEnabled","PointerEvent","supportsTouch","maxTouchPoints","_intervalTime","_velocityCalculated","isDragging","isZooming","raf","_tapTimer","drag","tapHandler","on","events","scrollWrap","_onClick","bind","_bindEvents","ontouchmove","ontouchend","pref","down","up","cancel","cancelEvent","onPointerDown","onPointerMove","onPointerUp","isMousePointer","pointerType","button","preventDefault","mouseDetected","_preventPointerEventBehaviour","_updatePoints","_clearTapTimer","_finishDrag","_updateStartPoints","_rafStopLoop","_rafRenderLoop","_calculateDragDirection","Date","_updateVelocity","_finishTap","_updatePrevPoints","requestAnimationFrame","time","_getVelocity","indexOf","tapDelay","doubleTapAction","setTimeout","clearTimeout","displacement","cancelAnimationFrame","applyFilters","pointerIndex","findIndex","ongoingPointer","pointerEvent","pointerId","splice","_convertEventPosToPoint","length","touchEvent","touches","diff","axisToCheck","pageX","offset","pageY","identifier","stopPropagation","$fafca69a57f78827$var$MainScroll","slideWidth","_currPositionIndex","_prevPositionIndex","_containerShiftIndex","itemHolders","resizeSlides","newSlideWidth","spacing","slideWidthChanged","itemHolder","resetPosition","appendHolders","i","setAttribute","display","canBeSwiped","getNumItems","animate","velocityX","newIndex","potentialIndex","numSlides","canLoop","getLoopedIndex","distance","stopMainScroll","destinationX","isMainScroll","updateCurrItem","currDiff","currDistance","_this$itemHolders$","tempHolder","positionDifference","diffAbs","_itemHolder$slide","shift","setContent","pop","unshift","updateLazy","dragging","newSlideIndexOffset","$fafca69a57f78827$var$KeyboardKeyCodesMap","Escape","z","ArrowLeft","ArrowUp","ArrowRight","ArrowDown","Tab","$fafca69a57f78827$var$getKeyboardEventKey","key","isKeySupported","$fafca69a57f78827$var$Keyboard","_wasFocused","trapFocus","initialPointerPos","_focusRoot","_onFocusIn","_onKeyDown","lastActiveElement","activeElement","returnFocus","focus","keydownAction","ctrlKey","metaKey","altKey","shiftKey","isForward","keyCode","escKey","arrowKeys","template","$fafca69a57f78827$var$CSSAnimation","props","_props$prop","onFinish","_target","_onComplete","_finished","_onTransitionEnd","_helperTimeout","_finalizeAnimation","removeEventListener","$fafca69a57f78827$var$SpringEaser","initialVelocity","_dampingRatio","_naturalFrequency","_dampedFrequency","easeFrame","deltaPosition","deltaTime","coeff","naturalDumpingPow","E","dumpedFCos","cos","dumpedFSin","sin","$fafca69a57f78827$var$SpringAnimation","_raf","easer","prevTime","animationLoop","$fafca69a57f78827$var$Animations","activeAnimations","_start","isSpring","animation","stop","isPanRunning","some","$fafca69a57f78827$var$ScrollWheel","_onWheel","deltaX","deltaY","wheelToZoom","deltaMode","clientX","clientY","$fafca69a57f78827$var$UIElement","_container","elementHTML","html","isButton","toLowerCase","title","ariaLabel","ariaText","innerHTML","$fafca69a57f78827$var$addElementHTML","htmlData","isCustomSVG","out","join","svgData","size","outlineID","inner","onInit","onClick","onclick","appendTo","topBar","$fafca69a57f78827$var$initArrowButton","isNextButton","loop","disabled","$fafca69a57f78827$var$arrowPrev","order","$fafca69a57f78827$var$arrowNext","$fafca69a57f78827$var$closeButton","$fafca69a57f78827$var$zoomButton","$fafca69a57f78827$var$loadingIndicator","indicatorElement","isVisible","delayTimeout","toggleIndicatorClass","setIndicatorVisibility","visible","updatePreloaderVisibility","_pswp$currSlide","isLoading","_pswp$currSlide2","preloaderDelay","ui","$fafca69a57f78827$var$counterIndicator","counterElement","innerText","indexIndicatorSep","$fafca69a57f78827$var$setZoomedIn","isZoomedIn","$fafca69a57f78827$var$UI","isRegistered","uiElementsData","items","_lastUpdatedZoomLevel","init","sort","a","b","uiElementData","registerElement","_pswp$element","_onZoomPanUpdate","elementData","isClosing","potentialZoomLevel","imageClickAction","$fafca69a57f78827$var$PhotoSwipeEvent","details","assign","$fafca69a57f78827$var$Eventable","_listeners","_filters","addFilter","fn","priority","_this$_filters$name","_this$_filters$name2","_this$pswp","f1","f2","removeFilter","args","_this$_filters$name3","apply","_this$_listeners$name","_this$pswp2","off","_this$pswp3","_this$_listeners$name2","$fafca69a57f78827$var$Placeholder","imageSrc","imgEl","decoding","alt","src","_this$element","parentNode","$fafca69a57f78827$var$Content","instance","displayedImageWidth","displayedImageHeight","isAttached","isDecoding","state","removePlaceholder","keepPlaceholder","isLazy","reload","usePlaceholder","placeholderEl","parentElement","prepend","placeholderSrc","msrc","isImageContent","loadImage","_this$data$src","_this$data$alt","imageElement","updateSrcsetSizes","srcset","complete","onLoaded","onload","onerror","onError","setSlide","displayError","isError","isInitialSizeUpdate","image","sizesWidth","dataset","largestUsedSize","parseInt","sizes","String","lazyLoad","_this$instance$option","_this$instance$option2","errorMsgEl","errorMsg","supportsDecode","decode","catch","finally","appendImage","$fafca69a57f78827$var$lazyLoadData","zoomLevel","createContentFromData","ceil","$fafca69a57f78827$var$ContentLoader","limit","preload","_cachedItems","loadSlideByIndex","initialIndex","getContentByIndex","$fafca69a57f78827$var$lazyLoadSlide","getItemData","addToCache","removeByIndex","indexToRemove","item","removedItem","find","$fafca69a57f78827$var$PhotoSwipeBase","_this$options","numItems","dataSource","_getGalleryDOMElements","gallery","_this$options2","dataSourceItem","Array","isArray","Element","_domElementToItemData","galleryElement","_this$options3","_this$options4","children","childSelector","$fafca69a57f78827$var$getElementsFromOption","option","legacySelector","parent","elements","NodeList","from","selector","querySelectorAll","linkEl","querySelector","pswpSrc","href","pswpSrcset","pswpWidth","pswpHeight","pswpType","thumbnailEl","_thumbnailEl$getAttri","currentSrc","getAttribute","pswpCropped","cropped","thumbCropped","lazyLoadData","$fafca69a57f78827$var$Opener","isClosed","isOpening","_duration","_useAnimation","_croppedZoom","_animateRootOpacity","_animateBgOpacity","_placeholder","_opacityElement","_cropContainer1","_cropContainer2","_thumbBounds","_prepareOpen","open","hideAnimationDuration","maxWidthToAnimate","_applyStartProps","showAnimationDuration","_options$showHideOpac","showHideAnimationType","showHideOpacity","_initialThumbBounds","getThumbBounds","_animateZoom","bg","opacity","innerRect","overflow","_setClosedStateZoomPan","willChange","Promise","resolve","img","decoded","isDelaying","$fafca69a57f78827$var$decodeImage","reject","_initiate","_this$pswp$element","_this$pswp$element2","setProperty","_animateToOpenState","_animateToClosedState","_onAnimationComplete","_animateTo","containerOnePanX","containerOnePanY","containerTwoPanX","containerTwoPanY","animProps","$fafca69a57f78827$var$defaultOptions","bgClickAction","tapAction","_prepareOptions","_prevViewportSize","isDestroying","hasMouse","_initialItemData","keyboard","_createMainStructure","rootClasses","mainClass","scrollWheel","isNaN","updateSize","pageYOffset","_handlePageResize","_updatePageScrollOffset","goTo","next","prev","_this$currSlide","_this$currSlide2","_itemHolder$slide2","refreshSlideContent","slideIndex","_this$currSlide$index","_this$currSlide3","_itemHolder$slide3","potentialHolderIndex","holder","matchMedia","matches","_this$element2","test","userAgent","setScrollOffset","body","$fafca69a57f78827$var$getThumbBounds","thumbBounds","thumbnail","thumbSelector","$fafca69a57f78827$var$getCroppedBoundsByElement","imageWidth","imageHeight","thumbAreaRect","getBoundingClientRect","fillZoomLevel","offsetX","offsetY","left","top","$fafca69a57f78827$var$getBoundsByElement","equalizePoints","roundPoint","getDistanceBetween","pointsEqual","clamp","toTransformString","setTransform","defaultCSSEasing","setTransitionStyle","setWidthHeight","removeTransitionStyle","decodeImage","LOAD_STATE","specialKeyUsed","getElementsFromOption","isSafari","supportsPassive","DOMEvents","getViewportSize","parsePaddingOption","getPanAreaSize","PanBounds","paddingProp","MAX_IMAGE_WIDTH","ZoomLevel","optionName","Slide","appendHeavyNearby","PAN_END_FRICTION","VERTICAL_DRAG_FRICTION","MIN_RATIO_TO_CLOSE","MIN_NEXT_SLIDE_SPEED","project","decelerationRate","DragHandler","mainScrollChanged","isRightToLeft","wasAtMinPanPosition","wasAtMaxPanPosition","UPPER_ZOOM_FRICTION","LOWER_ZOOM_FRICTION","getZoomPointsCenter","ZoomHandler","didTapOnMainContent","TapHandler","AXIS_SWIPE_HYSTERISIS","DOUBLE_TAP_DELAY","MIN_TAP_DISTANCE","Gestures","preventPointerEvent","MAIN_SCROLL_END_FRICTION","MainScroll","KeyboardKeyCodesMap","getKeyboardEventKey","Keyboard","DEFAULT_EASING","CSSAnimation","DEFAULT_NATURAL_FREQUENCY","DEFAULT_DAMPING_RATIO","SpringEaser","SpringAnimation","Animations","ScrollWheel","addElementHTML","UIElement","initArrowButton","arrowPrev","arrowNext","closeButton","zoomButton","loadingIndicator","counterIndicator","setZoomedIn","UI","currZoomLevelDiff","getBoundsByElement","getCroppedBoundsByElement","PhotoSwipeEvent","Eventable","Placeholder","Content","MIN_SLIDES_TO_CACHE","lazyLoadSlide","ContentLoader","PhotoSwipeBase","MIN_OPACITY","Opener","defaultOptions","PhotoSwipe"],"version":3,"file":"photoswipe.esm.b9f46f1c.js.map"} \ No newline at end of file diff --git a/start.43e10e4a.css b/start.43e10e4a.css new file mode 100644 index 0000000..98092cf --- /dev/null +++ b/start.43e10e4a.css @@ -0,0 +1,3 @@ +/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */ +.pswp{--pswp-bg:#000;--pswp-placeholder-bg:#222;--pswp-root-z-index:100000;--pswp-preloader-color:#4f4f4f66;--pswp-preloader-color-secondary:#ffffffe6;--pswp-icon-color:#fff;--pswp-icon-color-secondary:#4f4f4f;--pswp-icon-stroke-color:#4f4f4f;--pswp-icon-stroke-width:2px;--pswp-error-text-color:var(--pswp-icon-color);width:100%;height:100%;z-index:var(--pswp-root-z-index);touch-action:none;opacity:.003;contain:layout style size;-webkit-tap-highlight-color:#0000;outline:0;display:none;position:fixed;top:0;left:0}.pswp:focus{outline:0}.pswp *{box-sizing:border-box}.pswp img{max-width:none}.pswp--open{display:block}.pswp,.pswp__bg{will-change:opacity;transform:translateZ(0)}.pswp__bg{opacity:.005;background:var(--pswp-bg)}.pswp,.pswp__scroll-wrap{overflow:hidden}.pswp__scroll-wrap,.pswp__bg,.pswp__container,.pswp__item,.pswp__content,.pswp__img,.pswp__zoom-wrap{width:100%;height:100%;position:absolute;top:0;left:0}.pswp__img,.pswp__zoom-wrap{width:auto;height:auto}.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img{cursor:-webkit-zoom-in;cursor:-moz-zoom-in;cursor:zoom-in}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img,.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active,.pswp__img{cursor:-webkit-zoom-out;cursor:-moz-zoom-out;cursor:zoom-out}.pswp__container,.pswp__img,.pswp__button,.pswp__counter{-webkit-user-select:none;user-select:none}.pswp__item{z-index:1;overflow:hidden}.pswp__hidden{display:none!important}.pswp__content{pointer-events:none}.pswp__content>*{pointer-events:auto}.pswp__error-msg-container{display:grid}.pswp__error-msg{color:var(--pswp-error-text-color);margin:auto;font-size:1em;line-height:1}.pswp .pswp__hide-on-close{opacity:.005;will-change:opacity;transition:opacity var(--pswp-transition-duration)cubic-bezier(.4,0,.22,1);z-index:10;pointer-events:none}.pswp--ui-visible .pswp__hide-on-close{opacity:1;pointer-events:auto}.pswp__button{cursor:pointer;width:50px;height:60px;box-shadow:none;opacity:.85;-webkit-appearance:none;-webkit-touch-callout:none;background:0 0;border:0;margin:0;padding:0;display:block;position:relative;overflow:hidden}.pswp__button:hover,.pswp__button:active,.pswp__button:focus{box-shadow:none;opacity:1;background:0 0;border:0;padding:0;transition:none}.pswp__button:disabled{opacity:.3;cursor:auto}.pswp__icn{fill:var(--pswp-icon-color);color:var(--pswp-icon-color-secondary);pointer-events:none;width:32px;height:32px;position:absolute;top:14px;left:9px;overflow:hidden}.pswp__icn-shadow{stroke:var(--pswp-icon-stroke-color);stroke-width:var(--pswp-icon-stroke-width);fill:none}.pswp__icn:focus{outline:0}div.pswp__img--placeholder,.pswp__img--with-bg{background:var(--pswp-placeholder-bg)}.pswp__top-bar{z-index:10;flex-direction:row;justify-content:flex-end;width:100%;height:60px;display:flex;position:absolute;top:0;left:0;pointer-events:none!important}.pswp__top-bar>*{pointer-events:auto;will-change:opacity}.pswp__button--close{margin-right:6px}.pswp__button--arrow{width:75px;height:100px;margin-top:-50px;position:absolute;top:50%}.pswp__button--arrow:disabled{cursor:default;display:none}.pswp__button--arrow .pswp__icn{background:0 0;border-radius:0;width:60px;height:60px;margin-top:-30px;top:50%}.pswp--one-slide .pswp__button--arrow{display:none}.pswp--touch .pswp__button--arrow{visibility:hidden}.pswp--has_mouse .pswp__button--arrow{visibility:visible}.pswp__button--arrow--prev{left:0;right:auto}.pswp__button--arrow--next{right:0}.pswp__button--arrow--next .pswp__icn{left:auto;right:14px;transform:scaleX(-1)}.pswp__button--zoom{display:none}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__zoom-icn-bar-v{display:none}.pswp__preloader{width:50px;height:60px;margin-right:auto;position:relative;overflow:hidden}.pswp__preloader .pswp__icn{opacity:0;transition:opacity .2s linear;animation:.6s linear infinite pswp-clockwise}.pswp__preloader--active .pswp__icn{opacity:.85}@keyframes pswp-clockwise{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.pswp__counter{height:30px;color:var(--pswp-icon-color);text-shadow:1px 1px 3px var(--pswp-icon-color-secondary);opacity:.85;margin-top:15px;margin-inline-start:20px;font-size:14px;line-height:30px}.pswp--one-slide .pswp__counter{display:none} +/*# sourceMappingURL=start.43e10e4a.css.map */ diff --git a/start.43e10e4a.css.map b/start.43e10e4a.css.map new file mode 100644 index 0000000..f19f1b7 --- /dev/null +++ b/start.43e10e4a.css.map @@ -0,0 +1 @@ +{"mappings":"8D,qgB,sB,8B,yB,0B,4D,iD,yC,2J,mD,6G,6G,oH,+K,mG,sC,qC,mC,qC,wC,4F,sK,qE,8N,yI,8C,6K,4G,2B,qF,uK,yD,sC,wF,0D,+G,mD,oD,yD,6C,mC,gF,iC,sD,oD,4F,iH,gD,8E,sM","sources":["start.43e10e4a.css"],"sourcesContent":["/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */\n.pswp {\n --pswp-bg: #000;\n --pswp-placeholder-bg: #222;\n --pswp-root-z-index: 100000;\n --pswp-preloader-color: #4f4f4f66;\n --pswp-preloader-color-secondary: #ffffffe6;\n --pswp-icon-color: #fff;\n --pswp-icon-color-secondary: #4f4f4f;\n --pswp-icon-stroke-color: #4f4f4f;\n --pswp-icon-stroke-width: 2px;\n --pswp-error-text-color: var(--pswp-icon-color);\n width: 100%;\n height: 100%;\n z-index: var(--pswp-root-z-index);\n touch-action: none;\n opacity: .003;\n contain: layout style size;\n -webkit-tap-highlight-color: #0000;\n outline: 0;\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n}\n\n.pswp:focus {\n outline: 0;\n}\n\n.pswp * {\n box-sizing: border-box;\n}\n\n.pswp img {\n max-width: none;\n}\n\n.pswp--open {\n display: block;\n}\n\n.pswp, .pswp__bg {\n will-change: opacity;\n transform: translateZ(0);\n}\n\n.pswp__bg {\n opacity: .005;\n background: var(--pswp-bg);\n}\n\n.pswp, .pswp__scroll-wrap {\n overflow: hidden;\n}\n\n.pswp__scroll-wrap, .pswp__bg, .pswp__container, .pswp__item, .pswp__content, .pswp__img, .pswp__zoom-wrap {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.pswp__img, .pswp__zoom-wrap {\n width: auto;\n height: auto;\n}\n\n.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img {\n cursor: -webkit-zoom-in;\n cursor: -moz-zoom-in;\n cursor: zoom-in;\n}\n\n.pswp--click-to-zoom.pswp--zoomed-in .pswp__img {\n cursor: move;\n cursor: -webkit-grab;\n cursor: -moz-grab;\n cursor: grab;\n}\n\n.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active {\n cursor: -webkit-grabbing;\n cursor: -moz-grabbing;\n cursor: grabbing;\n}\n\n.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img, .pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active, .pswp__img {\n cursor: -webkit-zoom-out;\n cursor: -moz-zoom-out;\n cursor: zoom-out;\n}\n\n.pswp__container, .pswp__img, .pswp__button, .pswp__counter {\n -webkit-user-select: none;\n user-select: none;\n}\n\n.pswp__item {\n z-index: 1;\n overflow: hidden;\n}\n\n.pswp__hidden {\n display: none !important;\n}\n\n.pswp__content {\n pointer-events: none;\n}\n\n.pswp__content > * {\n pointer-events: auto;\n}\n\n.pswp__error-msg-container {\n display: grid;\n}\n\n.pswp__error-msg {\n color: var(--pswp-error-text-color);\n margin: auto;\n font-size: 1em;\n line-height: 1;\n}\n\n.pswp .pswp__hide-on-close {\n opacity: .005;\n will-change: opacity;\n transition: opacity var(--pswp-transition-duration) cubic-bezier(.4, 0, .22, 1);\n z-index: 10;\n pointer-events: none;\n}\n\n.pswp--ui-visible .pswp__hide-on-close {\n opacity: 1;\n pointer-events: auto;\n}\n\n.pswp__button {\n cursor: pointer;\n width: 50px;\n height: 60px;\n box-shadow: none;\n opacity: .85;\n -webkit-appearance: none;\n -webkit-touch-callout: none;\n background: none;\n border: 0;\n margin: 0;\n padding: 0;\n display: block;\n position: relative;\n overflow: hidden;\n}\n\n.pswp__button:hover, .pswp__button:active, .pswp__button:focus {\n box-shadow: none;\n opacity: 1;\n background: none;\n border: 0;\n padding: 0;\n transition: none;\n}\n\n.pswp__button:disabled {\n opacity: .3;\n cursor: auto;\n}\n\n.pswp__icn {\n fill: var(--pswp-icon-color);\n color: var(--pswp-icon-color-secondary);\n pointer-events: none;\n width: 32px;\n height: 32px;\n position: absolute;\n top: 14px;\n left: 9px;\n overflow: hidden;\n}\n\n.pswp__icn-shadow {\n stroke: var(--pswp-icon-stroke-color);\n stroke-width: var(--pswp-icon-stroke-width);\n fill: none;\n}\n\n.pswp__icn:focus {\n outline: 0;\n}\n\ndiv.pswp__img--placeholder, .pswp__img--with-bg {\n background: var(--pswp-placeholder-bg);\n}\n\n.pswp__top-bar {\n z-index: 10;\n flex-direction: row;\n justify-content: flex-end;\n width: 100%;\n height: 60px;\n display: flex;\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none !important;\n}\n\n.pswp__top-bar > * {\n pointer-events: auto;\n will-change: opacity;\n}\n\n.pswp__button--close {\n margin-right: 6px;\n}\n\n.pswp__button--arrow {\n width: 75px;\n height: 100px;\n margin-top: -50px;\n position: absolute;\n top: 50%;\n}\n\n.pswp__button--arrow:disabled {\n cursor: default;\n display: none;\n}\n\n.pswp__button--arrow .pswp__icn {\n background: none;\n border-radius: 0;\n width: 60px;\n height: 60px;\n margin-top: -30px;\n top: 50%;\n}\n\n.pswp--one-slide .pswp__button--arrow {\n display: none;\n}\n\n.pswp--touch .pswp__button--arrow {\n visibility: hidden;\n}\n\n.pswp--has_mouse .pswp__button--arrow {\n visibility: visible;\n}\n\n.pswp__button--arrow--prev {\n left: 0;\n right: auto;\n}\n\n.pswp__button--arrow--next {\n right: 0;\n}\n\n.pswp__button--arrow--next .pswp__icn {\n left: auto;\n right: 14px;\n transform: scale(-1, 1);\n}\n\n.pswp__button--zoom {\n display: none;\n}\n\n.pswp--zoom-allowed .pswp__button--zoom {\n display: block;\n}\n\n.pswp--zoomed-in .pswp__zoom-icn-bar-v {\n display: none;\n}\n\n.pswp__preloader {\n width: 50px;\n height: 60px;\n margin-right: auto;\n position: relative;\n overflow: hidden;\n}\n\n.pswp__preloader .pswp__icn {\n opacity: 0;\n transition: opacity .2s linear;\n animation: .6s linear infinite pswp-clockwise;\n}\n\n.pswp__preloader--active .pswp__icn {\n opacity: .85;\n}\n\n@keyframes pswp-clockwise {\n 0% {\n transform: rotate(0);\n }\n\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.pswp__counter {\n height: 30px;\n color: var(--pswp-icon-color);\n text-shadow: 1px 1px 3px var(--pswp-icon-color-secondary);\n opacity: .85;\n margin-top: 15px;\n margin-inline-start: 20px;\n font-size: 14px;\n line-height: 30px;\n}\n\n.pswp--one-slide .pswp__counter {\n display: none;\n}\n/*# sourceMappingURL=start.43e10e4a.css.map */\n"],"names":[],"version":3,"file":"start.43e10e4a.css.map"} \ No newline at end of file diff --git a/start.d08064e2.js b/start.d08064e2.js new file mode 100644 index 0000000..fa90968 --- /dev/null +++ b/start.d08064e2.js @@ -0,0 +1,5 @@ +!function(){function t(t,e,i,s){Object.defineProperty(t,e,{get:i,set:s,enumerable:!0,configurable:!0})}var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},i={},s={},n=e.parcelRequire94c2;null==n&&((n=function(t){if(t in i)return i[t].exports;if(t in s){var e=s[t];delete s[t];var n={id:t,exports:{}};return i[t]=n,e.call(n.exports,n,n.exports),n.exports}var l=Error("Cannot find module '"+t+"'");throw l.code="MODULE_NOT_FOUND",l}).register=function(t,e){s[t]=e},e.parcelRequire94c2=n);var l=n.register;/*! + * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com + * (c) 2024 Dmytro Semenov + */function r(t,e,i){let s=document.createElement(e);return t&&(s.className=t),i&&i.appendChild(s),s}function a(t,e,i){t.style.width="number"==typeof e?`${e}px`:e,t.style.height="number"==typeof i?`${i}px`:i}l("gXOAl",function(e,i){t(e.exports,"register",function(){return s},function(t){return s=t}),t(e.exports,"resolve",function(){return n},function(t){return n=t});var s,n,l=new Map;s=function(t,e){for(var i=0;in("gG83T"))}),l("8rY0l",function(t,e){var i=n("bhTHU");t.exports=i(function(t){return new Promise(function(e,i){if([].concat(document.getElementsByTagName("script")).some(function(e){return e.src===t})){e();return}var s=document.createElement("link");s.href=t,s.rel="preload",s.as="script",document.head.appendChild(s);var n=document.createElement("script");n.async=!0,n.type="text/javascript",n.src=t,n.onerror=function(e){var s=TypeError("Failed to fetch dynamically imported module: ".concat(t,". Error: ").concat(e.message));n.onerror=n.onload=null,n.remove(),i(s)},n.onload=function(){n.onerror=n.onload=null,e()},document.getElementsByTagName("head")[0].appendChild(n)})})}),l("bhTHU",function(t,e){var i={},s={},n={};t.exports=function(t,e){return function(l){var r=function(t){switch(t){case"preload":return s;case"prefetch":return n;default:return i}}(e);return r[l]?r[l]:r[l]=t.apply(null,arguments).catch(function(t){throw delete r[l],t})}}}),n("gXOAl").register(n("3qTPU").getBundleURL("Y24sw"),JSON.parse('["Y24sw","start.d08064e2.js","9fYSr","photoswipe.esm.2e2aa850.js","1Fjha","start.43e10e4a.css"]'));let o={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function h(t,e,i=document){let s=[];if(t instanceof Element)s=[t];else if(t instanceof NodeList||Array.isArray(t))s=Array.from(t);else{let n="string"==typeof t?t:e;n&&(s=Array.from(i.querySelectorAll(n)))}return s}function d(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}class p{constructor(t,e){this.type=t,this.defaultPrevented=!1,e&&Object.assign(this,e)}preventDefault(){this.defaultPrevented=!0}}class c{constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,e,i=100){var s,n,l;this._filters[t]||(this._filters[t]=[]),null===(s=this._filters[t])||void 0===s||s.push({fn:e,priority:i}),null===(n=this._filters[t])||void 0===n||n.sort((t,e)=>t.priority-e.priority),null===(l=this.pswp)||void 0===l||l.addFilter(t,e,i)}removeFilter(t,e){this._filters[t]&&(this._filters[t]=this._filters[t].filter(t=>t.fn!==e)),this.pswp&&this.pswp.removeFilter(t,e)}applyFilters(t,...e){var i;return null===(i=this._filters[t])||void 0===i||i.forEach(t=>{e[0]=t.fn.apply(this,e)}),e[0]}on(t,e){var i,s;this._listeners[t]||(this._listeners[t]=[]),null===(i=this._listeners[t])||void 0===i||i.push(e),null===(s=this.pswp)||void 0===s||s.on(t,e)}off(t,e){var i;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(t=>e!==t)),null===(i=this.pswp)||void 0===i||i.off(t,e)}dispatch(t,e){var i;if(this.pswp)return this.pswp.dispatch(t,e);let s=new p(t,e);return null===(i=this._listeners[t])||void 0===i||i.forEach(t=>{t.call(this,s)}),s}}class u{constructor(t,e){if(this.element=r("pswp__img pswp__img--placeholder",t?"img":"div",e),t){let e=this.element;e.decoding="async",e.alt="",e.src=t,e.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,e){if(this.element){if("IMG"===this.element.tagName){var i;let e;a(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=(e="translate3d(0px,0px,0)",i=t/250,e+=` scale3d(${i},${i},1)`)}else a(this.element,t,e)}}destroy(){var t;null!==(t=this.element)&&void 0!==t&&t.parentNode&&this.element.remove(),this.element=null}}class m{constructor(t,e,i){this.instance=e,this.data=t,this.index=i,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=o.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,e){if(this.slide&&this.usePlaceholder()){if(this.placeholder){let t=this.placeholder.element;t&&!t.parentElement&&this.slide.container.prepend(t)}else{let t=this.instance.applyFilters("placeholderSrc",!!this.data.msrc&&!!this.slide.isFirstSlide&&this.data.msrc,this);this.placeholder=new u(t,this.slide.container)}}(!this.element||e)&&!this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented&&(this.isImageContent()?(this.element=r("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=r("pswp__content","div"),this.element.innerHTML=this.data.html||""),e&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){var e,i;if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;let s=this.element;this.updateSrcsetSizes(),this.data.srcset&&(s.srcset=this.data.srcset),s.src=null!==(e=this.data.src)&&void 0!==e?e:"",s.alt=null!==(i=this.data.alt)&&void 0!==i?i:"",this.state=o.LOADING,s.complete?this.onLoaded():(s.onload=()=>{this.onLoaded()},s.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=o.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===o.LOADED||this.state===o.ERROR)&&this.removePlaceholder())}onError(){this.state=o.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===o.LOADING,this)}isError(){return this.state===o.ERROR}isImageContent(){return"image"===this.type}setDisplayedSize(t,e){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,e),!this.instance.dispatch("contentResize",{content:this,width:t,height:e}).defaultPrevented&&(a(this.element,t,e),this.isImageContent()&&!this.isError()))){let i=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=e,i?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:e,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==o.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;let t=this.element,e=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||e>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=e+"px",t.dataset.largestUsedSize=String(e))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){if(this.slide){var t,e;let i=r("pswp__error-msg","div");i.innerText=null!==(t=null===(e=this.instance.options)||void 0===e?void 0:e.errorMsg)&&void 0!==t?t:"",i=this.instance.applyFilters("contentErrorElement",i,this),this.element=r("pswp__content pswp__error-msg-container","div"),this.element.appendChild(i),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===o.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;let t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||d())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){!this.instance.dispatch("contentActivate",{content:this}).defaultPrevented&&this.slide&&(this.isImageContent()&&this.isDecoding&&!d()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===o.LOADED||this.state===o.ERROR)&&this.removePlaceholder()))}}function f(t,e,i,s,n){let l=0;if(e.paddingFn)l=e.paddingFn(i,s,n)[t];else if(e.padding)l=e.padding[t];else{let i="padding"+t[0].toUpperCase()+t.slice(1);e[i]&&(l=e[i])}return Number(l)||0}class g{constructor(t,e,i,s){this.pswp=s,this.options=t,this.itemData=e,this.index=i,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,e,i){let s={x:t,y:e};this.elementSize=s,this.panAreaSize=i;let n=i.x/s.x,l=i.y/s.y;this.fit=Math.min(1,nl?n:l),this.vFill=Math.min(1,l),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){let e=this.options[t+"ZoomLevel"];if(e)return"function"==typeof e?e(this):"fill"===e?this.fill:"fit"===e?this.fit:Number(e)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,3*this.fit),this.elementSize&&t*this.elementSize.x>4e3&&(t=4e3/this.elementSize.x)),t}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,4*this.fit)}}function y(t,e,i){let s;let n=e.createContentFromData(t,i),{options:l}=e;if(l){let r;s=new g(l,t,-1);let a={x:(r=e.pswp?e.pswp.viewportSize:function(t,e){if(t.getViewportSizeFn){let i=t.getViewportSizeFn(t,e);if(i)return i}return{x:document.documentElement.clientWidth,y:window.innerHeight}}(l,e)).x-f("left",l,r,t,i)-f("right",l,r,t,i),y:r.y-f("top",l,r,t,i)-f("bottom",l,r,t,i)};s.update(n.width,n.height,a)}return n.lazyLoad(),s&&n.setDisplayedSize(Math.ceil(n.width*s.initial),Math.ceil(n.height*s.initial)),n}class v extends c{getNumItems(){var t;let e=0,i=null===(t=this.options)||void 0===t?void 0:t.dataSource;i&&"length"in i?e=i.length:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),i.items&&(e=i.items.length));let s=this.dispatch("numItems",{dataSource:i,numItems:e});return this.applyFilters("numItems",s.numItems,i)}createContentFromData(t,e){return new m(t,this,e)}getItemData(t){var e;let i=null===(e=this.options)||void 0===e?void 0:e.dataSource,s={};Array.isArray(i)?s=i[t]:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),s=i.items[t]);let n=s;n instanceof Element&&(n=this._domElementToItemData(n));let l=this.dispatch("itemData",{itemData:n||{},index:t});return this.applyFilters("itemData",l.itemData,t)}_getGalleryDOMElements(t){var e,i;return null!==(e=this.options)&&void 0!==e&&e.children||null!==(i=this.options)&&void 0!==i&&i.childSelector?h(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){let e={element:t},i="A"===t.tagName?t:t.querySelector("a");if(i){e.src=i.dataset.pswpSrc||i.href,i.dataset.pswpSrcset&&(e.srcset=i.dataset.pswpSrcset),e.width=i.dataset.pswpWidth?parseInt(i.dataset.pswpWidth,10):0,e.height=i.dataset.pswpHeight?parseInt(i.dataset.pswpHeight,10):0,e.w=e.width,e.h=e.height,i.dataset.pswpType&&(e.type=i.dataset.pswpType);let n=t.querySelector("img");if(n){var s;e.msrc=n.currentSrc||n.src,e.alt=null!==(s=n.getAttribute("alt"))&&void 0!==s?s:""}(i.dataset.pswpCropped||i.dataset.cropped)&&(e.thumbCropped=!0)}return this.applyFilters("domItemData",e,t,i)}lazyLoadData(t,e){return y(t,this,e)}}new class extends v{constructor(t){super(),this.options=t||{},this._uid=0,this.shouldOpen=!1,this._preloadedContent=void 0,this.onThumbnailsClick=this.onThumbnailsClick.bind(this)}init(){h(this.options.gallery,this.options.gallerySelector).forEach(t=>{t.addEventListener("click",this.onThumbnailsClick,!1)})}onThumbnailsClick(t){if("button"in t&&1===t.button||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||window.pswp)return;let e={x:t.clientX,y:t.clientY};e.x||e.y||(e=null);let i=this.getClickedIndex(t);i=this.applyFilters("clickedIndex",i,t,this);let s={gallery:t.currentTarget};i>=0&&(t.preventDefault(),this.loadAndOpen(i,s,e))}getClickedIndex(t){if(this.options.getClickedIndexFn)return this.options.getClickedIndexFn.call(this,t);let e=t.target,i=h(this.options.children,this.options.childSelector,t.currentTarget).findIndex(t=>t===e||t.contains(e));return -1!==i?i:this.options.children||this.options.childSelector?-1:0}loadAndOpen(t,e,i){if(window.pswp||!this.options)return!1;if(!e&&this.options.gallery&&this.options.children){let t=h(this.options.gallery);t[0]&&(e={gallery:t[0]})}return this.options.index=t,this.options.initialPointerPos=i,this.shouldOpen=!0,this.preload(t,e),!0}preload(t,e){var i;let{options:s}=this;e&&(s.dataSource=e);let n=[],l=typeof s.pswpModule;if("function"==typeof(i=s.pswpModule)&&i.prototype&&i.prototype.goTo)n.push(Promise.resolve(s.pswpModule));else if("string"===l)throw Error("pswpModule as string is no longer supported");else if("function"===l)n.push(s.pswpModule());else throw Error("pswpModule is not valid");"function"==typeof s.openPromise&&n.push(s.openPromise()),!1!==s.preloadFirstSlide&&t>=0&&(this._preloadedContent=function(t,e){let i=e.getItemData(t);if(!e.dispatch("lazyLoadSlide",{index:t,itemData:i}).defaultPrevented)return y(i,e,t)}(t,this));let r=++this._uid;Promise.all(n).then(t=>{if(this.shouldOpen){let e=t[0];this._openPhotoswipe(e,r)}})}_openPhotoswipe(t,e){if(e!==this._uid&&this.shouldOpen||(this.shouldOpen=!1,window.pswp))return;let i="object"==typeof t?new t.default(this.options):new t(this.options);this.pswp=i,window.pswp=i,Object.keys(this._listeners).forEach(t=>{var e;null===(e=this._listeners[t])||void 0===e||e.forEach(e=>{i.on(t,e)})}),Object.keys(this._filters).forEach(t=>{var e;null===(e=this._filters[t])||void 0===e||e.forEach(e=>{i.addFilter(t,e.fn,e.priority)})}),this._preloadedContent&&(i.contentLoader.addToCache(this._preloadedContent),this._preloadedContent=void 0),i.on("destroy",()=>{this.pswp=void 0,delete window.pswp}),i.init()}destroy(){var t;null===(t=this.pswp)||void 0===t||t.destroy(),this.shouldOpen=!1,this._listeners={},h(this.options.gallery,this.options.gallerySelector).forEach(t=>{t.removeEventListener("click",this.onThumbnailsClick,!1)})}}({gallery:"#gallery--zoom-transition",children:"a",showHideAnimationType:"zoom",pswpModule:()=>n("5j4xs")}).init()}(); +//# sourceMappingURL=start.d08064e2.js.map diff --git a/start.d08064e2.js.map b/start.d08064e2.js.map new file mode 100644 index 0000000..8210922 --- /dev/null +++ b/start.d08064e2.js.map @@ -0,0 +1 @@ +{"mappings":"C,A,W,S,E,C,C,C,C,C,C,C,E,O,c,C,E,E,C,I,E,I,E,W,C,E,a,C,C,E,C,I,E,A,a,O,W,W,A,a,O,K,K,A,a,O,O,O,A,a,O,O,O,C,E,E,C,E,E,C,E,E,E,iB,A,O,I,A,C,E,S,C,E,G,K,E,O,C,C,E,C,O,C,G,K,E,C,I,E,C,C,E,A,Q,C,C,E,C,I,E,C,G,E,Q,C,C,E,O,C,C,E,C,E,E,I,C,E,O,C,E,E,O,E,E,O,A,C,I,E,A,M,uB,E,I,O,E,I,C,mB,C,C,E,Q,C,S,C,C,C,E,C,C,E,C,C,E,E,iB,C,G,I,E,E,Q,A;;;E,ESSO,SAASmC,EAAcL,CAAvB,CAAkCC,CAAlC,CAA2CC,CAA3C,EACL,IAAMC,EAAKC,SAASC,aAAT,CAAuBJ,GAOlC,OANID,GACFG,CAAAA,EAAGH,SAAH,CAAeA,CADjB,EAGIE,GACFA,EAAWI,WAAX,CAAuBH,GAElBA,CACR,CAoHM,SAASqV,EAAerV,CAAxB,CAA4BK,CAA5B,CAA+BC,CAA/B,EACLN,EAAGO,KAAH,CAASC,KAAT,CAAkB,AAAa,UAAb,OAAOH,EAAmB,CAAA,EAAEA,EAAE,EAAA,CAA/B,CAAqCA,EACtDL,EAAGO,KAAH,CAASE,MAAT,CAAmB,AAAa,UAAb,OAAOH,EAAmB,CAAA,EAAEA,EAAE,EAAA,CAA/B,CAAqCA,CACxD,C,E,Q,S,C,C,C,E,E,E,O,C,W,W,O,C,E,S,C,E,O,E,C,G,E,E,O,C,U,W,O,C,E,S,C,E,O,E,C,GRvID,IAgBA,EACA,EAjBI,EAAU,IAAI,IAgBlB,EAfA,SAAkB,CAAO,CAAE,CAAQ,EACjC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,MAAM,CAAG,EAAG,GAAK,EAC5C,EAAQ,GAAG,CAAC,CAAQ,CAAC,EAAE,CAAE,CACvB,QAAS,EACT,KAAM,CAAQ,CAAC,EAAI,EAAE,AACvB,EAEJ,EASA,EARA,SAAiB,CAAE,EACjB,IAAI,EAAW,EAAQ,GAAG,CAAC,GAC3B,GAAI,AAAY,MAAZ,EACF,MAAM,AAAI,MAAM,oCAAsC,GAExD,OAAO,IAAI,IAAI,EAAS,IAAI,CAAE,EAAS,OAAO,EAAE,QAAQ,EA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","sources":["","node_modules/@parcel/runtime-js/lib/helpers/bundle-manifest.js","node_modules/@parcel/runtime-js/lib/helpers/bundle-url.js","node_modules/@parcel/runtime-js/lib/runtime-f328dc44482734e3.js","node_modules/@parcel/runtime-js/lib/helpers/browser/js-loader.js","node_modules/@parcel/runtime-js/lib/helpers/cacheLoader.js","node_modules/@parcel/runtime-js/lib/runtime-d497c813a9215bd1.js","src/js/gallery.js","node_modules/photoswipe/dist/photoswipe-lightbox.esm.js","src/js/util/util.js","src/js/core/eventable.js","src/js/slide/placeholder.js","src/js/slide/content.js","src/js/util/viewport-size.js","src/js/slide/zoom-level.js","src/js/slide/loader.js","src/js/core/base.js","src/js/lightbox/lightbox.js"],"sourcesContent":["(function () {\n\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n \nvar $parcel$modules = {};\nvar $parcel$inits = {};\n\nvar parcelRequire = $parcel$global[\"parcelRequire94c2\"];\n\nif (parcelRequire == null) {\n parcelRequire = function(id) {\n if (id in $parcel$modules) {\n return $parcel$modules[id].exports;\n }\n if (id in $parcel$inits) {\n var init = $parcel$inits[id];\n delete $parcel$inits[id];\n var module = {id: id, exports: {}};\n $parcel$modules[id] = module;\n init.call(module.exports, module, module.exports);\n return module.exports;\n }\n var err = new Error(\"Cannot find module '\" + id + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n };\n\n parcelRequire.register = function register(id, init) {\n $parcel$inits[id] = init;\n };\n\n $parcel$global[\"parcelRequire94c2\"] = parcelRequire;\n}\n\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"gXOAl\", function(module, exports) {\n\n$parcel$export(module.exports, \"register\", function () { return $c5996531136d329f$export$6503ec6e8aabbaf; }, function (v) { return $c5996531136d329f$export$6503ec6e8aabbaf = v; });\n$parcel$export(module.exports, \"resolve\", function () { return $c5996531136d329f$export$f7ad0328861e2f03; }, function (v) { return $c5996531136d329f$export$f7ad0328861e2f03 = v; });\nvar $c5996531136d329f$export$6503ec6e8aabbaf;\nvar $c5996531136d329f$export$f7ad0328861e2f03;\n\"use strict\";\nvar $c5996531136d329f$var$mapping = new Map();\nfunction $c5996531136d329f$var$register(baseUrl, manifest) {\n for(var i = 0; i < manifest.length - 1; i += 2)$c5996531136d329f$var$mapping.set(manifest[i], {\n baseUrl: baseUrl,\n path: manifest[i + 1]\n });\n}\nfunction $c5996531136d329f$var$resolve(id) {\n var resolved = $c5996531136d329f$var$mapping.get(id);\n if (resolved == null) throw new Error('Could not resolve bundle with id ' + id);\n return new URL(resolved.path, resolved.baseUrl).toString();\n}\n$c5996531136d329f$export$6503ec6e8aabbaf = $c5996531136d329f$var$register;\n$c5996531136d329f$export$f7ad0328861e2f03 = $c5996531136d329f$var$resolve;\n\n});\n\nparcelRegister(\"3qTPU\", function(module, exports) {\n\n$parcel$export(module.exports, \"getBundleURL\", function () { return $27ff1cb64c26d98d$export$bdfd709ae4826697; }, function (v) { return $27ff1cb64c26d98d$export$bdfd709ae4826697 = v; });\nvar $27ff1cb64c26d98d$export$bdfd709ae4826697;\nvar $27ff1cb64c26d98d$export$c9e73fbda7da57b6;\nvar $27ff1cb64c26d98d$export$5a759dc7a1cfb72a;\n\"use strict\";\nvar $27ff1cb64c26d98d$var$bundleURL = {};\nfunction $27ff1cb64c26d98d$var$getBundleURLCached(id) {\n var value = $27ff1cb64c26d98d$var$bundleURL[id];\n if (!value) {\n value = $27ff1cb64c26d98d$var$getBundleURL();\n $27ff1cb64c26d98d$var$bundleURL[id] = value;\n }\n return value;\n}\nfunction $27ff1cb64c26d98d$var$getBundleURL() {\n try {\n throw new Error();\n } catch (err) {\n var matches = ('' + err.stack).match(/(https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/[^)\\n]+/g);\n if (matches) // The first two stack frames will be this function and getBundleURLCached.\n // Use the 3rd one, which will be a runtime in the original bundle.\n return $27ff1cb64c26d98d$var$getBaseURL(matches[2]);\n }\n return '/';\n}\nfunction $27ff1cb64c26d98d$var$getBaseURL(url) {\n return ('' + url).replace(/^((?:https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/.+)\\/[^/]+$/, '$1') + '/';\n}\n// TODO: Replace uses with `new URL(url).origin` when ie11 is no longer supported.\nfunction $27ff1cb64c26d98d$var$getOrigin(url) {\n var matches = ('' + url).match(/(https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/[^/]+/);\n if (!matches) throw new Error('Origin not found');\n return matches[0];\n}\n$27ff1cb64c26d98d$export$bdfd709ae4826697 = $27ff1cb64c26d98d$var$getBundleURLCached;\n$27ff1cb64c26d98d$export$c9e73fbda7da57b6 = $27ff1cb64c26d98d$var$getBaseURL;\n$27ff1cb64c26d98d$export$5a759dc7a1cfb72a = $27ff1cb64c26d98d$var$getOrigin;\n\n});\n\nparcelRegister(\"5j4xs\", function(module, exports) {\n\n\nmodule.exports = (parcelRequire(\"8rY0l\"))((parcelRequire(\"gXOAl\")).resolve(\"9fYSr\")).then(()=>parcelRequire('gG83T'));\n\n});\nparcelRegister(\"8rY0l\", function(module, exports) {\n\"use strict\";\n\nvar $bhTHU = parcelRequire(\"bhTHU\");\nmodule.exports = $bhTHU(function(bundle) {\n return new Promise(function(resolve, reject) {\n // Don't insert the same script twice (e.g. if it was already in the HTML)\n var existingScripts = document.getElementsByTagName('script');\n if ([].concat(existingScripts).some(function(script) {\n return script.src === bundle;\n })) {\n resolve();\n return;\n }\n var preloadLink = document.createElement('link');\n preloadLink.href = bundle;\n preloadLink.rel = 'preload';\n preloadLink.as = 'script';\n document.head.appendChild(preloadLink);\n var script = document.createElement('script');\n script.async = true;\n script.type = 'text/javascript';\n script.src = bundle;\n script.onerror = function(e) {\n var error = new TypeError(\"Failed to fetch dynamically imported module: \".concat(bundle, \". Error: \").concat(e.message));\n script.onerror = script.onload = null;\n script.remove();\n reject(error);\n };\n script.onload = function() {\n script.onerror = script.onload = null;\n resolve();\n };\n document.getElementsByTagName('head')[0].appendChild(script);\n });\n});\n\n});\nparcelRegister(\"bhTHU\", function(module, exports) {\n\"use strict\";\nvar $837c7e8249871e82$var$cachedBundles = {};\nvar $837c7e8249871e82$var$cachedPreloads = {};\nvar $837c7e8249871e82$var$cachedPrefetches = {};\nfunction $837c7e8249871e82$var$getCache(type) {\n switch(type){\n case 'preload':\n return $837c7e8249871e82$var$cachedPreloads;\n case 'prefetch':\n return $837c7e8249871e82$var$cachedPrefetches;\n default:\n return $837c7e8249871e82$var$cachedBundles;\n }\n}\nmodule.exports = function(loader, type) {\n return function(bundle) {\n var cache = $837c7e8249871e82$var$getCache(type);\n if (cache[bundle]) return cache[bundle];\n return cache[bundle] = loader.apply(null, arguments).catch(function(e) {\n delete cache[bundle];\n throw e;\n });\n };\n};\n\n});\n\n\n\nvar $86e14355d5893f61$exports = {};\n\n\n(parcelRequire(\"gXOAl\")).register((parcelRequire(\"3qTPU\")).getBundleURL('Y24sw'), JSON.parse(\"[\\\"Y24sw\\\",\\\"start.d08064e2.js\\\",\\\"9fYSr\\\",\\\"photoswipe.esm.2e2aa850.js\\\",\\\"1Fjha\\\",\\\"start.43e10e4a.css\\\"]\"));\n\n/*!\n * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */ /** @typedef {import('../photoswipe.js').Point} Point */ /**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */ function $a30b46f7f651be66$var$createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) el.className = className;\n if (appendToEl) appendToEl.appendChild(el);\n return el;\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */ function $a30b46f7f651be66$var$toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n if (scale !== undefined) propValue += ` scale3d(${scale},${scale},1)`;\n return propValue;\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */ function $a30b46f7f651be66$var$setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ /** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ const $a30b46f7f651be66$var$LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */ function $a30b46f7f651be66$var$specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */ function $a30b46f7f651be66$var$getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */ let elements = [];\n if (option instanceof Element) elements = [\n option\n ];\n else if (option instanceof NodeList || Array.isArray(option)) elements = Array.from(option);\n else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) elements = Array.from(parent.querySelectorAll(selector));\n }\n return elements;\n}\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */ function $a30b46f7f651be66$var$isPswpClass(fn) {\n return typeof fn === 'function' && fn.prototype && fn.prototype.goTo;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */ function $a30b46f7f651be66$var$isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../slide/content.js').default} ContentDefault */ /** @typedef {import('../slide/slide.js').default} Slide */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ /** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ /**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */ /** @typedef {{ x?: number; y?: number }} Point */ /**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */ /**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */ /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */ /**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */ class $a30b46f7f651be66$var$PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */ constructor(type, details){\n this.type = type;\n this.defaultPrevented = false;\n if (details) Object.assign(this, details);\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */ class $a30b46f7f651be66$var$Eventable {\n constructor(){\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */ this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */ this._filters = {};\n /** @type {PhotoSwipe | undefined} */ this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */ this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */ addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n if (!this._filters[name]) this._filters[name] = [];\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn: fn,\n priority: priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2)=>f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */ removeFilter(name, fn) {\n if (this._filters[name]) // @ts-expect-error\n this._filters[name] = this._filters[name].filter((filter)=>filter.fn !== fn);\n if (this.pswp) this.pswp.removeFilter(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */ applyFilters(name, ...args) {\n var _this$_filters$name3;\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach((filter)=>{\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n if (!this._listeners[name]) this._listeners[name] = [];\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ off(name, fn) {\n var _this$pswp3;\n if (this._listeners[name]) // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter((listener)=>fn !== listener);\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */ dispatch(name, details) {\n var _this$_listeners$name2;\n if (this.pswp) return this.pswp.dispatch(name, details);\n const event = /** @type {AugmentedEvent} */ new $a30b46f7f651be66$var$PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach((listener)=>{\n listener.call(this, event);\n });\n return event;\n }\n}\nclass $a30b46f7f651be66$var$Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */ constructor(imageSrc, container){\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */ this.element = $a30b46f7f651be66$var$createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n $a30b46f7f651be66$var$setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = $a30b46f7f651be66$var$toTransformString(0, 0, width / 250);\n } else $a30b46f7f651be66$var$setWidthHeight(this.element, width, height);\n }\n destroy() {\n var _this$element;\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) this.element.remove();\n this.element = null;\n }\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../util/util.js').LoadState} LoadState */ class $a30b46f7f651be66$var$Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */ constructor(itemData, instance, index){\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {Placeholder | undefined} */ this.placeholder = undefined;\n /** @type {Slide | undefined} */ this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */ this.state = $a30b46f7f651be66$var$LOAD_STATE.IDLE;\n if (this.data.type) this.type = this.data.type;\n else if (this.data.src) this.type = 'image';\n else this.type = 'html';\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) // With delay, as image might be loaded, but not rendered\n setTimeout(()=>{\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */ load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new $a30b46f7f651be66$var$Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) this.slide.container.prepend(placeholderEl);\n }\n }\n if (this.element && !reload) return;\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n if (this.isImageContent()) {\n this.element = $a30b46f7f651be66$var$createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) this.loadImage(isLazy);\n } else {\n this.element = $a30b46f7f651be66$var$createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n if (reload && this.slide) this.slide.updateContentSize(true);\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */ loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n const imageElement = /** @type HTMLImageElement */ this.element;\n this.updateSrcsetSizes();\n if (this.data.srcset) imageElement.srcset = this.data.srcset;\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = $a30b46f7f651be66$var$LOAD_STATE.LOADING;\n if (imageElement.complete) this.onLoaded();\n else {\n imageElement.onload = ()=>{\n this.onLoaded();\n };\n imageElement.onerror = ()=>{\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */ setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */ onLoaded() {\n this.state = $a30b46f7f651be66$var$LOAD_STATE.LOADED;\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n if (this.state === $a30b46f7f651be66$var$LOAD_STATE.LOADED || this.state === $a30b46f7f651be66$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n }\n /**\r\n * Content load error handler\r\n */ onError() {\n this.state = $a30b46f7f651be66$var$LOAD_STATE.ERROR;\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */ isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === $a30b46f7f651be66$var$LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */ isError() {\n return this.state === $a30b46f7f651be66$var$LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */ isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.placeholder) this.placeholder.setDisplayedSize(width, height);\n if (this.instance.dispatch('contentResize', {\n content: this,\n width: width,\n height: height\n }).defaultPrevented) return;\n $a30b46f7f651be66$var$setWidthHeight(this.element, width, height);\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n if (isInitialSizeUpdate) this.loadImage(false);\n else this.updateSrcsetSizes();\n if (this.slide) this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width: width,\n height: height,\n content: this\n });\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */ isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== $a30b46f7f651be66$var$LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */ updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) return;\n const image = /** @type HTMLImageElement */ this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */ usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */ lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) return;\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */ keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */ destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) return;\n this.remove();\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */ displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n let errorMsgEl = $a30b46f7f651be66$var$createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl = /** @type {HTMLDivElement} */ this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = $a30b46f7f651be66$var$createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */ append() {\n if (this.isAttached || !this.element) return;\n this.isAttached = true;\n if (this.state === $a30b46f7f651be66$var$LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) return;\n const supportsDecode = 'decode' in this.element;\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || $a30b46f7f651be66$var$isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */ this.element.decode().catch(()=>{}).finally(()=>{\n this.isDecoding = false;\n this.appendImage();\n });\n } else this.appendImage();\n } else if (this.slide && !this.element.parentNode) this.slide.container.appendChild(this.element);\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */ activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) return;\n if (this.isImageContent() && this.isDecoding && !$a30b46f7f651be66$var$isSafari()) // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n else if (this.isError()) this.load(false, true); // try to reload\n if (this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n /**\r\n * Deactivate the content\r\n */ deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n if (this.slide && this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * Remove the content from DOM\r\n */ remove() {\n this.isAttached = false;\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) return;\n if (this.element && this.element.parentNode) this.element.remove();\n if (this.placeholder && this.placeholder.element) this.placeholder.element.remove();\n }\n /**\r\n * Append the image content to slide container\r\n */ appendImage() {\n if (!this.isAttached) return;\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) return;\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) this.slide.container.appendChild(this.element);\n if (this.state === $a30b46f7f651be66$var$LOAD_STATE.LOADED || this.state === $a30b46f7f651be66$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n}\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */ function $a30b46f7f651be66$var$getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) return newViewportSize;\n }\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */ function $a30b46f7f651be66$var$parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n if (options.paddingFn) paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n else if (options.padding) paddingValue = options.padding[prop];\n else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n if (options[legacyPropName]) // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */ function $a30b46f7f651be66$var$getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - $a30b46f7f651be66$var$parsePaddingOption('left', options, viewportSize, itemData, index) - $a30b46f7f651be66$var$parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - $a30b46f7f651be66$var$parsePaddingOption('top', options, viewportSize, itemData, index) - $a30b46f7f651be66$var$parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\nconst $a30b46f7f651be66$var$MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ /**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */ class $a30b46f7f651be66$var$ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */ constructor(options, itemData, index, pswp){\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */ this.panAreaSize = null;\n /** @type { Point | null } */ this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */ update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */ const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n if (this.pswp) this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */ _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n if (!optionValue) return;\n if (typeof optionValue === 'function') return optionValue(this);\n if (optionValue === 'fill') return this.fill;\n if (optionValue === 'fit') return this.fit;\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n if (currZoomLevel) return currZoomLevel;\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n if (this.elementSize && currZoomLevel * this.elementSize.x > $a30b46f7f651be66$var$MAX_IMAGE_WIDTH) currZoomLevel = $a30b46f7f651be66$var$MAX_IMAGE_WIDTH / this.elementSize.x;\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ function $a30b46f7f651be66$var$lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */ let zoomLevel;\n const { options: options } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new $a30b46f7f651be66$var$ZoomLevel(options, itemData, -1);\n let viewportSize;\n if (instance.pswp) viewportSize = instance.pswp.viewportSize;\n else viewportSize = $a30b46f7f651be66$var$getViewportSize(options, instance);\n const panAreaSize = $a30b46f7f651be66$var$getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n content.lazyLoad();\n if (zoomLevel) content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */ function $a30b46f7f651be66$var$lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n if (instance.dispatch('lazyLoadSlide', {\n index: index,\n itemData: itemData\n }).defaultPrevented) return;\n return $a30b46f7f651be66$var$lazyLoadData(itemData, instance, index);\n}\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */ /** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */ /**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */ class $a30b46f7f651be66$var$PhotoSwipeBase extends $a30b46f7f651be66$var$Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */ getNumItems() {\n var _this$options;\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n if (dataSource && 'length' in dataSource) // may be an array or just object with length property\n numItems = dataSource.length;\n else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n if (dataSource.items) numItems = dataSource.items.length;\n } // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource: dataSource,\n numItems: numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */ createContentFromData(slideData, index) {\n return new $a30b46f7f651be66$var$Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */ getItemData(index) {\n var _this$options2;\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */ let dataSourceItem = {};\n if (Array.isArray(dataSource)) // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n dataSourceItem = dataSource.items[index];\n }\n let itemData = dataSourceItem;\n if (itemData instanceof Element) itemData = this._domElementToItemData(itemData);\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index: index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */ _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) return $a30b46f7f651be66$var$getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n return [\n galleryElement\n ];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */ _domElementToItemData(element) {\n /** @type {SlideData} */ const itemData = {\n element: element\n };\n const linkEl = /** @type {HTMLAnchorElement} */ element.tagName === 'A' ? element : element.querySelector('a');\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n if (linkEl.dataset.pswpSrcset) itemData.srcset = linkEl.dataset.pswpSrcset;\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n if (linkEl.dataset.pswpType) itemData.type = linkEl.dataset.pswpType;\n const thumbnailEl = element.querySelector('img');\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) itemData.thumbCropped = true;\n }\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ lazyLoadData(itemData, index) {\n return $a30b46f7f651be66$var$lazyLoadData(itemData, this, index);\n }\n}\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/content.js').default} Content */ /** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ /** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */ /**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */ class $a30b46f7f651be66$export$2e2bcd8739ae039 extends $a30b46f7f651be66$var$PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */ constructor(options){\n super();\n /** @type {PhotoSwipeOptions} */ this.options = options || {};\n this._uid = 0;\n this.shouldOpen = false;\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */ this._preloadedContent = undefined;\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n }\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */ init() {\n // Bind click events to each gallery\n $a30b46f7f651be66$var$getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach((galleryElement)=>{\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n });\n }\n /**\r\n * @param {MouseEvent} e\r\n */ onThumbnailsClick(e) {\n // Exit and allow default browser action if:\n if ($a30b46f7f651be66$var$specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n || window.pswp) // ... if PhotoSwipe is already open\n return;\n // If both clientX and clientY are 0 or not defined,\n // the event is likely triggered by keyboard,\n // so we do not pass the initialPoint\n //\n // Note that some screen readers emulate the mouse position,\n // so it's not the ideal way to detect them.\n //\n /** @type {Point | null} */ let initialPoint = {\n x: e.clientX,\n y: e.clientY\n };\n if (!initialPoint.x && !initialPoint.y) initialPoint = null;\n let clickedIndex = this.getClickedIndex(e);\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n /** @type {DataSource} */ const dataSource = {\n gallery: /** @type {HTMLElement} */ e.currentTarget\n };\n if (clickedIndex >= 0) {\n e.preventDefault();\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n }\n }\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */ getClickedIndex(e) {\n // legacy option\n if (this.options.getClickedIndexFn) return this.options.getClickedIndexFn.call(this, e);\n const clickedTarget = /** @type {HTMLElement} */ e.target;\n const childElements = $a30b46f7f651be66$var$getElementsFromOption(this.options.children, this.options.childSelector, /** @type {HTMLElement} */ e.currentTarget);\n const clickedChildIndex = childElements.findIndex((child)=>child === clickedTarget || child.contains(clickedTarget));\n if (clickedChildIndex !== -1) return clickedChildIndex;\n else if (this.options.children || this.options.childSelector) // click wasn't on a child element\n return -1;\n // There is only one item (which is the gallery)\n return 0;\n }\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */ loadAndOpen(index, dataSource, initialPoint) {\n // Check if the gallery is already open\n if (window.pswp || !this.options) return false;\n // Use the first gallery element if dataSource is not provided\n if (!dataSource && this.options.gallery && this.options.children) {\n const galleryElements = $a30b46f7f651be66$var$getElementsFromOption(this.options.gallery);\n if (galleryElements[0]) dataSource = {\n gallery: galleryElements[0]\n };\n } // set initial index\n this.options.index = index; // define options for PhotoSwipe constructor\n this.options.initialPointerPos = initialPoint;\n this.shouldOpen = true;\n this.preload(index, dataSource);\n return true;\n }\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */ preload(index, dataSource) {\n const { options: options } = this;\n if (dataSource) options.dataSource = dataSource;\n // Add the main module\n /** @type {Promise>[]} */ const promiseArray = [];\n const pswpModuleType = typeof options.pswpModule;\n if ($a30b46f7f651be66$var$isPswpClass(options.pswpModule)) promiseArray.push(Promise.resolve(/** @type {Type} */ options.pswpModule));\n else if (pswpModuleType === 'string') throw new Error('pswpModule as string is no longer supported');\n else if (pswpModuleType === 'function') promiseArray.push(/** @type {() => Promise>} */ options.pswpModule());\n else throw new Error('pswpModule is not valid');\n // Add custom-defined promise, if any\n if (typeof options.openPromise === 'function') // allow developers to perform some task before opening\n promiseArray.push(options.openPromise());\n if (options.preloadFirstSlide !== false && index >= 0) this._preloadedContent = $a30b46f7f651be66$var$lazyLoadSlide(index, this);\n // Wait till all promises resolve and open PhotoSwipe\n const uid = ++this._uid;\n Promise.all(promiseArray).then((iterableModules)=>{\n if (this.shouldOpen) {\n const mainModule = iterableModules[0];\n this._openPhotoswipe(mainModule, uid);\n }\n });\n }\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */ _openPhotoswipe(module, uid) {\n // Cancel opening if UID doesn't match the current one\n // (if user clicked on another gallery item before current was loaded).\n //\n // Or if shouldOpen flag is set to false\n // (developer may modify it via public API)\n if (uid !== this._uid && this.shouldOpen) return;\n this.shouldOpen = false; // PhotoSwipe is already open\n if (window.pswp) return;\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */ const pswp = typeof module === 'object' ? new module.default(this.options) // eslint-disable-line\n : new module(this.options); // eslint-disable-line\n this.pswp = pswp;\n window.pswp = pswp; // map listeners from Lightbox to PhotoSwipe Core\n /** @type {(keyof PhotoSwipeEventsMap)[]} */ Object.keys(this._listeners).forEach((name)=>{\n var _this$_listeners$name;\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.forEach((fn)=>{\n pswp.on(name, /** @type {EventCallback} */ fn);\n });\n }); // same with filters\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */ Object.keys(this._filters).forEach((name)=>{\n var _this$_filters$name;\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.forEach((filter)=>{\n pswp.addFilter(name, filter.fn, filter.priority);\n });\n });\n if (this._preloadedContent) {\n pswp.contentLoader.addToCache(this._preloadedContent);\n this._preloadedContent = undefined;\n }\n pswp.on('destroy', ()=>{\n // clean up public variables\n this.pswp = undefined;\n delete window.pswp;\n });\n pswp.init();\n }\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */ destroy() {\n var _this$pswp;\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.destroy();\n this.shouldOpen = false;\n this._listeners = {};\n $a30b46f7f651be66$var$getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach((galleryElement)=>{\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n });\n }\n}\n\n\n\n\nconst $d95fd0c27456b0f2$var$lightbox = new (0, $a30b46f7f651be66$export$2e2bcd8739ae039)({\n gallery: '#gallery--zoom-transition',\n children: 'a',\n showHideAnimationType: 'zoom',\n pswpModule: ()=>(parcelRequire(\"5j4xs\"))\n});\n$d95fd0c27456b0f2$var$lightbox.init();\n\n})();\n//# sourceMappingURL=start.d08064e2.js.map\n","\"use strict\";\n\nvar mapping = new Map();\nfunction register(baseUrl, manifest) {\n for (var i = 0; i < manifest.length - 1; i += 2) {\n mapping.set(manifest[i], {\n baseUrl: baseUrl,\n path: manifest[i + 1]\n });\n }\n}\nfunction resolve(id) {\n var resolved = mapping.get(id);\n if (resolved == null) {\n throw new Error('Could not resolve bundle with id ' + id);\n }\n return new URL(resolved.path, resolved.baseUrl).toString();\n}\nmodule.exports.register = register;\nmodule.exports.resolve = resolve;","\"use strict\";\n\nvar bundleURL = {};\nfunction getBundleURLCached(id) {\n var value = bundleURL[id];\n if (!value) {\n value = getBundleURL();\n bundleURL[id] = value;\n }\n return value;\n}\nfunction getBundleURL() {\n try {\n throw new Error();\n } catch (err) {\n var matches = ('' + err.stack).match(/(https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/[^)\\n]+/g);\n if (matches) {\n // The first two stack frames will be this function and getBundleURLCached.\n // Use the 3rd one, which will be a runtime in the original bundle.\n return getBaseURL(matches[2]);\n }\n }\n return '/';\n}\nfunction getBaseURL(url) {\n return ('' + url).replace(/^((?:https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/.+)\\/[^/]+$/, '$1') + '/';\n}\n\n// TODO: Replace uses with `new URL(url).origin` when ie11 is no longer supported.\nfunction getOrigin(url) {\n var matches = ('' + url).match(/(https?|file|ftp|(chrome|moz|safari-web)-extension):\\/\\/[^/]+/);\n if (!matches) {\n throw new Error('Origin not found');\n }\n return matches[0];\n}\nexports.getBundleURL = getBundleURLCached;\nexports.getBaseURL = getBaseURL;\nexports.getOrigin = getOrigin;","module.exports = (require(\"./helpers/browser/js-loader\")(require('./helpers/bundle-manifest').resolve(\"9fYSr\"))).then(() => parcelRequire('gG83T'));","\"use strict\";\n\nvar cacheLoader = require('../cacheLoader');\nmodule.exports = cacheLoader(function (bundle) {\n return new Promise(function (resolve, reject) {\n // Don't insert the same script twice (e.g. if it was already in the HTML)\n var existingScripts = document.getElementsByTagName('script');\n if ([].concat(existingScripts).some(function (script) {\n return script.src === bundle;\n })) {\n resolve();\n return;\n }\n var preloadLink = document.createElement('link');\n preloadLink.href = bundle;\n preloadLink.rel = 'preload';\n preloadLink.as = 'script';\n document.head.appendChild(preloadLink);\n var script = document.createElement('script');\n script.async = true;\n script.type = 'text/javascript';\n script.src = bundle;\n script.onerror = function (e) {\n var error = new TypeError(\"Failed to fetch dynamically imported module: \".concat(bundle, \". Error: \").concat(e.message));\n script.onerror = script.onload = null;\n script.remove();\n reject(error);\n };\n script.onload = function () {\n script.onerror = script.onload = null;\n resolve();\n };\n document.getElementsByTagName('head')[0].appendChild(script);\n });\n});","\"use strict\";\n\nvar cachedBundles = {};\nvar cachedPreloads = {};\nvar cachedPrefetches = {};\nfunction getCache(type) {\n switch (type) {\n case 'preload':\n return cachedPreloads;\n case 'prefetch':\n return cachedPrefetches;\n default:\n return cachedBundles;\n }\n}\nmodule.exports = function (loader, type) {\n return function (bundle) {\n var cache = getCache(type);\n if (cache[bundle]) {\n return cache[bundle];\n }\n return cache[bundle] = loader.apply(null, arguments).catch(function (e) {\n delete cache[bundle];\n throw e;\n });\n };\n};","require('./helpers/bundle-manifest').register(require('./helpers/bundle-url').getBundleURL('Y24sw'),JSON.parse(\"[\\\"Y24sw\\\",\\\"start.d08064e2.js\\\",\\\"9fYSr\\\",\\\"photoswipe.esm.2e2aa850.js\\\",\\\"1Fjha\\\",\\\"start.43e10e4a.css\\\"]\"));","import PhotoSwipeLightbox from 'photoswipe/dist/photoswipe-lightbox.esm.js';\nimport 'photoswipe/dist/photoswipe.css';\n\nconst lightbox = new PhotoSwipeLightbox({\n gallery: '#gallery--zoom-transition',\n children: 'a',\n showHideAnimationType: 'zoom',\n pswpModule: () => import('photoswipe/dist/photoswipe.esm.js')\n});\nlightbox.init();\n","/*!\n * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\nfunction createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n\n if (className) {\n el.className = className;\n }\n\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n\n return el;\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\n\nfunction toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\n\nfunction setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\n\nconst LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\n\nfunction specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\n\nfunction getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\n\nfunction isPswpClass(fn) {\n return typeof fn === 'function' && fn.prototype && fn.prototype.goTo;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\n\nfunction isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n\n/** @typedef {import('../slide/slide.js').default} Slide */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\n\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\n\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\n\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\nclass PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\n\n\nclass Eventable {\n constructor() {\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\n this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\n\n this._filters = {};\n /** @type {PhotoSwipe | undefined} */\n\n this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */\n\n this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\n\n\n addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn,\n priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2) => f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\n\n\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => filter.fn !== fn);\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\n\n\n applyFilters(name, ...args) {\n var _this$_filters$name3;\n\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach(filter => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n off(name, fn) {\n var _this$pswp3;\n\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => fn !== listener);\n }\n\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\n\n\n dispatch(name, details) {\n var _this$_listeners$name2;\n\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event =\n /** @type {AugmentedEvent} */\n new PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach(listener => {\n listener.call(this, event);\n });\n return event;\n }\n\n}\n\nclass Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n\n if (imageSrc) {\n const imgEl =\n /** @type {HTMLImageElement} */\n this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n var _this$element;\n\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) {\n this.element.remove();\n }\n\n this.element = null;\n }\n\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n\n this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\n\n\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\n\n\n loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n const imageElement =\n /** @type HTMLImageElement */\n this.element;\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\n\n\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */\n\n\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n /**\r\n * Content load error handler\r\n */\n\n\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\n\n\n isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\n\n\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */\n\n\n isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch('contentResize', {\n content: this,\n width,\n height\n }).defaultPrevented) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width,\n height,\n content: this\n });\n }\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\n\n\n isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\n\n\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image =\n /** @type HTMLImageElement */\n this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\n\n\n usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */\n\n\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\n\n\n keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */\n\n\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */\n\n\n displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl =\n /** @type {HTMLDivElement} */\n this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */\n\n\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n\n /** @type {HTMLImageElement} */\n\n this.element.decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\n\n\n activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n /**\r\n * Deactivate the content\r\n */\n\n\n deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n /**\r\n * Remove the content from DOM\r\n */\n\n\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n /**\r\n * Append the image content to slide container\r\n */\n\n\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) {\n return;\n } // ensure that element exists and is not already appended\n\n\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\nfunction getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\n\nfunction parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\n\nfunction getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - parsePaddingOption('left', options, viewportSize, itemData, index) - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - parsePaddingOption('top', options, viewportSize, itemData, index) - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n\nconst MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\n\nclass ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n\n this.panAreaSize = null;\n /** @type { Point | null } */\n\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\n\n\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\n\n\n _parseZoomLevelOption(optionPrefix) {\n const optionName =\n /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */\n optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n } // 3x of \"fit\" state, but not larger than original\n\n\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n\n}\n\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\nfunction lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n\n let zoomLevel;\n const {\n options\n } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n let viewportSize;\n\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n }\n\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\n\nfunction lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', {\n index,\n itemData\n }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\n\nclass PhotoSwipeBase extends Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\n getNumItems() {\n var _this$options;\n\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n } // legacy event, before filters were introduced\n\n\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\n\n\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\n\n\n getItemData(index) {\n var _this$options2;\n\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */\n\n let dataSourceItem = {};\n\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n } // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n\n\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\n\n\n _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) {\n return getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n }\n\n return [galleryElement];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\n\n\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n const linkEl =\n /** @type {HTMLAnchorElement} */\n element.tagName === 'A' ? element : element.querySelector('a');\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\n\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n\n}\n\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/content.js').default} Content */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */\n\n/**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\n\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\n constructor(options) {\n super();\n /** @type {PhotoSwipeOptions} */\n\n this.options = options || {};\n this._uid = 0;\n this.shouldOpen = false;\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */\n\n this._preloadedContent = undefined;\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n }\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */\n\n\n init() {\n // Bind click events to each gallery\n getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n });\n }\n /**\r\n * @param {MouseEvent} e\r\n */\n\n\n onThumbnailsClick(e) {\n // Exit and allow default browser action if:\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n || window.pswp) {\n // ... if PhotoSwipe is already open\n return;\n } // If both clientX and clientY are 0 or not defined,\n // the event is likely triggered by keyboard,\n // so we do not pass the initialPoint\n //\n // Note that some screen readers emulate the mouse position,\n // so it's not the ideal way to detect them.\n //\n\n /** @type {Point | null} */\n\n\n let initialPoint = {\n x: e.clientX,\n y: e.clientY\n };\n\n if (!initialPoint.x && !initialPoint.y) {\n initialPoint = null;\n }\n\n let clickedIndex = this.getClickedIndex(e);\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n /** @type {DataSource} */\n\n const dataSource = {\n gallery:\n /** @type {HTMLElement} */\n e.currentTarget\n };\n\n if (clickedIndex >= 0) {\n e.preventDefault();\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n }\n }\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */\n\n\n getClickedIndex(e) {\n // legacy option\n if (this.options.getClickedIndexFn) {\n return this.options.getClickedIndexFn.call(this, e);\n }\n\n const clickedTarget =\n /** @type {HTMLElement} */\n e.target;\n const childElements = getElementsFromOption(this.options.children, this.options.childSelector,\n /** @type {HTMLElement} */\n e.currentTarget);\n const clickedChildIndex = childElements.findIndex(child => child === clickedTarget || child.contains(clickedTarget));\n\n if (clickedChildIndex !== -1) {\n return clickedChildIndex;\n } else if (this.options.children || this.options.childSelector) {\n // click wasn't on a child element\n return -1;\n } // There is only one item (which is the gallery)\n\n\n return 0;\n }\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */\n\n\n loadAndOpen(index, dataSource, initialPoint) {\n // Check if the gallery is already open\n if (window.pswp || !this.options) {\n return false;\n } // Use the first gallery element if dataSource is not provided\n\n\n if (!dataSource && this.options.gallery && this.options.children) {\n const galleryElements = getElementsFromOption(this.options.gallery);\n\n if (galleryElements[0]) {\n dataSource = {\n gallery: galleryElements[0]\n };\n }\n } // set initial index\n\n\n this.options.index = index; // define options for PhotoSwipe constructor\n\n this.options.initialPointerPos = initialPoint;\n this.shouldOpen = true;\n this.preload(index, dataSource);\n return true;\n }\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */\n\n\n preload(index, dataSource) {\n const {\n options\n } = this;\n\n if (dataSource) {\n options.dataSource = dataSource;\n } // Add the main module\n\n /** @type {Promise>[]} */\n\n\n const promiseArray = [];\n const pswpModuleType = typeof options.pswpModule;\n\n if (isPswpClass(options.pswpModule)) {\n promiseArray.push(Promise.resolve(\n /** @type {Type} */\n options.pswpModule));\n } else if (pswpModuleType === 'string') {\n throw new Error('pswpModule as string is no longer supported');\n } else if (pswpModuleType === 'function') {\n promiseArray.push(\n /** @type {() => Promise>} */\n options.pswpModule());\n } else {\n throw new Error('pswpModule is not valid');\n } // Add custom-defined promise, if any\n\n\n if (typeof options.openPromise === 'function') {\n // allow developers to perform some task before opening\n promiseArray.push(options.openPromise());\n }\n\n if (options.preloadFirstSlide !== false && index >= 0) {\n this._preloadedContent = lazyLoadSlide(index, this);\n } // Wait till all promises resolve and open PhotoSwipe\n\n\n const uid = ++this._uid;\n Promise.all(promiseArray).then(iterableModules => {\n if (this.shouldOpen) {\n const mainModule = iterableModules[0];\n\n this._openPhotoswipe(mainModule, uid);\n }\n });\n }\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */\n\n\n _openPhotoswipe(module, uid) {\n // Cancel opening if UID doesn't match the current one\n // (if user clicked on another gallery item before current was loaded).\n //\n // Or if shouldOpen flag is set to false\n // (developer may modify it via public API)\n if (uid !== this._uid && this.shouldOpen) {\n return;\n }\n\n this.shouldOpen = false; // PhotoSwipe is already open\n\n if (window.pswp) {\n return;\n }\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */\n\n\n const pswp = typeof module === 'object' ? new module.default(this.options) // eslint-disable-line\n : new module(this.options); // eslint-disable-line\n\n this.pswp = pswp;\n window.pswp = pswp; // map listeners from Lightbox to PhotoSwipe Core\n\n /** @type {(keyof PhotoSwipeEventsMap)[]} */\n\n Object.keys(this._listeners).forEach(name => {\n var _this$_listeners$name;\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.forEach(fn => {\n pswp.on(name,\n /** @type {EventCallback} */\n fn);\n });\n }); // same with filters\n\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */\n\n Object.keys(this._filters).forEach(name => {\n var _this$_filters$name;\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.forEach(filter => {\n pswp.addFilter(name, filter.fn, filter.priority);\n });\n });\n\n if (this._preloadedContent) {\n pswp.contentLoader.addToCache(this._preloadedContent);\n this._preloadedContent = undefined;\n }\n\n pswp.on('destroy', () => {\n // clean up public variables\n this.pswp = undefined;\n delete window.pswp;\n });\n pswp.init();\n }\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */\n\n\n destroy() {\n var _this$pswp;\n\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.destroy();\n this.shouldOpen = false;\n this._listeners = {};\n getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n });\n }\n\n}\n\nexport { PhotoSwipeLightbox as default };\n//# sourceMappingURL=photoswipe-lightbox.esm.js.map\n","/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\r\nexport function createElement(className, tagName, appendToEl) {\r\n const el = document.createElement(tagName);\r\n if (className) {\r\n el.className = className;\r\n }\r\n if (appendToEl) {\r\n appendToEl.appendChild(el);\r\n }\r\n return el;\r\n}\r\n\r\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nexport function equalizePoints(p1, p2) {\r\n p1.x = p2.x;\r\n p1.y = p2.y;\r\n if (p2.id !== undefined) {\r\n p1.id = p2.id;\r\n }\r\n return p1;\r\n}\r\n\r\n/**\r\n * @param {Point} p\r\n */\r\nexport function roundPoint(p) {\r\n p.x = Math.round(p.x);\r\n p.y = Math.round(p.y);\r\n}\r\n\r\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\r\nexport function getDistanceBetween(p1, p2) {\r\n const x = Math.abs(p1.x - p2.x);\r\n const y = Math.abs(p1.y - p2.y);\r\n return Math.sqrt((x * x) + (y * y));\r\n}\r\n\r\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\r\nexport function pointsEqual(p1, p2) {\r\n return p1.x === p2.x && p1.y === p2.y;\r\n}\r\n\r\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\r\nexport function clamp(val, min, max) {\r\n return Math.min(Math.max(val, min), max);\r\n}\r\n\r\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\r\nexport function toTransformString(x, y, scale) {\r\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\r\n\r\n if (scale !== undefined) {\r\n propValue += ` scale3d(${scale},${scale},1)`;\r\n }\r\n\r\n return propValue;\r\n}\r\n\r\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\r\nexport function setTransform(el, x, y, scale) {\r\n el.style.transform = toTransformString(x, y, scale);\r\n}\r\n\r\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\r\nexport function setTransitionStyle(el, prop, duration, ease) {\r\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\r\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\r\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\r\n el.style.transition = prop\r\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\r\n : 'none';\r\n}\r\n\r\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\r\nexport function setWidthHeight(el, w, h) {\r\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\r\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n */\r\nexport function removeTransitionStyle(el) {\r\n setTransitionStyle(el);\r\n}\r\n\r\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\r\nexport function decodeImage(img) {\r\n if ('decode' in img) {\r\n return img.decode().catch(() => {});\r\n }\r\n\r\n if (img.complete) {\r\n return Promise.resolve(img);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n img.onload = () => resolve(img);\r\n img.onerror = reject;\r\n });\r\n}\r\n\r\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\r\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\r\nexport const LOAD_STATE = {\r\n IDLE: 'idle',\r\n LOADING: 'loading',\r\n LOADED: 'loaded',\r\n ERROR: 'error',\r\n};\r\n\r\n\r\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\r\nexport function specialKeyUsed(e) {\r\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\r\n}\r\n\r\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\r\nexport function getElementsFromOption(option, legacySelector, parent = document) {\r\n /** @type {HTMLElement[]} */\r\n let elements = [];\r\n\r\n if (option instanceof Element) {\r\n elements = [option];\r\n } else if (option instanceof NodeList || Array.isArray(option)) {\r\n elements = Array.from(option);\r\n } else {\r\n const selector = typeof option === 'string' ? option : legacySelector;\r\n if (selector) {\r\n elements = Array.from(parent.querySelectorAll(selector));\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\r\nexport function isPswpClass(fn) {\r\n return typeof fn === 'function'\r\n && fn.prototype\r\n && fn.prototype.goTo;\r\n}\r\n\r\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\r\nexport function isSafari() {\r\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\r\n}\r\n\r\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../slide/content.js').default} ContentDefault */\r\n/** @typedef {import('../slide/slide.js').default} Slide */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\r\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\r\n\r\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\r\n/** @typedef {{ x?: number; y?: number }} Point */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\r\n\r\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\r\nclass PhotoSwipeEvent {\r\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\r\n constructor(type, details) {\r\n this.type = type;\r\n this.defaultPrevented = false;\r\n if (details) {\r\n Object.assign(this, details);\r\n }\r\n }\r\n\r\n preventDefault() {\r\n this.defaultPrevented = true;\r\n }\r\n}\r\n\r\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\r\nclass Eventable {\r\n constructor() {\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\r\n this._listeners = {};\r\n\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\r\n this._filters = {};\r\n\r\n /** @type {PhotoSwipe | undefined} */\r\n this.pswp = undefined;\r\n\r\n /** @type {PhotoSwipeOptions | undefined} */\r\n this.options = undefined;\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\r\n addFilter(name, fn, priority = 100) {\r\n if (!this._filters[name]) {\r\n this._filters[name] = [];\r\n }\r\n\r\n this._filters[name]?.push({ fn, priority });\r\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\r\n\r\n this.pswp?.addFilter(name, fn, priority);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\r\n removeFilter(name, fn) {\r\n if (this._filters[name]) {\r\n // @ts-expect-error\r\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\r\n }\r\n\r\n if (this.pswp) {\r\n this.pswp.removeFilter(name, fn);\r\n }\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\r\n applyFilters(name, ...args) {\r\n this._filters[name]?.forEach((filter) => {\r\n // @ts-expect-error\r\n args[0] = filter.fn.apply(this, args);\r\n });\r\n return args[0];\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n on(name, fn) {\r\n if (!this._listeners[name]) {\r\n this._listeners[name] = [];\r\n }\r\n this._listeners[name]?.push(fn);\r\n\r\n // When binding events to lightbox,\r\n // also bind events to PhotoSwipe Core,\r\n // if it's open.\r\n this.pswp?.on(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n off(name, fn) {\r\n if (this._listeners[name]) {\r\n // @ts-expect-error\r\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\r\n }\r\n\r\n this.pswp?.off(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\r\n dispatch(name, details) {\r\n if (this.pswp) {\r\n return this.pswp.dispatch(name, details);\r\n }\r\n\r\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\r\n\r\n this._listeners[name]?.forEach((listener) => {\r\n listener.call(this, event);\r\n });\r\n\r\n return event;\r\n }\r\n}\r\n\r\nexport default Eventable;\r\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\r\n\r\nclass Placeholder {\r\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\r\n constructor(imageSrc, container) {\r\n // Create placeholder\r\n // (stretched thumbnail or simple div behind the main image)\r\n /** @type {HTMLImageElement | HTMLDivElement | null} */\r\n this.element = createElement(\r\n 'pswp__img pswp__img--placeholder',\r\n imageSrc ? 'img' : 'div',\r\n container\r\n );\r\n\r\n if (imageSrc) {\r\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\r\n imgEl.decoding = 'async';\r\n imgEl.alt = '';\r\n imgEl.src = imageSrc;\r\n imgEl.setAttribute('role', 'presentation');\r\n }\r\n\r\n this.element.setAttribute('aria-hidden', 'true');\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.element.tagName === 'IMG') {\r\n // Use transform scale() to modify img placeholder size\r\n // (instead of changing width/height directly).\r\n // This helps with performance, specifically in iOS15 Safari.\r\n setWidthHeight(this.element, 250, 'auto');\r\n this.element.style.transformOrigin = '0 0';\r\n this.element.style.transform = toTransformString(0, 0, width / 250);\r\n } else {\r\n setWidthHeight(this.element, width, height);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.element?.parentNode) {\r\n this.element.remove();\r\n }\r\n this.element = null;\r\n }\r\n}\r\n\r\nexport default Placeholder;\r\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\r\nimport Placeholder from './placeholder.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../util/util.js').LoadState} LoadState */\r\n\r\nclass Content {\r\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\r\n constructor(itemData, instance, index) {\r\n this.instance = instance;\r\n this.data = itemData;\r\n this.index = index;\r\n\r\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {Placeholder | undefined} */\r\n this.placeholder = undefined;\r\n /** @type {Slide | undefined} */\r\n this.slide = undefined;\r\n\r\n this.displayedImageWidth = 0;\r\n this.displayedImageHeight = 0;\r\n\r\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\r\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\r\n\r\n this.isAttached = false;\r\n this.hasSlide = false;\r\n this.isDecoding = false;\r\n /** @type {LoadState} */\r\n this.state = LOAD_STATE.IDLE;\r\n\r\n if (this.data.type) {\r\n this.type = this.data.type;\r\n } else if (this.data.src) {\r\n this.type = 'image';\r\n } else {\r\n this.type = 'html';\r\n }\r\n\r\n this.instance.dispatch('contentInit', { content: this });\r\n }\r\n\r\n removePlaceholder() {\r\n if (this.placeholder && !this.keepPlaceholder()) {\r\n // With delay, as image might be loaded, but not rendered\r\n setTimeout(() => {\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\r\n load(isLazy, reload) {\r\n if (this.slide && this.usePlaceholder()) {\r\n if (!this.placeholder) {\r\n const placeholderSrc = this.instance.applyFilters(\r\n 'placeholderSrc',\r\n // use image-based placeholder only for the first slide,\r\n // as rendering (even small stretched thumbnail) is an expensive operation\r\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\r\n this\r\n );\r\n this.placeholder = new Placeholder(\r\n placeholderSrc,\r\n this.slide.container\r\n );\r\n } else {\r\n const placeholderEl = this.placeholder.element;\r\n // Add placeholder to DOM if it was already created\r\n if (placeholderEl && !placeholderEl.parentElement) {\r\n this.slide.container.prepend(placeholderEl);\r\n }\r\n }\r\n }\r\n\r\n if (this.element && !reload) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent()) {\r\n this.element = createElement('pswp__img', 'img');\r\n // Start loading only after width is defined, as sizes might depend on it.\r\n // Due to Safari feature, we must define sizes before srcset.\r\n if (this.displayedImageWidth) {\r\n this.loadImage(isLazy);\r\n }\r\n } else {\r\n this.element = createElement('pswp__content', 'div');\r\n this.element.innerHTML = this.data.html || '';\r\n }\r\n\r\n if (reload && this.slide) {\r\n this.slide.updateContentSize(true);\r\n }\r\n }\r\n\r\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\r\n loadImage(isLazy) {\r\n if (!this.isImageContent()\r\n || !this.element\r\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const imageElement = /** @type HTMLImageElement */ (this.element);\r\n\r\n this.updateSrcsetSizes();\r\n\r\n if (this.data.srcset) {\r\n imageElement.srcset = this.data.srcset;\r\n }\r\n\r\n imageElement.src = this.data.src ?? '';\r\n imageElement.alt = this.data.alt ?? '';\r\n\r\n this.state = LOAD_STATE.LOADING;\r\n\r\n if (imageElement.complete) {\r\n this.onLoaded();\r\n } else {\r\n imageElement.onload = () => {\r\n this.onLoaded();\r\n };\r\n\r\n imageElement.onerror = () => {\r\n this.onError();\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\r\n setSlide(slide) {\r\n this.slide = slide;\r\n this.hasSlide = true;\r\n this.instance = slide.pswp;\r\n\r\n // todo: do we need to unset slide?\r\n }\r\n\r\n /**\r\n * Content load success handler\r\n */\r\n onLoaded() {\r\n this.state = LOAD_STATE.LOADED;\r\n\r\n if (this.slide && this.element) {\r\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\r\n\r\n // if content is reloaded\r\n if (this.slide.isActive\r\n && this.slide.heavyAppended\r\n && !this.element.parentNode) {\r\n this.append();\r\n this.slide.updateContentSize(true);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Content load error handler\r\n */\r\n onError() {\r\n this.state = LOAD_STATE.ERROR;\r\n\r\n if (this.slide) {\r\n this.displayError();\r\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\r\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\r\n }\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\r\n isLoading() {\r\n return this.instance.applyFilters(\r\n 'isContentLoading',\r\n this.state === LOAD_STATE.LOADING,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\r\n isError() {\r\n return this.state === LOAD_STATE.ERROR;\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content is image\r\n */\r\n isImageContent() {\r\n return this.type === 'image';\r\n }\r\n\r\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.placeholder) {\r\n this.placeholder.setDisplayedSize(width, height);\r\n }\r\n\r\n if (this.instance.dispatch(\r\n 'contentResize',\r\n { content: this, width, height }).defaultPrevented\r\n ) {\r\n return;\r\n }\r\n\r\n setWidthHeight(this.element, width, height);\r\n\r\n if (this.isImageContent() && !this.isError()) {\r\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\r\n\r\n this.displayedImageWidth = width;\r\n this.displayedImageHeight = height;\r\n\r\n if (isInitialSizeUpdate) {\r\n this.loadImage(false);\r\n } else {\r\n this.updateSrcsetSizes();\r\n }\r\n\r\n if (this.slide) {\r\n this.instance.dispatch(\r\n 'imageSizeChange',\r\n { slide: this.slide, width, height, content: this }\r\n );\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\r\n isZoomable() {\r\n return this.instance.applyFilters(\r\n 'isContentZoomable',\r\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\r\n updateSrcsetSizes() {\r\n // Handle srcset sizes attribute.\r\n //\r\n // Never lower quality, if it was increased previously.\r\n // Chrome does this automatically, Firefox and Safari do not,\r\n // so we store largest used size in dataset.\r\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\r\n return;\r\n }\r\n\r\n const image = /** @type HTMLImageElement */ (this.element);\r\n const sizesWidth = this.instance.applyFilters(\r\n 'srcsetSizesWidth',\r\n this.displayedImageWidth,\r\n this\r\n );\r\n\r\n if (\r\n !image.dataset.largestUsedSize\r\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\r\n ) {\r\n image.sizes = sizesWidth + 'px';\r\n image.dataset.largestUsedSize = String(sizesWidth);\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\r\n usePlaceholder() {\r\n return this.instance.applyFilters(\r\n 'useContentPlaceholder',\r\n this.isImageContent(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Preload content with lazy-loading param\r\n */\r\n lazyLoad() {\r\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.load(true);\r\n }\r\n\r\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\r\n keepPlaceholder() {\r\n return this.instance.applyFilters(\r\n 'isKeepingPlaceholder',\r\n this.isLoading(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Destroy the content\r\n */\r\n destroy() {\r\n this.hasSlide = false;\r\n this.slide = undefined;\r\n\r\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.remove();\r\n\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n\r\n if (this.isImageContent() && this.element) {\r\n this.element.onload = null;\r\n this.element.onerror = null;\r\n this.element = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * Display error message\r\n */\r\n displayError() {\r\n if (this.slide) {\r\n let errorMsgEl = createElement('pswp__error-msg', 'div');\r\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\r\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\r\n 'contentErrorElement',\r\n errorMsgEl,\r\n this\r\n ));\r\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\r\n this.element.appendChild(errorMsgEl);\r\n this.slide.container.innerText = '';\r\n this.slide.container.appendChild(this.element);\r\n this.slide.updateContentSize(true);\r\n this.removePlaceholder();\r\n }\r\n }\r\n\r\n /**\r\n * Append the content\r\n */\r\n append() {\r\n if (this.isAttached || !this.element) {\r\n return;\r\n }\r\n\r\n this.isAttached = true;\r\n\r\n if (this.state === LOAD_STATE.ERROR) {\r\n this.displayError();\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const supportsDecode = ('decode' in this.element);\r\n\r\n if (this.isImageContent()) {\r\n // Use decode() on nearby slides\r\n //\r\n // Nearby slide images are in DOM and not hidden via display:none.\r\n // However, they are placed offscreen (to the left and right side).\r\n //\r\n // Some browsers do not composite the image until it's actually visible,\r\n // using decode() helps.\r\n //\r\n // You might ask \"why dont you just decode() and then append all images\",\r\n // that's because I want to show image before it's fully loaded,\r\n // as browser can render parts of image while it is loading.\r\n // We do not do this in Safari due to partial loading bug.\r\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\r\n this.isDecoding = true;\r\n // purposefully using finally instead of then,\r\n // as if srcset sizes changes dynamically - it may cause decode error\r\n /** @type {HTMLImageElement} */\r\n (this.element).decode().catch(() => {}).finally(() => {\r\n this.isDecoding = false;\r\n this.appendImage();\r\n });\r\n } else {\r\n this.appendImage();\r\n }\r\n } else if (this.slide && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n }\r\n\r\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\r\n activate() {\r\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\r\n || !this.slide) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\r\n // add image to slide when it becomes active,\r\n // even if it's not finished decoding\r\n this.appendImage();\r\n } else if (this.isError()) {\r\n this.load(false, true); // try to reload\r\n }\r\n\r\n if (this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\r\n }\r\n }\r\n\r\n /**\r\n * Deactivate the content\r\n */\r\n deactivate() {\r\n this.instance.dispatch('contentDeactivate', { content: this });\r\n if (this.slide && this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Remove the content from DOM\r\n */\r\n remove() {\r\n this.isAttached = false;\r\n\r\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.element && this.element.parentNode) {\r\n this.element.remove();\r\n }\r\n\r\n if (this.placeholder && this.placeholder.element) {\r\n this.placeholder.element.remove();\r\n }\r\n }\r\n\r\n /**\r\n * Append the image content to slide container\r\n */\r\n appendImage() {\r\n if (!this.isAttached) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n // ensure that element exists and is not already appended\r\n if (this.slide && this.element && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n}\r\n\r\nexport default Content;\r\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\r\nexport function getViewportSize(options, pswp) {\r\n if (options.getViewportSizeFn) {\r\n const newViewportSize = options.getViewportSizeFn(options, pswp);\r\n if (newViewportSize) {\r\n return newViewportSize;\r\n }\r\n }\r\n\r\n return {\r\n x: document.documentElement.clientWidth,\r\n\r\n // TODO: height on mobile is very incosistent due to toolbar\r\n // find a way to improve this\r\n //\r\n // document.documentElement.clientHeight - doesn't seem to work well\r\n y: window.innerHeight\r\n };\r\n}\r\n\r\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\r\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\r\n let paddingValue = 0;\r\n\r\n if (options.paddingFn) {\r\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\r\n } else if (options.padding) {\r\n paddingValue = options.padding[prop];\r\n } else {\r\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\r\n // @ts-expect-error\r\n if (options[legacyPropName]) {\r\n // @ts-expect-error\r\n paddingValue = options[legacyPropName];\r\n }\r\n }\r\n\r\n return Number(paddingValue) || 0;\r\n}\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\r\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\r\n return {\r\n x: viewportSize.x\r\n - parsePaddingOption('left', options, viewportSize, itemData, index)\r\n - parsePaddingOption('right', options, viewportSize, itemData, index),\r\n y: viewportSize.y\r\n - parsePaddingOption('top', options, viewportSize, itemData, index)\r\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\r\n };\r\n}\r\n","const MAX_IMAGE_WIDTH = 4000;\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\r\n\r\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\r\nclass ZoomLevel {\r\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\r\n constructor(options, itemData, index, pswp) {\r\n this.pswp = pswp;\r\n this.options = options;\r\n this.itemData = itemData;\r\n this.index = index;\r\n /** @type { Point | null } */\r\n this.panAreaSize = null;\r\n /** @type { Point | null } */\r\n this.elementSize = null;\r\n this.fit = 1;\r\n this.fill = 1;\r\n this.vFill = 1;\r\n this.initial = 1;\r\n this.secondary = 1;\r\n this.max = 1;\r\n this.min = 1;\r\n }\r\n\r\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\r\n update(maxWidth, maxHeight, panAreaSize) {\r\n /** @type {Point} */\r\n const elementSize = { x: maxWidth, y: maxHeight };\r\n this.elementSize = elementSize;\r\n this.panAreaSize = panAreaSize;\r\n\r\n const hRatio = panAreaSize.x / elementSize.x;\r\n const vRatio = panAreaSize.y / elementSize.y;\r\n\r\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\r\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\r\n\r\n // zoom.vFill defines zoom level of the image\r\n // when it has 100% of viewport vertical space (height)\r\n this.vFill = Math.min(1, vRatio);\r\n\r\n this.initial = this._getInitial();\r\n this.secondary = this._getSecondary();\r\n this.max = Math.max(\r\n this.initial,\r\n this.secondary,\r\n this._getMax()\r\n );\r\n\r\n this.min = Math.min(\r\n this.fit,\r\n this.initial,\r\n this.secondary\r\n );\r\n\r\n if (this.pswp) {\r\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\r\n }\r\n }\r\n\r\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\r\n _parseZoomLevelOption(optionPrefix) {\r\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\r\n optionPrefix + 'ZoomLevel'\r\n );\r\n const optionValue = this.options[optionName];\r\n\r\n if (!optionValue) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n return optionValue(this);\r\n }\r\n\r\n if (optionValue === 'fill') {\r\n return this.fill;\r\n }\r\n\r\n if (optionValue === 'fit') {\r\n return this.fit;\r\n }\r\n\r\n return Number(optionValue);\r\n }\r\n\r\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getSecondary() {\r\n let currZoomLevel = this._parseZoomLevelOption('secondary');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // 3x of \"fit\" state, but not larger than original\r\n currZoomLevel = Math.min(1, this.fit * 3);\r\n\r\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\r\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\r\n }\r\n\r\n return currZoomLevel;\r\n }\r\n\r\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getInitial() {\r\n return this._parseZoomLevelOption('initial') || this.fit;\r\n }\r\n\r\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getMax() {\r\n // max zoom level is x4 from \"fit state\",\r\n // used for zoom gesture and ctrl/trackpad zoom\r\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\r\n }\r\n}\r\n\r\nexport default ZoomLevel;\r\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\r\nimport ZoomLevel from './zoom-level.js';\r\n\r\n/** @typedef {import('./content.js').default} Content */\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\nconst MIN_SLIDES_TO_CACHE = 5;\r\n\r\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\nexport function lazyLoadData(itemData, instance, index) {\r\n const content = instance.createContentFromData(itemData, index);\r\n /** @type {ZoomLevel | undefined} */\r\n let zoomLevel;\r\n\r\n const { options } = instance;\r\n\r\n // We need to know dimensions of the image to preload it,\r\n // as it might use srcset, and we need to define sizes\r\n if (options) {\r\n zoomLevel = new ZoomLevel(options, itemData, -1);\r\n\r\n let viewportSize;\r\n if (instance.pswp) {\r\n viewportSize = instance.pswp.viewportSize;\r\n } else {\r\n viewportSize = getViewportSize(options, instance);\r\n }\r\n\r\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\r\n zoomLevel.update(content.width, content.height, panAreaSize);\r\n }\r\n\r\n content.lazyLoad();\r\n\r\n if (zoomLevel) {\r\n content.setDisplayedSize(\r\n Math.ceil(content.width * zoomLevel.initial),\r\n Math.ceil(content.height * zoomLevel.initial)\r\n );\r\n }\r\n\r\n return content;\r\n}\r\n\r\n\r\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\r\nexport function lazyLoadSlide(index, instance) {\r\n const itemData = instance.getItemData(index);\r\n\r\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n return lazyLoadData(itemData, instance, index);\r\n}\r\n\r\nclass ContentLoader {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n // Total amount of cached images\r\n this.limit = Math.max(\r\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\r\n MIN_SLIDES_TO_CACHE\r\n );\r\n /** @type {Content[]} */\r\n this._cachedItems = [];\r\n }\r\n\r\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\r\n updateLazy(diff) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\r\n return;\r\n }\r\n\r\n const { preload } = pswp.options;\r\n const isForward = diff === undefined ? true : (diff >= 0);\r\n let i;\r\n\r\n // preload[1] - num items to preload in forward direction\r\n for (i = 0; i <= preload[1]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\r\n }\r\n\r\n // preload[0] - num items to preload in backward direction\r\n for (i = 1; i <= preload[0]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} initialIndex\r\n */\r\n loadSlideByIndex(initialIndex) {\r\n const index = this.pswp.getLoopedIndex(initialIndex);\r\n // try to get cached content\r\n let content = this.getContentByIndex(index);\r\n if (!content) {\r\n // no cached content, so try to load from scratch:\r\n content = lazyLoadSlide(index, this.pswp);\r\n // if content can be loaded, add it to cache:\r\n if (content) {\r\n this.addToCache(content);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\r\n getContentBySlide(slide) {\r\n let content = this.getContentByIndex(slide.index);\r\n if (!content) {\r\n // create content if not found in cache\r\n content = this.pswp.createContentFromData(slide.data, slide.index);\r\n this.addToCache(content);\r\n }\r\n\r\n // assign slide to content\r\n content.setSlide(slide);\r\n\r\n return content;\r\n }\r\n\r\n /**\r\n * @param {Content} content\r\n */\r\n addToCache(content) {\r\n // move to the end of array\r\n this.removeByIndex(content.index);\r\n this._cachedItems.push(content);\r\n\r\n if (this._cachedItems.length > this.limit) {\r\n // Destroy the first content that's not attached\r\n const indexToRemove = this._cachedItems.findIndex((item) => {\r\n return !item.isAttached && !item.hasSlide;\r\n });\r\n if (indexToRemove !== -1) {\r\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\r\n removedItem.destroy();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\r\n removeByIndex(index) {\r\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\r\n if (indexToRemove !== -1) {\r\n this._cachedItems.splice(indexToRemove, 1);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\r\n getContentByIndex(index) {\r\n return this._cachedItems.find(content => content.index === index);\r\n }\r\n\r\n destroy() {\r\n this._cachedItems.forEach(content => content.destroy());\r\n this._cachedItems = [];\r\n }\r\n}\r\n\r\nexport default ContentLoader;\r\n","import Eventable from './eventable.js';\r\nimport { getElementsFromOption } from '../util/util.js';\r\nimport Content from '../slide/content.js';\r\nimport { lazyLoadData } from '../slide/loader.js';\r\n\r\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\r\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\r\n\r\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\r\nclass PhotoSwipeBase extends Eventable {\r\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\r\n getNumItems() {\r\n let numItems = 0;\r\n const dataSource = this.options?.dataSource;\r\n\r\n if (dataSource && 'length' in dataSource) {\r\n // may be an array or just object with length property\r\n numItems = dataSource.length;\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n if (dataSource.items) {\r\n numItems = dataSource.items.length;\r\n }\r\n }\r\n\r\n // legacy event, before filters were introduced\r\n const event = this.dispatch('numItems', {\r\n dataSource,\r\n numItems\r\n });\r\n return this.applyFilters('numItems', event.numItems, dataSource);\r\n }\r\n\r\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\r\n createContentFromData(slideData, index) {\r\n return new Content(slideData, this, index);\r\n }\r\n\r\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\r\n getItemData(index) {\r\n const dataSource = this.options?.dataSource;\r\n /** @type {SlideData | HTMLElement} */\r\n let dataSourceItem = {};\r\n if (Array.isArray(dataSource)) {\r\n // Datasource is an array of elements\r\n dataSourceItem = dataSource[index];\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // dataSource has gallery property,\r\n // thus it was created by Lightbox, based on\r\n // gallery and children options\r\n\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n dataSourceItem = dataSource.items[index];\r\n }\r\n\r\n let itemData = dataSourceItem;\r\n\r\n if (itemData instanceof Element) {\r\n itemData = this._domElementToItemData(itemData);\r\n }\r\n\r\n // Dispatching the itemData event,\r\n // it's a legacy verion before filters were introduced\r\n const event = this.dispatch('itemData', {\r\n itemData: itemData || {},\r\n index\r\n });\r\n\r\n return this.applyFilters('itemData', event.itemData, index);\r\n }\r\n\r\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\r\n _getGalleryDOMElements(galleryElement) {\r\n if (this.options?.children || this.options?.childSelector) {\r\n return getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n galleryElement\r\n ) || [];\r\n }\r\n\r\n return [galleryElement];\r\n }\r\n\r\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\r\n _domElementToItemData(element) {\r\n /** @type {SlideData} */\r\n const itemData = {\r\n element\r\n };\r\n\r\n const linkEl = /** @type {HTMLAnchorElement} */ (\r\n element.tagName === 'A'\r\n ? element\r\n : element.querySelector('a')\r\n );\r\n\r\n if (linkEl) {\r\n // src comes from data-pswp-src attribute,\r\n // if it's empty link href is used\r\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\r\n\r\n if (linkEl.dataset.pswpSrcset) {\r\n itemData.srcset = linkEl.dataset.pswpSrcset;\r\n }\r\n\r\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\r\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\r\n\r\n // support legacy w & h properties\r\n itemData.w = itemData.width;\r\n itemData.h = itemData.height;\r\n\r\n if (linkEl.dataset.pswpType) {\r\n itemData.type = linkEl.dataset.pswpType;\r\n }\r\n\r\n const thumbnailEl = element.querySelector('img');\r\n\r\n if (thumbnailEl) {\r\n // msrc is URL to placeholder image that's displayed before large image is loaded\r\n // by default it's displayed only for the first slide\r\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\r\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\r\n }\r\n\r\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\r\n itemData.thumbCropped = true;\r\n }\r\n }\r\n\r\n return this.applyFilters('domItemData', itemData, element, linkEl);\r\n }\r\n\r\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\n lazyLoadData(itemData, index) {\r\n return lazyLoadData(itemData, this, index);\r\n }\r\n}\r\n\r\nexport default PhotoSwipeBase;\r\n","import {\r\n specialKeyUsed,\r\n getElementsFromOption,\r\n isPswpClass\r\n} from '../util/util.js';\r\n\r\nimport PhotoSwipeBase from '../core/base.js';\r\nimport { lazyLoadSlide } from '../slide/loader.js';\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/content.js').default} Content */\r\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\r\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */\r\n\r\n/**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\r\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\r\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\r\n constructor(options) {\r\n super();\r\n /** @type {PhotoSwipeOptions} */\r\n this.options = options || {};\r\n this._uid = 0;\r\n this.shouldOpen = false;\r\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */\r\n this._preloadedContent = undefined;\r\n\r\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\r\n }\r\n\r\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */\r\n init() {\r\n // Bind click events to each gallery\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n\r\n /**\r\n * @param {MouseEvent} e\r\n */\r\n onThumbnailsClick(e) {\r\n // Exit and allow default browser action if:\r\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\r\n || window.pswp) { // ... if PhotoSwipe is already open\r\n return;\r\n }\r\n\r\n // If both clientX and clientY are 0 or not defined,\r\n // the event is likely triggered by keyboard,\r\n // so we do not pass the initialPoint\r\n //\r\n // Note that some screen readers emulate the mouse position,\r\n // so it's not the ideal way to detect them.\r\n //\r\n /** @type {Point | null} */\r\n let initialPoint = { x: e.clientX, y: e.clientY };\r\n\r\n if (!initialPoint.x && !initialPoint.y) {\r\n initialPoint = null;\r\n }\r\n\r\n let clickedIndex = this.getClickedIndex(e);\r\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\r\n /** @type {DataSource} */\r\n const dataSource = {\r\n gallery: /** @type {HTMLElement} */ (e.currentTarget)\r\n };\r\n\r\n if (clickedIndex >= 0) {\r\n e.preventDefault();\r\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\r\n }\r\n }\r\n\r\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */\r\n getClickedIndex(e) {\r\n // legacy option\r\n if (this.options.getClickedIndexFn) {\r\n return this.options.getClickedIndexFn.call(this, e);\r\n }\r\n\r\n const clickedTarget = /** @type {HTMLElement} */ (e.target);\r\n const childElements = getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n /** @type {HTMLElement} */ (e.currentTarget)\r\n );\r\n const clickedChildIndex = childElements.findIndex(\r\n child => child === clickedTarget || child.contains(clickedTarget)\r\n );\r\n\r\n if (clickedChildIndex !== -1) {\r\n return clickedChildIndex;\r\n } else if (this.options.children || this.options.childSelector) {\r\n // click wasn't on a child element\r\n return -1;\r\n }\r\n\r\n // There is only one item (which is the gallery)\r\n return 0;\r\n }\r\n\r\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */\r\n loadAndOpen(index, dataSource, initialPoint) {\r\n // Check if the gallery is already open\r\n if (window.pswp || !this.options) {\r\n return false;\r\n }\r\n\r\n // Use the first gallery element if dataSource is not provided\r\n if (!dataSource && this.options.gallery && this.options.children) {\r\n const galleryElements = getElementsFromOption(this.options.gallery);\r\n if (galleryElements[0]) {\r\n dataSource = {\r\n gallery: galleryElements[0]\r\n };\r\n }\r\n }\r\n\r\n // set initial index\r\n this.options.index = index;\r\n\r\n // define options for PhotoSwipe constructor\r\n this.options.initialPointerPos = initialPoint;\r\n\r\n this.shouldOpen = true;\r\n this.preload(index, dataSource);\r\n return true;\r\n }\r\n\r\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */\r\n preload(index, dataSource) {\r\n const { options } = this;\r\n\r\n if (dataSource) {\r\n options.dataSource = dataSource;\r\n }\r\n\r\n // Add the main module\r\n /** @type {Promise>[]} */\r\n const promiseArray = [];\r\n\r\n const pswpModuleType = typeof options.pswpModule;\r\n if (isPswpClass(options.pswpModule)) {\r\n promiseArray.push(Promise.resolve(/** @type {Type} */ (options.pswpModule)));\r\n } else if (pswpModuleType === 'string') {\r\n throw new Error('pswpModule as string is no longer supported');\r\n } else if (pswpModuleType === 'function') {\r\n promiseArray.push(/** @type {() => Promise>} */ (options.pswpModule)());\r\n } else {\r\n throw new Error('pswpModule is not valid');\r\n }\r\n\r\n // Add custom-defined promise, if any\r\n if (typeof options.openPromise === 'function') {\r\n // allow developers to perform some task before opening\r\n promiseArray.push(options.openPromise());\r\n }\r\n\r\n if (options.preloadFirstSlide !== false && index >= 0) {\r\n this._preloadedContent = lazyLoadSlide(index, this);\r\n }\r\n\r\n // Wait till all promises resolve and open PhotoSwipe\r\n const uid = ++this._uid;\r\n Promise.all(promiseArray).then((iterableModules) => {\r\n if (this.shouldOpen) {\r\n const mainModule = iterableModules[0];\r\n this._openPhotoswipe(mainModule, uid);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */\r\n _openPhotoswipe(module, uid) {\r\n // Cancel opening if UID doesn't match the current one\r\n // (if user clicked on another gallery item before current was loaded).\r\n //\r\n // Or if shouldOpen flag is set to false\r\n // (developer may modify it via public API)\r\n if (uid !== this._uid && this.shouldOpen) {\r\n return;\r\n }\r\n\r\n this.shouldOpen = false;\r\n\r\n // PhotoSwipe is already open\r\n if (window.pswp) {\r\n return;\r\n }\r\n\r\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */\r\n const pswp = typeof module === 'object'\r\n ? new module.default(this.options) // eslint-disable-line\r\n : new module(this.options); // eslint-disable-line\r\n\r\n this.pswp = pswp;\r\n window.pswp = pswp;\r\n\r\n // map listeners from Lightbox to PhotoSwipe Core\r\n /** @type {(keyof PhotoSwipeEventsMap)[]} */\r\n (Object.keys(this._listeners)).forEach((name) => {\r\n this._listeners[name]?.forEach((fn) => {\r\n pswp.on(name, /** @type {EventCallback} */(fn));\r\n });\r\n });\r\n\r\n // same with filters\r\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */\r\n (Object.keys(this._filters)).forEach((name) => {\r\n this._filters[name]?.forEach((filter) => {\r\n pswp.addFilter(name, filter.fn, filter.priority);\r\n });\r\n });\r\n\r\n if (this._preloadedContent) {\r\n pswp.contentLoader.addToCache(this._preloadedContent);\r\n this._preloadedContent = undefined;\r\n }\r\n\r\n pswp.on('destroy', () => {\r\n // clean up public variables\r\n this.pswp = undefined;\r\n delete window.pswp;\r\n });\r\n\r\n pswp.init();\r\n }\r\n\r\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */\r\n destroy() {\r\n this.pswp?.destroy();\r\n\r\n this.shouldOpen = false;\r\n this._listeners = {};\r\n\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n}\r\n\r\nexport default PhotoSwipeLightbox;\r\n"],"names":["$parcel$export","e","n","v","s","Object","defineProperty","get","set","enumerable","configurable","$parcel$global","globalThis","self","window","global","$parcel$modules","$parcel$inits","parcelRequire","id","exports","init","module","call","err","Error","code","register","parcelRegister","$a30b46f7f651be66$var$createElement","className","tagName","appendToEl","el","document","createElement","appendChild","$a30b46f7f651be66$var$setWidthHeight","w","h","style","width","height","$c5996531136d329f$export$6503ec6e8aabbaf","$c5996531136d329f$export$f7ad0328861e2f03","$c5996531136d329f$var$mapping","Map","baseUrl","manifest","i","length","path","resolved","URL","toString","$27ff1cb64c26d98d$export$bdfd709ae4826697","$27ff1cb64c26d98d$var$bundleURL","value","$27ff1cb64c26d98d$var$getBundleURL","matches","stack","match","replace","resolve","then","$bhTHU","bundle","Promise","reject","concat","getElementsByTagName","some","script","src","preloadLink","href","rel","as","head","async","type","onerror","error","TypeError","message","onload","remove","$837c7e8249871e82$var$cachedBundles","$837c7e8249871e82$var$cachedPreloads","$837c7e8249871e82$var$cachedPrefetches","loader","cache","$837c7e8249871e82$var$getCache","apply","arguments","catch","getBundleURL","JSON","parse","$a30b46f7f651be66$var$LOAD_STATE","IDLE","LOADING","LOADED","ERROR","$a30b46f7f651be66$var$getElementsFromOption","option","legacySelector","parent","elements","Element","NodeList","Array","isArray","from","selector","querySelectorAll","$a30b46f7f651be66$var$isSafari","navigator","vendor","$a30b46f7f651be66$var$PhotoSwipeEvent","constructor","details","defaultPrevented","assign","preventDefault","$a30b46f7f651be66$var$Eventable","_listeners","_filters","pswp","undefined","options","addFilter","name","fn","priority","_this$_filters$name","_this$_filters$name2","_this$pswp","push","sort","f1","f2","removeFilter","filter","applyFilters","args","_this$_filters$name3","forEach","on","_this$_listeners$name","_this$pswp2","off","_this$pswp3","listener","dispatch","_this$_listeners$name2","event","$a30b46f7f651be66$var$Placeholder","imageSrc","container","element","imgEl","decoding","alt","setAttribute","setDisplayedSize","scale","propValue","transformOrigin","transform","destroy","_this$element","parentNode","$a30b46f7f651be66$var$Content","itemData","instance","index","data","placeholder","slide","displayedImageWidth","displayedImageHeight","Number","isAttached","hasSlide","isDecoding","state","content","removePlaceholder","keepPlaceholder","setTimeout","load","isLazy","reload","usePlaceholder","placeholderEl","parentElement","prepend","placeholderSrc","msrc","isFirstSlide","isImageContent","loadImage","innerHTML","html","updateContentSize","_this$data$src","_this$data$alt","imageElement","updateSrcsetSizes","srcset","complete","onLoaded","onError","setSlide","isActive","heavyAppended","append","displayError","isError","isLoading","isInitialSizeUpdate","isZoomable","image","sizesWidth","dataset","largestUsedSize","parseInt","sizes","String","lazyLoad","_this$instance$option","_this$instance$option2","errorMsgEl","innerText","errorMsg","supportsDecode","decode","finally","appendImage","activate","holderElement","deactivate","$a30b46f7f651be66$var$parsePaddingOption","prop","viewportSize","paddingValue","paddingFn","padding","legacyPropName","toUpperCase","slice","$a30b46f7f651be66$var$ZoomLevel","panAreaSize","elementSize","fit","fill","vFill","initial","secondary","max","min","update","maxWidth","maxHeight","x","y","hRatio","vRatio","Math","_getInitial","_getSecondary","_getMax","zoomLevels","slideData","_parseZoomLevelOption","optionPrefix","optionValue","currZoomLevel","$a30b46f7f651be66$var$MAX_IMAGE_WIDTH","$a30b46f7f651be66$var$lazyLoadData","zoomLevel","createContentFromData","$a30b46f7f651be66$var$getViewportSize","getViewportSizeFn","newViewportSize","documentElement","clientWidth","innerHeight","ceil","$a30b46f7f651be66$var$PhotoSwipeBase","getNumItems","_this$options","numItems","dataSource","items","_getGalleryDOMElements","gallery","getItemData","_this$options2","dataSourceItem","_domElementToItemData","galleryElement","_this$options3","_this$options4","children","childSelector","linkEl","querySelector","pswpSrc","pswpSrcset","pswpWidth","pswpHeight","pswpType","thumbnailEl","_thumbnailEl$getAttri","currentSrc","getAttribute","pswpCropped","cropped","thumbCropped","lazyLoadData","$d95fd0c27456b0f2$var$lightbox","_uid","shouldOpen","_preloadedContent","onThumbnailsClick","bind","gallerySelector","addEventListener","$a30b46f7f651be66$var$specialKeyUsed","button","ctrlKey","metaKey","altKey","shiftKey","initialPoint","clientX","clientY","clickedIndex","getClickedIndex","currentTarget","loadAndOpen","getClickedIndexFn","clickedTarget","target","clickedChildIndex","childElements","findIndex","child","contains","galleryElements","initialPointerPos","preload","promiseArray","pswpModuleType","pswpModule","prototype","goTo","openPromise","preloadFirstSlide","$a30b46f7f651be66$var$lazyLoadSlide","uid","all","iterableModules","mainModule","_openPhotoswipe","default","keys","contentLoader","addToCache","removeEventListener","showHideAnimationType","toTransformString","setWidthHeight","LOAD_STATE","specialKeyUsed","getElementsFromOption","isPswpClass","isSafari","PhotoSwipeEvent","Eventable","Placeholder","Content","getViewportSize","parsePaddingOption","getPanAreaSize","MAX_IMAGE_WIDTH","ZoomLevel","optionName","lazyLoadSlide","PhotoSwipeBase","PhotoSwipeLightbox"],"version":3,"file":"start.d08064e2.js.map"} \ No newline at end of file diff --git a/start.dd6dc2f2.js b/start.dd6dc2f2.js new file mode 100644 index 0000000..f9875d7 --- /dev/null +++ b/start.dd6dc2f2.js @@ -0,0 +1,5 @@ +function t(t,e,i,s){Object.defineProperty(t,e,{get:i,set:s,enumerable:!0,configurable:!0})}var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},i={},s={},n=e.parcelRequire94c2;null==n&&((n=function(t){if(t in i)return i[t].exports;if(t in s){var e=s[t];delete s[t];var n={id:t,exports:{}};return i[t]=n,e.call(n.exports,n,n.exports),n.exports}var l=Error("Cannot find module '"+t+"'");throw l.code="MODULE_NOT_FOUND",l}).register=function(t,e){s[t]=e},e.parcelRequire94c2=n);var l=n.register;/*! + * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com + * (c) 2024 Dmytro Semenov + */function h(t,e,i){let s=document.createElement(e);return t&&(s.className=t),i&&i.appendChild(s),s}function a(t,e,i){t.style.width="number"==typeof e?`${e}px`:e,t.style.height="number"==typeof i?`${i}px`:i}l("2Ivnh",function(e,i){t(e.exports,"register",function(){return s},function(t){return s=t}),t(e.exports,"resolve",function(){return n},function(t){return n=t});var s,n,l=new Map;s=function(t,e){for(var i=0;in("lxZQh"))}),l("dCVga",function(t,e){t.exports=function(t){return import(n("2Ivnh").resolve(t))}}),n("2Ivnh").register(new URL("",import.meta.url).toString(),JSON.parse('["bCNIK","start.dd6dc2f2.js","dqXFg","photoswipe.esm.b9f46f1c.js"]'));const r={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function o(t,e,i=document){let s=[];if(t instanceof Element)s=[t];else if(t instanceof NodeList||Array.isArray(t))s=Array.from(t);else{let n="string"==typeof t?t:e;n&&(s=Array.from(i.querySelectorAll(n)))}return s}function d(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}class p{constructor(t,e){this.type=t,this.defaultPrevented=!1,e&&Object.assign(this,e)}preventDefault(){this.defaultPrevented=!0}}class c{constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,e,i=100){var s,n,l;this._filters[t]||(this._filters[t]=[]),null===(s=this._filters[t])||void 0===s||s.push({fn:e,priority:i}),null===(n=this._filters[t])||void 0===n||n.sort((t,e)=>t.priority-e.priority),null===(l=this.pswp)||void 0===l||l.addFilter(t,e,i)}removeFilter(t,e){this._filters[t]&&(this._filters[t]=this._filters[t].filter(t=>t.fn!==e)),this.pswp&&this.pswp.removeFilter(t,e)}applyFilters(t,...e){var i;return null===(i=this._filters[t])||void 0===i||i.forEach(t=>{e[0]=t.fn.apply(this,e)}),e[0]}on(t,e){var i,s;this._listeners[t]||(this._listeners[t]=[]),null===(i=this._listeners[t])||void 0===i||i.push(e),null===(s=this.pswp)||void 0===s||s.on(t,e)}off(t,e){var i;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(t=>e!==t)),null===(i=this.pswp)||void 0===i||i.off(t,e)}dispatch(t,e){var i;if(this.pswp)return this.pswp.dispatch(t,e);let s=new p(t,e);return null===(i=this._listeners[t])||void 0===i||i.forEach(t=>{t.call(this,s)}),s}}class m{constructor(t,e){if(this.element=h("pswp__img pswp__img--placeholder",t?"img":"div",e),t){let e=this.element;e.decoding="async",e.alt="",e.src=t,e.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,e){if(this.element){if("IMG"===this.element.tagName){var i;let e;a(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=(e="translate3d(0px,0px,0)",i=t/250,e+=` scale3d(${i},${i},1)`)}else a(this.element,t,e)}}destroy(){var t;null!==(t=this.element)&&void 0!==t&&t.parentNode&&this.element.remove(),this.element=null}}class u{constructor(t,e,i){this.instance=e,this.data=t,this.index=i,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=r.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,e){if(this.slide&&this.usePlaceholder()){if(this.placeholder){let t=this.placeholder.element;t&&!t.parentElement&&this.slide.container.prepend(t)}else{let t=this.instance.applyFilters("placeholderSrc",!!this.data.msrc&&!!this.slide.isFirstSlide&&this.data.msrc,this);this.placeholder=new m(t,this.slide.container)}}(!this.element||e)&&!this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented&&(this.isImageContent()?(this.element=h("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=h("pswp__content","div"),this.element.innerHTML=this.data.html||""),e&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){var e,i;if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;let s=this.element;this.updateSrcsetSizes(),this.data.srcset&&(s.srcset=this.data.srcset),s.src=null!==(e=this.data.src)&&void 0!==e?e:"",s.alt=null!==(i=this.data.alt)&&void 0!==i?i:"",this.state=r.LOADING,s.complete?this.onLoaded():(s.onload=()=>{this.onLoaded()},s.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=r.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===r.LOADED||this.state===r.ERROR)&&this.removePlaceholder())}onError(){this.state=r.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===r.LOADING,this)}isError(){return this.state===r.ERROR}isImageContent(){return"image"===this.type}setDisplayedSize(t,e){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,e),!this.instance.dispatch("contentResize",{content:this,width:t,height:e}).defaultPrevented&&(a(this.element,t,e),this.isImageContent()&&!this.isError()))){let i=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=e,i?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:e,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==r.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;let t=this.element,e=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||e>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=e+"px",t.dataset.largestUsedSize=String(e))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){if(this.slide){var t,e;let i=h("pswp__error-msg","div");i.innerText=null!==(t=null===(e=this.instance.options)||void 0===e?void 0:e.errorMsg)&&void 0!==t?t:"",i=this.instance.applyFilters("contentErrorElement",i,this),this.element=h("pswp__content pswp__error-msg-container","div"),this.element.appendChild(i),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===r.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;let t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||d())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){!this.instance.dispatch("contentActivate",{content:this}).defaultPrevented&&this.slide&&(this.isImageContent()&&this.isDecoding&&!d()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===r.LOADED||this.state===r.ERROR)&&this.removePlaceholder()))}}function f(t,e,i,s,n){let l=0;if(e.paddingFn)l=e.paddingFn(i,s,n)[t];else if(e.padding)l=e.padding[t];else{let i="padding"+t[0].toUpperCase()+t.slice(1);e[i]&&(l=e[i])}return Number(l)||0}class g{constructor(t,e,i,s){this.pswp=s,this.options=t,this.itemData=e,this.index=i,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,e,i){let s={x:t,y:e};this.elementSize=s,this.panAreaSize=i;let n=i.x/s.x,l=i.y/s.y;this.fit=Math.min(1,nl?n:l),this.vFill=Math.min(1,l),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){let e=this.options[t+"ZoomLevel"];if(e)return"function"==typeof e?e(this):"fill"===e?this.fill:"fit"===e?this.fit:Number(e)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,3*this.fit),this.elementSize&&t*this.elementSize.x>4e3&&(t=4e3/this.elementSize.x)),t}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,4*this.fit)}}function y(t,e,i){let s;let n=e.createContentFromData(t,i),{options:l}=e;if(l){let h;s=new g(l,t,-1);let a={x:(h=e.pswp?e.pswp.viewportSize:function(t,e){if(t.getViewportSizeFn){let i=t.getViewportSizeFn(t,e);if(i)return i}return{x:document.documentElement.clientWidth,y:window.innerHeight}}(l,e)).x-f("left",l,h,t,i)-f("right",l,h,t,i),y:h.y-f("top",l,h,t,i)-f("bottom",l,h,t,i)};s.update(n.width,n.height,a)}return n.lazyLoad(),s&&n.setDisplayedSize(Math.ceil(n.width*s.initial),Math.ceil(n.height*s.initial)),n}class v extends c{getNumItems(){var t;let e=0,i=null===(t=this.options)||void 0===t?void 0:t.dataSource;i&&"length"in i?e=i.length:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),i.items&&(e=i.items.length));let s=this.dispatch("numItems",{dataSource:i,numItems:e});return this.applyFilters("numItems",s.numItems,i)}createContentFromData(t,e){return new u(t,this,e)}getItemData(t){var e;let i=null===(e=this.options)||void 0===e?void 0:e.dataSource,s={};Array.isArray(i)?s=i[t]:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),s=i.items[t]);let n=s;n instanceof Element&&(n=this._domElementToItemData(n));let l=this.dispatch("itemData",{itemData:n||{},index:t});return this.applyFilters("itemData",l.itemData,t)}_getGalleryDOMElements(t){var e,i;return null!==(e=this.options)&&void 0!==e&&e.children||null!==(i=this.options)&&void 0!==i&&i.childSelector?o(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){let e={element:t},i="A"===t.tagName?t:t.querySelector("a");if(i){e.src=i.dataset.pswpSrc||i.href,i.dataset.pswpSrcset&&(e.srcset=i.dataset.pswpSrcset),e.width=i.dataset.pswpWidth?parseInt(i.dataset.pswpWidth,10):0,e.height=i.dataset.pswpHeight?parseInt(i.dataset.pswpHeight,10):0,e.w=e.width,e.h=e.height,i.dataset.pswpType&&(e.type=i.dataset.pswpType);let n=t.querySelector("img");if(n){var s;e.msrc=n.currentSrc||n.src,e.alt=null!==(s=n.getAttribute("alt"))&&void 0!==s?s:""}(i.dataset.pswpCropped||i.dataset.cropped)&&(e.thumbCropped=!0)}return this.applyFilters("domItemData",e,t,i)}lazyLoadData(t,e){return y(t,this,e)}}new class extends v{constructor(t){super(),this.options=t||{},this._uid=0,this.shouldOpen=!1,this._preloadedContent=void 0,this.onThumbnailsClick=this.onThumbnailsClick.bind(this)}init(){o(this.options.gallery,this.options.gallerySelector).forEach(t=>{t.addEventListener("click",this.onThumbnailsClick,!1)})}onThumbnailsClick(t){if("button"in t&&1===t.button||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||window.pswp)return;let e={x:t.clientX,y:t.clientY};e.x||e.y||(e=null);let i=this.getClickedIndex(t);i=this.applyFilters("clickedIndex",i,t,this);let s={gallery:t.currentTarget};i>=0&&(t.preventDefault(),this.loadAndOpen(i,s,e))}getClickedIndex(t){if(this.options.getClickedIndexFn)return this.options.getClickedIndexFn.call(this,t);let e=t.target,i=o(this.options.children,this.options.childSelector,t.currentTarget).findIndex(t=>t===e||t.contains(e));return -1!==i?i:this.options.children||this.options.childSelector?-1:0}loadAndOpen(t,e,i){if(window.pswp||!this.options)return!1;if(!e&&this.options.gallery&&this.options.children){let t=o(this.options.gallery);t[0]&&(e={gallery:t[0]})}return this.options.index=t,this.options.initialPointerPos=i,this.shouldOpen=!0,this.preload(t,e),!0}preload(t,e){var i;let{options:s}=this;e&&(s.dataSource=e);let n=[],l=typeof s.pswpModule;if("function"==typeof(i=s.pswpModule)&&i.prototype&&i.prototype.goTo)n.push(Promise.resolve(s.pswpModule));else if("string"===l)throw Error("pswpModule as string is no longer supported");else if("function"===l)n.push(s.pswpModule());else throw Error("pswpModule is not valid");"function"==typeof s.openPromise&&n.push(s.openPromise()),!1!==s.preloadFirstSlide&&t>=0&&(this._preloadedContent=function(t,e){let i=e.getItemData(t);if(!e.dispatch("lazyLoadSlide",{index:t,itemData:i}).defaultPrevented)return y(i,e,t)}(t,this));let h=++this._uid;Promise.all(n).then(t=>{if(this.shouldOpen){let e=t[0];this._openPhotoswipe(e,h)}})}_openPhotoswipe(t,e){if(e!==this._uid&&this.shouldOpen||(this.shouldOpen=!1,window.pswp))return;let i="object"==typeof t?new t.default(this.options):new t(this.options);this.pswp=i,window.pswp=i,Object.keys(this._listeners).forEach(t=>{var e;null===(e=this._listeners[t])||void 0===e||e.forEach(e=>{i.on(t,e)})}),Object.keys(this._filters).forEach(t=>{var e;null===(e=this._filters[t])||void 0===e||e.forEach(e=>{i.addFilter(t,e.fn,e.priority)})}),this._preloadedContent&&(i.contentLoader.addToCache(this._preloadedContent),this._preloadedContent=void 0),i.on("destroy",()=>{this.pswp=void 0,delete window.pswp}),i.init()}destroy(){var t;null===(t=this.pswp)||void 0===t||t.destroy(),this.shouldOpen=!1,this._listeners={},o(this.options.gallery,this.options.gallerySelector).forEach(t=>{t.removeEventListener("click",this.onThumbnailsClick,!1)})}}({gallery:"#gallery--zoom-transition",children:"a",showHideAnimationType:"zoom",pswpModule:()=>n("fmY5d")}).init(); +//# sourceMappingURL=start.dd6dc2f2.js.map diff --git a/start.dd6dc2f2.js.map b/start.dd6dc2f2.js.map new file mode 100644 index 0000000..7cdc741 --- /dev/null +++ b/start.dd6dc2f2.js.map @@ -0,0 +1 @@ +{"mappings":"A,S,E,C,C,C,C,C,C,C,E,O,c,C,E,E,C,I,E,I,E,W,C,E,a,C,C,E,C,I,E,A,a,O,W,W,A,a,O,K,K,A,a,O,O,O,A,a,O,O,O,C,E,E,C,E,E,C,E,E,E,iB,A,O,I,A,C,E,S,C,E,G,K,E,O,C,C,E,C,O,C,G,K,E,C,I,E,C,C,E,A,Q,C,C,E,C,I,E,C,G,E,Q,C,C,E,O,C,C,E,C,E,E,I,C,E,O,C,E,E,O,E,E,O,A,C,I,E,A,M,uB,E,I,O,E,I,C,mB,C,C,E,Q,C,S,C,C,C,E,C,C,E,C,C,E,E,iB,C,G,I,E,E,Q,A;;;E,EOSO,SAASmC,EAAcL,CAAvB,CAAkCC,CAAlC,CAA2CC,CAA3C,EACL,IAAMC,EAAKC,SAASC,aAAT,CAAuBJ,GAOlC,OANID,GACFG,CAAAA,EAAGH,SAAH,CAAeA,CADjB,EAGIE,GACFA,EAAWI,WAAX,CAAuBH,GAElBA,CACR,CAoHM,SAASyT,EAAezT,CAAxB,CAA4BK,CAA5B,CAA+BC,CAA/B,EACLN,EAAGO,KAAH,CAASC,KAAT,CAAkB,AAAa,UAAb,OAAOH,EAAmB,CAAA,EAAEA,EAAE,EAAA,CAA/B,CAAqCA,EACtDL,EAAGO,KAAH,CAASE,MAAT,CAAmB,AAAa,UAAb,OAAOH,EAAmB,CAAA,EAAEA,EAAE,EAAA,CAA/B,CAAqCA,CACxD,C,E,Q,S,C,C,C,E,E,E,O,C,W,W,O,C,E,S,C,E,O,E,C,G,E,E,O,C,U,W,O,C,E,S,C,E,O,E,C,GNvID,IAgBA,EACA,EAjBI,EAAU,IAAI,IAgBlB,EAfA,SAAkB,CAAO,CAAE,CAAQ,EACjC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,MAAM,CAAG,EAAG,GAAK,EAC5C,EAAQ,GAAG,CAAC,CAAQ,CAAC,EAAE,CAAE,CACvB,QAAS,EACT,KAAM,CAAQ,CAAC,EAAI,EAAE,AACvB,EAEJ,EASA,EARA,SAAiB,CAAE,EACjB,IAAI,EAAW,EAAQ,GAAG,CAAC,GAC3B,GAAI,AAAY,MAAZ,EACF,MAAM,AAAI,MAAM,oCAAsC,GAExD,OAAO,IAAI,IAAI,EAAS,IAAI,CAAE,EAAS,OAAO,EAAE,QAAQ,EAC1D,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","sources":["","node_modules/@parcel/runtime-js/lib/helpers/bundle-manifest.js","node_modules/@parcel/runtime-js/lib/runtime-77ab6b670c1e93b1.js","node_modules/@parcel/runtime-js/lib/helpers/browser/esm-js-loader.js","node_modules/@parcel/runtime-js/lib/runtime-d55d619967c5bac9.js","src/js/gallery.js","node_modules/photoswipe/dist/photoswipe-lightbox.esm.js","src/js/util/util.js","src/js/core/eventable.js","src/js/slide/placeholder.js","src/js/slide/content.js","src/js/util/viewport-size.js","src/js/slide/zoom-level.js","src/js/slide/loader.js","src/js/core/base.js","src/js/lightbox/lightbox.js"],"sourcesContent":["\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n \nvar $parcel$modules = {};\nvar $parcel$inits = {};\n\nvar parcelRequire = $parcel$global[\"parcelRequire94c2\"];\n\nif (parcelRequire == null) {\n parcelRequire = function(id) {\n if (id in $parcel$modules) {\n return $parcel$modules[id].exports;\n }\n if (id in $parcel$inits) {\n var init = $parcel$inits[id];\n delete $parcel$inits[id];\n var module = {id: id, exports: {}};\n $parcel$modules[id] = module;\n init.call(module.exports, module, module.exports);\n return module.exports;\n }\n var err = new Error(\"Cannot find module '\" + id + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n };\n\n parcelRequire.register = function register(id, init) {\n $parcel$inits[id] = init;\n };\n\n $parcel$global[\"parcelRequire94c2\"] = parcelRequire;\n}\n\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"2Ivnh\", function(module, exports) {\n\n$parcel$export(module.exports, \"register\", function () { return $1fa8072a7f2bd73f$export$6503ec6e8aabbaf; }, function (v) { return $1fa8072a7f2bd73f$export$6503ec6e8aabbaf = v; });\n$parcel$export(module.exports, \"resolve\", function () { return $1fa8072a7f2bd73f$export$f7ad0328861e2f03; }, function (v) { return $1fa8072a7f2bd73f$export$f7ad0328861e2f03 = v; });\nvar $1fa8072a7f2bd73f$export$6503ec6e8aabbaf;\nvar $1fa8072a7f2bd73f$export$f7ad0328861e2f03;\n\"use strict\";\nvar $1fa8072a7f2bd73f$var$mapping = new Map();\nfunction $1fa8072a7f2bd73f$var$register(baseUrl, manifest) {\n for(var i = 0; i < manifest.length - 1; i += 2)$1fa8072a7f2bd73f$var$mapping.set(manifest[i], {\n baseUrl: baseUrl,\n path: manifest[i + 1]\n });\n}\nfunction $1fa8072a7f2bd73f$var$resolve(id) {\n var resolved = $1fa8072a7f2bd73f$var$mapping.get(id);\n if (resolved == null) throw new Error('Could not resolve bundle with id ' + id);\n return new URL(resolved.path, resolved.baseUrl).toString();\n}\n$1fa8072a7f2bd73f$export$6503ec6e8aabbaf = $1fa8072a7f2bd73f$var$register;\n$1fa8072a7f2bd73f$export$f7ad0328861e2f03 = $1fa8072a7f2bd73f$var$resolve;\n\n});\n\nparcelRegister(\"fmY5d\", function(module, exports) {\n\nvar $dCVga = parcelRequire(\"dCVga\");\nmodule.exports = $dCVga(\"dqXFg\").then(()=>parcelRequire('lxZQh'));\n\n});\nparcelRegister(\"dCVga\", function(module, exports) {\n\"use strict\";\n\nfunction $9ebb3d8cd4a1fb0a$var$load(id) {\n // eslint-disable-next-line no-undef\n return import((parcelRequire(\"2Ivnh\")).resolve(id));\n}\nmodule.exports = $9ebb3d8cd4a1fb0a$var$load;\n\n});\n\n\nvar $fa9fa132a3973561$exports = {};\n\n(parcelRequire(\"2Ivnh\")).register(new URL(\"\", import.meta.url).toString(), JSON.parse(\"[\\\"bCNIK\\\",\\\"start.dd6dc2f2.js\\\",\\\"dqXFg\\\",\\\"photoswipe.esm.b9f46f1c.js\\\"]\"));\n\n/*!\n * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */ /** @typedef {import('../photoswipe.js').Point} Point */ /**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */ function $50cf2b1817a85608$var$createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) el.className = className;\n if (appendToEl) appendToEl.appendChild(el);\n return el;\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */ function $50cf2b1817a85608$var$toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n if (scale !== undefined) propValue += ` scale3d(${scale},${scale},1)`;\n return propValue;\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */ function $50cf2b1817a85608$var$setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ /** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ const $50cf2b1817a85608$var$LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */ function $50cf2b1817a85608$var$specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */ function $50cf2b1817a85608$var$getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */ let elements = [];\n if (option instanceof Element) elements = [\n option\n ];\n else if (option instanceof NodeList || Array.isArray(option)) elements = Array.from(option);\n else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) elements = Array.from(parent.querySelectorAll(selector));\n }\n return elements;\n}\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */ function $50cf2b1817a85608$var$isPswpClass(fn) {\n return typeof fn === 'function' && fn.prototype && fn.prototype.goTo;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */ function $50cf2b1817a85608$var$isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ /** @typedef {import('../slide/content.js').default} ContentDefault */ /** @typedef {import('../slide/slide.js').default} Slide */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ /** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ /**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */ /** @typedef {{ x?: number; y?: number }} Point */ /**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */ /**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */ /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */ /**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */ class $50cf2b1817a85608$var$PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */ constructor(type, details){\n this.type = type;\n this.defaultPrevented = false;\n if (details) Object.assign(this, details);\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */ class $50cf2b1817a85608$var$Eventable {\n constructor(){\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */ this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */ this._filters = {};\n /** @type {PhotoSwipe | undefined} */ this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */ this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */ addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n if (!this._filters[name]) this._filters[name] = [];\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn: fn,\n priority: priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2)=>f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */ removeFilter(name, fn) {\n if (this._filters[name]) // @ts-expect-error\n this._filters[name] = this._filters[name].filter((filter)=>filter.fn !== fn);\n if (this.pswp) this.pswp.removeFilter(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */ applyFilters(name, ...args) {\n var _this$_filters$name3;\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach((filter)=>{\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n if (!this._listeners[name]) this._listeners[name] = [];\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */ off(name, fn) {\n var _this$pswp3;\n if (this._listeners[name]) // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter((listener)=>fn !== listener);\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */ dispatch(name, details) {\n var _this$_listeners$name2;\n if (this.pswp) return this.pswp.dispatch(name, details);\n const event = /** @type {AugmentedEvent} */ new $50cf2b1817a85608$var$PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach((listener)=>{\n listener.call(this, event);\n });\n return event;\n }\n}\nclass $50cf2b1817a85608$var$Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */ constructor(imageSrc, container){\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */ this.element = $50cf2b1817a85608$var$createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n $50cf2b1817a85608$var$setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = $50cf2b1817a85608$var$toTransformString(0, 0, width / 250);\n } else $50cf2b1817a85608$var$setWidthHeight(this.element, width, height);\n }\n destroy() {\n var _this$element;\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) this.element.remove();\n this.element = null;\n }\n}\n/** @typedef {import('./slide.js').default} Slide */ /** @typedef {import('./slide.js').SlideData} SlideData */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../util/util.js').LoadState} LoadState */ class $50cf2b1817a85608$var$Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */ constructor(itemData, instance, index){\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */ this.element = undefined;\n /** @type {Placeholder | undefined} */ this.placeholder = undefined;\n /** @type {Slide | undefined} */ this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */ this.state = $50cf2b1817a85608$var$LOAD_STATE.IDLE;\n if (this.data.type) this.type = this.data.type;\n else if (this.data.src) this.type = 'image';\n else this.type = 'html';\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) // With delay, as image might be loaded, but not rendered\n setTimeout(()=>{\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */ load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new $50cf2b1817a85608$var$Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) this.slide.container.prepend(placeholderEl);\n }\n }\n if (this.element && !reload) return;\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n if (this.isImageContent()) {\n this.element = $50cf2b1817a85608$var$createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) this.loadImage(isLazy);\n } else {\n this.element = $50cf2b1817a85608$var$createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n if (reload && this.slide) this.slide.updateContentSize(true);\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */ loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy: isLazy\n }).defaultPrevented) return;\n const imageElement = /** @type HTMLImageElement */ this.element;\n this.updateSrcsetSizes();\n if (this.data.srcset) imageElement.srcset = this.data.srcset;\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = $50cf2b1817a85608$var$LOAD_STATE.LOADING;\n if (imageElement.complete) this.onLoaded();\n else {\n imageElement.onload = ()=>{\n this.onLoaded();\n };\n imageElement.onerror = ()=>{\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */ setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */ onLoaded() {\n this.state = $50cf2b1817a85608$var$LOAD_STATE.LOADED;\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n if (this.state === $50cf2b1817a85608$var$LOAD_STATE.LOADED || this.state === $50cf2b1817a85608$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n }\n /**\r\n * Content load error handler\r\n */ onError() {\n this.state = $50cf2b1817a85608$var$LOAD_STATE.ERROR;\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */ isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === $50cf2b1817a85608$var$LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */ isError() {\n return this.state === $50cf2b1817a85608$var$LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */ isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */ setDisplayedSize(width, height) {\n if (!this.element) return;\n if (this.placeholder) this.placeholder.setDisplayedSize(width, height);\n if (this.instance.dispatch('contentResize', {\n content: this,\n width: width,\n height: height\n }).defaultPrevented) return;\n $50cf2b1817a85608$var$setWidthHeight(this.element, width, height);\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n if (isInitialSizeUpdate) this.loadImage(false);\n else this.updateSrcsetSizes();\n if (this.slide) this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width: width,\n height: height,\n content: this\n });\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */ isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== $50cf2b1817a85608$var$LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */ updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) return;\n const image = /** @type HTMLImageElement */ this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */ usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */ lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) return;\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */ keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */ destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) return;\n this.remove();\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */ displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n let errorMsgEl = $50cf2b1817a85608$var$createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl = /** @type {HTMLDivElement} */ this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = $50cf2b1817a85608$var$createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */ append() {\n if (this.isAttached || !this.element) return;\n this.isAttached = true;\n if (this.state === $50cf2b1817a85608$var$LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) return;\n const supportsDecode = 'decode' in this.element;\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || $50cf2b1817a85608$var$isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */ this.element.decode().catch(()=>{}).finally(()=>{\n this.isDecoding = false;\n this.appendImage();\n });\n } else this.appendImage();\n } else if (this.slide && !this.element.parentNode) this.slide.container.appendChild(this.element);\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */ activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) return;\n if (this.isImageContent() && this.isDecoding && !$50cf2b1817a85608$var$isSafari()) // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n else if (this.isError()) this.load(false, true); // try to reload\n if (this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n /**\r\n * Deactivate the content\r\n */ deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n if (this.slide && this.slide.holderElement) this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * Remove the content from DOM\r\n */ remove() {\n this.isAttached = false;\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) return;\n if (this.element && this.element.parentNode) this.element.remove();\n if (this.placeholder && this.placeholder.element) this.placeholder.element.remove();\n }\n /**\r\n * Append the image content to slide container\r\n */ appendImage() {\n if (!this.isAttached) return;\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) return;\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) this.slide.container.appendChild(this.element);\n if (this.state === $50cf2b1817a85608$var$LOAD_STATE.LOADED || this.state === $50cf2b1817a85608$var$LOAD_STATE.ERROR) this.removePlaceholder();\n }\n}\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../core/base.js').default} PhotoSwipeBase */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */ function $50cf2b1817a85608$var$getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) return newViewportSize;\n }\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */ function $50cf2b1817a85608$var$parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n if (options.paddingFn) paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n else if (options.padding) paddingValue = options.padding[prop];\n else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n if (options[legacyPropName]) // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */ function $50cf2b1817a85608$var$getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - $50cf2b1817a85608$var$parsePaddingOption('left', options, viewportSize, itemData, index) - $50cf2b1817a85608$var$parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - $50cf2b1817a85608$var$parsePaddingOption('top', options, viewportSize, itemData, index) - $50cf2b1817a85608$var$parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\nconst $50cf2b1817a85608$var$MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/slide.js').SlideData} SlideData */ /** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ /**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */ class $50cf2b1817a85608$var$ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */ constructor(options, itemData, index, pswp){\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */ this.panAreaSize = null;\n /** @type { Point | null } */ this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */ update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */ const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n if (this.pswp) this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */ _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n if (!optionValue) return;\n if (typeof optionValue === 'function') return optionValue(this);\n if (optionValue === 'fill') return this.fill;\n if (optionValue === 'fit') return this.fit;\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n if (currZoomLevel) return currZoomLevel;\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n if (this.elementSize && currZoomLevel * this.elementSize.x > $50cf2b1817a85608$var$MAX_IMAGE_WIDTH) currZoomLevel = $50cf2b1817a85608$var$MAX_IMAGE_WIDTH / this.elementSize.x;\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */ _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ function $50cf2b1817a85608$var$lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */ let zoomLevel;\n const { options: options } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new $50cf2b1817a85608$var$ZoomLevel(options, itemData, -1);\n let viewportSize;\n if (instance.pswp) viewportSize = instance.pswp.viewportSize;\n else viewportSize = $50cf2b1817a85608$var$getViewportSize(options, instance);\n const panAreaSize = $50cf2b1817a85608$var$getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n content.lazyLoad();\n if (zoomLevel) content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */ function $50cf2b1817a85608$var$lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n if (instance.dispatch('lazyLoadSlide', {\n index: index,\n itemData: itemData\n }).defaultPrevented) return;\n return $50cf2b1817a85608$var$lazyLoadData(itemData, instance, index);\n}\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */ /** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */ /**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */ class $50cf2b1817a85608$var$PhotoSwipeBase extends $50cf2b1817a85608$var$Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */ getNumItems() {\n var _this$options;\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n if (dataSource && 'length' in dataSource) // may be an array or just object with length property\n numItems = dataSource.length;\n else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n if (dataSource.items) numItems = dataSource.items.length;\n } // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource: dataSource,\n numItems: numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */ createContentFromData(slideData, index) {\n return new $50cf2b1817a85608$var$Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */ getItemData(index) {\n var _this$options2;\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */ let dataSourceItem = {};\n if (Array.isArray(dataSource)) // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n dataSourceItem = dataSource.items[index];\n }\n let itemData = dataSourceItem;\n if (itemData instanceof Element) itemData = this._domElementToItemData(itemData);\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index: index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */ _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) return $50cf2b1817a85608$var$getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n return [\n galleryElement\n ];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */ _domElementToItemData(element) {\n /** @type {SlideData} */ const itemData = {\n element: element\n };\n const linkEl = /** @type {HTMLAnchorElement} */ element.tagName === 'A' ? element : element.querySelector('a');\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n if (linkEl.dataset.pswpSrcset) itemData.srcset = linkEl.dataset.pswpSrcset;\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n if (linkEl.dataset.pswpType) itemData.type = linkEl.dataset.pswpType;\n const thumbnailEl = element.querySelector('img');\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) itemData.thumbCropped = true;\n }\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */ lazyLoadData(itemData, index) {\n return $50cf2b1817a85608$var$lazyLoadData(itemData, this, index);\n }\n}\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */ /** @typedef {import('../photoswipe.js').default} PhotoSwipe */ /** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ /** @typedef {import('../photoswipe.js').DataSource} DataSource */ /** @typedef {import('../photoswipe.js').Point} Point */ /** @typedef {import('../slide/content.js').default} Content */ /** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ /** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */ /**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */ class $50cf2b1817a85608$export$2e2bcd8739ae039 extends $50cf2b1817a85608$var$PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */ constructor(options){\n super();\n /** @type {PhotoSwipeOptions} */ this.options = options || {};\n this._uid = 0;\n this.shouldOpen = false;\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */ this._preloadedContent = undefined;\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n }\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */ init() {\n // Bind click events to each gallery\n $50cf2b1817a85608$var$getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach((galleryElement)=>{\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n });\n }\n /**\r\n * @param {MouseEvent} e\r\n */ onThumbnailsClick(e) {\n // Exit and allow default browser action if:\n if ($50cf2b1817a85608$var$specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n || window.pswp) // ... if PhotoSwipe is already open\n return;\n // If both clientX and clientY are 0 or not defined,\n // the event is likely triggered by keyboard,\n // so we do not pass the initialPoint\n //\n // Note that some screen readers emulate the mouse position,\n // so it's not the ideal way to detect them.\n //\n /** @type {Point | null} */ let initialPoint = {\n x: e.clientX,\n y: e.clientY\n };\n if (!initialPoint.x && !initialPoint.y) initialPoint = null;\n let clickedIndex = this.getClickedIndex(e);\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n /** @type {DataSource} */ const dataSource = {\n gallery: /** @type {HTMLElement} */ e.currentTarget\n };\n if (clickedIndex >= 0) {\n e.preventDefault();\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n }\n }\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */ getClickedIndex(e) {\n // legacy option\n if (this.options.getClickedIndexFn) return this.options.getClickedIndexFn.call(this, e);\n const clickedTarget = /** @type {HTMLElement} */ e.target;\n const childElements = $50cf2b1817a85608$var$getElementsFromOption(this.options.children, this.options.childSelector, /** @type {HTMLElement} */ e.currentTarget);\n const clickedChildIndex = childElements.findIndex((child)=>child === clickedTarget || child.contains(clickedTarget));\n if (clickedChildIndex !== -1) return clickedChildIndex;\n else if (this.options.children || this.options.childSelector) // click wasn't on a child element\n return -1;\n // There is only one item (which is the gallery)\n return 0;\n }\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */ loadAndOpen(index, dataSource, initialPoint) {\n // Check if the gallery is already open\n if (window.pswp || !this.options) return false;\n // Use the first gallery element if dataSource is not provided\n if (!dataSource && this.options.gallery && this.options.children) {\n const galleryElements = $50cf2b1817a85608$var$getElementsFromOption(this.options.gallery);\n if (galleryElements[0]) dataSource = {\n gallery: galleryElements[0]\n };\n } // set initial index\n this.options.index = index; // define options for PhotoSwipe constructor\n this.options.initialPointerPos = initialPoint;\n this.shouldOpen = true;\n this.preload(index, dataSource);\n return true;\n }\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */ preload(index, dataSource) {\n const { options: options } = this;\n if (dataSource) options.dataSource = dataSource;\n // Add the main module\n /** @type {Promise>[]} */ const promiseArray = [];\n const pswpModuleType = typeof options.pswpModule;\n if ($50cf2b1817a85608$var$isPswpClass(options.pswpModule)) promiseArray.push(Promise.resolve(/** @type {Type} */ options.pswpModule));\n else if (pswpModuleType === 'string') throw new Error('pswpModule as string is no longer supported');\n else if (pswpModuleType === 'function') promiseArray.push(/** @type {() => Promise>} */ options.pswpModule());\n else throw new Error('pswpModule is not valid');\n // Add custom-defined promise, if any\n if (typeof options.openPromise === 'function') // allow developers to perform some task before opening\n promiseArray.push(options.openPromise());\n if (options.preloadFirstSlide !== false && index >= 0) this._preloadedContent = $50cf2b1817a85608$var$lazyLoadSlide(index, this);\n // Wait till all promises resolve and open PhotoSwipe\n const uid = ++this._uid;\n Promise.all(promiseArray).then((iterableModules)=>{\n if (this.shouldOpen) {\n const mainModule = iterableModules[0];\n this._openPhotoswipe(mainModule, uid);\n }\n });\n }\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */ _openPhotoswipe(module, uid) {\n // Cancel opening if UID doesn't match the current one\n // (if user clicked on another gallery item before current was loaded).\n //\n // Or if shouldOpen flag is set to false\n // (developer may modify it via public API)\n if (uid !== this._uid && this.shouldOpen) return;\n this.shouldOpen = false; // PhotoSwipe is already open\n if (window.pswp) return;\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */ const pswp = typeof module === 'object' ? new module.default(this.options) // eslint-disable-line\n : new module(this.options); // eslint-disable-line\n this.pswp = pswp;\n window.pswp = pswp; // map listeners from Lightbox to PhotoSwipe Core\n /** @type {(keyof PhotoSwipeEventsMap)[]} */ Object.keys(this._listeners).forEach((name)=>{\n var _this$_listeners$name;\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.forEach((fn)=>{\n pswp.on(name, /** @type {EventCallback} */ fn);\n });\n }); // same with filters\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */ Object.keys(this._filters).forEach((name)=>{\n var _this$_filters$name;\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.forEach((filter)=>{\n pswp.addFilter(name, filter.fn, filter.priority);\n });\n });\n if (this._preloadedContent) {\n pswp.contentLoader.addToCache(this._preloadedContent);\n this._preloadedContent = undefined;\n }\n pswp.on('destroy', ()=>{\n // clean up public variables\n this.pswp = undefined;\n delete window.pswp;\n });\n pswp.init();\n }\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */ destroy() {\n var _this$pswp;\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.destroy();\n this.shouldOpen = false;\n this._listeners = {};\n $50cf2b1817a85608$var$getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach((galleryElement)=>{\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n });\n }\n}\n\n\n\n\nconst $239507fc38a64297$var$lightbox = new (0, $50cf2b1817a85608$export$2e2bcd8739ae039)({\n gallery: '#gallery--zoom-transition',\n children: 'a',\n showHideAnimationType: 'zoom',\n pswpModule: ()=>(parcelRequire(\"fmY5d\"))\n});\n$239507fc38a64297$var$lightbox.init();\n\n\n//# sourceMappingURL=start.dd6dc2f2.js.map\n","\"use strict\";\n\nvar mapping = new Map();\nfunction register(baseUrl, manifest) {\n for (var i = 0; i < manifest.length - 1; i += 2) {\n mapping.set(manifest[i], {\n baseUrl: baseUrl,\n path: manifest[i + 1]\n });\n }\n}\nfunction resolve(id) {\n var resolved = mapping.get(id);\n if (resolved == null) {\n throw new Error('Could not resolve bundle with id ' + id);\n }\n return new URL(resolved.path, resolved.baseUrl).toString();\n}\nmodule.exports.register = register;\nmodule.exports.resolve = resolve;","let load = require('./helpers/browser/esm-js-loader');\nmodule.exports = (load(\"dqXFg\")).then(() => parcelRequire('lxZQh'));","\"use strict\";\n\nfunction load(id) {\n // eslint-disable-next-line no-undef\n return __parcel__import__(require('../bundle-manifest').resolve(id));\n}\nmodule.exports = load;","require('./helpers/bundle-manifest').register(new __parcel__URL__(\"\").toString(),JSON.parse(\"[\\\"bCNIK\\\",\\\"start.dd6dc2f2.js\\\",\\\"dqXFg\\\",\\\"photoswipe.esm.b9f46f1c.js\\\"]\"));","import PhotoSwipeLightbox from 'photoswipe/dist/photoswipe-lightbox.esm.js';\nimport 'photoswipe/dist/photoswipe.css';\n\nconst lightbox = new PhotoSwipeLightbox({\n gallery: '#gallery--zoom-transition',\n children: 'a',\n showHideAnimationType: 'zoom',\n pswpModule: () => import('photoswipe/dist/photoswipe.esm.js')\n});\nlightbox.init();\n","/*!\n * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com\n * (c) 2024 Dmytro Semenov\n */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\nfunction createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n\n if (className) {\n el.className = className;\n }\n\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n\n return el;\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\n\nfunction toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\n\nfunction setWidthHeight(el, w, h) {\n el.style.width = typeof w === 'number' ? `${w}px` : w;\n el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\n\nconst LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\n\nfunction specialKeyUsed(e) {\n return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\n\nfunction getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\n\nfunction isPswpClass(fn) {\n return typeof fn === 'function' && fn.prototype && fn.prototype.goTo;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\n\nfunction isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n\n/** @typedef {import('../slide/slide.js').default} Slide */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\n\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\n\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\n\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\nclass PhotoSwipeEvent {\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\n\n\nclass Eventable {\n constructor() {\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\n this._listeners = {};\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\n\n this._filters = {};\n /** @type {PhotoSwipe | undefined} */\n\n this.pswp = undefined;\n /** @type {PhotoSwipeOptions | undefined} */\n\n this.options = undefined;\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\n\n\n addFilter(name, fn, priority = 100) {\n var _this$_filters$name, _this$_filters$name2, _this$pswp;\n\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n fn,\n priority\n });\n (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2) => f1.priority - f2.priority);\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\n\n\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => filter.fn !== fn);\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\n\n\n applyFilters(name, ...args) {\n var _this$_filters$name3;\n\n (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach(filter => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n on(name, fn) {\n var _this$_listeners$name, _this$pswp2;\n\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n\n (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\n\n\n off(name, fn) {\n var _this$pswp3;\n\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => fn !== listener);\n }\n\n (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n }\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\n\n\n dispatch(name, details) {\n var _this$_listeners$name2;\n\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event =\n /** @type {AugmentedEvent} */\n new PhotoSwipeEvent(name, details);\n (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach(listener => {\n listener.call(this, event);\n });\n return event;\n }\n\n}\n\nclass Placeholder {\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n\n if (imageSrc) {\n const imgEl =\n /** @type {HTMLImageElement} */\n this.element;\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n var _this$element;\n\n if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) {\n this.element.remove();\n }\n\n this.element = null;\n }\n\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n\n this.slide = undefined;\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', {\n content: this\n });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\n\n\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters('placeholderSrc', // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n this.placeholder = new Placeholder(placeholderSrc, this.slide.container);\n } else {\n const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\n\n\n loadImage(isLazy) {\n var _this$data$src, _this$data$alt;\n\n if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n content: this,\n isLazy\n }).defaultPrevented) {\n return;\n }\n\n const imageElement =\n /** @type HTMLImageElement */\n this.element;\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\n\n\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp; // todo: do we need to unset slide?\n }\n /**\r\n * Content load success handler\r\n */\n\n\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n content: this\n }); // if content is reloaded\n\n if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n /**\r\n * Content load error handler\r\n */\n\n\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', {\n slide: this.slide,\n isError: true,\n content: this\n });\n this.instance.dispatch('loadError', {\n slide: this.slide,\n content: this\n });\n }\n }\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\n\n\n isLoading() {\n return this.instance.applyFilters('isContentLoading', this.state === LOAD_STATE.LOADING, this);\n }\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\n\n\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n /**\r\n * @returns {boolean} If the content is image\r\n */\n\n\n isImageContent() {\n return this.type === 'image';\n }\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\n\n\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch('contentResize', {\n content: this,\n width,\n height\n }).defaultPrevented) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = !this.displayedImageWidth && width;\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch('imageSizeChange', {\n slide: this.slide,\n width,\n height,\n content: this\n });\n }\n }\n }\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\n\n\n isZoomable() {\n return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== LOAD_STATE.ERROR, this);\n }\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\n\n\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image =\n /** @type HTMLImageElement */\n this.element;\n const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n\n if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\n\n\n usePlaceholder() {\n return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n }\n /**\r\n * Preload content with lazy-loading param\r\n */\n\n\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\n\n\n keepPlaceholder() {\n return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n }\n /**\r\n * Destroy the content\r\n */\n\n\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n /**\r\n * Display error message\r\n */\n\n\n displayError() {\n if (this.slide) {\n var _this$instance$option, _this$instance$option2;\n\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n errorMsgEl =\n /** @type {HTMLDivElement} */\n this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n /**\r\n * Append the content\r\n */\n\n\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true; // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n\n /** @type {HTMLImageElement} */\n\n this.element.decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\n\n\n activate() {\n if (this.instance.dispatch('contentActivate', {\n content: this\n }).defaultPrevented || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n /**\r\n * Deactivate the content\r\n */\n\n\n deactivate() {\n this.instance.dispatch('contentDeactivate', {\n content: this\n });\n\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n /**\r\n * Remove the content from DOM\r\n */\n\n\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', {\n content: this\n }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n /**\r\n * Append the image content to slide container\r\n */\n\n\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', {\n content: this\n }).defaultPrevented) {\n return;\n } // ensure that element exists and is not already appended\n\n\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n\n}\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\nfunction getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\n\nfunction parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\n\nfunction getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x - parsePaddingOption('left', options, viewportSize, itemData, index) - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y - parsePaddingOption('top', options, viewportSize, itemData, index) - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n\nconst MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\n\nclass ZoomLevel {\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n\n this.panAreaSize = null;\n /** @type { Point | null } */\n\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\n\n\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = {\n x: maxWidth,\n y: maxHeight\n };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n\n this.vFill = Math.min(1, vRatio);\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(this.initial, this.secondary, this._getMax());\n this.min = Math.min(this.fit, this.initial, this.secondary);\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', {\n zoomLevels: this,\n slideData: this.itemData\n });\n }\n }\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\n\n\n _parseZoomLevelOption(optionPrefix) {\n const optionName =\n /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */\n optionPrefix + 'ZoomLevel';\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n } // 3x of \"fit\" state, but not larger than original\n\n\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\n\n\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n\n}\n\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\nfunction lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n\n let zoomLevel;\n const {\n options\n } = instance; // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n let viewportSize;\n\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n }\n\n return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\n\nfunction lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', {\n index,\n itemData\n }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\n\nclass PhotoSwipeBase extends Eventable {\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\n getNumItems() {\n var _this$options;\n\n let numItems = 0;\n const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n } // legacy event, before filters were introduced\n\n\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\n\n\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\n\n\n getItemData(index) {\n var _this$options2;\n\n const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n /** @type {SlideData | HTMLElement} */\n\n let dataSourceItem = {};\n\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n } // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n\n\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n return this.applyFilters('itemData', event.itemData, index);\n }\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\n\n\n _getGalleryDOMElements(galleryElement) {\n var _this$options3, _this$options4;\n\n if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) {\n return getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n }\n\n return [galleryElement];\n }\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\n\n\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n const linkEl =\n /** @type {HTMLAnchorElement} */\n element.tagName === 'A' ? element : element.querySelector('a');\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n var _thumbnailEl$getAttri;\n\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\n\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n\n}\n\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/content.js').default} Content */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */\n\n/**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\n\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\n constructor(options) {\n super();\n /** @type {PhotoSwipeOptions} */\n\n this.options = options || {};\n this._uid = 0;\n this.shouldOpen = false;\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */\n\n this._preloadedContent = undefined;\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n }\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */\n\n\n init() {\n // Bind click events to each gallery\n getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n });\n }\n /**\r\n * @param {MouseEvent} e\r\n */\n\n\n onThumbnailsClick(e) {\n // Exit and allow default browser action if:\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n || window.pswp) {\n // ... if PhotoSwipe is already open\n return;\n } // If both clientX and clientY are 0 or not defined,\n // the event is likely triggered by keyboard,\n // so we do not pass the initialPoint\n //\n // Note that some screen readers emulate the mouse position,\n // so it's not the ideal way to detect them.\n //\n\n /** @type {Point | null} */\n\n\n let initialPoint = {\n x: e.clientX,\n y: e.clientY\n };\n\n if (!initialPoint.x && !initialPoint.y) {\n initialPoint = null;\n }\n\n let clickedIndex = this.getClickedIndex(e);\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n /** @type {DataSource} */\n\n const dataSource = {\n gallery:\n /** @type {HTMLElement} */\n e.currentTarget\n };\n\n if (clickedIndex >= 0) {\n e.preventDefault();\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n }\n }\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */\n\n\n getClickedIndex(e) {\n // legacy option\n if (this.options.getClickedIndexFn) {\n return this.options.getClickedIndexFn.call(this, e);\n }\n\n const clickedTarget =\n /** @type {HTMLElement} */\n e.target;\n const childElements = getElementsFromOption(this.options.children, this.options.childSelector,\n /** @type {HTMLElement} */\n e.currentTarget);\n const clickedChildIndex = childElements.findIndex(child => child === clickedTarget || child.contains(clickedTarget));\n\n if (clickedChildIndex !== -1) {\n return clickedChildIndex;\n } else if (this.options.children || this.options.childSelector) {\n // click wasn't on a child element\n return -1;\n } // There is only one item (which is the gallery)\n\n\n return 0;\n }\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */\n\n\n loadAndOpen(index, dataSource, initialPoint) {\n // Check if the gallery is already open\n if (window.pswp || !this.options) {\n return false;\n } // Use the first gallery element if dataSource is not provided\n\n\n if (!dataSource && this.options.gallery && this.options.children) {\n const galleryElements = getElementsFromOption(this.options.gallery);\n\n if (galleryElements[0]) {\n dataSource = {\n gallery: galleryElements[0]\n };\n }\n } // set initial index\n\n\n this.options.index = index; // define options for PhotoSwipe constructor\n\n this.options.initialPointerPos = initialPoint;\n this.shouldOpen = true;\n this.preload(index, dataSource);\n return true;\n }\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */\n\n\n preload(index, dataSource) {\n const {\n options\n } = this;\n\n if (dataSource) {\n options.dataSource = dataSource;\n } // Add the main module\n\n /** @type {Promise>[]} */\n\n\n const promiseArray = [];\n const pswpModuleType = typeof options.pswpModule;\n\n if (isPswpClass(options.pswpModule)) {\n promiseArray.push(Promise.resolve(\n /** @type {Type} */\n options.pswpModule));\n } else if (pswpModuleType === 'string') {\n throw new Error('pswpModule as string is no longer supported');\n } else if (pswpModuleType === 'function') {\n promiseArray.push(\n /** @type {() => Promise>} */\n options.pswpModule());\n } else {\n throw new Error('pswpModule is not valid');\n } // Add custom-defined promise, if any\n\n\n if (typeof options.openPromise === 'function') {\n // allow developers to perform some task before opening\n promiseArray.push(options.openPromise());\n }\n\n if (options.preloadFirstSlide !== false && index >= 0) {\n this._preloadedContent = lazyLoadSlide(index, this);\n } // Wait till all promises resolve and open PhotoSwipe\n\n\n const uid = ++this._uid;\n Promise.all(promiseArray).then(iterableModules => {\n if (this.shouldOpen) {\n const mainModule = iterableModules[0];\n\n this._openPhotoswipe(mainModule, uid);\n }\n });\n }\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */\n\n\n _openPhotoswipe(module, uid) {\n // Cancel opening if UID doesn't match the current one\n // (if user clicked on another gallery item before current was loaded).\n //\n // Or if shouldOpen flag is set to false\n // (developer may modify it via public API)\n if (uid !== this._uid && this.shouldOpen) {\n return;\n }\n\n this.shouldOpen = false; // PhotoSwipe is already open\n\n if (window.pswp) {\n return;\n }\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */\n\n\n const pswp = typeof module === 'object' ? new module.default(this.options) // eslint-disable-line\n : new module(this.options); // eslint-disable-line\n\n this.pswp = pswp;\n window.pswp = pswp; // map listeners from Lightbox to PhotoSwipe Core\n\n /** @type {(keyof PhotoSwipeEventsMap)[]} */\n\n Object.keys(this._listeners).forEach(name => {\n var _this$_listeners$name;\n\n (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.forEach(fn => {\n pswp.on(name,\n /** @type {EventCallback} */\n fn);\n });\n }); // same with filters\n\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */\n\n Object.keys(this._filters).forEach(name => {\n var _this$_filters$name;\n\n (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.forEach(filter => {\n pswp.addFilter(name, filter.fn, filter.priority);\n });\n });\n\n if (this._preloadedContent) {\n pswp.contentLoader.addToCache(this._preloadedContent);\n this._preloadedContent = undefined;\n }\n\n pswp.on('destroy', () => {\n // clean up public variables\n this.pswp = undefined;\n delete window.pswp;\n });\n pswp.init();\n }\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */\n\n\n destroy() {\n var _this$pswp;\n\n (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.destroy();\n this.shouldOpen = false;\n this._listeners = {};\n getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n });\n }\n\n}\n\nexport { PhotoSwipeLightbox as default };\n//# sourceMappingURL=photoswipe-lightbox.esm.js.map\n","/** @typedef {import('../photoswipe.js').Point} Point */\r\n\r\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\r\nexport function createElement(className, tagName, appendToEl) {\r\n const el = document.createElement(tagName);\r\n if (className) {\r\n el.className = className;\r\n }\r\n if (appendToEl) {\r\n appendToEl.appendChild(el);\r\n }\r\n return el;\r\n}\r\n\r\n/**\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {Point}\r\n */\r\nexport function equalizePoints(p1, p2) {\r\n p1.x = p2.x;\r\n p1.y = p2.y;\r\n if (p2.id !== undefined) {\r\n p1.id = p2.id;\r\n }\r\n return p1;\r\n}\r\n\r\n/**\r\n * @param {Point} p\r\n */\r\nexport function roundPoint(p) {\r\n p.x = Math.round(p.x);\r\n p.y = Math.round(p.y);\r\n}\r\n\r\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {number}\r\n */\r\nexport function getDistanceBetween(p1, p2) {\r\n const x = Math.abs(p1.x - p2.x);\r\n const y = Math.abs(p1.y - p2.y);\r\n return Math.sqrt((x * x) + (y * y));\r\n}\r\n\r\n/**\r\n * Whether X and Y positions of points are equal\r\n *\r\n * @param {Point} p1\r\n * @param {Point} p2\r\n * @returns {boolean}\r\n */\r\nexport function pointsEqual(p1, p2) {\r\n return p1.x === p2.x && p1.y === p2.y;\r\n}\r\n\r\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {number} val\r\n * @param {number} min\r\n * @param {number} max\r\n * @returns {number}\r\n */\r\nexport function clamp(val, min, max) {\r\n return Math.min(Math.max(val, min), max);\r\n}\r\n\r\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\r\nexport function toTransformString(x, y, scale) {\r\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\r\n\r\n if (scale !== undefined) {\r\n propValue += ` scale3d(${scale},${scale},1)`;\r\n }\r\n\r\n return propValue;\r\n}\r\n\r\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n */\r\nexport function setTransform(el, x, y, scale) {\r\n el.style.transform = toTransformString(x, y, scale);\r\n}\r\n\r\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string} [prop] CSS property to animate\r\n * @param {number} [duration] in ms\r\n * @param {string} [ease] CSS easing function\r\n */\r\nexport function setTransitionStyle(el, prop, duration, ease) {\r\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\r\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\r\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\r\n el.style.transition = prop\r\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\r\n : 'none';\r\n}\r\n\r\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\r\nexport function setWidthHeight(el, w, h) {\r\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\r\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el\r\n */\r\nexport function removeTransitionStyle(el) {\r\n setTransitionStyle(el);\r\n}\r\n\r\n/**\r\n * @param {HTMLImageElement} img\r\n * @returns {Promise}\r\n */\r\nexport function decodeImage(img) {\r\n if ('decode' in img) {\r\n return img.decode().catch(() => {});\r\n }\r\n\r\n if (img.complete) {\r\n return Promise.resolve(img);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n img.onload = () => resolve(img);\r\n img.onerror = reject;\r\n });\r\n}\r\n\r\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\r\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\r\nexport const LOAD_STATE = {\r\n IDLE: 'idle',\r\n LOADING: 'loading',\r\n LOADED: 'loaded',\r\n ERROR: 'error',\r\n};\r\n\r\n\r\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\r\nexport function specialKeyUsed(e) {\r\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\r\n}\r\n\r\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\r\nexport function getElementsFromOption(option, legacySelector, parent = document) {\r\n /** @type {HTMLElement[]} */\r\n let elements = [];\r\n\r\n if (option instanceof Element) {\r\n elements = [option];\r\n } else if (option instanceof NodeList || Array.isArray(option)) {\r\n elements = Array.from(option);\r\n } else {\r\n const selector = typeof option === 'string' ? option : legacySelector;\r\n if (selector) {\r\n elements = Array.from(parent.querySelectorAll(selector));\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\r\nexport function isPswpClass(fn) {\r\n return typeof fn === 'function'\r\n && fn.prototype\r\n && fn.prototype.goTo;\r\n}\r\n\r\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\r\nexport function isSafari() {\r\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\r\n}\r\n\r\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\r\n/** @typedef {import('../slide/content.js').default} ContentDefault */\r\n/** @typedef {import('../slide/slide.js').default} Slide */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\r\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\r\n\r\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record} Content\r\n */\r\n/** @typedef {{ x?: number; y?: number }} Point */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\r\n\r\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent) => void} EventCallback\r\n */\r\n\r\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\r\nclass PhotoSwipeEvent {\r\n /**\r\n * @param {T} type\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n */\r\n constructor(type, details) {\r\n this.type = type;\r\n this.defaultPrevented = false;\r\n if (details) {\r\n Object.assign(this, details);\r\n }\r\n }\r\n\r\n preventDefault() {\r\n this.defaultPrevented = true;\r\n }\r\n}\r\n\r\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\r\nclass Eventable {\r\n constructor() {\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\r\n */\r\n this._listeners = {};\r\n\r\n /**\r\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\r\n */\r\n this._filters = {};\r\n\r\n /** @type {PhotoSwipe | undefined} */\r\n this.pswp = undefined;\r\n\r\n /** @type {PhotoSwipeOptions | undefined} */\r\n this.options = undefined;\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n * @param {number} priority\r\n */\r\n addFilter(name, fn, priority = 100) {\r\n if (!this._filters[name]) {\r\n this._filters[name] = [];\r\n }\r\n\r\n this._filters[name]?.push({ fn, priority });\r\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\r\n\r\n this.pswp?.addFilter(name, fn, priority);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeFiltersMap[T]} fn\r\n */\r\n removeFilter(name, fn) {\r\n if (this._filters[name]) {\r\n // @ts-expect-error\r\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\r\n }\r\n\r\n if (this.pswp) {\r\n this.pswp.removeFilter(name, fn);\r\n }\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @param {T} name\r\n * @param {Parameters} args\r\n * @returns {Parameters[0]}\r\n */\r\n applyFilters(name, ...args) {\r\n this._filters[name]?.forEach((filter) => {\r\n // @ts-expect-error\r\n args[0] = filter.fn.apply(this, args);\r\n });\r\n return args[0];\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n on(name, fn) {\r\n if (!this._listeners[name]) {\r\n this._listeners[name] = [];\r\n }\r\n this._listeners[name]?.push(fn);\r\n\r\n // When binding events to lightbox,\r\n // also bind events to PhotoSwipe Core,\r\n // if it's open.\r\n this.pswp?.on(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {EventCallback} fn\r\n */\r\n off(name, fn) {\r\n if (this._listeners[name]) {\r\n // @ts-expect-error\r\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\r\n }\r\n\r\n this.pswp?.off(name, fn);\r\n }\r\n\r\n /**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @param {T} name\r\n * @param {PhotoSwipeEventsMap[T]} [details]\r\n * @returns {AugmentedEvent}\r\n */\r\n dispatch(name, details) {\r\n if (this.pswp) {\r\n return this.pswp.dispatch(name, details);\r\n }\r\n\r\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\r\n\r\n this._listeners[name]?.forEach((listener) => {\r\n listener.call(this, event);\r\n });\r\n\r\n return event;\r\n }\r\n}\r\n\r\nexport default Eventable;\r\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\r\n\r\nclass Placeholder {\r\n /**\r\n * @param {string | false} imageSrc\r\n * @param {HTMLElement} container\r\n */\r\n constructor(imageSrc, container) {\r\n // Create placeholder\r\n // (stretched thumbnail or simple div behind the main image)\r\n /** @type {HTMLImageElement | HTMLDivElement | null} */\r\n this.element = createElement(\r\n 'pswp__img pswp__img--placeholder',\r\n imageSrc ? 'img' : 'div',\r\n container\r\n );\r\n\r\n if (imageSrc) {\r\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\r\n imgEl.decoding = 'async';\r\n imgEl.alt = '';\r\n imgEl.src = imageSrc;\r\n imgEl.setAttribute('role', 'presentation');\r\n }\r\n\r\n this.element.setAttribute('aria-hidden', 'true');\r\n }\r\n\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.element.tagName === 'IMG') {\r\n // Use transform scale() to modify img placeholder size\r\n // (instead of changing width/height directly).\r\n // This helps with performance, specifically in iOS15 Safari.\r\n setWidthHeight(this.element, 250, 'auto');\r\n this.element.style.transformOrigin = '0 0';\r\n this.element.style.transform = toTransformString(0, 0, width / 250);\r\n } else {\r\n setWidthHeight(this.element, width, height);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.element?.parentNode) {\r\n this.element.remove();\r\n }\r\n this.element = null;\r\n }\r\n}\r\n\r\nexport default Placeholder;\r\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\r\nimport Placeholder from './placeholder.js';\r\n\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../util/util.js').LoadState} LoadState */\r\n\r\nclass Content {\r\n /**\r\n * @param {SlideData} itemData Slide data\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n */\r\n constructor(itemData, instance, index) {\r\n this.instance = instance;\r\n this.data = itemData;\r\n this.index = index;\r\n\r\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\r\n this.element = undefined;\r\n /** @type {Placeholder | undefined} */\r\n this.placeholder = undefined;\r\n /** @type {Slide | undefined} */\r\n this.slide = undefined;\r\n\r\n this.displayedImageWidth = 0;\r\n this.displayedImageHeight = 0;\r\n\r\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\r\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\r\n\r\n this.isAttached = false;\r\n this.hasSlide = false;\r\n this.isDecoding = false;\r\n /** @type {LoadState} */\r\n this.state = LOAD_STATE.IDLE;\r\n\r\n if (this.data.type) {\r\n this.type = this.data.type;\r\n } else if (this.data.src) {\r\n this.type = 'image';\r\n } else {\r\n this.type = 'html';\r\n }\r\n\r\n this.instance.dispatch('contentInit', { content: this });\r\n }\r\n\r\n removePlaceholder() {\r\n if (this.placeholder && !this.keepPlaceholder()) {\r\n // With delay, as image might be loaded, but not rendered\r\n setTimeout(() => {\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n /**\r\n * Preload content\r\n *\r\n * @param {boolean} isLazy\r\n * @param {boolean} [reload]\r\n */\r\n load(isLazy, reload) {\r\n if (this.slide && this.usePlaceholder()) {\r\n if (!this.placeholder) {\r\n const placeholderSrc = this.instance.applyFilters(\r\n 'placeholderSrc',\r\n // use image-based placeholder only for the first slide,\r\n // as rendering (even small stretched thumbnail) is an expensive operation\r\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\r\n this\r\n );\r\n this.placeholder = new Placeholder(\r\n placeholderSrc,\r\n this.slide.container\r\n );\r\n } else {\r\n const placeholderEl = this.placeholder.element;\r\n // Add placeholder to DOM if it was already created\r\n if (placeholderEl && !placeholderEl.parentElement) {\r\n this.slide.container.prepend(placeholderEl);\r\n }\r\n }\r\n }\r\n\r\n if (this.element && !reload) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent()) {\r\n this.element = createElement('pswp__img', 'img');\r\n // Start loading only after width is defined, as sizes might depend on it.\r\n // Due to Safari feature, we must define sizes before srcset.\r\n if (this.displayedImageWidth) {\r\n this.loadImage(isLazy);\r\n }\r\n } else {\r\n this.element = createElement('pswp__content', 'div');\r\n this.element.innerHTML = this.data.html || '';\r\n }\r\n\r\n if (reload && this.slide) {\r\n this.slide.updateContentSize(true);\r\n }\r\n }\r\n\r\n /**\r\n * Preload image\r\n *\r\n * @param {boolean} isLazy\r\n */\r\n loadImage(isLazy) {\r\n if (!this.isImageContent()\r\n || !this.element\r\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const imageElement = /** @type HTMLImageElement */ (this.element);\r\n\r\n this.updateSrcsetSizes();\r\n\r\n if (this.data.srcset) {\r\n imageElement.srcset = this.data.srcset;\r\n }\r\n\r\n imageElement.src = this.data.src ?? '';\r\n imageElement.alt = this.data.alt ?? '';\r\n\r\n this.state = LOAD_STATE.LOADING;\r\n\r\n if (imageElement.complete) {\r\n this.onLoaded();\r\n } else {\r\n imageElement.onload = () => {\r\n this.onLoaded();\r\n };\r\n\r\n imageElement.onerror = () => {\r\n this.onError();\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Assign slide to content\r\n *\r\n * @param {Slide} slide\r\n */\r\n setSlide(slide) {\r\n this.slide = slide;\r\n this.hasSlide = true;\r\n this.instance = slide.pswp;\r\n\r\n // todo: do we need to unset slide?\r\n }\r\n\r\n /**\r\n * Content load success handler\r\n */\r\n onLoaded() {\r\n this.state = LOAD_STATE.LOADED;\r\n\r\n if (this.slide && this.element) {\r\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\r\n\r\n // if content is reloaded\r\n if (this.slide.isActive\r\n && this.slide.heavyAppended\r\n && !this.element.parentNode) {\r\n this.append();\r\n this.slide.updateContentSize(true);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Content load error handler\r\n */\r\n onError() {\r\n this.state = LOAD_STATE.ERROR;\r\n\r\n if (this.slide) {\r\n this.displayError();\r\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\r\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\r\n }\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is currently loading\r\n */\r\n isLoading() {\r\n return this.instance.applyFilters(\r\n 'isContentLoading',\r\n this.state === LOAD_STATE.LOADING,\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * @returns {Boolean} If the content is in error state\r\n */\r\n isError() {\r\n return this.state === LOAD_STATE.ERROR;\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content is image\r\n */\r\n isImageContent() {\r\n return this.type === 'image';\r\n }\r\n\r\n /**\r\n * Update content size\r\n *\r\n * @param {Number} width\r\n * @param {Number} height\r\n */\r\n setDisplayedSize(width, height) {\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n if (this.placeholder) {\r\n this.placeholder.setDisplayedSize(width, height);\r\n }\r\n\r\n if (this.instance.dispatch(\r\n 'contentResize',\r\n { content: this, width, height }).defaultPrevented\r\n ) {\r\n return;\r\n }\r\n\r\n setWidthHeight(this.element, width, height);\r\n\r\n if (this.isImageContent() && !this.isError()) {\r\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\r\n\r\n this.displayedImageWidth = width;\r\n this.displayedImageHeight = height;\r\n\r\n if (isInitialSizeUpdate) {\r\n this.loadImage(false);\r\n } else {\r\n this.updateSrcsetSizes();\r\n }\r\n\r\n if (this.slide) {\r\n this.instance.dispatch(\r\n 'imageSizeChange',\r\n { slide: this.slide, width, height, content: this }\r\n );\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If the content can be zoomed\r\n */\r\n isZoomable() {\r\n return this.instance.applyFilters(\r\n 'isContentZoomable',\r\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Update image srcset sizes attribute based on width and height\r\n */\r\n updateSrcsetSizes() {\r\n // Handle srcset sizes attribute.\r\n //\r\n // Never lower quality, if it was increased previously.\r\n // Chrome does this automatically, Firefox and Safari do not,\r\n // so we store largest used size in dataset.\r\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\r\n return;\r\n }\r\n\r\n const image = /** @type HTMLImageElement */ (this.element);\r\n const sizesWidth = this.instance.applyFilters(\r\n 'srcsetSizesWidth',\r\n this.displayedImageWidth,\r\n this\r\n );\r\n\r\n if (\r\n !image.dataset.largestUsedSize\r\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\r\n ) {\r\n image.sizes = sizesWidth + 'px';\r\n image.dataset.largestUsedSize = String(sizesWidth);\r\n }\r\n }\r\n\r\n /**\r\n * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n */\r\n usePlaceholder() {\r\n return this.instance.applyFilters(\r\n 'useContentPlaceholder',\r\n this.isImageContent(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Preload content with lazy-loading param\r\n */\r\n lazyLoad() {\r\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.load(true);\r\n }\r\n\r\n /**\r\n * @returns {boolean} If placeholder should be kept after content is loaded\r\n */\r\n keepPlaceholder() {\r\n return this.instance.applyFilters(\r\n 'isKeepingPlaceholder',\r\n this.isLoading(),\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Destroy the content\r\n */\r\n destroy() {\r\n this.hasSlide = false;\r\n this.slide = undefined;\r\n\r\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n this.remove();\r\n\r\n if (this.placeholder) {\r\n this.placeholder.destroy();\r\n this.placeholder = undefined;\r\n }\r\n\r\n if (this.isImageContent() && this.element) {\r\n this.element.onload = null;\r\n this.element.onerror = null;\r\n this.element = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * Display error message\r\n */\r\n displayError() {\r\n if (this.slide) {\r\n let errorMsgEl = createElement('pswp__error-msg', 'div');\r\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\r\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\r\n 'contentErrorElement',\r\n errorMsgEl,\r\n this\r\n ));\r\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\r\n this.element.appendChild(errorMsgEl);\r\n this.slide.container.innerText = '';\r\n this.slide.container.appendChild(this.element);\r\n this.slide.updateContentSize(true);\r\n this.removePlaceholder();\r\n }\r\n }\r\n\r\n /**\r\n * Append the content\r\n */\r\n append() {\r\n if (this.isAttached || !this.element) {\r\n return;\r\n }\r\n\r\n this.isAttached = true;\r\n\r\n if (this.state === LOAD_STATE.ERROR) {\r\n this.displayError();\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n const supportsDecode = ('decode' in this.element);\r\n\r\n if (this.isImageContent()) {\r\n // Use decode() on nearby slides\r\n //\r\n // Nearby slide images are in DOM and not hidden via display:none.\r\n // However, they are placed offscreen (to the left and right side).\r\n //\r\n // Some browsers do not composite the image until it's actually visible,\r\n // using decode() helps.\r\n //\r\n // You might ask \"why dont you just decode() and then append all images\",\r\n // that's because I want to show image before it's fully loaded,\r\n // as browser can render parts of image while it is loading.\r\n // We do not do this in Safari due to partial loading bug.\r\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\r\n this.isDecoding = true;\r\n // purposefully using finally instead of then,\r\n // as if srcset sizes changes dynamically - it may cause decode error\r\n /** @type {HTMLImageElement} */\r\n (this.element).decode().catch(() => {}).finally(() => {\r\n this.isDecoding = false;\r\n this.appendImage();\r\n });\r\n } else {\r\n this.appendImage();\r\n }\r\n } else if (this.slide && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n }\r\n\r\n /**\r\n * Activate the slide,\r\n * active slide is generally the current one,\r\n * meaning the user can see it.\r\n */\r\n activate() {\r\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\r\n || !this.slide) {\r\n return;\r\n }\r\n\r\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\r\n // add image to slide when it becomes active,\r\n // even if it's not finished decoding\r\n this.appendImage();\r\n } else if (this.isError()) {\r\n this.load(false, true); // try to reload\r\n }\r\n\r\n if (this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\r\n }\r\n }\r\n\r\n /**\r\n * Deactivate the content\r\n */\r\n deactivate() {\r\n this.instance.dispatch('contentDeactivate', { content: this });\r\n if (this.slide && this.slide.holderElement) {\r\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Remove the content from DOM\r\n */\r\n remove() {\r\n this.isAttached = false;\r\n\r\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n if (this.element && this.element.parentNode) {\r\n this.element.remove();\r\n }\r\n\r\n if (this.placeholder && this.placeholder.element) {\r\n this.placeholder.element.remove();\r\n }\r\n }\r\n\r\n /**\r\n * Append the image content to slide container\r\n */\r\n appendImage() {\r\n if (!this.isAttached) {\r\n return;\r\n }\r\n\r\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n // ensure that element exists and is not already appended\r\n if (this.slide && this.element && !this.element.parentNode) {\r\n this.slide.container.appendChild(this.element);\r\n }\r\n\r\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\r\n this.removePlaceholder();\r\n }\r\n }\r\n}\r\n\r\nexport default Content;\r\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\r\nexport function getViewportSize(options, pswp) {\r\n if (options.getViewportSizeFn) {\r\n const newViewportSize = options.getViewportSizeFn(options, pswp);\r\n if (newViewportSize) {\r\n return newViewportSize;\r\n }\r\n }\r\n\r\n return {\r\n x: document.documentElement.clientWidth,\r\n\r\n // TODO: height on mobile is very incosistent due to toolbar\r\n // find a way to improve this\r\n //\r\n // document.documentElement.clientHeight - doesn't seem to work well\r\n y: window.innerHeight\r\n };\r\n}\r\n\r\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n * return {\r\n * top: 0,\r\n * bottom: 0,\r\n * left: 0,\r\n * right: 0\r\n * };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\r\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\r\n let paddingValue = 0;\r\n\r\n if (options.paddingFn) {\r\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\r\n } else if (options.padding) {\r\n paddingValue = options.padding[prop];\r\n } else {\r\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\r\n // @ts-expect-error\r\n if (options[legacyPropName]) {\r\n // @ts-expect-error\r\n paddingValue = options[legacyPropName];\r\n }\r\n }\r\n\r\n return Number(paddingValue) || 0;\r\n}\r\n\r\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\r\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\r\n return {\r\n x: viewportSize.x\r\n - parsePaddingOption('left', options, viewportSize, itemData, index)\r\n - parsePaddingOption('right', options, viewportSize, itemData, index),\r\n y: viewportSize.y\r\n - parsePaddingOption('top', options, viewportSize, itemData, index)\r\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\r\n };\r\n}\r\n","const MAX_IMAGE_WIDTH = 4000;\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\r\n\r\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\r\n\r\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\r\nclass ZoomLevel {\r\n /**\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {SlideData} itemData Slide data\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n */\r\n constructor(options, itemData, index, pswp) {\r\n this.pswp = pswp;\r\n this.options = options;\r\n this.itemData = itemData;\r\n this.index = index;\r\n /** @type { Point | null } */\r\n this.panAreaSize = null;\r\n /** @type { Point | null } */\r\n this.elementSize = null;\r\n this.fit = 1;\r\n this.fill = 1;\r\n this.vFill = 1;\r\n this.initial = 1;\r\n this.secondary = 1;\r\n this.max = 1;\r\n this.min = 1;\r\n }\r\n\r\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {number} maxWidth\r\n * @param {number} maxHeight\r\n * @param {Point} panAreaSize\r\n */\r\n update(maxWidth, maxHeight, panAreaSize) {\r\n /** @type {Point} */\r\n const elementSize = { x: maxWidth, y: maxHeight };\r\n this.elementSize = elementSize;\r\n this.panAreaSize = panAreaSize;\r\n\r\n const hRatio = panAreaSize.x / elementSize.x;\r\n const vRatio = panAreaSize.y / elementSize.y;\r\n\r\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\r\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\r\n\r\n // zoom.vFill defines zoom level of the image\r\n // when it has 100% of viewport vertical space (height)\r\n this.vFill = Math.min(1, vRatio);\r\n\r\n this.initial = this._getInitial();\r\n this.secondary = this._getSecondary();\r\n this.max = Math.max(\r\n this.initial,\r\n this.secondary,\r\n this._getMax()\r\n );\r\n\r\n this.min = Math.min(\r\n this.fit,\r\n this.initial,\r\n this.secondary\r\n );\r\n\r\n if (this.pswp) {\r\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\r\n }\r\n }\r\n\r\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @private\r\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n * @returns { number | undefined }\r\n */\r\n _parseZoomLevelOption(optionPrefix) {\r\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\r\n optionPrefix + 'ZoomLevel'\r\n );\r\n const optionValue = this.options[optionName];\r\n\r\n if (!optionValue) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n return optionValue(this);\r\n }\r\n\r\n if (optionValue === 'fill') {\r\n return this.fill;\r\n }\r\n\r\n if (optionValue === 'fit') {\r\n return this.fit;\r\n }\r\n\r\n return Number(optionValue);\r\n }\r\n\r\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getSecondary() {\r\n let currZoomLevel = this._parseZoomLevelOption('secondary');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // 3x of \"fit\" state, but not larger than original\r\n currZoomLevel = Math.min(1, this.fit * 3);\r\n\r\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\r\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\r\n }\r\n\r\n return currZoomLevel;\r\n }\r\n\r\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getInitial() {\r\n return this._parseZoomLevelOption('initial') || this.fit;\r\n }\r\n\r\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @private\r\n * @return {number}\r\n */\r\n _getMax() {\r\n // max zoom level is x4 from \"fit state\",\r\n // used for zoom gesture and ctrl/trackpad zoom\r\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\r\n }\r\n}\r\n\r\nexport default ZoomLevel;\r\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\r\nimport ZoomLevel from './zoom-level.js';\r\n\r\n/** @typedef {import('./content.js').default} Content */\r\n/** @typedef {import('./slide.js').default} Slide */\r\n/** @typedef {import('./slide.js').SlideData} SlideData */\r\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n\r\nconst MIN_SLIDES_TO_CACHE = 5;\r\n\r\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\nexport function lazyLoadData(itemData, instance, index) {\r\n const content = instance.createContentFromData(itemData, index);\r\n /** @type {ZoomLevel | undefined} */\r\n let zoomLevel;\r\n\r\n const { options } = instance;\r\n\r\n // We need to know dimensions of the image to preload it,\r\n // as it might use srcset, and we need to define sizes\r\n if (options) {\r\n zoomLevel = new ZoomLevel(options, itemData, -1);\r\n\r\n let viewportSize;\r\n if (instance.pswp) {\r\n viewportSize = instance.pswp.viewportSize;\r\n } else {\r\n viewportSize = getViewportSize(options, instance);\r\n }\r\n\r\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\r\n zoomLevel.update(content.width, content.height, panAreaSize);\r\n }\r\n\r\n content.lazyLoad();\r\n\r\n if (zoomLevel) {\r\n content.setDisplayedSize(\r\n Math.ceil(content.width * zoomLevel.initial),\r\n Math.ceil(content.height * zoomLevel.initial)\r\n );\r\n }\r\n\r\n return content;\r\n}\r\n\r\n\r\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\r\nexport function lazyLoadSlide(index, instance) {\r\n const itemData = instance.getItemData(index);\r\n\r\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n return lazyLoadData(itemData, instance, index);\r\n}\r\n\r\nclass ContentLoader {\r\n /**\r\n * @param {PhotoSwipe} pswp\r\n */\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n // Total amount of cached images\r\n this.limit = Math.max(\r\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\r\n MIN_SLIDES_TO_CACHE\r\n );\r\n /** @type {Content[]} */\r\n this._cachedItems = [];\r\n }\r\n\r\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\r\n */\r\n updateLazy(diff) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\r\n return;\r\n }\r\n\r\n const { preload } = pswp.options;\r\n const isForward = diff === undefined ? true : (diff >= 0);\r\n let i;\r\n\r\n // preload[1] - num items to preload in forward direction\r\n for (i = 0; i <= preload[1]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\r\n }\r\n\r\n // preload[0] - num items to preload in backward direction\r\n for (i = 1; i <= preload[0]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} initialIndex\r\n */\r\n loadSlideByIndex(initialIndex) {\r\n const index = this.pswp.getLoopedIndex(initialIndex);\r\n // try to get cached content\r\n let content = this.getContentByIndex(index);\r\n if (!content) {\r\n // no cached content, so try to load from scratch:\r\n content = lazyLoadSlide(index, this.pswp);\r\n // if content can be loaded, add it to cache:\r\n if (content) {\r\n this.addToCache(content);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * @param {Slide} slide\r\n * @returns {Content}\r\n */\r\n getContentBySlide(slide) {\r\n let content = this.getContentByIndex(slide.index);\r\n if (!content) {\r\n // create content if not found in cache\r\n content = this.pswp.createContentFromData(slide.data, slide.index);\r\n this.addToCache(content);\r\n }\r\n\r\n // assign slide to content\r\n content.setSlide(slide);\r\n\r\n return content;\r\n }\r\n\r\n /**\r\n * @param {Content} content\r\n */\r\n addToCache(content) {\r\n // move to the end of array\r\n this.removeByIndex(content.index);\r\n this._cachedItems.push(content);\r\n\r\n if (this._cachedItems.length > this.limit) {\r\n // Destroy the first content that's not attached\r\n const indexToRemove = this._cachedItems.findIndex((item) => {\r\n return !item.isAttached && !item.hasSlide;\r\n });\r\n if (indexToRemove !== -1) {\r\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\r\n removedItem.destroy();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Removes an image from cache, does not destroy() it, just removes.\r\n *\r\n * @param {number} index\r\n */\r\n removeByIndex(index) {\r\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\r\n if (indexToRemove !== -1) {\r\n this._cachedItems.splice(indexToRemove, 1);\r\n }\r\n }\r\n\r\n /**\r\n * @param {number} index\r\n * @returns {Content | undefined}\r\n */\r\n getContentByIndex(index) {\r\n return this._cachedItems.find(content => content.index === index);\r\n }\r\n\r\n destroy() {\r\n this._cachedItems.forEach(content => content.destroy());\r\n this._cachedItems = [];\r\n }\r\n}\r\n\r\nexport default ContentLoader;\r\n","import Eventable from './eventable.js';\r\nimport { getElementsFromOption } from '../util/util.js';\r\nimport Content from '../slide/content.js';\r\nimport { lazyLoadData } from '../slide/loader.js';\r\n\r\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\r\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\r\n\r\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\r\nclass PhotoSwipeBase extends Eventable {\r\n /**\r\n * Get total number of slides\r\n *\r\n * @returns {number}\r\n */\r\n getNumItems() {\r\n let numItems = 0;\r\n const dataSource = this.options?.dataSource;\r\n\r\n if (dataSource && 'length' in dataSource) {\r\n // may be an array or just object with length property\r\n numItems = dataSource.length;\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n if (dataSource.items) {\r\n numItems = dataSource.items.length;\r\n }\r\n }\r\n\r\n // legacy event, before filters were introduced\r\n const event = this.dispatch('numItems', {\r\n dataSource,\r\n numItems\r\n });\r\n return this.applyFilters('numItems', event.numItems, dataSource);\r\n }\r\n\r\n /**\r\n * @param {SlideData} slideData\r\n * @param {number} index\r\n * @returns {Content}\r\n */\r\n createContentFromData(slideData, index) {\r\n return new Content(slideData, this, index);\r\n }\r\n\r\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {number} index\r\n * @returns {SlideData}\r\n */\r\n getItemData(index) {\r\n const dataSource = this.options?.dataSource;\r\n /** @type {SlideData | HTMLElement} */\r\n let dataSourceItem = {};\r\n if (Array.isArray(dataSource)) {\r\n // Datasource is an array of elements\r\n dataSourceItem = dataSource[index];\r\n } else if (dataSource && 'gallery' in dataSource) {\r\n // dataSource has gallery property,\r\n // thus it was created by Lightbox, based on\r\n // gallery and children options\r\n\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n dataSourceItem = dataSource.items[index];\r\n }\r\n\r\n let itemData = dataSourceItem;\r\n\r\n if (itemData instanceof Element) {\r\n itemData = this._domElementToItemData(itemData);\r\n }\r\n\r\n // Dispatching the itemData event,\r\n // it's a legacy verion before filters were introduced\r\n const event = this.dispatch('itemData', {\r\n itemData: itemData || {},\r\n index\r\n });\r\n\r\n return this.applyFilters('itemData', event.itemData, index);\r\n }\r\n\r\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {HTMLElement} galleryElement\r\n * @returns {HTMLElement[]}\r\n */\r\n _getGalleryDOMElements(galleryElement) {\r\n if (this.options?.children || this.options?.childSelector) {\r\n return getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n galleryElement\r\n ) || [];\r\n }\r\n\r\n return [galleryElement];\r\n }\r\n\r\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {HTMLElement} element DOM element\r\n * @returns {SlideData}\r\n */\r\n _domElementToItemData(element) {\r\n /** @type {SlideData} */\r\n const itemData = {\r\n element\r\n };\r\n\r\n const linkEl = /** @type {HTMLAnchorElement} */ (\r\n element.tagName === 'A'\r\n ? element\r\n : element.querySelector('a')\r\n );\r\n\r\n if (linkEl) {\r\n // src comes from data-pswp-src attribute,\r\n // if it's empty link href is used\r\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\r\n\r\n if (linkEl.dataset.pswpSrcset) {\r\n itemData.srcset = linkEl.dataset.pswpSrcset;\r\n }\r\n\r\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\r\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\r\n\r\n // support legacy w & h properties\r\n itemData.w = itemData.width;\r\n itemData.h = itemData.height;\r\n\r\n if (linkEl.dataset.pswpType) {\r\n itemData.type = linkEl.dataset.pswpType;\r\n }\r\n\r\n const thumbnailEl = element.querySelector('img');\r\n\r\n if (thumbnailEl) {\r\n // msrc is URL to placeholder image that's displayed before large image is loaded\r\n // by default it's displayed only for the first slide\r\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\r\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\r\n }\r\n\r\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\r\n itemData.thumbCropped = true;\r\n }\r\n }\r\n\r\n return this.applyFilters('domItemData', itemData, element, linkEl);\r\n }\r\n\r\n /**\r\n * Lazy-load by slide data\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\r\n lazyLoadData(itemData, index) {\r\n return lazyLoadData(itemData, this, index);\r\n }\r\n}\r\n\r\nexport default PhotoSwipeBase;\r\n","import {\r\n specialKeyUsed,\r\n getElementsFromOption,\r\n isPswpClass\r\n} from '../util/util.js';\r\n\r\nimport PhotoSwipeBase from '../core/base.js';\r\nimport { lazyLoadSlide } from '../slide/loader.js';\r\n\r\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type} Type\r\n */\r\n\r\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\r\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\r\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\r\n/** @typedef {import('../photoswipe.js').Point} Point */\r\n/** @typedef {import('../slide/content.js').default} Content */\r\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\r\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\r\n\r\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\r\n */\r\n\r\n/**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\r\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\r\n /**\r\n * @param {PhotoSwipeOptions} [options]\r\n */\r\n constructor(options) {\r\n super();\r\n /** @type {PhotoSwipeOptions} */\r\n this.options = options || {};\r\n this._uid = 0;\r\n this.shouldOpen = false;\r\n /**\r\n * @private\r\n * @type {Content | undefined}\r\n */\r\n this._preloadedContent = undefined;\r\n\r\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\r\n }\r\n\r\n /**\r\n * Initialize lightbox, should be called only once.\r\n * It's not included in the main constructor, so you may bind events before it.\r\n */\r\n init() {\r\n // Bind click events to each gallery\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n\r\n /**\r\n * @param {MouseEvent} e\r\n */\r\n onThumbnailsClick(e) {\r\n // Exit and allow default browser action if:\r\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\r\n || window.pswp) { // ... if PhotoSwipe is already open\r\n return;\r\n }\r\n\r\n // If both clientX and clientY are 0 or not defined,\r\n // the event is likely triggered by keyboard,\r\n // so we do not pass the initialPoint\r\n //\r\n // Note that some screen readers emulate the mouse position,\r\n // so it's not the ideal way to detect them.\r\n //\r\n /** @type {Point | null} */\r\n let initialPoint = { x: e.clientX, y: e.clientY };\r\n\r\n if (!initialPoint.x && !initialPoint.y) {\r\n initialPoint = null;\r\n }\r\n\r\n let clickedIndex = this.getClickedIndex(e);\r\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\r\n /** @type {DataSource} */\r\n const dataSource = {\r\n gallery: /** @type {HTMLElement} */ (e.currentTarget)\r\n };\r\n\r\n if (clickedIndex >= 0) {\r\n e.preventDefault();\r\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\r\n }\r\n }\r\n\r\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {MouseEvent} e click event\r\n * @returns {number}\r\n */\r\n getClickedIndex(e) {\r\n // legacy option\r\n if (this.options.getClickedIndexFn) {\r\n return this.options.getClickedIndexFn.call(this, e);\r\n }\r\n\r\n const clickedTarget = /** @type {HTMLElement} */ (e.target);\r\n const childElements = getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n /** @type {HTMLElement} */ (e.currentTarget)\r\n );\r\n const clickedChildIndex = childElements.findIndex(\r\n child => child === clickedTarget || child.contains(clickedTarget)\r\n );\r\n\r\n if (clickedChildIndex !== -1) {\r\n return clickedChildIndex;\r\n } else if (this.options.children || this.options.childSelector) {\r\n // click wasn't on a child element\r\n return -1;\r\n }\r\n\r\n // There is only one item (which is the gallery)\r\n return 0;\r\n }\r\n\r\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n * @param {Point | null} [initialPoint]\r\n * @returns {boolean}\r\n */\r\n loadAndOpen(index, dataSource, initialPoint) {\r\n // Check if the gallery is already open\r\n if (window.pswp || !this.options) {\r\n return false;\r\n }\r\n\r\n // Use the first gallery element if dataSource is not provided\r\n if (!dataSource && this.options.gallery && this.options.children) {\r\n const galleryElements = getElementsFromOption(this.options.gallery);\r\n if (galleryElements[0]) {\r\n dataSource = {\r\n gallery: galleryElements[0]\r\n };\r\n }\r\n }\r\n\r\n // set initial index\r\n this.options.index = index;\r\n\r\n // define options for PhotoSwipe constructor\r\n this.options.initialPointerPos = initialPoint;\r\n\r\n this.shouldOpen = true;\r\n this.preload(index, dataSource);\r\n return true;\r\n }\r\n\r\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {number} index\r\n * @param {DataSource} [dataSource]\r\n */\r\n preload(index, dataSource) {\r\n const { options } = this;\r\n\r\n if (dataSource) {\r\n options.dataSource = dataSource;\r\n }\r\n\r\n // Add the main module\r\n /** @type {Promise>[]} */\r\n const promiseArray = [];\r\n\r\n const pswpModuleType = typeof options.pswpModule;\r\n if (isPswpClass(options.pswpModule)) {\r\n promiseArray.push(Promise.resolve(/** @type {Type} */ (options.pswpModule)));\r\n } else if (pswpModuleType === 'string') {\r\n throw new Error('pswpModule as string is no longer supported');\r\n } else if (pswpModuleType === 'function') {\r\n promiseArray.push(/** @type {() => Promise>} */ (options.pswpModule)());\r\n } else {\r\n throw new Error('pswpModule is not valid');\r\n }\r\n\r\n // Add custom-defined promise, if any\r\n if (typeof options.openPromise === 'function') {\r\n // allow developers to perform some task before opening\r\n promiseArray.push(options.openPromise());\r\n }\r\n\r\n if (options.preloadFirstSlide !== false && index >= 0) {\r\n this._preloadedContent = lazyLoadSlide(index, this);\r\n }\r\n\r\n // Wait till all promises resolve and open PhotoSwipe\r\n const uid = ++this._uid;\r\n Promise.all(promiseArray).then((iterableModules) => {\r\n if (this.shouldOpen) {\r\n const mainModule = iterableModules[0];\r\n this._openPhotoswipe(mainModule, uid);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @private\r\n * @param {Type | { default: Type }} module\r\n * @param {number} uid\r\n */\r\n _openPhotoswipe(module, uid) {\r\n // Cancel opening if UID doesn't match the current one\r\n // (if user clicked on another gallery item before current was loaded).\r\n //\r\n // Or if shouldOpen flag is set to false\r\n // (developer may modify it via public API)\r\n if (uid !== this._uid && this.shouldOpen) {\r\n return;\r\n }\r\n\r\n this.shouldOpen = false;\r\n\r\n // PhotoSwipe is already open\r\n if (window.pswp) {\r\n return;\r\n }\r\n\r\n /**\r\n * Pass data to PhotoSwipe and open init\r\n *\r\n * @type {PhotoSwipe}\r\n */\r\n const pswp = typeof module === 'object'\r\n ? new module.default(this.options) // eslint-disable-line\r\n : new module(this.options); // eslint-disable-line\r\n\r\n this.pswp = pswp;\r\n window.pswp = pswp;\r\n\r\n // map listeners from Lightbox to PhotoSwipe Core\r\n /** @type {(keyof PhotoSwipeEventsMap)[]} */\r\n (Object.keys(this._listeners)).forEach((name) => {\r\n this._listeners[name]?.forEach((fn) => {\r\n pswp.on(name, /** @type {EventCallback} */(fn));\r\n });\r\n });\r\n\r\n // same with filters\r\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */\r\n (Object.keys(this._filters)).forEach((name) => {\r\n this._filters[name]?.forEach((filter) => {\r\n pswp.addFilter(name, filter.fn, filter.priority);\r\n });\r\n });\r\n\r\n if (this._preloadedContent) {\r\n pswp.contentLoader.addToCache(this._preloadedContent);\r\n this._preloadedContent = undefined;\r\n }\r\n\r\n pswp.on('destroy', () => {\r\n // clean up public variables\r\n this.pswp = undefined;\r\n delete window.pswp;\r\n });\r\n\r\n pswp.init();\r\n }\r\n\r\n /**\r\n * Unbinds all events, closes PhotoSwipe if it's open.\r\n */\r\n destroy() {\r\n this.pswp?.destroy();\r\n\r\n this.shouldOpen = false;\r\n this._listeners = {};\r\n\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n}\r\n\r\nexport default PhotoSwipeLightbox;\r\n"],"names":["$parcel$export","e","n","v","s","Object","defineProperty","get","set","enumerable","configurable","$parcel$global","globalThis","self","window","global","$parcel$modules","$parcel$inits","parcelRequire","id","exports","init","module","call","err","Error","code","register","parcelRegister","$50cf2b1817a85608$var$createElement","className","tagName","appendToEl","el","document","createElement","appendChild","$50cf2b1817a85608$var$setWidthHeight","w","h","style","width","height","$1fa8072a7f2bd73f$export$6503ec6e8aabbaf","$1fa8072a7f2bd73f$export$f7ad0328861e2f03","$1fa8072a7f2bd73f$var$mapping","Map","baseUrl","manifest","i","length","path","resolved","URL","toString","$dCVga","then","resolve","url","JSON","parse","$50cf2b1817a85608$var$LOAD_STATE","IDLE","LOADING","LOADED","ERROR","$50cf2b1817a85608$var$getElementsFromOption","option","legacySelector","parent","elements","Element","NodeList","Array","isArray","from","selector","querySelectorAll","$50cf2b1817a85608$var$isSafari","navigator","vendor","match","$50cf2b1817a85608$var$PhotoSwipeEvent","constructor","type","details","defaultPrevented","assign","preventDefault","$50cf2b1817a85608$var$Eventable","_listeners","_filters","pswp","undefined","options","addFilter","name","fn","priority","_this$_filters$name","_this$_filters$name2","_this$pswp","push","sort","f1","f2","removeFilter","filter","applyFilters","args","_this$_filters$name3","forEach","apply","on","_this$_listeners$name","_this$pswp2","off","_this$pswp3","listener","dispatch","_this$_listeners$name2","event","$50cf2b1817a85608$var$Placeholder","imageSrc","container","element","imgEl","decoding","alt","src","setAttribute","setDisplayedSize","scale","propValue","transformOrigin","transform","destroy","_this$element","parentNode","remove","$50cf2b1817a85608$var$Content","itemData","instance","index","data","placeholder","slide","displayedImageWidth","displayedImageHeight","Number","isAttached","hasSlide","isDecoding","state","content","removePlaceholder","keepPlaceholder","setTimeout","load","isLazy","reload","usePlaceholder","placeholderEl","parentElement","prepend","placeholderSrc","msrc","isFirstSlide","isImageContent","loadImage","innerHTML","html","updateContentSize","_this$data$src","_this$data$alt","imageElement","updateSrcsetSizes","srcset","complete","onLoaded","onload","onerror","onError","setSlide","isActive","heavyAppended","append","displayError","isError","isLoading","isInitialSizeUpdate","isZoomable","image","sizesWidth","dataset","largestUsedSize","parseInt","sizes","String","lazyLoad","_this$instance$option","_this$instance$option2","errorMsgEl","innerText","errorMsg","supportsDecode","decode","catch","finally","appendImage","activate","holderElement","deactivate","$50cf2b1817a85608$var$parsePaddingOption","prop","viewportSize","paddingValue","paddingFn","padding","legacyPropName","toUpperCase","slice","$50cf2b1817a85608$var$ZoomLevel","panAreaSize","elementSize","fit","fill","vFill","initial","secondary","max","min","update","maxWidth","maxHeight","x","y","hRatio","vRatio","Math","_getInitial","_getSecondary","_getMax","zoomLevels","slideData","_parseZoomLevelOption","optionPrefix","optionValue","currZoomLevel","$50cf2b1817a85608$var$MAX_IMAGE_WIDTH","$50cf2b1817a85608$var$lazyLoadData","zoomLevel","createContentFromData","$50cf2b1817a85608$var$getViewportSize","getViewportSizeFn","newViewportSize","documentElement","clientWidth","innerHeight","ceil","$50cf2b1817a85608$var$PhotoSwipeBase","getNumItems","_this$options","numItems","dataSource","items","_getGalleryDOMElements","gallery","getItemData","_this$options2","dataSourceItem","_domElementToItemData","galleryElement","_this$options3","_this$options4","children","childSelector","linkEl","querySelector","pswpSrc","href","pswpSrcset","pswpWidth","pswpHeight","pswpType","thumbnailEl","_thumbnailEl$getAttri","currentSrc","getAttribute","pswpCropped","cropped","thumbCropped","lazyLoadData","$239507fc38a64297$var$lightbox","_uid","shouldOpen","_preloadedContent","onThumbnailsClick","bind","gallerySelector","addEventListener","$50cf2b1817a85608$var$specialKeyUsed","button","ctrlKey","metaKey","altKey","shiftKey","initialPoint","clientX","clientY","clickedIndex","getClickedIndex","currentTarget","loadAndOpen","getClickedIndexFn","clickedTarget","target","clickedChildIndex","childElements","findIndex","child","contains","galleryElements","initialPointerPos","preload","promiseArray","pswpModuleType","pswpModule","prototype","goTo","Promise","openPromise","preloadFirstSlide","$50cf2b1817a85608$var$lazyLoadSlide","uid","all","iterableModules","mainModule","_openPhotoswipe","default","keys","contentLoader","addToCache","removeEventListener","showHideAnimationType","toTransformString","setWidthHeight","LOAD_STATE","specialKeyUsed","getElementsFromOption","isPswpClass","isSafari","PhotoSwipeEvent","Eventable","Placeholder","Content","getViewportSize","parsePaddingOption","getPanAreaSize","MAX_IMAGE_WIDTH","ZoomLevel","optionName","lazyLoadSlide","PhotoSwipeBase","PhotoSwipeLightbox"],"version":3,"file":"start.dd6dc2f2.js.map"} \ No newline at end of file diff --git a/start.html b/start.html new file mode 100644 index 0000000..b06642b --- /dev/null +++ b/start.html @@ -0,0 +1 @@ +Inici - Sopa de cabra

Presentació

Sopa de Cabra o els Sopa és un grup de música gironí actiu entre 1986 i 2001 i des del 2015. De l'inici va pertànyer al moviment de Rock català, tot i que va sovint tocar amb un estil propi. Les cançons més populars de Sopa de Cabra han estat «L'Empordà», «Camins», «El far del sud» i «El boig de la ciutat».

Final de gira Sopa de Cabra 30 anys Ben Endins al Palau Sant Jordi

Gira

Explora les actuacions
Data Hora Lloc Enllaç
Dijous 11 Juliol 2024 22:00h Jardins del Palau de Pedralbes, Barcelona Info
Divendres 12 Juliol 2024 23:00h Recinte Firal, Es Mercadal Info
Diumenge 21 Juliol 2024 22:15h Jardí Botànic de Cap Roig, Calella de Palafrugell Info
Dissabte 27 Juliol 2024 22:15h Jardins Terramar, Sitges Info
Dijous 08 Agost 2024 22:00h Fòrum Romà d'Empúries, L'Escala Info
Dissabte 10 Agost 2024 21:00h Espai La Llàntia, Santa Susanna Info
**Els horaris poden estar subjectes a canvis.

Història

Goats Head Soup
Goats Head Soup, the Rolling Stones

Els orígens del grup Sopa de Cabra es remunten a la formació Copacabana, format el 1979 per companys d'institut. Moltes de les primeres cançons de Sopa de Cabra, entre elles «L'Empordà», van ser escrites originalment per Copacabana, amb el cantant Jaume Rufí i el guitarrista Josep Thió. La banda es va dissoldre el 1984, quan Thió marxa per complir el servei militar obligatori i el llavors cantant se'n va a estudiar a Barcelona. Al seu retorn a Girona, Thió es va dedicar a formar una nova banda, que es convertiria en Sopa de Cabra, amb contractació del baixista Francesc "Cuco" Lisicic, el guitarrista Joan "Ninyín" Cardona i el bateria Josep Bosch. La formació es va completar amb la incorporació de Gerard Quintana, que també havia anat a l'escola amb els membres de Copacabana, a la veu. Tanmateix, hi ha fonts que consideren la formació Ninyin's Mine Workers Union Band, integrada originalment per "Ninyín" i "Cuco", com l'embrió principal dels Sopa. El nom d'aquest grup gironí prové del nom del disc Goats Head Soup, de principis dels anys 70, dels The Rolling Stones.

Galeria

\ No newline at end of file