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