@redot-src/glare 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +41 -9
  2. package/dist/core/animation.d.ts +7 -0
  3. package/dist/core/bind.d.ts +8 -0
  4. package/dist/core/dom.d.ts +18 -0
  5. package/dist/core/glare.d.ts +65 -0
  6. package/dist/core/idle.d.ts +9 -0
  7. package/dist/core/interactions.d.ts +3 -0
  8. package/dist/core/loaders.d.ts +5 -0
  9. package/dist/core/options.d.ts +5 -0
  10. package/dist/core/registry.d.ts +9 -0
  11. package/dist/core/zoom.d.ts +36 -0
  12. package/dist/defaults.d.ts +5 -5
  13. package/dist/esm.d.ts +3 -0
  14. package/dist/glare.css +1 -1
  15. package/dist/glare.esm.js +1101 -1173
  16. package/dist/glare.esm.js.map +1 -1
  17. package/dist/glare.js +25 -23
  18. package/dist/glare.js.map +1 -1
  19. package/dist/i18n.d.ts +4 -0
  20. package/dist/icons.d.ts +13 -13
  21. package/dist/index.d.ts +5 -7
  22. package/dist/media/detect.d.ts +4 -0
  23. package/dist/media/items.d.ts +6 -0
  24. package/dist/media/providers.d.ts +6 -0
  25. package/dist/modules/fullscreen.d.ts +15 -0
  26. package/dist/modules/gestures.d.ts +45 -0
  27. package/dist/modules/hash.d.ts +22 -0
  28. package/dist/modules/share.d.ts +17 -0
  29. package/dist/modules/slideshow.d.ts +25 -0
  30. package/dist/modules/thumbs.d.ts +22 -0
  31. package/dist/modules/wheel.d.ts +19 -0
  32. package/dist/templates.d.ts +7 -0
  33. package/dist/types.d.ts +121 -132
  34. package/dist/umd.d.ts +3 -0
  35. package/dist/utils/dom.d.ts +20 -0
  36. package/dist/utils/env.d.ts +5 -0
  37. package/dist/utils/object.d.ts +3 -0
  38. package/dist/utils/template.d.ts +5 -0
  39. package/package.json +18 -24
  40. package/dist/defaults.d.ts.map +0 -1
  41. package/dist/fullscreen.d.ts +0 -14
  42. package/dist/fullscreen.d.ts.map +0 -1
  43. package/dist/gestures.d.ts +0 -24
  44. package/dist/gestures.d.ts.map +0 -1
  45. package/dist/hash.d.ts +0 -20
  46. package/dist/hash.d.ts.map +0 -1
  47. package/dist/icons.d.ts.map +0 -1
  48. package/dist/index.d.ts.map +0 -1
  49. package/dist/instance.d.ts +0 -103
  50. package/dist/instance.d.ts.map +0 -1
  51. package/dist/media.d.ts +0 -5
  52. package/dist/media.d.ts.map +0 -1
  53. package/dist/share.d.ts +0 -13
  54. package/dist/share.d.ts.map +0 -1
  55. package/dist/slideshow.d.ts +0 -19
  56. package/dist/slideshow.d.ts.map +0 -1
  57. package/dist/thumbs.d.ts +0 -17
  58. package/dist/thumbs.d.ts.map +0 -1
  59. package/dist/types.d.ts.map +0 -1
  60. package/dist/utils.d.ts +0 -31
  61. package/dist/utils.d.ts.map +0 -1
  62. package/dist/wheel.d.ts +0 -11
  63. package/dist/wheel.d.ts.map +0 -1
package/dist/glare.esm.js CHANGED
@@ -1,1339 +1,1267 @@
1
- const d = {
2
- close: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',
3
- next: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>',
4
- prev: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>',
5
- zoomIn: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/><path d="M11 8v6"/><path d="M8 11h6"/></svg>',
6
- zoomOut: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/><path d="M8 11h6"/></svg>',
7
- download: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>',
8
- share: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg>',
9
- thumbs: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>',
10
- play: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="6 3 20 12 6 21 6 3"/></svg>',
11
- pause: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="4" height="16" x="6" y="4"/><rect width="4" height="16" x="14" y="4"/></svg>',
12
- fullscreen: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></svg>',
13
- fullscreenExit: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/></svg>'
14
- }, N = {
1
+ const it = {
15
2
  CLOSE: "Close",
16
3
  NEXT: "Next",
17
4
  PREV: "Previous",
18
5
  ERROR: "The requested content cannot be loaded.<br/>Please try again later.",
6
+ LOADING: "Loading",
7
+ LIGHTBOX: "Media lightbox",
8
+ GO_TO_SLIDE: "Go to slide {{index}}",
9
+ VIDEO_UNSUPPORTED: "Your browser does not support HTML5 video.",
19
10
  PLAY_START: "Start slideshow",
20
11
  PLAY_STOP: "Pause slideshow",
21
12
  FULL_SCREEN: "Full screen",
13
+ FULL_SCREEN_EXIT: "Exit full screen",
22
14
  THUMBS: "Thumbnails",
23
15
  DOWNLOAD: "Download",
24
16
  SHARE: "Share",
25
- ZOOM: "Zoom"
26
- }, _ = {
17
+ MORE: "More options",
18
+ COPY: "Copy link",
19
+ ZOOM: "Zoom",
20
+ ZOOM_OUT: "Zoom out"
21
+ };
22
+ function pt(e) {
23
+ const t = e.lang ?? "en";
24
+ return { ...it, ...e.i18n?.en, ...e.i18n?.[t] };
25
+ }
26
+ function y(e, t) {
27
+ return e.replace(/\{\{(\w+)\}\}/g, (s, i) => t[i] ?? "");
28
+ }
29
+ function mt(e) {
30
+ return Object.entries(e).map(([t, s]) => `${encodeURIComponent(t)}=${encodeURIComponent(String(s))}`).join("&");
31
+ }
32
+ function gt(e, t) {
33
+ return e.replace(/\$(\d+)/g, (s, i) => t[Number(i)] ?? "");
34
+ }
35
+ const yt = {
27
36
  youtube: {
28
37
  matcher: /(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\/(?:watch\?(?:.*&)?v=|v\/|u\/\w\/|embed\/|shorts\/)?([\w-]{11})/i,
29
- type: "iframe",
30
- url: (r, t) => `https://www.youtube-nocookie.com/embed/${r[1]}`,
31
- thumb: (r) => `https://img.youtube.com/vi/${r[1]}/hqdefault.jpg`,
32
- params: {
33
- autoplay: 1,
34
- rel: 0,
35
- modestbranding: 1,
36
- playsinline: 1
37
- }
38
+ type: "embed",
39
+ url: "https://www.youtube-nocookie.com/embed/$1",
40
+ thumb: "https://img.youtube.com/vi/$1/hqdefault.jpg",
41
+ params: { autoplay: 1, rel: 0, modestbranding: 1, playsinline: 1 }
38
42
  },
39
43
  vimeo: {
40
- matcher: /(?:vimeo\.com)\/(?:video\/)?(\d+)/i,
41
- type: "iframe",
42
- url: (r) => `https://player.vimeo.com/video/${r[1]}`,
43
- params: {
44
- autoplay: 1,
45
- title: 0,
46
- byline: 0,
47
- portrait: 0
48
- }
44
+ matcher: /vimeo\.com\/(?:video\/)?(\d+)/i,
45
+ type: "embed",
46
+ url: "https://player.vimeo.com/video/$1",
47
+ params: { autoplay: 1, title: 0, byline: 0, portrait: 0 }
49
48
  },
50
49
  gmap: {
51
50
  matcher: /(?:maps\.)?google\.([a-z]{2,3}(?:\.[a-z]{2})?)\/(?:maps\/(?:place\/[^/]+\/)?@([^/]+)|maps\?q=([^&]+)|maps\/search\/([^/?]+))/i,
52
51
  type: "iframe",
53
- url: (r) => {
54
- const t = r[1];
55
- if (r[2]) {
56
- const s = r[2].split(","), i = s[0], n = s[1], o = s[2] ? Math.floor(parseFloat(s[2])) : 14;
57
- return `https://maps.google.${t}/maps?ll=${i},${n}&z=${o}&output=embed`;
52
+ url: (e) => {
53
+ const [, t, s, i, r] = e;
54
+ if (s) {
55
+ const [n, a, l] = s.split(","), d = l ? Math.floor(parseFloat(l)) : 14;
56
+ return `https://maps.google.${t}/maps?ll=${n},${a}&z=${d}&output=embed`;
58
57
  }
59
- const e = decodeURIComponent(r[3] || r[4] || "");
60
- return `https://maps.google.${t}/maps?q=${encodeURIComponent(e)}&output=embed`;
58
+ const o = encodeURIComponent(decodeURIComponent(i || r || ""));
59
+ return `https://maps.google.${t}/maps?q=${o}&output=embed`;
61
60
  }
62
61
  }
63
- }, T = {
62
+ };
63
+ function q(e, t, s) {
64
+ if (typeof e == "function") return e(t, s);
65
+ if (typeof e == "string") return gt(e, t);
66
+ }
67
+ function bt(e, t) {
68
+ for (const s of Object.values(t ?? {})) {
69
+ const i = e.match(s.matcher);
70
+ if (!i) continue;
71
+ let r = q(s.url, i, e) ?? e;
72
+ return s.params && (r += (r.includes("?") ? "&" : "?") + mt(s.params)), {
73
+ src: r,
74
+ type: s.type ?? "iframe",
75
+ thumb: q(s.thumb, i, e)
76
+ };
77
+ }
78
+ return null;
79
+ }
80
+ const f = (e) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${e}</svg>`, u = {
81
+ close: f('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>'),
82
+ next: f('<path d="m9 18 6-6-6-6"/>'),
83
+ prev: f('<path d="m15 18-6-6 6-6"/>'),
84
+ zoomIn: f('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/><path d="M11 8v6"/><path d="M8 11h6"/>'),
85
+ zoomOut: f('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/><path d="M8 11h6"/>'),
86
+ download: f('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/>'),
87
+ share: f('<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/>'),
88
+ thumbs: f('<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/>'),
89
+ play: f('<polygon points="6 3 20 12 6 21 6 3"/>'),
90
+ pause: f('<rect width="4" height="16" x="6" y="4"/><rect width="4" height="16" x="14" y="4"/>'),
91
+ fullscreen: f('<path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>'),
92
+ fullscreenExit: f('<path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/>'),
93
+ more: f('<circle cx="5" cy="12" r="1" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1" fill="currentColor" stroke="none"/><circle cx="19" cy="12" r="1" fill="currentColor" stroke="none"/>')
94
+ }, v = (e, t, s, i = "") => `<button type="button" class="glare-button glare-button--${e}" data-glare-${e} title="{{${t}}}" aria-label="{{${t}}}"${i}>${s}</button>`, vt = `
95
+ <div class="glare-container" role="dialog" aria-modal="true" tabindex="-1">
96
+ <div class="glare-bg"></div>
97
+ <div class="glare-progress" hidden></div>
98
+ <div class="glare-inner">
99
+ <div class="glare-live glare-sr-only" aria-live="polite" aria-atomic="true"></div>
100
+ <div class="glare-infobar"><span class="glare-infobar-index"></span></div>
101
+ <div class="glare-toolbar"></div>
102
+ <div class="glare-navigation">
103
+ ${v("prev", "PREV", u.prev)}
104
+ ${v("next", "NEXT", u.next)}
105
+ </div>
106
+ <div class="glare-stage"></div>
107
+ <div class="glare-caption"></div>
108
+ </div>
109
+ </div>`, xt = {
110
+ zoom: v("zoom", "ZOOM", u.zoomIn),
111
+ slideshow: v("slideshow", "PLAY_START", u.play),
112
+ thumbs: v("thumbs", "THUMBS", u.thumbs, ' aria-expanded="false"'),
113
+ share: v("share", "SHARE", u.share),
114
+ fullscreen: v("fullscreen", "FULL_SCREEN", u.fullscreen),
115
+ more: v("more", "MORE", u.more, ' aria-expanded="false" aria-haspopup="true"'),
116
+ close: v("close", "CLOSE", u.close),
117
+ download: `<a class="glare-button glare-button--download" data-glare-download download target="_blank" rel="noopener" title="{{DOWNLOAD}}" aria-label="{{DOWNLOAD}}">${u.download}</a>`,
118
+ smallBtn: `<button type="button" class="glare-button glare-close-small" data-glare-close title="{{CLOSE}}" aria-label="{{CLOSE}}">${u.close}</button>`
119
+ }, wt = '<div class="glare-spinner" role="status" aria-label="{{LOADING}}"></div>', Et = '<div class="glare-error"><p>{{ERROR}}</p></div>', St = '<video class="glare-video" controls playsinline controlsList="nodownload" poster="{{poster}}"><source src="{{src}}" type="{{format}}"/>{{VIDEO_UNSUPPORTED}}</video>', Tt = '<iframe class="glare-iframe"></iframe>', Lt = `
120
+ <div class="glare-share" role="dialog" aria-label="{{SHARE}}">
121
+ <div class="glare-share-head">
122
+ <h4 class="glare-share-title">{{SHARE}}</h4>
123
+ <button type="button" class="glare-button glare-share-close" data-glare-share-close title="{{CLOSE}}" aria-label="{{CLOSE}}">${u.close}</button>
124
+ </div>
125
+ <p><a class="glare-share-link" href="{{url_facebook}}" target="_blank" rel="noopener">Facebook</a></p>
126
+ <p><a class="glare-share-link" href="{{url_twitter}}" target="_blank" rel="noopener">X / Twitter</a></p>
127
+ <p><a class="glare-share-link" href="{{url_pinterest}}" target="_blank" rel="noopener">Pinterest</a></p>
128
+ <div class="glare-share-row">
129
+ <input class="glare-share-input" type="text" value="{{url_direct}}" readonly />
130
+ <button type="button" class="glare-share-copy" data-glare-share-copy>{{COPY}}</button>
131
+ </div>
132
+ </div>`, rt = {
133
+ autoStart: !1,
134
+ axis: "x"
135
+ }, z = {
136
+ autoStart: !1,
137
+ speed: 3e3
138
+ }, ot = {
139
+ autoStart: !1
140
+ }, nt = {
64
141
  closeExisting: !1,
65
142
  loop: !1,
66
- gutter: 50,
67
143
  keyboard: !0,
68
- preventCaptionOverlap: !0,
144
+ protect: !1,
145
+ modal: !1,
146
+ idleTime: 3,
147
+ hideScrollbar: !0,
148
+ autoFocus: !0,
149
+ backFocus: !0,
150
+ trapFocus: !0,
151
+ defaultType: "image",
152
+ parentEl: "body",
153
+ baseClass: "",
154
+ slideClass: "",
69
155
  arrows: !0,
70
156
  infobar: !0,
71
- smallBtn: "auto",
72
157
  toolbar: "auto",
158
+ smallBtn: "auto",
73
159
  buttons: ["zoom", "slideshow", "thumbs", "share", "download", "fullscreen", "close"],
74
- idleTime: 3,
75
- protect: !1,
76
- modal: !1,
77
- image: {
78
- preload: !1
79
- },
80
- ajax: {
81
- settings: {
82
- headers: {
83
- "X-Requested-With": "XMLHttpRequest"
84
- }
85
- }
86
- },
87
- iframe: {
88
- preload: !0,
89
- css: {},
90
- attr: {
91
- allowfullscreen: "true",
92
- allow: "autoplay; fullscreen; picture-in-picture"
93
- },
94
- tpl: '<iframe class="glare-iframe" allowfullscreen allow="autoplay; fullscreen; picture-in-picture" src=""></iframe>'
95
- },
96
- video: {
97
- tpl: '<video class="glare-video" controls playsinline controlsList="nodownload" poster="{{poster}}"><source src="{{src}}" type="{{format}}"/>Your browser does not support HTML5 video.</video>',
98
- format: "",
99
- autoStart: !0
100
- },
101
- defaultType: "image",
102
160
  animationEffect: "zoom",
103
161
  animationDuration: 366,
104
- zoomOpacity: "auto",
162
+ zoomOpacity: !0,
105
163
  transitionEffect: "fade",
106
164
  transitionDuration: 366,
107
- slideClass: "",
108
- baseClass: "",
109
- parentEl: "body",
110
- hideScrollbar: !0,
111
- autoFocus: !0,
112
- backFocus: !0,
113
- trapFocus: !0,
114
- fullScreen: {
115
- autoStart: !1
116
- },
117
- touch: {
118
- vertical: !0,
119
- momentum: !0
120
- },
121
- hash: !0,
122
- media: _,
123
- slideShow: {
124
- autoStart: !1,
125
- speed: 3e3
126
- },
127
- thumbs: {
128
- autoStart: !1,
129
- hideOnClose: !0,
130
- parentEl: ".glare-container",
131
- axis: "y"
132
- },
133
- share: !0,
134
- wheel: "auto",
135
- clickContent: function(r) {
136
- return r.type === "image" ? "zoom" : !1;
137
- },
165
+ clickContent: (e) => e.type === "image" ? "zoom" : !1,
138
166
  clickSlide: "close",
139
- clickOutside: "close",
140
167
  dblclickContent: !1,
141
168
  dblclickSlide: !1,
142
- dblclickOutside: !1,
169
+ wheel: "auto",
170
+ touch: { vertical: !0, momentum: !0 },
143
171
  mobile: {
144
- preventCaptionOverlap: !1,
145
172
  idleTime: !1,
146
- clickContent: function(r) {
147
- return r.type === "image" ? "toggleControls" : !1;
148
- },
149
- clickSlide: function(r) {
150
- return r.type === "image" ? "toggleControls" : "close";
151
- },
152
- dblclickContent: function(r) {
153
- return r.type === "image" ? "zoom" : !1;
154
- },
155
- dblclickSlide: function(r) {
156
- return r.type === "image" ? "zoom" : !1;
157
- }
173
+ clickContent: (e) => e.type === "image" ? "toggleControls" : !1,
174
+ clickSlide: (e) => e.type === "image" ? "toggleControls" : "close",
175
+ dblclickContent: (e) => e.type === "image" ? "zoom" : !1,
176
+ dblclickSlide: (e) => e.type === "image" ? "zoom" : !1
158
177
  },
159
- lang: "en",
160
- i18n: {
161
- en: N
178
+ image: { preload: !1 },
179
+ video: { tpl: St, format: "", autoStart: !0 },
180
+ iframe: {
181
+ preload: !0,
182
+ css: {},
183
+ attr: { allowfullscreen: "true", allow: "autoplay; fullscreen; picture-in-picture" },
184
+ tpl: Tt
162
185
  },
163
- spinnerTpl: '<div class="glare-spinner" role="status" aria-label="Loading"></div>',
164
- errorTpl: '<div class="glare-error"><p>{{ERROR}}</p></div>',
165
- baseTpl: `
166
- <div class="glare-container" role="dialog" aria-modal="true" tabindex="-1">
167
- <div class="glare-bg"></div>
168
- <div class="glare-inner">
169
- <div class="glare-infobar"><span class="glare-infobar-index"></span></div>
170
- <div class="glare-toolbar"></div>
171
- <div class="glare-navigation">
172
- <button type="button" class="glare-button glare-button--prev" data-glare-prev title="{{PREV}}" aria-label="{{PREV}}">${d.prev}</button>
173
- <button type="button" class="glare-button glare-button--next" data-glare-next title="{{NEXT}}" aria-label="{{NEXT}}">${d.next}</button>
174
- </div>
175
- <div class="glare-stage"></div>
176
- <div class="glare-caption"></div>
177
- </div>
178
- </div>
179
- `,
180
- btnTpl: {
181
- download: `<a class="glare-button glare-button--download" data-glare-download download title="{{DOWNLOAD}}" aria-label="{{DOWNLOAD}}" href="javascript:;">${d.download}</a>`,
182
- zoom: `<button type="button" class="glare-button glare-button--zoom" data-glare-zoom title="{{ZOOM}}" aria-label="{{ZOOM}}">${d.zoomIn}</button>`,
183
- close: `<button type="button" class="glare-button glare-button--close" data-glare-close title="{{CLOSE}}" aria-label="{{CLOSE}}">${d.close}</button>`,
184
- share: `<button type="button" class="glare-button glare-button--share" data-glare-share title="{{SHARE}}" aria-label="{{SHARE}}">${d.share}</button>`,
185
- thumbs: `<button type="button" class="glare-button glare-button--thumbs" data-glare-thumbs title="{{THUMBS}}" aria-label="{{THUMBS}}">${d.thumbs}</button>`,
186
- slideshow: `<button type="button" class="glare-button glare-button--slideshow" data-glare-slideshow title="{{PLAY_START}}" aria-label="{{PLAY_START}}">${d.play}</button>`,
187
- fullscreen: `<button type="button" class="glare-button glare-button--fullscreen" data-glare-fullscreen title="{{FULL_SCREEN}}" aria-label="{{FULL_SCREEN}}">${d.fullscreen}</button>`,
188
- smallBtn: `<button type="button" class="glare-button glare-close-small" data-glare-close title="{{CLOSE}}" aria-label="{{CLOSE}}">${d.close}</button>`
189
- }
190
- };
191
- function D(r) {
192
- return typeof r == "object" && r !== null && !Array.isArray(r);
193
- }
194
- function L(r, ...t) {
195
- const e = { ...r };
196
- for (const s of t)
197
- if (!(!s || typeof s != "object"))
198
- for (const [i, n] of Object.entries(s)) {
199
- if (n === void 0) continue;
200
- const o = e[i];
201
- D(o) && D(n) && !Array.isArray(n) ? e[i] = L(
202
- o,
203
- n
204
- ) : e[i] = n;
205
- }
206
- return e;
186
+ ajax: { settings: { headers: { "X-Requested-With": "XMLHttpRequest" } } },
187
+ media: yt,
188
+ hash: !0,
189
+ slideshow: z,
190
+ thumbs: rt,
191
+ fullscreen: ot,
192
+ share: !0,
193
+ lang: "en",
194
+ i18n: { en: it },
195
+ baseTpl: vt,
196
+ btnTpl: xt,
197
+ spinnerTpl: wt,
198
+ errorTpl: Et
199
+ }, Ct = /\.(avif|bmp|gif|jpe?g|png|svg|webp|ico)(\?.*)?$/i, Mt = /\.(mp4|webm|ogg|ogv|mov|m4v)(\?.*)?$/i, $t = /\.pdf(\?.*)?$/i, Ot = /^(#[\w-]+|\.[\w-]+)$/;
200
+ function At(e, t = "image") {
201
+ return e ? Ot.test(e) ? "inline" : Ct.test(e) ? "image" : Mt.test(e) ? "video" : $t.test(e) ? "iframe" : t : "html";
207
202
  }
208
- function p(r, t = document) {
209
- return t.querySelector(r);
203
+ function It(e) {
204
+ const t = e.match(/\.(\w+)(?:\?|$)/)?.[1]?.toLowerCase();
205
+ return t ? `video/${t === "ogv" ? "ogg" : t}` : "video/mp4";
210
206
  }
211
- function S(r, t = document) {
212
- return Array.from(t.querySelectorAll(r));
207
+ function at(e, t, s) {
208
+ const i = typeof e == "string" ? { src: e } : { ...e };
209
+ let r = i.src ?? "", o = i.type, n = i.thumb;
210
+ const a = r ? bt(r, s.media) : null;
211
+ return a && (r = a.src ?? r, o ??= a.type, n ??= a.thumb), o || (o = i.html || i.content ? "html" : At(r, s.defaultType)), {
212
+ ...i,
213
+ index: t,
214
+ src: r,
215
+ type: o,
216
+ thumb: n,
217
+ caption: i.caption ?? i.title ?? "",
218
+ isLoaded: !1,
219
+ hasError: !1
220
+ };
221
+ }
222
+ const m = (e, t) => e.getAttribute(t) || void 0;
223
+ function Dt(e, t) {
224
+ return e.map((s, i) => {
225
+ const r = s.querySelector("img"), o = m(s, "data-caption") ?? m(s, "title") ?? "";
226
+ return at(
227
+ {
228
+ src: m(s, "data-src") ?? m(s, "href") ?? "",
229
+ type: m(s, "data-type"),
230
+ caption: o,
231
+ alt: r?.getAttribute("alt") || o,
232
+ thumb: m(s, "data-thumb") ?? r?.getAttribute("src") ?? void 0,
233
+ width: m(s, "data-width"),
234
+ height: m(s, "data-height"),
235
+ ratio: m(s, "data-ratio"),
236
+ poster: m(s, "data-poster"),
237
+ downloadSrc: m(s, "data-download-src"),
238
+ html: m(s, "data-html"),
239
+ $trigger: s
240
+ },
241
+ i,
242
+ t
243
+ );
244
+ });
213
245
  }
214
- function b(r, t, e) {
215
- const s = document.createElement(r);
216
- return t && (s.className = t), e !== void 0 && (s.innerHTML = e), s;
246
+ function kt(e, t) {
247
+ return e.length && e[0] instanceof HTMLElement ? Dt(e, t) : e.map((s, i) => at(s, i, t));
217
248
  }
218
- function c(r, t, e, s) {
219
- return r.addEventListener(t, e, s), () => r.removeEventListener(t, e, s);
249
+ function c(e, t = document) {
250
+ return t.querySelector(e);
220
251
  }
221
- function m(r, t) {
222
- for (const [e, s] of Object.entries(t))
223
- s == null ? r.style.removeProperty(U(e)) : r.style[e] = String(s);
252
+ function $(e, t = document) {
253
+ return Array.from(t.querySelectorAll(e));
224
254
  }
225
- function U(r) {
226
- return r.replace(/[A-Z]/g, (t) => `-${t.toLowerCase()}`);
255
+ function g(e, t = "", s = "") {
256
+ const i = document.createElement(e);
257
+ return t && (i.className = t), s && (i.innerHTML = s), i;
227
258
  }
228
- function x(r, t, e) {
229
- return Math.min(e, Math.max(t, r));
259
+ function Rt(e) {
260
+ return g("div", "", e.trim()).firstElementChild;
230
261
  }
231
- function W() {
232
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
233
- navigator.userAgent
234
- ) || navigator.maxTouchPoints > 1 && window.matchMedia("(pointer: coarse)").matches;
262
+ function O(e) {
263
+ return /[<&]/.test(e) ? new DOMParser().parseFromString(e, "text/html").body.textContent?.trim() ?? "" : e.trim();
235
264
  }
236
- function X() {
237
- return window.innerWidth - document.documentElement.clientWidth;
265
+ function _t(e, t = document) {
266
+ return e ? typeof e != "string" ? e : c(e, t) ?? c(e) : null;
238
267
  }
239
- function R(r) {
240
- const t = document.documentElement;
241
- if (r) {
242
- const e = X();
243
- t.classList.add("glare-lock"), e > 0 && (t.style.marginRight = `${e}px`);
244
- } else document.querySelector(".glare-container") || (t.classList.remove("glare-lock"), t.style.marginRight = "");
268
+ function U(e) {
269
+ return typeof e == "number" ? `${e}px` : e;
245
270
  }
246
- function $(r, t) {
247
- return r.replace(/\{\{(\w+)\}\}/g, (e, s) => t[s] ?? "");
271
+ function h(e, t, s, i) {
272
+ return e.addEventListener(t, s, i), () => e.removeEventListener(t, s, i);
248
273
  }
249
- function E(r) {
250
- return r.getBoundingClientRect();
274
+ function lt(e) {
275
+ requestAnimationFrame(() => requestAnimationFrame(e));
251
276
  }
252
- function q(r) {
253
- return window.requestAnimationFrame(r);
277
+ function Ft(e, t, s) {
278
+ let i = !1;
279
+ const r = () => {
280
+ i || (i = !0, clearTimeout(n), e.removeEventListener("transitionend", o), s());
281
+ }, o = (a) => {
282
+ a.target === e && r();
283
+ };
284
+ e.addEventListener("transitionend", o);
285
+ const n = setTimeout(r, t + 50);
254
286
  }
255
- function A(r) {
256
- q(() => q(r));
287
+ function Ht() {
288
+ return navigator.maxTouchPoints > 0 && window.matchMedia("(pointer: coarse)").matches;
257
289
  }
258
- function M() {
290
+ function A() {
259
291
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
260
292
  }
261
- function Y(r) {
262
- return Object.entries(r).map(([t, e]) => `${encodeURIComponent(t)}=${encodeURIComponent(String(e))}`).join("&");
263
- }
264
- function j(r, t) {
265
- const e = r.x - t.x, s = r.y - t.y;
266
- return Math.hypot(e, s);
293
+ function ct() {
294
+ const e = document;
295
+ return !!(e.fullscreenEnabled ?? e.webkitFullscreenEnabled);
267
296
  }
268
- function V(r, t) {
269
- return { x: (r.x + t.x) / 2, y: (r.y + t.y) / 2 };
297
+ const B = "glare-lock";
298
+ function W(e) {
299
+ const t = document.documentElement;
300
+ if (e) {
301
+ const s = window.innerWidth - t.clientWidth;
302
+ t.classList.add(B), s > 0 && (t.style.marginRight = `${s}px`);
303
+ } else
304
+ t.classList.remove(B), t.style.marginRight = "";
270
305
  }
271
- function I(r) {
272
- return "touches" in r ? Array.from(r.touches).map((t) => ({ x: t.clientX, y: t.clientY })) : [{ x: r.clientX, y: r.clientY }];
306
+ const S = "glare-hidden";
307
+ function Pt(e, t, s, i) {
308
+ const r = Rt(y(e.baseTpl, t));
309
+ r.dataset.glareId = String(s), e.baseClass && r.classList.add(e.baseClass), e.modal && r.classList.add("glare-is-modal");
310
+ const o = c(".glare-stage", r);
311
+ if (!o) throw new Error("baseTpl must contain a .glare-stage element");
312
+ const n = {
313
+ container: r,
314
+ bg: c(".glare-bg", r),
315
+ inner: c(".glare-inner", r),
316
+ stage: o,
317
+ caption: c(".glare-caption", r),
318
+ toolbar: c(".glare-toolbar", r),
319
+ infobar: c(".glare-infobar", r),
320
+ navigation: c(".glare-navigation", r)
321
+ }, a = i < 2;
322
+ return n.navigation?.classList.toggle(S, !e.arrows || a), n.infobar?.classList.toggle(S, !e.infobar || a), n.toolbar && zt(n.toolbar, e, t, a), n;
273
323
  }
274
- class G {
275
- constructor(t) {
276
- this.state = {
277
- isPanning: !1,
278
- isSwiping: !1,
279
- isZooming: !1,
280
- startPoints: [],
281
- lastPoints: [],
282
- startDistance: 0,
283
- startScale: 1,
284
- startTranslate: { x: 0, y: 0 },
285
- currentTranslate: { x: 0, y: 0 },
286
- scale: 1,
287
- startTime: 0,
288
- moved: !1
289
- }, this.cleanups = [], this.pointerId = null, this.instance = t;
290
- }
291
- attach(t) {
292
- this.detach(), this.cleanups.push(
293
- c(t, "pointerdown", (e) => this.onPointerDown(e), { passive: !1 }),
294
- c(window, "pointermove", (e) => this.onPointerMove(e), { passive: !1 }),
295
- c(window, "pointerup", (e) => this.onPointerUp(e)),
296
- c(window, "pointercancel", (e) => this.onPointerUp(e)),
297
- c(t, "touchstart", (e) => this.onTouchStart(e), { passive: !1 }),
298
- c(t, "touchmove", (e) => this.onTouchMove(e), { passive: !1 }),
299
- c(t, "touchend", (e) => this.onTouchEnd(e)),
300
- c(t, "touchcancel", (e) => this.onTouchEnd(e))
301
- );
302
- }
303
- detach() {
304
- this.cleanups.forEach((t) => t()), this.cleanups = [];
305
- }
306
- touchEnabled() {
307
- return this.instance.opts.touch !== !1;
308
- }
309
- onPointerDown(t) {
310
- if (!this.touchEnabled() || t.pointerType === "touch" || t.button !== 0 || t.target.closest("a, button, input, textarea, select, .glare-thumbs")) return;
311
- this.pointerId = t.pointerId;
312
- const s = [{ x: t.clientX, y: t.clientY }];
313
- this.begin(s);
314
- }
315
- onPointerMove(t) {
316
- this.pointerId === t.pointerId && this.move([{ x: t.clientX, y: t.clientY }], t);
317
- }
318
- onPointerUp(t) {
319
- this.pointerId === t.pointerId && (this.pointerId = null, this.end([{ x: t.clientX, y: t.clientY }]));
320
- }
321
- onTouchStart(t) {
322
- !this.touchEnabled() || t.target.closest("a, button, input, textarea, select, .glare-thumbs") || this.begin(I(t));
323
- }
324
- onTouchMove(t) {
325
- this.move(I(t), t);
326
- }
327
- onTouchEnd(t) {
328
- this.end(I(t));
329
- }
330
- begin(t) {
331
- const e = this.instance.getZoomState();
332
- this.state = {
333
- isPanning: !1,
334
- isSwiping: !1,
335
- isZooming: t.length >= 2,
336
- startPoints: t,
337
- lastPoints: t,
338
- startDistance: t.length >= 2 ? j(t[0], t[1]) : 0,
339
- startScale: e.scale,
340
- startTranslate: { x: e.x, y: e.y },
341
- currentTranslate: { x: e.x, y: e.y },
342
- scale: e.scale,
343
- startTime: performance.now(),
344
- moved: !1
345
- };
346
- }
347
- move(t, e) {
348
- if (!this.state.startPoints.length) return;
349
- const s = this.instance.current;
350
- if (!s) return;
351
- if (t.length >= 2 && this.state.startPoints.length >= 2) {
352
- e.preventDefault(), this.state.isZooming = !0, this.state.moved = !0;
353
- const h = j(t[0], t[1]), f = x(
354
- h / (this.state.startDistance || h) * this.state.startScale,
355
- 1,
356
- 5
357
- ), w = V(t[0], t[1]);
358
- this.state.scale = f, this.instance.applyZoom(f, w.x, w.y, !1), this.state.lastPoints = t;
359
- return;
360
- }
361
- if (!t.length || !this.state.startPoints.length) return;
362
- const i = t[0].x - this.state.startPoints[0].x, n = t[0].y - this.state.startPoints[0].y, o = Math.abs(i), a = Math.abs(n);
363
- if (!this.state.moved && o < 6 && a < 6) return;
364
- this.state.moved = !0;
365
- const l = this.instance.getZoomState();
366
- if (l.scale > 1.01 && s.type === "image" || this.state.isPanning) {
367
- e.preventDefault(), this.state.isPanning = !0;
368
- const h = this.state.startTranslate.x + i, f = this.state.startTranslate.y + n;
369
- this.state.currentTranslate = { x: h, y: f }, this.instance.applyZoom(l.scale, h, f, !1);
370
- } else {
371
- const h = this.instance.opts.touch;
372
- if (!(h && typeof h == "object" ? h.vertical !== !1 : !0) && a > o) return;
373
- e.preventDefault(), this.state.isSwiping = !0, this.instance.onSwipe(i, n, !1);
374
- }
375
- this.state.lastPoints = t;
376
- }
377
- end(t) {
378
- if (!this.state.startPoints.length) return;
379
- const e = Math.max(performance.now() - this.state.startTime, 1), s = t[0] || this.state.lastPoints[0] || this.state.startPoints[0], i = this.state.startPoints[0], n = s.x - i.x, o = s.y - i.y, a = { x: n / e, y: o / e };
380
- if (this.state.isSwiping)
381
- this.instance.onSwipe(n, o, !0, a);
382
- else if (this.state.isPanning) {
383
- const l = this.instance.opts.touch;
384
- if (l && typeof l == "object" ? l.momentum !== !1 : !0) {
385
- const h = this.instance.getZoomState();
386
- this.instance.applyZoom(
387
- h.scale,
388
- this.state.currentTranslate.x + a.x * 120,
389
- this.state.currentTranslate.y + a.y * 120,
390
- !0
391
- );
392
- }
393
- }
394
- this.state.startPoints = [], this.state.isPanning = !1, this.state.isSwiping = !1, this.state.isZooming = !1;
395
- }
396
- wasMoved() {
397
- return this.state.moved;
398
- }
399
- resetMoved() {
400
- this.state.moved = !1;
324
+ function zt(e, t, s, i) {
325
+ if (t.toolbar === !1) {
326
+ e.classList.add(S);
327
+ return;
328
+ }
329
+ const r = g("div", "glare-toolbar-menu");
330
+ r.id = `glare-toolbar-menu-${e.closest(".glare-container")?.dataset.glareId ?? ""}`;
331
+ for (const o of t.buttons) {
332
+ if (i && (o === "thumbs" || o === "slideshow") || o === "fullscreen" && !ct() || o === "more" || o === "close") continue;
333
+ const n = t.btnTpl[o];
334
+ n && r.insertAdjacentHTML("beforeend", y(n, s));
335
+ }
336
+ if (r.childElementCount) {
337
+ e.appendChild(r);
338
+ const o = t.btnTpl.more;
339
+ o && (e.insertAdjacentHTML("beforeend", y(o, s)), e.querySelector("[data-glare-more]")?.setAttribute("aria-controls", r.id));
340
+ }
341
+ if (t.buttons.includes("close")) {
342
+ const o = t.btnTpl.close;
343
+ o && e.insertAdjacentHTML("beforeend", y(o, s));
401
344
  }
402
345
  }
403
- class K {
404
- constructor(t) {
405
- this.cleanups = [], this.instance = t;
406
- }
407
- init() {
408
- this.cleanups.push(
409
- c(document, "fullscreenchange", () => this.sync()),
410
- c(document, "webkitfullscreenchange", () => this.sync())
411
- );
346
+ function Nt(e, t, s) {
347
+ const i = g("div", `glare-slide glare-slide--${t.type}`);
348
+ s.slideClass && i.classList.add(s.slideClass);
349
+ const r = g("div", "glare-content");
350
+ return i.appendChild(r), e.appendChild(i), t.$slide = i, t.$content = r, i;
351
+ }
352
+ function Zt(e, t) {
353
+ t && (e.style.transition = "none"), e.offsetWidth, e.classList.add("glare-slide--current"), t && (e.offsetWidth, e.style.transition = "");
354
+ }
355
+ function qt(e, t, s) {
356
+ for (const i of $(".glare-slide", e))
357
+ i !== t && (i.classList.remove("glare-slide--current"), i.classList.add("glare-slide--out"), setTimeout(() => i.remove(), s));
358
+ }
359
+ function Ut(e, t, s) {
360
+ e.insertAdjacentHTML("beforeend", y(t.btnTpl.smallBtn ?? "", s));
361
+ }
362
+ function Bt(e, t, s) {
363
+ e.querySelector(":scope > .glare-spinner") || e.insertAdjacentHTML("beforeend", y(t.spinnerTpl, s));
364
+ }
365
+ function Wt(e) {
366
+ e.querySelector(":scope > .glare-spinner")?.remove();
367
+ }
368
+ function jt(e, t, s, i) {
369
+ e.hasError = !0, e.error = t, e.$content && (e.$content.className = "glare-content glare-content--error", e.$content.innerHTML = y(s.errorTpl, i));
370
+ }
371
+ function ht(e, t) {
372
+ return typeof e.toolbar == "boolean" ? e.toolbar : t.type === "image";
373
+ }
374
+ function Xt(e, t) {
375
+ return typeof e.smallBtn == "boolean" ? e.smallBtn : !ht(e, t);
376
+ }
377
+ function Yt(e, t, s, i, r, o) {
378
+ const { container: n, toolbar: a, infobar: l } = e;
379
+ ee(n, i.type), a && Gt(a, t, i), Vt(n, i), l && Kt(l, i.index, r), e.caption && Qt(e.caption, o), Jt(n, t, i.index, r), te(n, s, i, r);
380
+ }
381
+ function Gt(e, t, s) {
382
+ if (t.toolbar === !1) return;
383
+ e.classList.remove("glare-toolbar--expanded"), e.querySelector("[data-glare-more]")?.setAttribute("aria-expanded", "false");
384
+ const i = ht(t, s);
385
+ if (e.classList.toggle(S, !i), !i) return;
386
+ const r = s.type === "image";
387
+ c("[data-glare-zoom]", e)?.classList.toggle(S, !r);
388
+ }
389
+ function Vt(e, t) {
390
+ const s = e.querySelector("[data-glare-download]");
391
+ if (!s) return;
392
+ const i = t.downloadSrc || (t.type === "image" ? t.src : "");
393
+ s.classList.toggle(S, !i), i && (s.href = i);
394
+ }
395
+ function Kt(e, t, s) {
396
+ const i = c(".glare-infobar-index", e);
397
+ i && (i.textContent = `${t + 1} / ${s}`);
398
+ }
399
+ function Qt(e, t) {
400
+ e.innerHTML = t, e.classList.toggle(S, !t);
401
+ }
402
+ function Jt(e, t, s, i) {
403
+ const r = !t.loop && s === 0, o = !t.loop && s === i - 1;
404
+ j(c("[data-glare-prev]", e), r), j(c("[data-glare-next]", e), o);
405
+ }
406
+ function j(e, t) {
407
+ e && (e.classList.toggle("glare-is-disabled", t), e.setAttribute("aria-disabled", String(t)));
408
+ }
409
+ function te(e, t, s, i) {
410
+ const r = O(s.caption) || s.alt || t.LIGHTBOX, o = i > 1 ? `${r} (${s.index + 1} of ${i})` : r;
411
+ e.setAttribute("aria-label", o);
412
+ const n = c(".glare-live", e);
413
+ n && (n.textContent = o);
414
+ }
415
+ function ee(e, t) {
416
+ const s = e.dataset.type;
417
+ s && e.classList.remove(`glare-type-${s}`), e.dataset.type = t, e.classList.add(`glare-type-${t}`);
418
+ }
419
+ function se(e, t, s, i) {
420
+ e.classList.toggle("glare-can-zoom-out", s), e.classList.toggle("glare-can-zoom-in", !s && i);
421
+ const r = c("[data-glare-zoom]", e), o = s ? "out" : "in";
422
+ !r || r.dataset.state === o || (r.dataset.state = o, N(r, s, s ? t.ZOOM_OUT : t.ZOOM, s ? u.zoomOut : u.zoomIn));
423
+ }
424
+ function N(e, t, s, i) {
425
+ e.setAttribute("title", s), e.setAttribute("aria-label", s), e.innerHTML = i, e.classList.toggle("glare-is-active", t);
426
+ }
427
+ class ie {
428
+ constructor(t, s, i) {
429
+ this.glare = t, this.container = s, this.offs = [
430
+ h(document, "fullscreenchange", () => this.sync()),
431
+ h(document, "webkitfullscreenchange", () => this.sync())
432
+ ], i.autoStart && this.request();
412
433
  }
413
434
  isFullscreen() {
414
435
  const t = document;
415
- return !!(document.fullscreenElement || t.webkitFullscreenElement || t.mozFullScreenElement || t.msFullscreenElement);
436
+ return !!(t.fullscreenElement ?? t.webkitFullscreenElement);
416
437
  }
417
438
  request() {
418
- const t = this.instance.$refs.container || document.documentElement;
419
- (t.requestFullscreen || t.webkitRequestFullscreen || t.mozRequestFullScreen || t.msRequestFullscreen)?.call(t);
439
+ const t = this.container;
440
+ (t.requestFullscreen ?? t.webkitRequestFullscreen)?.call(t);
420
441
  }
421
442
  exit() {
422
- const t = document, e = document.exitFullscreen || t.webkitExitFullscreen || t.mozCancelFullScreen || t.msExitFullscreen;
423
- this.isFullscreen() && e?.call(document);
443
+ if (!this.isFullscreen()) return;
444
+ const t = document;
445
+ (t.exitFullscreen ?? t.webkitExitFullscreen)?.call(document);
424
446
  }
425
447
  toggle() {
426
448
  this.isFullscreen() ? this.exit() : this.request();
427
449
  }
450
+ destroy() {
451
+ this.exit(), this.offs.forEach((t) => t());
452
+ }
428
453
  sync() {
429
454
  const t = this.isFullscreen();
430
- this.instance.$refs.container?.classList.toggle("glare-is-fullscreen", t);
431
- const e = this.instance.$refs.container?.querySelector(
432
- "[data-glare-fullscreen]"
455
+ this.container.classList.toggle("glare-is-fullscreen", t);
456
+ const s = c("[data-glare-fullscreen]", this.container);
457
+ if (!s) return;
458
+ const { dict: i } = this.glare;
459
+ N(
460
+ s,
461
+ t,
462
+ t ? i.FULL_SCREEN_EXIT : i.FULL_SCREEN,
463
+ t ? u.fullscreenExit : u.fullscreen
433
464
  );
434
- e && (e.innerHTML = t ? d.fullscreenExit : d.fullscreen, e.classList.toggle("is-active", t));
465
+ }
466
+ }
467
+ function X(e) {
468
+ if (typeof e != "object" || e === null) return !1;
469
+ const t = Object.getPrototypeOf(e);
470
+ return t === Object.prototype || t === null;
471
+ }
472
+ function R(...e) {
473
+ const t = {};
474
+ for (const s of e)
475
+ if (s)
476
+ for (const [i, r] of Object.entries(s)) {
477
+ if (r === void 0) continue;
478
+ const o = t[i];
479
+ t[i] = X(r) ? R(X(o) ? o : {}, r) : r;
480
+ }
481
+ return t;
482
+ }
483
+ function E(e, t, s) {
484
+ return Math.min(s, Math.max(t, e));
485
+ }
486
+ const T = 1, _ = 5, re = 1.01;
487
+ class oe {
488
+ constructor(t) {
489
+ this.target = t, this.scale = T, this.x = 0, this.y = 0;
490
+ }
491
+ get isZoomed() {
492
+ return this.scale > re;
493
+ }
494
+ get state() {
495
+ return { scale: this.scale, x: this.x, y: this.y };
496
+ }
497
+ /** Centre of the image in viewport coordinates, ignoring the current translation. */
498
+ center() {
499
+ const t = this.target.image();
500
+ if (!t) return null;
501
+ const s = t.getBoundingClientRect();
502
+ return { x: s.left + s.width / 2 - this.x, y: s.top + s.height / 2 - this.y };
503
+ }
504
+ apply(t, s, i, r = 0) {
505
+ const o = this.target.image();
506
+ if (!o) return;
507
+ this.scale = E(t, T, _);
508
+ const n = this.isZoomed ? this.bounded(s, i) : { x: 0, y: 0 };
509
+ this.x = n.x, this.y = n.y, o.style.transitionDuration = `${r}ms`, o.style.transform = `translate3d(${this.x}px, ${this.y}px, 0) scale(${this.scale})`, this.target.onChange(this.isZoomed);
510
+ }
511
+ toFit(t = 300) {
512
+ this.apply(T, 0, 0, t);
513
+ }
514
+ /** Zooms to the image's natural size (at least 1.5x), keeping `focus` under the pointer. */
515
+ toActual(t, s = 300) {
516
+ const i = this.target.image(), r = this.center();
517
+ if (!i || !r) return;
518
+ const o = i.naturalWidth / Math.max(i.offsetWidth, 1), n = E(Math.max(o, 1.5), T, _), a = t?.x ?? r.x, l = t?.y ?? r.y;
519
+ this.apply(n, (r.x - a) * (n - 1), (r.y - l) * (n - 1), s);
520
+ }
521
+ reset() {
522
+ const t = this.target.image();
523
+ t && (t.style.transform = "", t.style.transitionDuration = ""), this.scale = T, this.x = 0, this.y = 0, this.target.onChange(!1);
524
+ }
525
+ /** Keeps the scaled image from being dragged fully out of the stage. */
526
+ bounded(t, s) {
527
+ const i = this.target.image(), r = this.target.stage();
528
+ if (!i || !r) return { x: t, y: s };
529
+ const o = Math.max(0, (i.offsetWidth * this.scale - r.clientWidth) / 2), n = Math.max(0, (i.offsetHeight * this.scale - r.clientHeight) / 2);
530
+ return { x: E(t, -o, o), y: E(s, -n, n) };
531
+ }
532
+ }
533
+ const ne = 6, Y = 120, ae = 100, le = 0.5, ce = 80, he = 0.4, ue = "a, button, input, textarea, select, video, .glare-thumbs", G = (e, t) => Math.hypot(e.x - t.x, e.y - t.y), V = (e, t) => ({ x: (e.x + t.x) / 2, y: (e.y + t.y) / 2 }), I = (e) => ({ x: e.clientX, y: e.clientY });
534
+ class de {
535
+ constructor(t, s) {
536
+ this.stage = t, this.host = s, this.pointers = /* @__PURE__ */ new Map(), this.mode = "idle", this.moved = !1, this.start = [], this.startTime = 0, this.startZoom = { scale: 1, x: 0, y: 0 }, this.startMid = { x: 0, y: 0 }, this.startDistance = 0, this.offs = [
537
+ h(t, "pointerdown", (i) => this.onDown(i)),
538
+ h(window, "pointermove", (i) => this.onMove(i), { passive: !1 }),
539
+ h(window, "pointerup", (i) => this.onUp(i)),
540
+ h(window, "pointercancel", (i) => this.onUp(i))
541
+ ];
435
542
  }
436
543
  destroy() {
437
- this.isFullscreen() && this.exit(), this.cleanups.forEach((t) => t()), this.cleanups = [];
544
+ this.offs.forEach((t) => t()), this.pointers.clear();
545
+ }
546
+ /** Returns whether the last gesture moved, then clears the flag. */
547
+ consumeMoved() {
548
+ const t = this.moved;
549
+ return this.moved = !1, t;
550
+ }
551
+ onDown(t) {
552
+ t.pointerType === "mouse" && t.button !== 0 || t.target.closest(ue) || (this.pointers.set(t.pointerId, I(t)), this.pointers.size <= 2 && this.begin());
553
+ }
554
+ onMove(t) {
555
+ this.pointers.has(t.pointerId) && (this.pointers.set(t.pointerId, I(t)), this.move(t));
556
+ }
557
+ onUp(t) {
558
+ this.pointers.has(t.pointerId) && (this.pointers.delete(t.pointerId), this.pointers.size === 0 ? this.end(I(t)) : this.begin());
559
+ }
560
+ /** Anchors a new gesture on the currently pressed pointers. */
561
+ begin() {
562
+ this.mode === "swipe" && this.releaseStage();
563
+ const t = [...this.pointers.values()];
564
+ this.start = t, this.startTime = performance.now(), this.startZoom = this.host.zoom.state, this.mode = t.length >= 2 ? "pinch" : "idle", t.length >= 2 && (this.startDistance = G(t[0], t[1]), this.startMid = V(t[0], t[1]));
565
+ }
566
+ move(t) {
567
+ const s = [...this.pointers.values()];
568
+ if (!this.start.length || !s.length) return;
569
+ if (this.mode === "pinch" && s.length >= 2) {
570
+ t.preventDefault(), this.moved = !0, this.pinch(s[0], s[1]);
571
+ return;
572
+ }
573
+ const i = s[0].x - this.start[0].x, r = s[0].y - this.start[0].y;
574
+ if (!(!this.moved && Math.hypot(i, r) < ne)) {
575
+ if (this.moved = !0, this.mode === "idle" && (this.mode = this.host.zoom.isZoomed && this.host.canPan() ? "pan" : "swipe"), this.mode === "pan")
576
+ t.preventDefault(), this.host.zoom.apply(this.startZoom.scale, this.startZoom.x + i, this.startZoom.y + r);
577
+ else if (this.mode === "swipe") {
578
+ const o = this.host.touch.vertical !== !1;
579
+ if (!o && Math.abs(r) > Math.abs(i)) return;
580
+ t.preventDefault(), this.dragStage(i, o ? r : 0);
581
+ }
582
+ }
583
+ }
584
+ /** Scales around the pinch midpoint so the content under the fingers stays put. */
585
+ pinch(t, s) {
586
+ const { zoom: i } = this.host, r = V(t, s), o = i.center() ?? r, n = E(
587
+ this.startZoom.scale * G(t, s) / (this.startDistance || 1),
588
+ T,
589
+ _
590
+ ), a = (this.startMid.x - o.x - this.startZoom.x) / this.startZoom.scale, l = (this.startMid.y - o.y - this.startZoom.y) / this.startZoom.scale;
591
+ i.apply(n, r.x - o.x - n * a, r.y - o.y - n * l);
592
+ }
593
+ end(t) {
594
+ if (!this.start.length) return;
595
+ const s = Math.max(performance.now() - this.startTime, 1), i = t.x - this.start[0].x, r = t.y - this.start[0].y, o = { x: i / s, y: r / s };
596
+ if (this.mode === "swipe")
597
+ this.releaseStage(), this.finishSwipe(i, r, o);
598
+ else if (this.mode === "pan" && this.host.touch.momentum !== !1) {
599
+ const { zoom: n } = this.host;
600
+ n.apply(n.scale, n.x + o.x * Y, n.y + o.y * Y, 250);
601
+ }
602
+ this.mode = "idle", this.start = [], this.moved && setTimeout(() => this.moved = !1, 0);
603
+ }
604
+ /** Moves the whole stage with the finger and dims the backdrop on vertical drags. */
605
+ dragStage(t, s) {
606
+ this.stage.style.transitionDuration = "0ms", this.stage.style.transform = `translate3d(${t}px, ${s}px, 0)`;
607
+ const { bg: i } = this.host;
608
+ i && (i.style.transitionDuration = "0ms", i.style.opacity = String(E(1 - Math.abs(s) / 400, 0.35, 1)));
609
+ }
610
+ releaseStage() {
611
+ this.stage.style.transitionDuration = "", this.stage.style.transform = "";
612
+ const { bg: t } = this.host;
613
+ t && (t.style.transitionDuration = "", t.style.opacity = "");
614
+ }
615
+ /** A long or fast vertical swipe closes; a horizontal one navigates. */
616
+ finishSwipe(t, s, i) {
617
+ if (Math.abs(s) > Math.abs(t)) {
618
+ (Math.abs(s) > ae || Math.abs(i.y) > le) && this.host.close();
619
+ return;
620
+ }
621
+ (Math.abs(t) > ce || Math.abs(i.x) > he) && (t < 0 ? this.host.next() : this.host.prev());
438
622
  }
439
623
  }
440
- function P() {
441
- const r = window.location.hash.replace(/^#/, "");
442
- if (!r) return null;
443
- const t = r.match(/^(?:glare-)?(.+?)(?:-|\/)(\d+)$/);
624
+ const fe = /^(.+)-(\d+)$/;
625
+ function F(e = window.location.hash) {
626
+ const t = e.replace(/^#/, "").match(fe);
444
627
  return t ? { gallery: t[1], index: Math.max(0, parseInt(t[2], 10) - 1) } : null;
445
628
  }
446
- function Q(r, t) {
447
- return `${r}-${t + 1}`;
448
- }
449
- const F = class F {
450
- constructor(t, e) {
451
- this.cleanups = [], this.skipping = !1, this.instance = t, this.gallery = e || "gallery";
452
- }
453
- init() {
454
- this.cleanups.push(
455
- c(window, "hashchange", () => {
456
- if (this.skipping) return;
457
- const t = P();
458
- if (!t || t.gallery !== this.gallery) {
459
- this.instance.isActive && this.instance.close();
460
- return;
461
- }
462
- t.index !== this.instance.currIndex && this.instance.jumpTo(t.index);
463
- })
464
- ), this.update();
465
- }
466
- update(t = this.instance.currIndex) {
467
- if (!this.gallery) return;
468
- const e = Q(this.gallery, t);
469
- if (window.location.hash.replace(/^#/, "") === e) return;
470
- this.skipping = !0;
471
- const s = `${window.location.pathname}${window.location.search}#${e}`;
472
- window.history.replaceState(null, "", s), queueMicrotask(() => {
473
- this.skipping = !1;
474
- });
629
+ function K(e, t) {
630
+ return `${e}-${t + 1}`;
631
+ }
632
+ class pe {
633
+ constructor(t, s) {
634
+ this.glare = t, this.gallery = s, this.pushed = !1, this.off = h(window, "hashchange", () => this.onHashChange());
635
+ const i = K(s, t.currIndex);
636
+ Q() !== i && (window.history.pushState(null, "", `#${i}`), this.pushed = !0);
475
637
  }
476
- clear() {
477
- const t = P();
478
- if (t && t.gallery === this.gallery) {
479
- this.skipping = !0;
480
- const e = `${window.location.pathname}${window.location.search}`;
481
- window.history.replaceState(null, "", e), queueMicrotask(() => {
482
- this.skipping = !1;
483
- });
484
- }
638
+ update(t = this.glare.currIndex) {
639
+ const s = K(this.gallery, t);
640
+ Q() !== s && this.replace(`#${s}`);
485
641
  }
486
642
  destroy() {
487
- this.clear(), this.cleanups.forEach((t) => t()), this.cleanups = [];
643
+ this.off(), F()?.gallery === this.gallery && (this.pushed ? window.history.back() : this.replace(""));
488
644
  }
489
- };
490
- F.parse = P;
491
- let O = F;
492
- const H = /\.(avif|bmp|gif|jpe?g|png|svg|webp|ico)(\?.*)?$/i, Z = /\.(mp4|webm|ogg|ogv|mov|m4v)(\?.*)?$/i, J = /\.pdf(\?.*)?$/i;
493
- function tt(r, t) {
494
- return t || (r ? r.startsWith("#") || r.startsWith(".") ? "inline" : H.test(r) ? "image" : Z.test(r) ? "video" : J.test(r) || /^https?:\/\//i.test(r) || r.startsWith("//") || r.startsWith("/") ? "iframe" : "html" : "html");
495
- }
496
- function et(r, t) {
497
- if (!t) return null;
498
- for (const e of Object.values(t)) {
499
- const s = r.match(e.matcher);
500
- if (!s) continue;
501
- let i = r;
502
- if (typeof e.url == "function" ? i = e.url(s, r) : typeof e.url == "string" && (i = e.url.replace(/\$(\d+)/g, (o, a) => s[Number(a)] || "")), e.params) {
503
- const o = i.includes("?") ? "&" : "?";
504
- i += o + Y(e.params);
505
- }
506
- let n;
507
- return typeof e.thumb == "function" ? n = e.thumb(s, r) : typeof e.thumb == "string" && (n = e.thumb.replace(/\$(\d+)/g, (o, a) => s[Number(a)] || "")), {
508
- src: i,
509
- type: e.type || "iframe",
510
- thumb: n
511
- };
645
+ onHashChange() {
646
+ const t = F();
647
+ !t || t.gallery !== this.gallery ? (this.pushed = !1, this.glare.close()) : t.index !== this.glare.currIndex && this.glare.jumpTo(t.index);
648
+ }
649
+ replace(t) {
650
+ const { pathname: s, search: i } = window.location;
651
+ window.history.replaceState(null, "", `${s}${i}${t}`);
512
652
  }
513
- return null;
514
- }
515
- function B(r, t, e) {
516
- const s = typeof r == "string" ? { src: r } : { ...r };
517
- let i = s.src || "", n = s.type, o = s.thumb;
518
- s.html && !i && (n = "html", i = "");
519
- const a = i ? et(i, e.media) : null;
520
- a && (i = a.src || i, n = a.type || n, o = o || a.thumb), n || (s.content || s.html ? n = "html" : n = tt(i, e.defaultType)), n === "iframe" && H.test(i) && (n = "image"), n === "iframe" && Z.test(i) && (n = "video");
521
- const l = {
522
- ...s,
523
- index: t,
524
- src: i,
525
- type: n,
526
- thumb: o,
527
- caption: s.caption ?? s.title ?? "",
528
- isLoaded: !1,
529
- isComplete: !1,
530
- hasError: !1,
531
- canZoomIn: !1,
532
- canZoomOut: !1
533
- };
534
- return s.opts && (l.opts = L({}, e, s.opts)), l;
535
- }
536
- function st(r, t) {
537
- return r.map((e, s) => {
538
- const i = e.getAttribute("data-src") || e.getAttribute("data-glare-src") || e.getAttribute("href") || "", n = e.getAttribute("data-type") || e.getAttribute("data-glare-type") || void 0, o = e.getAttribute("data-caption") || e.getAttribute("data-glare-caption") || e.getAttribute("title") || "", a = e.getAttribute("data-thumb") || e.getAttribute("data-glare-thumb") || e.querySelector("img")?.getAttribute("src") || void 0, l = e.getAttribute("data-width") || void 0, u = e.getAttribute("data-height") || void 0, h = e.getAttribute("data-poster") || void 0, f = e.getAttribute("data-download-src") || e.getAttribute("data-glare-download") || void 0;
539
- let w;
540
- const C = e.getAttribute("data-html") || e.getAttribute("data-glare-html");
541
- return C && (w = C), B(
542
- {
543
- src: i,
544
- type: n,
545
- caption: o,
546
- thumb: a,
547
- width: l,
548
- height: u,
549
- poster: h,
550
- downloadSrc: f,
551
- html: w,
552
- alt: e.querySelector("img")?.getAttribute("alt") || o || "",
553
- $trigger: e
554
- },
555
- s,
556
- t
557
- );
558
- });
559
653
  }
560
- const it = `
561
- <div class="glare-share">
562
- <h4 class="glare-share-title">{{SHARE}}</h4>
563
- <p><a class="glare-share-link" href="{{url_facebook}}" target="_blank" rel="noopener">Facebook</a></p>
564
- <p><a class="glare-share-link" href="{{url_twitter}}" target="_blank" rel="noopener">X / Twitter</a></p>
565
- <p><a class="glare-share-link" href="{{url_pinterest}}" target="_blank" rel="noopener">Pinterest</a></p>
566
- <p><input class="glare-share-input" type="text" value="{{url_direct}}" readonly /></p>
567
- </div>
568
- `;
569
- class nt {
570
- constructor(t, e) {
571
- this.$overlay = null, this.cleanups = [], this.instance = t, this.opts = e === !0 ? {} : e;
654
+ const Q = () => window.location.hash.replace(/^#/, "");
655
+ class me {
656
+ constructor(t, s, i) {
657
+ this.glare = t, this.container = s, this.opts = i, this.overlay = null, this.off = null;
658
+ }
659
+ get isOpen() {
660
+ return this.overlay !== null;
572
661
  }
573
662
  open() {
574
- const t = this.instance.current;
575
- if (!t || !this.instance.$refs.container) return;
663
+ const { current: t, dict: s } = this.glare;
664
+ if (!t) return;
576
665
  this.close();
577
- const e = this.resolveUrl(t), s = encodeURIComponent(e), i = encodeURIComponent(t.thumb || t.src || e), n = encodeURIComponent(t.caption || ""), o = this.instance.opts.lang || "en", a = {
578
- ...this.instance.opts.i18n?.en || {},
579
- ...this.instance.opts.i18n?.[o] || {},
580
- url_direct: e,
581
- url_facebook: `https://www.facebook.com/sharer/sharer.php?u=${s}`,
582
- url_twitter: `https://twitter.com/intent/tweet?url=${s}&text=${n}`,
583
- url_pinterest: `https://pinterest.com/pin/create/button/?url=${s}&media=${i}&description=${n}`
584
- }, l = $(this.opts.tpl || it, a);
585
- this.$overlay = b("div", "glare-share-overlay", l), this.instance.$refs.container.appendChild(this.$overlay), this.$overlay.querySelector(".glare-share-input")?.select(), this.cleanups.push(
586
- c(this.$overlay, "click", (h) => {
587
- h.target === this.$overlay && this.close();
588
- })
589
- );
666
+ const i = this.resolveUrl(t), r = encodeURIComponent(i), o = encodeURIComponent(t.thumb || t.src || i), n = encodeURIComponent(O(t.caption)), a = y(this.opts.tpl ?? Lt, {
667
+ ...s,
668
+ url_direct: i,
669
+ url_facebook: `https://www.facebook.com/sharer/sharer.php?u=${r}`,
670
+ url_twitter: `https://twitter.com/intent/tweet?url=${r}&text=${n}`,
671
+ url_pinterest: `https://pinterest.com/pin/create/button/?url=${r}&media=${o}&description=${n}`
672
+ });
673
+ this.overlay = g("div", "glare-share-overlay", a), this.container.appendChild(this.overlay);
674
+ const l = c(".glare-share-input", this.overlay);
675
+ l?.select(), this.off = h(this.overlay, "click", (d) => {
676
+ const p = d.target;
677
+ p === this.overlay || p.closest("[data-glare-share-close]") ? this.close() : p.closest("[data-glare-share-copy]") && this.copy(i, l);
678
+ });
590
679
  }
591
680
  close() {
592
- this.cleanups.forEach((t) => t()), this.cleanups = [], this.$overlay?.remove(), this.$overlay = null;
593
- }
594
- resolveUrl(t) {
595
- return typeof this.opts.url == "function" ? this.opts.url(t) : typeof this.opts.url == "string" ? this.opts.url : t.src && /^https?:\/\//i.test(t.src) ? t.src : window.location.href;
681
+ if (!this.overlay) return;
682
+ const t = this.overlay.contains(document.activeElement);
683
+ if (this.off?.(), this.off = null, this.overlay.remove(), this.overlay = null, !t) return;
684
+ const s = c("[data-glare-share]", this.container);
685
+ s ? s.focus() : this.glare.focus();
596
686
  }
597
687
  destroy() {
598
688
  this.close();
599
689
  }
600
- }
601
- class rt {
602
- constructor(t, e) {
603
- this.timer = null, this.active = !1, this.instance = t, this.opts = e;
690
+ async copy(t, s) {
691
+ try {
692
+ await navigator.clipboard.writeText(t);
693
+ } catch {
694
+ s?.select(), document.execCommand("copy");
695
+ }
696
+ s?.select();
604
697
  }
605
- init() {
606
- this.opts.autoStart && this.start();
698
+ resolveUrl(t) {
699
+ const { url: s } = this.opts;
700
+ return typeof s == "function" ? s(t) : s || (/^https?:\/\//i.test(t.src) ? t.src : window.location.href);
701
+ }
702
+ }
703
+ class ge {
704
+ constructor(t, s, i) {
705
+ this.glare = t, this.container = s, this.opts = i, this.timer = null, this.active = !1, this.bar = c(".glare-progress", s), this.button = c("[data-glare-slideshow]", s), i.autoStart && this.start();
607
706
  }
608
707
  isActive() {
609
708
  return this.active;
610
709
  }
611
710
  start() {
612
- this.instance.group.length < 2 || (this.active = !0, this.instance.$refs.container?.classList.add("glare-is-slideshow"), this.updateButton(), this.queue());
711
+ this.glare.group.length < 2 || (this.active = !0, this.container.classList.add("glare-is-slideshow"), this.syncButton(), this.schedule());
613
712
  }
614
713
  stop() {
615
- this.active = !1, this.clear(), this.instance.$refs.container?.classList.remove("glare-is-slideshow"), this.updateButton();
714
+ this.active = !1, this.clearTimer(), this.setProgress(0, !0), this.container.classList.remove("glare-is-slideshow"), this.syncButton();
616
715
  }
617
716
  toggle() {
618
717
  this.active ? this.stop() : this.start();
619
718
  }
620
- queue() {
621
- this.clear(), this.active && (this.timer = setTimeout(() => {
622
- this.active && (this.instance.next(), this.queue());
623
- }, this.opts.speed || 3e3));
624
- }
625
- clear() {
626
- this.timer && (clearTimeout(this.timer), this.timer = null);
627
- }
628
- updateButton() {
629
- const t = this.instance.$refs.container?.querySelector(
630
- "[data-glare-slideshow]"
631
- );
632
- if (!t) return;
633
- const e = this.active ? this.getLabel("PLAY_STOP") : this.getLabel("PLAY_START");
634
- t.setAttribute("title", e), t.setAttribute("aria-label", e), t.innerHTML = this.active ? d.pause : d.play, t.classList.toggle("is-active", this.active);
635
- }
636
- getLabel(t) {
637
- const e = this.instance.opts.lang || "en";
638
- return {
639
- ...this.instance.opts.i18n?.en || {},
640
- ...this.instance.opts.i18n?.[e] || {}
641
- }[t] || t;
719
+ onIndexChange() {
720
+ this.active && this.schedule();
642
721
  }
643
722
  destroy() {
644
723
  this.stop();
645
724
  }
646
- }
647
- class ot {
648
- constructor(t, e) {
649
- this.isActive = !1, this.$container = null, this.$list = null, this.cleanups = [], this.instance = t, this.opts = e;
650
- }
651
- init() {
652
- if (this.instance.group.length < 2) return;
653
- const t = typeof this.opts.parentEl == "string" ? p(this.opts.parentEl) || this.instance.$refs.container : this.opts.parentEl || this.instance.$refs.container;
654
- if (t) {
655
- this.$container = b("div", `glare-thumbs glare-thumbs--${this.opts.axis || "y"}`), this.$list = b("div", "glare-thumbs-list"), this.$container.appendChild(this.$list);
656
- for (const e of this.instance.group) {
657
- const s = b("button", "glare-thumbs-item");
658
- if (s.type = "button", s.setAttribute("aria-label", `Go to slide ${e.index + 1}`), s.dataset.index = String(e.index), e.thumb || e.type === "image" && e.src) {
659
- const i = b("img");
660
- i.src = e.thumb || e.src, i.alt = e.alt || e.caption || "", i.loading = "lazy", s.appendChild(i);
661
- } else
662
- s.textContent = String(e.index + 1);
663
- this.$list.appendChild(s), this.cleanups.push(
664
- c(s, "click", () => {
665
- this.instance.jumpTo(e.index);
666
- })
667
- );
668
- }
669
- t.appendChild(this.$container), this.opts.autoStart && this.show(), this.focus(this.instance.currIndex);
670
- }
725
+ get speed() {
726
+ return this.opts.speed ?? z.speed;
671
727
  }
672
- show() {
673
- this.$container && (this.isActive = !0, this.$container.classList.add("glare-thumbs--active"), this.instance.$refs.container?.classList.add("glare-show-thumbs"));
728
+ get atEnd() {
729
+ return !this.glare.opts.loop && this.glare.currIndex === this.glare.group.length - 1;
674
730
  }
675
- hide() {
676
- this.$container && (this.isActive = !1, this.$container.classList.remove("glare-thumbs--active"), this.instance.$refs.container?.classList.remove("glare-show-thumbs"));
731
+ schedule() {
732
+ this.clearTimer(), this.setProgress(0), A() || (this.bar?.offsetWidth, this.setProgress(1)), this.timer = setTimeout(() => this.atEnd ? this.stop() : this.glare.next(), this.speed);
677
733
  }
678
- toggle() {
679
- this.isActive ? this.hide() : this.show();
734
+ clearTimer() {
735
+ this.timer && clearTimeout(this.timer), this.timer = null;
680
736
  }
681
- focus(t = this.instance.currIndex) {
682
- if (!this.$list) return;
683
- S(".glare-thumbs-item", this.$list).forEach((s) => {
684
- s.classList.toggle("is-active", Number(s.dataset.index) === t);
685
- }), this.$list.querySelector(".is-active")?.scrollIntoView({ block: "nearest", inline: "nearest", behavior: "smooth" });
737
+ setProgress(t, s = !1) {
738
+ this.bar && (this.bar.hidden = s, this.bar.style.transitionDuration = t ? `${this.speed}ms` : "0ms", this.bar.style.transform = `scaleX(${t})`);
686
739
  }
687
- destroy() {
688
- this.opts.hideOnClose !== !1 && this.hide(), this.cleanups.forEach((t) => t()), this.cleanups = [], this.$container?.remove(), this.$container = null, this.$list = null;
689
- }
690
- }
691
- class at {
692
- constructor(t, e) {
693
- this.cleanups = [], this.locked = !1, this.instance = t, this.mode = e;
694
- }
695
- init(t) {
696
- this.mode !== !1 && this.cleanups.push(
697
- c(
698
- t,
699
- "wheel",
700
- (e) => {
701
- const s = e;
702
- if (this.locked) return;
703
- const i = this.instance.current;
704
- i && (this.mode === "auto" && i.type !== "image" || i.type === "image" && this.instance.$refs.container?.classList.contains("glare-can-zoom-out") || (s.preventDefault(), this.locked = !0, s.deltaY > 0 ? this.instance.next() : this.instance.prev(), setTimeout(() => {
705
- this.locked = !1;
706
- }, 350)));
707
- },
708
- { passive: !1 }
709
- )
740
+ syncButton() {
741
+ if (!this.button) return;
742
+ const { dict: t } = this.glare;
743
+ N(
744
+ this.button,
745
+ this.active,
746
+ this.active ? t.PLAY_STOP : t.PLAY_START,
747
+ this.active ? u.pause : u.play
710
748
  );
711
749
  }
712
- destroy() {
713
- this.cleanups.forEach((t) => t()), this.cleanups = [];
714
- }
715
- }
716
- let lt = 0;
717
- const g = [];
718
- function ct(r) {
719
- return r ? typeof r == "string" ? p(r) || document.body : r : document.body;
720
- }
721
- const v = class v {
722
- constructor(t, e = {}, s = 0, i = "") {
723
- this.group = [], this.current = null, this.currIndex = 0, this.prevIndex = 0, this.isActive = !1, this.isClosing = !1, this.isAnimating = !1, this.isIdle = !1, this.$refs = {
724
- container: null,
725
- stage: null,
726
- bg: null,
727
- inner: null,
728
- caption: null,
729
- toolbar: null,
730
- infobar: null,
731
- navigation: null
732
- }, this.galleryName = "", this.cleanups = [], this.idleTimer = null, this.gestures = null, this.hash = null, this.wheel = null, this.share = null, this.zoom = { scale: 1, x: 0, y: 0, min: 1, max: 5 }, this.previouslyFocused = null, this.openedFrom = null, this.id = ++lt, this.galleryName = i;
733
- const n = L(
734
- {},
735
- T,
736
- e
737
- );
738
- W() && n.mobile ? this.opts = L(
739
- {},
740
- n,
741
- n.mobile
742
- ) : this.opts = n, t.length && t[0] instanceof HTMLElement ? this.group = st(t, this.opts) : this.group = t.map(
743
- (o, a) => B(o, a, this.opts)
744
- ), this.currIndex = x(s, 0, Math.max(0, this.group.length - 1));
750
+ }
751
+ class ye {
752
+ constructor(t, s, i) {
753
+ this.glare = t, this.container = s, this.opts = i, this.isActive = !1, this.offs = [], this.axis = i.axis === "y" ? "y" : "x", this.list = g("div", "glare-thumbs-list"), this.strip = g("div", `glare-thumbs glare-thumbs--${this.axis}`), this.strip.appendChild(this.list), this.build();
745
754
  }
746
- open(t = this.currIndex) {
747
- if (this.isActive) {
748
- this.jumpTo(t);
749
- return;
750
- }
751
- this.opts.closeExisting && v.close(!0), this.currIndex = x(t, 0, Math.max(0, this.group.length - 1)), this.current = this.group[this.currIndex] || null, this.openedFrom = this.current?.$trigger || null, this.previouslyFocused = document.activeElement, this.trigger("onInit"), this.build(), this.isActive = !0, g.push(this), this.opts.hideScrollbar && R(!0), this.trigger("onActivate"), this.trigger("beforeShow", this.current || void 0), A(() => {
752
- this.$refs.container?.classList.add("glare-is-open", "glare-is-animated"), this.loadSlide(this.currIndex, !0), this.bindEvents(), this.initModules(), this.opts.autoFocus && this.focus(), this.resetIdle();
753
- });
755
+ show() {
756
+ this.setActive(!0);
754
757
  }
755
- close(t, e) {
756
- if (!this.isActive || this.isClosing || this.trigger("beforeClose", this.current || void 0) === !1) return;
757
- this.isClosing = !0, this.SlideShow?.stop(), this.clearIdle();
758
- const s = this.$refs.container, i = e ?? (M() ? 0 : this.opts.animationDuration || 0);
759
- s?.classList.add("glare-is-closing"), s?.classList.remove("glare-is-open");
760
- const n = () => {
761
- this.teardown();
762
- };
763
- if (i > 0 && s) {
764
- const o = (a) => {
765
- a.target === s && (s.removeEventListener("transitionend", o), n());
766
- };
767
- s.addEventListener("transitionend", o), setTimeout(n, i + 50);
768
- } else
769
- n();
758
+ hide() {
759
+ this.setActive(!1);
770
760
  }
771
- next(t) {
772
- this.jumpTo(this.currIndex + 1, t);
761
+ toggle() {
762
+ this.setActive(!this.isActive);
773
763
  }
774
- previous(t) {
775
- this.jumpTo(this.currIndex - 1, t);
764
+ /** Highlights the thumbnail for `index` and scrolls it into view. */
765
+ focus(t = this.glare.currIndex) {
766
+ for (const s of $(".glare-thumbs-item", this.list))
767
+ s.classList.toggle("glare-is-active", Number(s.dataset.index) === t);
768
+ this.list.querySelector(".glare-is-active")?.scrollIntoView({ block: "nearest", inline: "nearest", behavior: "smooth" });
776
769
  }
777
- prev(t) {
778
- this.previous(t);
770
+ destroy() {
771
+ this.offs.forEach((t) => t()), this.offs = [], this.container.classList.remove(`glare-thumbs-axis-${this.axis}`), this.strip.remove();
779
772
  }
780
- jumpTo(t, e) {
781
- if (!this.isActive || this.isClosing) return;
782
- const s = this.group.length;
783
- if (!s) return;
784
- let i = t;
785
- if (this.opts.loop)
786
- i = (t % s + s) % s;
787
- else if (i = x(t, 0, s - 1), i === this.currIndex && t !== this.currIndex) return;
788
- i !== this.currIndex && (this.prevIndex = this.currIndex, this.currIndex = i, this.current = this.group[i], this.resetZoom(), this.loadSlide(i, !1, e), this.updateChrome(), this.Thumbs?.focus(i), this.hash?.update(i), this.trigger("onUpdate", this.current));
773
+ setActive(t) {
774
+ this.isActive = t, this.strip.classList.toggle("glare-thumbs--active", t), this.container.classList.toggle("glare-show-thumbs", t);
775
+ const s = c("[data-glare-thumbs]", this.container);
776
+ s?.classList.toggle("glare-is-active", t), s?.setAttribute("aria-expanded", String(t));
789
777
  }
790
- scaleToFit(t = 300) {
791
- this.animateZoom(1, 0, 0, t), this.$refs.container?.classList.remove("glare-can-zoom-out"), this.$refs.container?.classList.add("glare-can-zoom-in"), this.updateZoomButton();
778
+ build() {
779
+ const { group: t, dict: s } = this.glare;
780
+ if (t.length < 2) return;
781
+ this.container.classList.add(`glare-thumbs-axis-${this.axis}`);
782
+ for (const r of t) {
783
+ const o = g("button", "glare-thumbs-item");
784
+ o.type = "button", o.dataset.index = String(r.index), o.setAttribute("aria-label", y(s.GO_TO_SLIDE, { index: String(r.index + 1) }));
785
+ const n = r.thumb || (r.type === "image" ? r.src : "");
786
+ if (n) {
787
+ const a = g("img");
788
+ a.src = n, a.alt = r.alt || O(r.caption), a.loading = "lazy", o.appendChild(a);
789
+ } else
790
+ o.textContent = String(r.index + 1);
791
+ this.list.appendChild(o), this.offs.push(h(o, "click", () => this.glare.jumpTo(r.index)));
792
+ }
793
+ (_t(this.opts.parentEl, this.container) ?? this.container).appendChild(this.strip), this.opts.autoStart && this.show(), this.focus();
792
794
  }
793
- scaleToActual(t, e, s = 300) {
794
- const i = this.getImageWrap();
795
- if (!i) return;
796
- const n = E(i), o = t ?? n.left + n.width / 2, a = e ?? n.top + n.height / 2, l = Math.min(this.zoom.max, 2.5), u = (n.left + n.width / 2 - o) * (l - 1), h = (n.top + n.height / 2 - a) * (l - 1);
797
- this.animateZoom(l, u, h, s), this.$refs.container?.classList.add("glare-can-zoom-out"), this.$refs.container?.classList.remove("glare-can-zoom-in"), this.updateZoomButton();
795
+ }
796
+ const be = 40, ve = 150, xe = 16;
797
+ class we {
798
+ constructor(t, s) {
799
+ this.distance = 0, this.fired = !1, this.settle = null, this.off = h(
800
+ t,
801
+ "wheel",
802
+ (i) => {
803
+ const r = s.current();
804
+ !r || i.deltaY === 0 || s.mode === "auto" && r.type !== "image" || r.type === "image" && s.isZoomed() || (i.preventDefault(), this.restartSettle(), !this.fired && (this.distance += Ee(i, t), !(Math.abs(this.distance) < be) && (this.fired = !0, this.distance > 0 ? s.next() : s.prev())));
805
+ },
806
+ { passive: !1 }
807
+ );
798
808
  }
799
- update() {
800
- this.updateChrome(), this.positionContent();
809
+ destroy() {
810
+ this.settle && clearTimeout(this.settle), this.off();
801
811
  }
802
- focus() {
803
- this.$refs.container?.focus({ preventScroll: !0 });
812
+ restartSettle() {
813
+ this.settle && clearTimeout(this.settle), this.settle = setTimeout(() => {
814
+ this.distance = 0, this.fired = !1;
815
+ }, ve);
804
816
  }
805
- toggleControls(t) {
806
- const e = this.$refs.container;
807
- if (!e) return;
808
- const s = t === void 0 ? !e.classList.contains("glare-is-idle") : t;
809
- e.classList.toggle("glare-is-idle", s), this.isIdle = s;
810
- }
811
- getContentEl() {
812
- return this.current?.$content || null;
813
- }
814
- getImageWrap() {
815
- return this.current?.$slide?.querySelector(".glare-content");
816
- }
817
- getZoomState() {
818
- return { ...this.zoom };
819
- }
820
- applyZoom(t, e, s, i = !1) {
821
- this.animateZoom(t, e, s, i ? 250 : 0);
822
- const n = t > 1.01;
823
- this.$refs.container?.classList.toggle("glare-can-zoom-out", n), this.$refs.container?.classList.toggle("glare-can-zoom-in", !n), this.updateZoomButton();
824
- }
825
- onSwipe(t, e, s, i) {
826
- const n = this.$refs.stage;
827
- if (!n) return;
828
- if (!s) {
829
- if (m(n, {
830
- transform: `translate3d(${t}px, ${e}px, 0)`,
831
- transitionDuration: "0ms"
832
- }), this.$refs.bg) {
833
- const h = x(1 - Math.abs(e) / 400, 0.35, 1);
834
- m(this.$refs.bg, { opacity: String(h) });
835
- }
836
- return;
837
- }
838
- const o = Math.abs(t), a = Math.abs(e), l = i?.x || 0, u = i?.y || 0;
839
- if (m(n, { transitionDuration: "" }), this.$refs.bg && m(this.$refs.bg, { opacity: "" }), (a > 100 || Math.abs(u) > 0.5) && a > o) {
840
- this.close();
841
- return;
817
+ }
818
+ function Ee(e, t) {
819
+ return e.deltaMode === WheelEvent.DOM_DELTA_LINE ? e.deltaY * xe : e.deltaMode === WheelEvent.DOM_DELTA_PAGE ? e.deltaY * t.clientHeight : e.deltaY;
820
+ }
821
+ function Se(e, t) {
822
+ const s = A(), i = s ? !1 : t.animationEffect, r = s ? !1 : t.transitionEffect;
823
+ e.dataset.animation = i || "none", e.style.setProperty("--glare-duration", `${i ? t.animationDuration : 0}ms`), e.style.setProperty("--glare-transition-duration", `${r ? t.transitionDuration : 0}ms`);
824
+ }
825
+ function Te(e, t) {
826
+ const s = A() ? !1 : t.transitionEffect;
827
+ e.dataset.transition = s || "none";
828
+ }
829
+ function Le(e, t, s) {
830
+ const i = t.$image, r = t.$trigger;
831
+ if (e.dataset.animation !== "zoom" || !i || !r) return;
832
+ const o = r.getBoundingClientRect(), n = i.getBoundingClientRect(), a = Math.max(o.width / Math.max(n.width, 1), o.height / Math.max(n.height, 1)), l = o.left + o.width / 2 - (n.left + n.width / 2), d = o.top + o.height / 2 - (n.top + n.height / 2);
833
+ Object.assign(i.style, {
834
+ transform: `translate3d(${l}px, ${d}px, 0) scale(${a})`,
835
+ opacity: s.zoomOpacity ? "0.2" : "1",
836
+ transitionDuration: "0ms"
837
+ }), lt(() => {
838
+ Object.assign(i.style, { transform: "", opacity: "", transitionDuration: "" });
839
+ });
840
+ }
841
+ function ut(e) {
842
+ const t = R(nt, e);
843
+ return Ht() && t.mobile ? R(t, t.mobile) : t;
844
+ }
845
+ function C(e, t) {
846
+ return e ? e === !0 ? { ...t } : { ...t, ...e } : null;
847
+ }
848
+ const M = [], H = (e) => e.getAttribute("data-glare") ?? "";
849
+ function Ce(e) {
850
+ return typeof e == "string" ? $(e) : e instanceof HTMLElement ? [e] : Array.from(e);
851
+ }
852
+ function Me(e, t, s) {
853
+ const i = Ce(e), r = (a) => {
854
+ const l = H(a), d = l ? i.filter((p) => H(p) === l) : [a];
855
+ s(d, d.indexOf(a), l);
856
+ }, o = i.map(
857
+ (a) => h(a, "click", (l) => {
858
+ l.preventDefault(), r(a);
859
+ })
860
+ ), n = {
861
+ elements: i,
862
+ destroy() {
863
+ o.forEach((l) => l());
864
+ const a = M.indexOf(n);
865
+ a >= 0 && M.splice(a, 1);
842
866
  }
843
- (o > 80 || Math.abs(l) > 0.4) && (t < 0 ? this.next() : this.prev()), m(n, { transform: "" });
867
+ };
868
+ return M.push(n), ut(t).hash && Oe(i, r), n;
869
+ }
870
+ function $e() {
871
+ for (const e of [...M]) e.destroy();
872
+ }
873
+ function Oe(e, t) {
874
+ const s = F();
875
+ if (!s) return;
876
+ const r = e.filter((o) => H(o) === s.gallery)[s.index];
877
+ r && t(r);
878
+ }
879
+ class Ae {
880
+ constructor(t, s) {
881
+ this.seconds = t, this.onIdle = s, this.timer = null;
844
882
  }
845
- /* -------------------- private -------------------- */
846
- build() {
847
- const t = this.dict(), e = $(this.opts.baseTpl || "", t), i = b("div", "", e).firstElementChild;
848
- i.dataset.glareId = String(this.id), this.opts.baseClass && i.classList.add(this.opts.baseClass), this.opts.modal && i.classList.add("glare-is-modal"), this.$refs.container = i, this.$refs.bg = p(".glare-bg", i), this.$refs.inner = p(".glare-inner", i), this.$refs.stage = p(".glare-stage", i), this.$refs.caption = p(".glare-caption", i), this.$refs.toolbar = p(".glare-toolbar", i), this.$refs.infobar = p(".glare-infobar", i), this.$refs.navigation = p(".glare-navigation", i), this.buildToolbar(), this.updateChrome(), (!this.opts.arrows || this.group.length < 2) && this.$refs.navigation?.classList.add("glare-hidden"), (!this.opts.infobar || this.group.length < 2) && this.$refs.infobar?.classList.add("glare-hidden"), ct(this.opts.parentEl).appendChild(i);
883
+ reset() {
884
+ this.stop(), this.seconds && (this.timer = setTimeout(this.onIdle, this.seconds * 1e3));
849
885
  }
850
- buildToolbar() {
851
- const t = this.$refs.toolbar;
852
- if (!t) return;
853
- if (!(this.opts.toolbar === !0 || this.opts.toolbar === "auto")) {
854
- t.classList.add("glare-hidden");
855
- return;
856
- }
857
- const s = this.dict(), i = this.opts.buttons || [];
858
- t.innerHTML = "";
859
- for (const n of i) {
860
- if (n === "thumbs" && this.group.length < 2 || n === "slideshow" && this.group.length < 2) continue;
861
- const o = this.opts.btnTpl?.[n];
862
- o && t.insertAdjacentHTML("beforeend", $(o, s));
863
- }
886
+ stop() {
887
+ this.timer && clearTimeout(this.timer), this.timer = null;
864
888
  }
865
- initModules() {
866
- const t = this.opts.thumbs;
867
- if (t) {
868
- const s = t === !0 ? { ...T.thumbs } : t;
869
- this.Thumbs = new ot(this, s), this.Thumbs.init();
870
- }
871
- const e = this.opts.slideShow;
872
- if (e) {
873
- const s = e === !0 ? { ...T.slideShow } : e;
874
- this.SlideShow = new rt(this, s), this.SlideShow.init();
875
- }
876
- if (this.opts.fullScreen !== !1) {
877
- this.FullScreen = new K(this), this.FullScreen.init();
878
- const s = this.opts.fullScreen;
879
- s && typeof s == "object" && s.autoStart && this.FullScreen.request();
880
- }
881
- this.opts.share && (this.share = new nt(this, this.opts.share)), this.opts.hash && this.galleryName && (this.hash = new O(this, this.galleryName), this.hash.init()), this.opts.wheel !== !1 && this.$refs.stage && (this.wheel = new at(this, this.opts.wheel || "auto"), this.wheel.init(this.$refs.stage)), this.opts.touch !== !1 && this.$refs.stage && (this.gestures = new G(this), this.gestures.attach(this.$refs.stage));
882
- }
883
- bindEvents() {
884
- const t = this.$refs.container;
885
- t && (this.cleanups.push(
886
- c(t, "click", (e) => this.onClick(e)),
887
- c(t, "dblclick", (e) => this.onDblClick(e)),
888
- c(document, "keydown", (e) => this.onKeydown(e)),
889
- c(window, "resize", () => this.positionContent()),
890
- c(window, "orientationchange", () => this.positionContent()),
891
- c(document, "mousemove", () => this.resetIdle()),
892
- c(document, "touchstart", () => this.resetIdle(), { passive: !0 })
893
- ), this.opts.trapFocus && this.cleanups.push(
894
- c(t, "keydown", (e) => {
895
- const s = e;
896
- if (s.key !== "Tab") return;
897
- const i = S('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', t).filter((a) => !a.hasAttribute("disabled") && a.offsetParent !== null);
898
- if (!i.length) return;
899
- const n = i[0], o = i[i.length - 1];
900
- s.shiftKey && document.activeElement === n ? (s.preventDefault(), o.focus()) : !s.shiftKey && document.activeElement === o && (s.preventDefault(), n.focus());
901
- })
902
- ), this.opts.protect && this.cleanups.push(
903
- c(t, "contextmenu", (e) => {
904
- e.preventDefault();
905
- }),
906
- c(t, "dragstart", (e) => {
907
- e.target.tagName === "IMG" && e.preventDefault();
908
- })
909
- ));
910
- }
911
- onClick(t) {
912
- if (this.gestures?.wasMoved()) {
913
- this.gestures.resetMoved();
914
- return;
915
- }
916
- const e = t.target;
917
- if (e.closest("[data-glare-close]")) {
918
- this.close(t);
919
- return;
920
- }
921
- if (e.closest("[data-glare-next]")) {
922
- this.next();
923
- return;
924
- }
925
- if (e.closest("[data-glare-prev]")) {
926
- this.prev();
927
- return;
928
- }
929
- if (e.closest("[data-glare-zoom]")) {
930
- this.toggleZoom(t);
931
- return;
932
- }
933
- if (e.closest("[data-glare-slideshow]")) {
934
- this.SlideShow?.toggle();
935
- return;
936
- }
937
- if (e.closest("[data-glare-thumbs]")) {
938
- this.Thumbs?.toggle();
939
- return;
940
- }
941
- if (e.closest("[data-glare-fullscreen]")) {
942
- this.FullScreen?.toggle();
943
- return;
944
- }
945
- if (e.closest("[data-glare-share]")) {
946
- this.share?.open();
947
- return;
948
- }
949
- if (!e.closest("[data-glare-download]")) {
950
- if (e.closest(".glare-content") || e.closest(".glare-space")) {
951
- this.handleClickAction(this.opts.clickContent, t);
952
- return;
953
- }
954
- if (e.closest(".glare-slide")) {
955
- this.handleClickAction(this.opts.clickSlide, t);
889
+ }
890
+ const x = [], b = {
891
+ add(e) {
892
+ x.push(e);
893
+ },
894
+ remove(e) {
895
+ const t = x.indexOf(e);
896
+ t >= 0 && x.splice(t, 1);
897
+ },
898
+ top() {
899
+ return x[x.length - 1] ?? null;
900
+ },
901
+ get(e) {
902
+ return x.find((t) => t.id === e) ?? null;
903
+ },
904
+ all() {
905
+ return [...x];
906
+ },
907
+ get size() {
908
+ return x.length;
909
+ }
910
+ }, Ie = [
911
+ ["[data-glare-close]", (e) => e.close()],
912
+ ["[data-glare-next]", (e) => e.next()],
913
+ ["[data-glare-prev]", (e) => e.prev()],
914
+ ["[data-glare-zoom]", (e) => e.toggleZoom()],
915
+ ["[data-glare-slideshow]", (e) => e.slideshow?.toggle()],
916
+ ["[data-glare-thumbs]", (e) => e.thumbs?.toggle()],
917
+ ["[data-glare-fullscreen]", (e) => e.fullscreen?.toggle()],
918
+ ["[data-glare-share]", (e) => e.share?.open()]
919
+ ], De = ".glare-content", ke = ".glare-slide, .glare-stage", Re = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', _e = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]), Fe = 300;
920
+ function He(e, t, s) {
921
+ let i = null;
922
+ const r = () => {
923
+ i && clearTimeout(i), i = null;
924
+ }, o = [
925
+ h(t, "click", (n) => {
926
+ if (e.consumeGesture()) return;
927
+ const a = n.target, l = a.closest("[data-glare-more]");
928
+ if (l) {
929
+ const L = l.closest(".glare-toolbar"), Z = !L?.classList.contains("glare-toolbar--expanded");
930
+ L?.classList.toggle("glare-toolbar--expanded", Z), l.setAttribute("aria-expanded", String(Z));
956
931
  return;
957
932
  }
958
- (e.classList.contains("glare-bg") || e.classList.contains("glare-stage")) && this.handleClickAction(this.opts.clickOutside, t);
959
- }
960
- }
961
- onDblClick(t) {
962
- const e = t.target;
963
- e.closest(".glare-content") || e.closest(".glare-space") ? this.handleClickAction(this.opts.dblclickContent, t) : e.closest(".glare-slide") ? this.handleClickAction(this.opts.dblclickSlide, t) : this.handleClickAction(this.opts.dblclickOutside, t);
964
- }
965
- handleClickAction(t, e) {
966
- if (!t || !this.current) return;
967
- let s = t;
968
- switch (typeof t == "function" && (s = t(this.current, e)), s) {
969
- case "close":
970
- this.close(e);
971
- break;
972
- case "next":
973
- this.next();
974
- break;
975
- case "nextOrClose":
976
- this.currIndex === this.group.length - 1 && !this.opts.loop ? this.close(e) : this.next();
977
- break;
978
- case "toggleControls":
979
- this.toggleControls();
980
- break;
981
- case "zoom":
982
- this.toggleZoom(e);
983
- break;
984
- }
985
- }
986
- onKeydown(t) {
987
- if (!this.isActive || !this.opts.keyboard || this.opts.modal || g[g.length - 1] !== this) return;
988
- const e = t.target?.tagName;
989
- if (!(e === "INPUT" || e === "TEXTAREA" || e === "SELECT"))
990
- switch (t.key) {
991
- case "Escape":
992
- t.preventDefault(), this.close(t);
993
- break;
994
- case "ArrowRight":
995
- case "ArrowDown":
996
- t.preventDefault(), this.next();
997
- break;
998
- case "ArrowLeft":
999
- case "ArrowUp":
1000
- t.preventDefault(), this.prev();
1001
- break;
1002
- case " ":
1003
- case "Spacebar":
1004
- t.preventDefault(), this.SlideShow?.toggle();
1005
- break;
1006
- case "f":
1007
- case "F":
1008
- this.FullScreen?.toggle();
1009
- break;
933
+ ft(t);
934
+ const d = Ie.find(([L]) => a.closest(L));
935
+ if (d) return d[1](e);
936
+ if (a.closest(".glare-button")) return;
937
+ const p = D(e, a, "click");
938
+ if (p) {
939
+ if (!dt(e, D(e, a, "dblclick"), n))
940
+ return k(e, p, n);
941
+ r(), i = setTimeout(() => k(e, p, n), Fe);
1010
942
  }
1011
- }
1012
- loadSlide(t, e, s) {
1013
- const i = this.$refs.stage;
1014
- if (!i) return;
1015
- const n = this.group[t];
1016
- if (!n) return;
1017
- S(".glare-slide", i).forEach((a) => {
1018
- Number(a.dataset.index) !== t && (a.classList.add("glare-slide--out"), setTimeout(() => a.remove(), this.opts.transitionDuration || 366));
1019
- });
1020
- let o = i.querySelector(`.glare-slide[data-index="${t}"]`);
1021
- if (o || (o = b("div", `glare-slide${this.opts.slideClass ? ` ${this.opts.slideClass}` : ""}`), o.dataset.index = String(t), o.innerHTML = `
1022
- <div class="glare-space">
1023
- <div class="glare-content"></div>
1024
- </div>
1025
- `, i.appendChild(o)), n.$slide = o, n.$content = p(".glare-content", o), n.pos = t, o.classList.add("glare-slide--current"), o.classList.remove("glare-slide--out"), this.shouldSmallBtn(n)) {
1026
- const a = this.dict();
1027
- o.querySelector(".glare-close-small") || o.insertAdjacentHTML(
1028
- "beforeend",
1029
- $(this.opts.btnTpl?.smallBtn || "", a)
1030
- );
943
+ }),
944
+ h(t, "dblclick", (n) => {
945
+ r();
946
+ const a = n.target;
947
+ a.closest(".glare-button") || k(e, D(e, a, "dblclick"), n);
948
+ }),
949
+ h(document, "keydown", (n) => Pe(e, n)),
950
+ h(document, "keydown", s),
951
+ h(document, "mousemove", s),
952
+ h(document, "touchstart", s, { passive: !0 })
953
+ ];
954
+ return e.opts.trapFocus && o.push(h(t, "keydown", (n) => ze(t, n))), e.opts.protect && o.push(
955
+ h(t, "contextmenu", (n) => n.preventDefault()),
956
+ h(t, "dragstart", (n) => {
957
+ n.target.tagName === "IMG" && n.preventDefault();
958
+ })
959
+ ), () => {
960
+ r(), o.forEach((n) => n());
961
+ };
962
+ }
963
+ function D(e, t, s) {
964
+ const { opts: i } = e;
965
+ if (t.closest(De)) return s === "click" ? i.clickContent : i.dblclickContent;
966
+ if (!(i.modal || !t.closest(ke)))
967
+ return s === "click" ? i.clickSlide : i.dblclickSlide;
968
+ }
969
+ function dt(e, t, s) {
970
+ return !t || !e.current ? !1 : typeof t == "function" ? t(e.current, s) : t;
971
+ }
972
+ function k(e, t, s) {
973
+ switch (dt(e, t, s)) {
974
+ case "close":
975
+ return e.close();
976
+ case "next":
977
+ return e.next();
978
+ case "nextOrClose":
979
+ return e.currIndex === e.group.length - 1 && !e.opts.loop ? e.close() : e.next();
980
+ case "toggleControls":
981
+ return e.toggleControls();
982
+ case "zoom": {
983
+ const i = s instanceof MouseEvent ? { x: s.clientX, y: s.clientY } : void 0;
984
+ return e.toggleZoom(i);
1031
985
  }
1032
- this.showSpinner(o), this.trigger("beforeLoad", n), this.resolveContent(n).then(() => {
1033
- !this.isActive || this.currIndex !== t || (this.hideSpinner(o), this.trigger("afterLoad", n), this.positionContent(), this.updateChrome(), this.updateDownload(n), e ? this.playOpenAnimation(n) : this.playTransition(), this.trigger("afterShow", n), this.trigger("onReveal", n));
1034
- }).catch(() => {
1035
- !this.isActive || this.currIndex !== t || (this.hideSpinner(o), this.showError(n));
1036
- }), this.opts.image?.preload && [t - 1, t + 1].forEach((a) => {
1037
- const l = this.group[a];
1038
- if (l?.type === "image" && l.src) {
1039
- const u = new Image();
1040
- u.src = l.src;
1041
- }
1042
- });
1043
986
  }
1044
- shouldSmallBtn(t) {
1045
- return this.opts.smallBtn === !0 ? !0 : this.opts.smallBtn === !1 ? !1 : t.type !== "image";
1046
- }
1047
- async resolveContent(t) {
1048
- const e = t.$content;
1049
- if (!e) throw new Error("Missing content node");
1050
- switch (e.innerHTML = "", e.className = `glare-content glare-content--${t.type}`, t.type) {
1051
- case "image":
1052
- await this.loadImage(t, e);
1053
- break;
1054
- case "video":
1055
- this.loadVideo(t, e);
1056
- break;
1057
- case "iframe":
1058
- await this.loadIframe(t, e);
1059
- break;
1060
- case "inline":
1061
- this.loadInline(t, e);
1062
- break;
1063
- case "ajax":
1064
- await this.loadAjax(t, e);
1065
- break;
1066
- default:
1067
- this.loadHtml(t, e);
1068
- break;
987
+ }
988
+ function Pe(e, t) {
989
+ if (b.top() !== e) return;
990
+ if (t.key === "Escape" && ft(e.$refs?.container ?? null)) {
991
+ t.preventDefault();
992
+ return;
993
+ }
994
+ if (t.key === "Escape" && e.share?.isOpen)
995
+ return t.preventDefault(), e.share.close();
996
+ if (!e.opts.keyboard || e.opts.modal) return;
997
+ const s = t.target;
998
+ if (!_e.has(s.tagName) && !(t.key === " " && s.closest("button")))
999
+ switch (t.key) {
1000
+ case "Escape":
1001
+ return t.preventDefault(), e.close();
1002
+ case "ArrowRight":
1003
+ case "ArrowDown":
1004
+ return t.preventDefault(), e.next();
1005
+ case "ArrowLeft":
1006
+ case "ArrowUp":
1007
+ return t.preventDefault(), e.prev();
1008
+ case " ":
1009
+ return t.preventDefault(), e.slideshow?.toggle();
1010
+ case "f":
1011
+ case "F":
1012
+ return e.fullscreen?.toggle();
1069
1013
  }
1070
- t.isLoaded = !0, t.isComplete = !0;
1071
- }
1072
- loadImage(t, e) {
1073
- return new Promise((s, i) => {
1074
- const n = b("img", "glare-image");
1075
- n.alt = t.alt || t.caption || "", n.decoding = "async", n.draggable = !1, this.opts.protect && (n.style.pointerEvents = "none"), n.onload = () => {
1076
- t.$image = n, t.contentWidth = n.naturalWidth, t.contentHeight = n.naturalHeight, t.canZoomIn = !0, e.appendChild(n), this.$refs.container?.classList.add("glare-can-zoom-in"), s();
1077
- }, n.onerror = () => {
1078
- t.hasError = !0, i(new Error("image error"));
1079
- }, n.src = t.src;
1080
- });
1014
+ }
1015
+ function ft(e) {
1016
+ const t = e?.querySelector(".glare-toolbar--expanded");
1017
+ return t ? (t.classList.remove("glare-toolbar--expanded"), t.querySelector("[data-glare-more]")?.setAttribute("aria-expanded", "false"), !0) : !1;
1018
+ }
1019
+ function ze(e, t) {
1020
+ if (t.key !== "Tab") return;
1021
+ const s = $(Re, e).filter(
1022
+ (o) => !o.hasAttribute("disabled") && o.offsetParent !== null && getComputedStyle(o).visibility !== "hidden"
1023
+ );
1024
+ if (!s.length) return;
1025
+ const i = s[0], r = s[s.length - 1];
1026
+ t.shiftKey && document.activeElement === i ? (t.preventDefault(), r.focus()) : !t.shiftKey && document.activeElement === r && (t.preventDefault(), i.focus());
1027
+ }
1028
+ const Ne = 1200, J = 16 / 9;
1029
+ function Ze(e, t, s) {
1030
+ if (t && s) return t / s;
1031
+ const i = String(e.ratio || J).replace(":", "/"), [r, o = "1"] = i.split("/").map((l) => l.trim()), n = parseFloat(r), a = parseFloat(o);
1032
+ return n > 0 && a > 0 ? n / a : J;
1033
+ }
1034
+ function tt(e, t, s) {
1035
+ if (!e) return 0;
1036
+ if (typeof e == "number") return e;
1037
+ const i = e.trim(), r = parseFloat(i);
1038
+ return r > 0 ? i.endsWith("%") ? t * r / 100 : i.endsWith("vw") || i.endsWith("vh") ? s * r / 100 : r : 0;
1039
+ }
1040
+ function et(e, t) {
1041
+ const s = t.parentElement;
1042
+ if (!s) return;
1043
+ const i = getComputedStyle(s), r = s.clientWidth - parseFloat(i.paddingLeft) - parseFloat(i.paddingRight), o = s.clientHeight - parseFloat(i.paddingTop) - parseFloat(i.paddingBottom);
1044
+ if (!(r > 0 && o > 0)) return;
1045
+ const n = e.width !== void 0 && e.height !== void 0;
1046
+ let a = n ? tt(e.width, r, innerWidth) : r, l = n ? tt(e.height, o, innerHeight) : o;
1047
+ const d = Ze(e, n ? a : void 0, n ? l : void 0), p = Math.min(1, r / a, o / l);
1048
+ a *= p, l *= p, l > a / d ? l = a / d : a > l * d && (a = l * d), t.style.width = `${a}px`, t.style.height = `${l}px`, t.style.aspectRatio = String(d);
1049
+ }
1050
+ function qe(e, t) {
1051
+ if (et(e, t), typeof ResizeObserver > "u" || !t.parentElement) return;
1052
+ const s = new ResizeObserver(() => {
1053
+ if (!t.isConnected) return s.disconnect();
1054
+ et(e, t);
1055
+ });
1056
+ s.observe(t.parentElement);
1057
+ }
1058
+ const Ue = (e, t, s) => new Promise((i, r) => {
1059
+ const o = g("img", "glare-image");
1060
+ o.alt = e.alt || O(e.caption), o.decoding = "async", o.draggable = !1, s.protect && (o.style.pointerEvents = "none"), o.onload = () => {
1061
+ e.$image = o, e.contentWidth = o.naturalWidth, e.contentHeight = o.naturalHeight, t.appendChild(o), i();
1062
+ }, o.onerror = () => r(new Error(`Failed to load image: ${e.src}`)), o.src = e.src;
1063
+ }), Be = (e, t, s, i) => {
1064
+ const r = e.format || s.video.format || It(e.src);
1065
+ t.innerHTML = y(s.video.tpl, {
1066
+ ...i,
1067
+ src: e.src,
1068
+ format: r,
1069
+ poster: e.poster ?? ""
1070
+ });
1071
+ const o = t.querySelector("video");
1072
+ o && (e.autoStart ?? s.video.autoStart) && o.play().catch(() => {
1073
+ });
1074
+ }, st = (e, t, s) => new Promise((i) => {
1075
+ const r = s.iframe, o = g("div", "glare-iframe-wrap", r.tpl), n = o.querySelector("iframe");
1076
+ if (!n) throw new Error("Iframe template must contain an <iframe>");
1077
+ for (const [a, l] of Object.entries(r.attr)) n.setAttribute(a, l);
1078
+ if (Object.assign(n.style, r.css), t.appendChild(o), e.type === "embed" ? qe(e, t) : (e.width && (o.style.width = U(e.width)), e.height && (o.style.height = U(e.height))), !r.preload) {
1079
+ n.src = e.src, i();
1080
+ return;
1081
+ }
1082
+ n.onload = () => i(), n.src = e.src, setTimeout(i, Ne);
1083
+ }), We = (e, t) => {
1084
+ const s = e.src ? c(e.src) : null;
1085
+ if (!s) throw new Error(`Inline target not found: ${e.src}`);
1086
+ const i = s.cloneNode(!0);
1087
+ i.removeAttribute("id"), i.hidden = !1, i.style.display = "", t.appendChild(i);
1088
+ }, je = async (e, t, s) => {
1089
+ const i = await fetch(e.src, s.ajax.settings);
1090
+ if (!i.ok) throw new Error(`Request failed: ${i.status} ${e.src}`);
1091
+ t.innerHTML = await i.text();
1092
+ }, Xe = (e, t) => {
1093
+ e.content instanceof HTMLElement ? t.appendChild(e.content) : t.innerHTML = e.html ?? e.content ?? e.src;
1094
+ }, Ye = { image: Ue, video: Be, embed: st, iframe: st, inline: We, ajax: je, html: Xe };
1095
+ async function Ge(e, t, s, i) {
1096
+ t.innerHTML = "", t.className = `glare-content glare-content--${e.type}`, await Ye[e.type](e, t, s, i), e.isLoaded = !0;
1097
+ }
1098
+ function Ve(e, t) {
1099
+ for (const s of [e[t - 1], e[t + 1]])
1100
+ s?.type === "image" && s.src && (new Image().src = s.src);
1101
+ }
1102
+ let Ke = 0;
1103
+ const w = class w {
1104
+ constructor(t, s = {}, i = 0, r = "") {
1105
+ this.id = ++Ke, this.current = null, this.currIndex = 0, this.prevIndex = 0, this.isActive = !1, this.isClosing = !1, this.isIdle = !1, this.$refs = null, this.hash = null, this.gestures = null, this.wheel = null, this.cleanups = [], this.previouslyFocused = null, this.opts = ut(s), this.dict = pt(this.opts), this.group = kt(t, this.opts), this.galleryName = r, this.currIndex = this.clampIndex(i), this.zoom = new oe({
1106
+ image: () => this.current?.$image ?? null,
1107
+ stage: () => this.$refs?.stage ?? null,
1108
+ onChange: (o) => this.syncZoomState(o)
1109
+ }), this.idle = new Ae(this.opts.modal ? !1 : this.opts.idleTime, () => this.toggleControls(!0));
1081
1110
  }
1082
- loadVideo(t, e) {
1083
- const s = t.format || this.opts.video?.format || (t.src.match(/\.(\w+)(?:\?|$)/)?.[1] ? `video/${t.src.match(/\.(\w+)(?:\?|$)/)?.[1]?.replace("ogv", "ogg")}` : "video/mp4"), i = $(this.opts.video?.tpl || "", {
1084
- src: t.src,
1085
- format: s,
1086
- poster: t.poster || ""
1087
- });
1088
- e.innerHTML = i;
1089
- const n = e.querySelector("video");
1090
- t.$content = e, n && (t.autoStart ?? this.opts.video?.autoStart) && n.play().catch(() => {
1111
+ open(t = this.currIndex) {
1112
+ if (this.isActive) return this.jumpTo(t);
1113
+ if (!this.group.length) return;
1114
+ this.opts.closeExisting && w.close(!0), this.currIndex = this.clampIndex(t), this.current = this.group[this.currIndex], this.previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null, this.emit("onInit");
1115
+ const s = Pt(this.opts, this.dict, this.id, this.group.length), { container: i } = s;
1116
+ this.$refs = s, Se(i, this.opts), this.syncChrome(), this.resolveParent().appendChild(i), this.isActive = !0, b.add(this), this.opts.hideScrollbar && W(!0), this.emit("onActivate"), this.emitSlide("beforeShow", this.current), lt(() => {
1117
+ this.isActive && (i.classList.add("glare-is-open"), this.showSlide(this.currIndex, !0), this.cleanups.push(He(this, i, () => this.onActivity())), this.startModules(s), this.opts.autoFocus && this.focus(), this.idle.reset());
1091
1118
  });
1092
1119
  }
1093
- loadIframe(t, e) {
1094
- return new Promise((s) => {
1095
- const i = b("div", "glare-iframe-wrap");
1096
- i.innerHTML = this.opts.iframe?.tpl || '<iframe class="glare-iframe"></iframe>';
1097
- const n = i.querySelector("iframe"), o = this.opts.iframe?.attr || {};
1098
- for (const [a, l] of Object.entries(o)) n.setAttribute(a, l);
1099
- if (this.opts.iframe?.css && m(n, this.opts.iframe.css), t.width && m(i, { width: typeof t.width == "number" ? `${t.width}px` : String(t.width) }), t.height && m(i, { height: typeof t.height == "number" ? `${t.height}px` : String(t.height) }), e.appendChild(i), this.opts.iframe?.preload === !1) {
1100
- n.src = t.src, s();
1101
- return;
1102
- }
1103
- n.onload = () => s(), n.src = t.src, setTimeout(() => s(), 1200);
1104
- });
1120
+ close() {
1121
+ if (!this.isActive || this.isClosing || !this.current || !this.$refs || this.emitSlide("beforeClose", this.current) === !1) return;
1122
+ this.isClosing = !0, this.slideshow?.stop(), this.idle.stop();
1123
+ const { container: t, bg: s } = this.$refs, i = A() ? 0 : this.opts.animationDuration;
1124
+ if (i === 0) return this.teardown();
1125
+ t.classList.remove("glare-is-open"), t.classList.add("glare-is-closing"), Ft(s ?? t, i, () => this.teardown());
1105
1126
  }
1106
- loadInline(t, e) {
1107
- const s = t.src ? p(t.src) : null;
1108
- if (!s)
1109
- throw t.hasError = !0, new Error("inline target missing");
1110
- const i = s.cloneNode(!0);
1111
- i.id = "", i.classList.remove("glare-hidden"), i.hidden = !1, i.style.display = "", e.appendChild(i);
1112
- }
1113
- async loadAjax(t, e) {
1114
- const s = this.opts.ajax?.settings || {}, i = await fetch(t.src, s);
1115
- if (!i.ok) throw new Error("ajax failed");
1116
- const n = await i.text();
1117
- e.innerHTML = n;
1118
- }
1119
- loadHtml(t, e) {
1120
- t.content instanceof HTMLElement ? e.appendChild(t.content) : e.innerHTML = t.html || t.content || t.src || "";
1121
- }
1122
- showSpinner(t) {
1123
- t.querySelector(".glare-spinner") || t.insertAdjacentHTML("beforeend", this.opts.spinnerTpl || "");
1124
- }
1125
- hideSpinner(t) {
1126
- t.querySelector(".glare-spinner")?.remove();
1127
- }
1128
- showError(t) {
1129
- t.hasError = !0;
1130
- const e = t.$content;
1131
- e && (e.className = "glare-content glare-content--error", e.innerHTML = $(this.opts.errorTpl || "", this.dict()));
1132
- }
1133
- playOpenAnimation(t) {
1134
- const e = this.$refs.container;
1135
- if (!e) return;
1136
- const s = M() ? !1 : this.opts.animationEffect;
1137
- if (e.dataset.animation = s ? String(s) : "none", e.style.setProperty("--glare-duration", `${this.opts.animationDuration || 0}ms`), s === "zoom" && t.$trigger && t.type === "image" && t.$image) {
1138
- const i = E(t.$trigger), n = E(t.$image), o = i.width / Math.max(n.width, 1), a = i.height / Math.max(n.height, 1), l = i.left + i.width / 2 - (n.left + n.width / 2), u = i.top + i.height / 2 - (n.top + n.height / 2);
1139
- m(t.$image, {
1140
- transform: `translate3d(${l}px, ${u}px, 0) scale(${Math.max(o, a)})`,
1141
- opacity: this.opts.zoomOpacity === !1 ? "1" : "0.2",
1142
- transitionDuration: "0ms"
1143
- }), A(() => {
1144
- t.$image && m(t.$image, {
1145
- transform: "",
1146
- opacity: "",
1147
- transitionDuration: `${this.opts.animationDuration || 366}ms`
1148
- });
1149
- });
1150
- }
1151
- A(() => e.classList.add("glare-is-ready"));
1127
+ next() {
1128
+ this.jumpTo(this.currIndex + 1);
1152
1129
  }
1153
- playTransition() {
1154
- const t = this.$refs.container;
1155
- if (!t) return;
1156
- const e = M() ? !1 : this.opts.transitionEffect;
1157
- t.dataset.transition = e ? String(e) : "none", t.style.setProperty(
1158
- "--glare-transition-duration",
1159
- `${this.opts.transitionDuration || 0}ms`
1160
- );
1130
+ prev() {
1131
+ this.jumpTo(this.currIndex - 1);
1161
1132
  }
1162
- positionContent() {
1163
- const t = this.current;
1164
- if (!t?.$image || !t.contentWidth || !t.contentHeight) return;
1165
- const e = t.$slide;
1166
- if (!e) return;
1167
- const s = p(".glare-space", e);
1168
- if (!s) return;
1169
- const i = E(s), n = Math.min(i.width / t.contentWidth, i.height / t.contentHeight, 1);
1170
- t.canZoomIn = n < 0.98 || t.contentWidth > i.width || t.contentHeight > i.height, this.$refs.container?.classList.toggle("glare-can-zoom-in", !!t.canZoomIn && this.zoom.scale <= 1.01);
1133
+ jumpTo(t) {
1134
+ if (!this.isActive || this.isClosing) return;
1135
+ const s = this.group.length, i = this.opts.loop ? (t % s + s) % s : E(t, 0, s - 1);
1136
+ i !== this.currIndex && (this.prevIndex = this.currIndex, this.currIndex = i, this.zoom.reset(), this.current = this.group[i], this.syncChrome(), this.showSlide(i, !1), this.thumbs?.focus(i), this.hash?.update(i), this.slideshow?.onIndexChange(), this.emitSlide("onUpdate", this.current));
1171
1137
  }
1172
- updateChrome() {
1173
- const t = this.current;
1174
- if (!t) return;
1175
- if (this.$refs.infobar) {
1176
- const i = p(".glare-infobar-index", this.$refs.infobar);
1177
- i && (i.textContent = `${this.currIndex + 1} / ${this.group.length}`);
1178
- }
1179
- if (this.$refs.caption) {
1180
- let i = t.caption || "";
1181
- typeof this.opts.caption == "function" ? i = this.opts.caption(this, t) : typeof this.opts.caption == "string" && (i = this.opts.caption), this.$refs.caption.innerHTML = i, this.$refs.caption.classList.toggle("glare-hidden", !i), this.$refs.container?.classList.toggle("glare-show-caption", !!i);
1182
- }
1183
- const e = this.currIndex === 0 && !this.opts.loop, s = this.currIndex === this.group.length - 1 && !this.opts.loop;
1184
- this.$refs.container?.querySelector("[data-glare-prev]")?.classList.toggle("glare-disabled", e), this.$refs.container?.querySelector("[data-glare-next]")?.classList.toggle("glare-disabled", s), this.$refs.container?.setAttribute("aria-label", ut(t, this.currIndex, this.group.length));
1138
+ toggleZoom(t) {
1139
+ this.current?.type === "image" && (this.zoom.isZoomed ? this.zoom.toFit() : this.zoom.toActual(t));
1185
1140
  }
1186
- updateDownload(t) {
1187
- const e = this.$refs.container?.querySelector("[data-glare-download]");
1188
- if (!e) return;
1189
- const s = t.downloadSrc || (t.type === "image" ? t.src : "");
1190
- s ? (e.href = s, e.classList.remove("glare-hidden")) : e.classList.add("glare-hidden");
1141
+ update() {
1142
+ this.syncChrome();
1191
1143
  }
1192
- toggleZoom(t) {
1193
- if (!(!this.current || this.current.type !== "image"))
1194
- if (this.zoom.scale > 1.01)
1195
- this.scaleToFit();
1196
- else {
1197
- const e = t ? { x: t.clientX, y: t.clientY } : void 0;
1198
- this.scaleToActual(e?.x, e?.y);
1199
- }
1144
+ focus() {
1145
+ this.$refs?.container.focus({ preventScroll: !0 });
1200
1146
  }
1201
- animateZoom(t, e, s, i = 0) {
1202
- const n = this.getImageWrap(), o = this.current?.$image;
1203
- !n || !o || (this.zoom.scale = x(t, this.zoom.min, this.zoom.max), this.zoom.x = e, this.zoom.y = s, m(o, {
1204
- transform: `translate3d(${e}px, ${s}px, 0) scale(${this.zoom.scale})`,
1205
- transitionDuration: `${i}ms`
1147
+ toggleControls(t) {
1148
+ this.$refs && (this.isIdle = t ?? !this.isIdle, this.$refs.container.classList.toggle("glare-is-idle", this.isIdle));
1149
+ }
1150
+ /** True once per drag gesture, so the click that follows it can be ignored. */
1151
+ consumeGesture() {
1152
+ return this.gestures?.consumeMoved() ?? !1;
1153
+ }
1154
+ async showSlide(t, s) {
1155
+ const i = this.group[t];
1156
+ if (!this.$refs || !i) return;
1157
+ const { container: r, stage: o } = this.$refs, n = Nt(o, i, this.opts);
1158
+ Xt(this.opts, i) && Ut(n, this.opts, this.dict), Bt(o, this.opts, this.dict), this.emitSlide("beforeLoad", i), this.opts.image.preload && Ve(this.group, t);
1159
+ let a = !1;
1160
+ try {
1161
+ await Ge(i, i.$content, this.opts, this.dict);
1162
+ } catch (l) {
1163
+ a = !0, jt(i, l, this.opts, this.dict), this.emitSlide("onError", i), this.opts.onError || console.warn("[glare]", l);
1164
+ }
1165
+ if (!this.isActive || this.currIndex !== t) return n.remove();
1166
+ a || this.emitSlide("afterLoad", i), Wt(o), s || Te(r, this.opts), Zt(n, s), qt(o, n, this.opts.transitionDuration), this.syncZoomState(this.zoom.isZoomed), !a && (s && Le(r, i, this.opts), this.emitSlide("afterShow", i));
1167
+ }
1168
+ syncChrome() {
1169
+ !this.$refs || !this.current || (Yt(this.$refs, this.opts, this.dict, this.current, this.group.length, this.captionFor(this.current)), this.syncZoomState(this.zoom.isZoomed));
1170
+ }
1171
+ captionFor(t) {
1172
+ const { caption: s } = this.opts;
1173
+ return typeof s == "function" ? s(this, t) : s ?? t.caption;
1174
+ }
1175
+ syncZoomState(t) {
1176
+ this.$refs && se(this.$refs.container, this.dict, t, !!this.current?.$image);
1177
+ }
1178
+ resolveParent() {
1179
+ const { parentEl: t } = this.opts;
1180
+ return (typeof t == "string" ? document.querySelector(t) : t) ?? document.body;
1181
+ }
1182
+ startModules({ container: t, stage: s, bg: i }) {
1183
+ const r = this.opts, o = C(r.thumbs, rt);
1184
+ o && (this.thumbs = new ye(this, t, o));
1185
+ const n = C(r.slideshow, z);
1186
+ n && (this.slideshow = new ge(this, t, n));
1187
+ const a = C(r.fullscreen, ot);
1188
+ a && ct() && (this.fullscreen = new ie(this, t, a));
1189
+ const l = C(r.share, {});
1190
+ l && (this.share = new me(this, t, l)), r.hash && this.galleryName && (this.hash = new pe(this, this.galleryName)), r.wheel && (this.wheel = new we(s, {
1191
+ mode: r.wheel,
1192
+ current: () => this.current,
1193
+ isZoomed: () => this.zoom.isZoomed,
1194
+ next: () => this.next(),
1195
+ prev: () => this.prev()
1196
+ })), r.touch && (this.gestures = new de(s, {
1197
+ zoom: this.zoom,
1198
+ touch: r.touch,
1199
+ bg: i,
1200
+ canPan: () => this.current?.type === "image",
1201
+ close: () => this.close(),
1202
+ next: () => this.next(),
1203
+ prev: () => this.prev()
1206
1204
  }));
1207
1205
  }
1208
- resetZoom() {
1209
- this.zoom = { scale: 1, x: 0, y: 0, min: 1, max: 5 }, this.$refs.container?.classList.remove("glare-can-zoom-out");
1210
- }
1211
- updateZoomButton() {
1212
- const t = this.$refs.container?.querySelector("[data-glare-zoom]");
1213
- t && (t.innerHTML = this.zoom.scale > 1.01 ? d.zoomOut : d.zoomIn, t.classList.toggle("is-active", this.zoom.scale > 1.01));
1214
- }
1215
- resetIdle() {
1216
- this.clearIdle(), this.isIdle && this.toggleControls(!1);
1217
- const t = this.opts.idleTime;
1218
- !t || this.opts.modal || (this.idleTimer = setTimeout(() => {
1219
- this.toggleControls(!0);
1220
- }, t * 1e3));
1221
- }
1222
- clearIdle() {
1223
- this.idleTimer && (clearTimeout(this.idleTimer), this.idleTimer = null);
1224
- }
1225
- dict() {
1226
- const t = this.opts.lang || "en";
1227
- return {
1228
- ...ht,
1229
- ...this.opts.i18n?.en || {},
1230
- ...this.opts.i18n?.[t] || {}
1231
- };
1232
- }
1233
- trigger(t, e, ...s) {
1234
- const i = this.opts[t];
1235
- if (typeof i == "function")
1236
- return i(this, e, ...s);
1206
+ onActivity() {
1207
+ this.isIdle && this.toggleControls(!1), this.idle.reset();
1237
1208
  }
1238
1209
  teardown() {
1239
- this.gestures?.detach(), this.wheel?.destroy(), this.hash?.destroy(), this.share?.destroy(), this.Thumbs?.destroy(), this.SlideShow?.destroy(), this.FullScreen?.destroy(), this.cleanups.forEach((e) => e()), this.cleanups = [], this.$refs.container?.remove(), this.$refs = {
1240
- container: null,
1241
- stage: null,
1242
- bg: null,
1243
- inner: null,
1244
- caption: null,
1245
- toolbar: null,
1246
- infobar: null,
1247
- navigation: null
1248
- };
1249
- const t = g.indexOf(this);
1250
- t >= 0 && g.splice(t, 1), this.opts.hideScrollbar && R(!1), this.opts.backFocus && (this.openedFrom || this.previouslyFocused)?.focus?.({ preventScroll: !0 }), this.isActive = !1, this.isClosing = !1, this.trigger("afterClose", this.current || void 0), this.trigger("onDeactivate"), this.trigger("onDestroy");
1210
+ for (const t of [
1211
+ this.gestures,
1212
+ this.wheel,
1213
+ this.hash,
1214
+ this.share,
1215
+ this.thumbs,
1216
+ this.slideshow,
1217
+ this.fullscreen
1218
+ ])
1219
+ t?.destroy();
1220
+ this.gestures = this.wheel = this.hash = null, this.share = this.thumbs = this.slideshow = this.fullscreen = void 0, this.cleanups.forEach((t) => t()), this.cleanups = [], this.$refs?.container.remove(), this.$refs = null, b.remove(this), this.opts.hideScrollbar && b.size === 0 && W(!1), this.opts.backFocus && (this.current?.$trigger ?? this.previouslyFocused)?.focus({ preventScroll: !0 }), this.isActive = !1, this.isClosing = !1, this.current && this.emitSlide("afterClose", this.current);
1221
+ }
1222
+ emit(t) {
1223
+ return this.opts[t]?.(this);
1224
+ }
1225
+ emitSlide(t, s) {
1226
+ return this.opts[t]?.(this, s);
1227
+ }
1228
+ clampIndex(t) {
1229
+ return E(t, 0, Math.max(0, this.group.length - 1));
1230
+ }
1231
+ static open(t, s = {}, i = 0) {
1232
+ const r = new w(t, s, i);
1233
+ return r.open(), r;
1234
+ }
1235
+ static bind(t, s = {}) {
1236
+ return Me(t, s, (i, r, o) => {
1237
+ new w(i, s, r, o).open();
1238
+ });
1239
+ }
1240
+ static close(t = !1) {
1241
+ t ? b.all().reverse().forEach((s) => s.close()) : b.top()?.close();
1251
1242
  }
1252
1243
  static getInstance(t) {
1253
- return t != null ? g.find((e) => e.id === t) || null : g[g.length - 1] || null;
1244
+ return t == null ? b.top() : b.get(t);
1254
1245
  }
1255
1246
  static getInstances() {
1256
- return [...g];
1257
- }
1258
- static open(t, e = {}, s = 0) {
1259
- const i = new v(t, e, s);
1260
- return i.open(s), i;
1261
- }
1262
- static close(t = !1) {
1263
- if (t) {
1264
- [...g].reverse().forEach((e) => e.close());
1265
- return;
1266
- }
1267
- g[g.length - 1]?.close();
1247
+ return b.all();
1268
1248
  }
1249
+ /** Closes every instance and removes all `bind()` handlers. */
1269
1250
  static destroy() {
1270
- v.close(!0), k.forEach((t) => t.destroy()), k.length = 0;
1271
- }
1272
- static bind(t, e = {}) {
1273
- const s = typeof t == "string" ? S(t) : t instanceof HTMLElement ? [t] : Array.from(t), i = (a) => {
1274
- const l = a.target;
1275
- if (!l) return;
1276
- const u = s.find((y) => y === l || y.contains(l));
1277
- if (!u) return;
1278
- a.preventDefault();
1279
- const h = u.getAttribute("data-glare") || u.getAttribute("data-glare") || "", f = h ? s.filter(
1280
- (y) => (y.getAttribute("data-glare") || y.getAttribute("data-glare") || "") === h
1281
- ) : [u], w = Math.max(0, f.indexOf(u));
1282
- new v(f, e, w, h || "gallery").open(w);
1283
- }, n = s.map((a) => c(a, "click", i)), o = {
1284
- selector: typeof t == "string" ? t : "",
1285
- options: e,
1286
- elements: s,
1287
- destroy: () => {
1288
- n.forEach((l) => l());
1289
- const a = k.indexOf(o);
1290
- a >= 0 && k.splice(a, 1);
1291
- }
1292
- };
1293
- return k.push(o), o;
1251
+ w.close(!0), $e();
1294
1252
  }
1295
- static fromSelector(t, e = {}) {
1296
- const s = S(t);
1297
- if (!s.length) return null;
1298
- const i = new v(s, e, 0, "gallery");
1299
- return i.open(0), i;
1253
+ /** Binds every `[data-glare]` element once the DOM is ready. */
1254
+ static autoBind(t = {}) {
1255
+ const s = () => w.bind("[data-glare]", t);
1256
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", s, { once: !0 }) : s();
1300
1257
  }
1301
1258
  };
1302
- v.defaults = T;
1303
- let z = v;
1304
- const k = [], ht = {
1305
- CLOSE: "Close",
1306
- NEXT: "Next",
1307
- PREV: "Previous",
1308
- ERROR: "The requested content cannot be loaded.<br/>Please try again later.",
1309
- PLAY_START: "Start slideshow",
1310
- PLAY_STOP: "Pause slideshow",
1311
- FULL_SCREEN: "Full screen",
1312
- THUMBS: "Thumbnails",
1313
- DOWNLOAD: "Download",
1314
- SHARE: "Share",
1315
- ZOOM: "Zoom"
1316
- };
1317
- function ut(r, t, e) {
1318
- const s = r.caption || r.alt || "Media lightbox";
1319
- return e > 1 ? `${s} (${t + 1} of ${e})` : s;
1320
- }
1321
- function dt() {
1322
- if (typeof document > "u") return;
1323
- const r = () => {
1324
- S("[data-glare], [data-glare]").length && z.bind("[data-glare], [data-glare]");
1325
- };
1326
- document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", r, { once: !0 }) : r();
1327
- }
1259
+ w.defaults = nt;
1260
+ let P = w;
1261
+ const Qe = P.autoBind;
1328
1262
  export {
1329
- z as Glare,
1330
- dt as autoBind,
1331
- z as default,
1332
- _ as defaultMedia,
1333
- T as defaults,
1334
- tt as detectType,
1335
- N as i18nEn,
1336
- st as itemsFromElements,
1337
- B as normalizeItem
1263
+ P as Glare,
1264
+ Qe as autoBind,
1265
+ P as default
1338
1266
  };
1339
1267
  //# sourceMappingURL=glare.esm.js.map