@projektemacher/storymapjs 0.10.5 → 0.10.7

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 (148) hide show
  1. package/CHANGELOG +11 -0
  2. package/dist/assets/{demo-CVQ7kFek.js → demo-D6cTmzn6.js} +1 -1
  3. package/dist/assets/{harness-C-VZV-ou.js → harness-BPFlzutp.js} +1 -1
  4. package/dist/assets/main-Y-MYUSJ4.js +17 -0
  5. package/dist/css/fonts/font.oldstandard.css +14 -32
  6. package/dist/demo.html +2 -2
  7. package/dist/docs/migration.html +1 -1
  8. package/dist/embed/index.html +129 -4
  9. package/dist/harness.html +2 -2
  10. package/dist/index.html +17 -0
  11. package/dist/js/storymap.d.ts +126 -7
  12. package/dist/js/storymap.js +4518 -3613
  13. package/dist/js/storymap.js.map +1 -1
  14. package/docs/migration-from-knightlab.md +139 -0
  15. package/docs/storymap-as-iiif-manifest.md +510 -0
  16. package/package.json +6 -3
  17. package/src/animation/easings.ts +18 -0
  18. package/src/animation/morpheus.d.ts +41 -0
  19. package/src/core/Browser.ts +19 -0
  20. package/src/core/Load.ts +180 -0
  21. package/src/core/Util.ts +354 -0
  22. package/src/core/mixins.ts +171 -0
  23. package/src/dom/Dom.ts +31 -0
  24. package/src/dom/DomEvent.ts +61 -0
  25. package/src/globals.d.ts +16 -0
  26. package/src/language/Language.ts +107 -0
  27. package/src/language/locale/be.json +18 -0
  28. package/src/language/locale/bg.json +18 -0
  29. package/src/language/locale/cs.json +18 -0
  30. package/src/language/locale/de.json +20 -0
  31. package/src/language/locale/el.json +18 -0
  32. package/src/language/locale/en.json +28 -0
  33. package/src/language/locale/es.json +18 -0
  34. package/src/language/locale/et.json +18 -0
  35. package/src/language/locale/fr.json +18 -0
  36. package/src/language/locale/he.json +18 -0
  37. package/src/language/locale/hu.json +18 -0
  38. package/src/language/locale/is.json +18 -0
  39. package/src/language/locale/it.json +18 -0
  40. package/src/language/locale/jp.json +18 -0
  41. package/src/language/locale/ko.json +18 -0
  42. package/src/language/locale/nl.json +18 -0
  43. package/src/language/locale/nn.json +18 -0
  44. package/src/language/locale/no.json +18 -0
  45. package/src/language/locale/pl.json +18 -0
  46. package/src/language/locale/pt.json +18 -0
  47. package/src/language/locale/ru.json +18 -0
  48. package/src/language/locale/sk.json +18 -0
  49. package/src/language/locale/sr.json +17 -0
  50. package/src/language/locale/sv.json +18 -0
  51. package/src/language/locale/tr.json +18 -0
  52. package/src/language/locale/uk.json +18 -0
  53. package/src/language/locale/ur.json +18 -0
  54. package/src/language/locale/zh-cn.json +18 -0
  55. package/src/language/locale/zh-tw.json +18 -0
  56. package/src/main.ts +51 -0
  57. package/src/map/Map.ts +717 -0
  58. package/src/map/MapMarker.ts +149 -0
  59. package/src/map/openlayers/Map.OpenLayers.ts +1879 -0
  60. package/src/map/openlayers/MapMarker.OpenLayers.ts +176 -0
  61. package/src/map/openlayers/zoomifyTiles.ts +28 -0
  62. package/src/map/types.ts +17 -0
  63. package/src/media/EmbedUtil.ts +168 -0
  64. package/src/media/Media.ts +409 -0
  65. package/src/media/MediaType.ts +163 -0
  66. package/src/media/types/Audio.ts +87 -0
  67. package/src/media/types/Blockquote.ts +40 -0
  68. package/src/media/types/DailyMotion.ts +58 -0
  69. package/src/media/types/DocumentCloud.ts +41 -0
  70. package/src/media/types/Facebook.ts +41 -0
  71. package/src/media/types/Flickr.ts +115 -0
  72. package/src/media/types/GoogleDoc.ts +59 -0
  73. package/src/media/types/IFrame.ts +51 -0
  74. package/src/media/types/Image.ts +49 -0
  75. package/src/media/types/Juxtapose.ts +32 -0
  76. package/src/media/types/SoundCloud.ts +77 -0
  77. package/src/media/types/Text.ts +172 -0
  78. package/src/media/types/Twitter.ts +96 -0
  79. package/src/media/types/Video.ts +84 -0
  80. package/src/media/types/Vimeo.ts +65 -0
  81. package/src/media/types/Website.ts +36 -0
  82. package/src/media/types/Wikipedia.ts +124 -0
  83. package/src/media/types/YouTube.ts +192 -0
  84. package/src/scss/Typography.scss +237 -0
  85. package/src/scss/VCO.StoryMap.Dark.scss +138 -0
  86. package/src/scss/VCO.StoryMap.scss +164 -0
  87. package/src/scss/Variables.Dark.scss +56 -0
  88. package/src/scss/Variables.scss +47 -0
  89. package/src/scss/core/Mixins.scss +112 -0
  90. package/src/scss/core/Reset.scss +206 -0
  91. package/src/scss/fonts/_font.base.scss +113 -0
  92. package/src/scss/fonts/font.abril-droidsans.scss +75 -0
  93. package/src/scss/fonts/font.amatic-andika.scss +73 -0
  94. package/src/scss/fonts/font.bitter-raleway.scss +86 -0
  95. package/src/scss/fonts/font.clicker-garamond.scss +92 -0
  96. package/src/scss/fonts/font.dancing-ledger.scss +74 -0
  97. package/src/scss/fonts/font.default.scss +9 -0
  98. package/src/scss/fonts/font.fjalla-average.scss +80 -0
  99. package/src/scss/fonts/font.georgia-helvetica.scss +58 -0
  100. package/src/scss/fonts/font.knightlab.scss +97 -0
  101. package/src/scss/fonts/font.lustria-lato.scss +80 -0
  102. package/src/scss/fonts/font.medula-lato.scss +73 -0
  103. package/src/scss/fonts/font.oldstandard.scss +88 -0
  104. package/src/scss/fonts/font.opensans-gentiumbook.scss +80 -0
  105. package/src/scss/fonts/font.playfair-faunaone.scss +86 -0
  106. package/src/scss/fonts/font.playfair.scss +85 -0
  107. package/src/scss/fonts/font.pt.scss +90 -0
  108. package/src/scss/fonts/font.roboto-megrim.scss +73 -0
  109. package/src/scss/fonts/font.rufina-sintony.scss +73 -0
  110. package/src/scss/fonts/font.ubuntu.scss +78 -0
  111. package/src/scss/fonts/font.unicaone-vollkorn.scss +85 -0
  112. package/src/scss/icons/Icons.scss +239 -0
  113. package/src/scss/map/VCO.ImageMarker.scss +23 -0
  114. package/src/scss/map/VCO.Map.scss +21 -0
  115. package/src/scss/map/VCO.MapMarker.scss +147 -0
  116. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +126 -0
  117. package/src/scss/media/VCO.Media.scss +222 -0
  118. package/src/scss/media/types/VCO.Media.Blockquote.scss +76 -0
  119. package/src/scss/media/types/VCO.Media.IFrame.scss +11 -0
  120. package/src/scss/media/types/VCO.Media.Image.scss +13 -0
  121. package/src/scss/media/types/VCO.Media.Instagram.scss +7 -0
  122. package/src/scss/media/types/VCO.Media.Profile.scss +5 -0
  123. package/src/scss/media/types/VCO.Media.Text.scss +90 -0
  124. package/src/scss/media/types/VCO.Media.Twitter.scss +87 -0
  125. package/src/scss/media/types/VCO.Media.Wikipedia.scss +64 -0
  126. package/src/scss/site/site.scss +748 -0
  127. package/src/scss/slider/VCO.Slide.scss +447 -0
  128. package/src/scss/slider/VCO.SlideNav.scss +338 -0
  129. package/src/scss/slider/VCO.StorySlider.scss +64 -0
  130. package/src/scss/snapmap/VCO.SnapMap.scss +103 -0
  131. package/src/scss/ui/VCO.Consent.scss +77 -0
  132. package/src/scss/ui/VCO.MenuBar.Button.scss +99 -0
  133. package/src/scss/ui/VCO.MenuBar.scss +20 -0
  134. package/src/scss/ui/VCO.Message.scss +104 -0
  135. package/src/site/site.ts +87 -0
  136. package/src/slider/Slide.ts +460 -0
  137. package/src/slider/SlideNav.ts +212 -0
  138. package/src/slider/StorySlider.ts +722 -0
  139. package/src/storymap/Consent.ts +146 -0
  140. package/src/storymap/StoryMap.ts +1108 -0
  141. package/src/storymap/iiif.ts +386 -0
  142. package/src/storymap/validate.ts +184 -0
  143. package/src/types.ts +297 -0
  144. package/src/ui/Draggable.ts +374 -0
  145. package/src/ui/MenuBar.ts +323 -0
  146. package/src/ui/Message.ts +118 -0
  147. package/src/ui/Swipable.ts +388 -0
  148. package/dist/assets/main-DwbXrrYn.js +0 -17
@@ -0,0 +1,722 @@
1
+ import { mergeData, unique_ID, findArrayNumberByUniqueID, parseCssColor, slideTransitionDuration } from "../core/Util";
2
+ import { Evented, type EventedInstance } from "../core/mixins";
3
+ import Dom from "../dom/Dom";
4
+ import { DomEvent } from "../dom/DomEvent";
5
+ import { easeInOutQuint } from "../animation/easings";
6
+ import SlideNav from "./SlideNav";
7
+ import Slide from "./Slide";
8
+ import Animate from "morpheus";
9
+ import Swipable from "../ui/Swipable";
10
+ import Message from "../ui/Message";
11
+ import { Browser } from "../core/Browser";
12
+ import { Language } from "../language/Language";
13
+ import { AnimationHandle, StorymapData, StorymapSlide } from "../types";
14
+
15
+ /* StorySlider
16
+ is the central class of the API - it is used to create a StorySlider
17
+
18
+ Events:
19
+ nav_next
20
+ nav_previous
21
+ slideDisplayUpdate
22
+ loaded
23
+ slideAdded
24
+ slideLoaded
25
+ slideRemoved
26
+
27
+
28
+ ================================================== */
29
+
30
+ /* StorySlider options: the fields it sets or reads; everything else
31
+ merged in from the StoryMap options is absorbed by the index signature. */
32
+ interface StorySliderOptions {
33
+ id?: string;
34
+ layout: string;
35
+ width: number;
36
+ height: number;
37
+ default_bg_color: { r: number; g: number; b: number };
38
+ slide_padding_lr: number;
39
+ start_at_slide: number;
40
+ slide_default_fade: string;
41
+ duration: number;
42
+ ease: unknown;
43
+ skinny_size?: number;
44
+ call_to_action?: boolean;
45
+ call_to_action_text?: string;
46
+ dragging?: boolean;
47
+ trackResize?: boolean;
48
+ [key: string]: unknown;
49
+ }
50
+
51
+ interface SlideBackgroundChange {
52
+ color_value?: string;
53
+ image?: boolean;
54
+ }
55
+
56
+ class StorySliderBase {
57
+ declare "_el": Record<string, HTMLElement>;
58
+ declare "_nav": { previous: SlideNav; next: SlideNav };
59
+ declare "slide_spacing": number;
60
+ declare "_slides": Slide[];
61
+ declare "_swipable": Swipable;
62
+ declare "preloadTimer": ReturnType<typeof setTimeout>;
63
+ declare "_message": Message;
64
+ declare "current_slide": number;
65
+ declare "current_bg_color": string | null;
66
+ declare "data": Partial<StorymapData>;
67
+ declare "options": StorySliderOptions;
68
+ declare "animator": AnimationHandle | null;
69
+ declare "animator_background": AnimationHandle | null;
70
+ declare "fire": EventedInstance["fire"];
71
+ declare "_loaded": boolean;
72
+ declare "hasEventListeners": EventedInstance["hasEventListeners"];
73
+
74
+ /* Private Methods
75
+ ================================================== */
76
+ constructor(
77
+ elem: HTMLElement | string,
78
+ data: Partial<StorymapData>,
79
+ options?: Partial<StorySliderOptions>,
80
+ init?: boolean,
81
+ ) {
82
+ // DOM ELEMENTS
83
+ this._el = {
84
+ container: {} as HTMLElement,
85
+ background: {} as HTMLElement,
86
+ slider_container_mask: {} as HTMLElement,
87
+ slider_container: {} as HTMLElement,
88
+ slider_item_container: {} as HTMLElement,
89
+ };
90
+
91
+ this._nav = {
92
+ previous: {} as SlideNav,
93
+ next: {} as SlideNav,
94
+ };
95
+
96
+ // Slide Spacing
97
+ this.slide_spacing = 0;
98
+
99
+ // Slides Array
100
+ this._slides = [];
101
+
102
+ // Current Slide
103
+ this.current_slide = 0;
104
+
105
+ // Current Background Color
106
+ this.current_bg_color = null;
107
+
108
+ // Data Object
109
+ this.data = {};
110
+
111
+ this.options = {
112
+ id: "",
113
+ layout: "portrait",
114
+ width: 600,
115
+ height: 600,
116
+ default_bg_color: { r: 255, g: 255, b: 255 },
117
+ slide_padding_lr: 40, // padding on slide of slide
118
+ start_at_slide: 1,
119
+ slide_default_fade: "0%", // landscape fade
120
+ // animation
121
+ duration: 1000,
122
+ ease: easeInOutQuint,
123
+ // interaction
124
+ dragging: true,
125
+ trackResize: true,
126
+ };
127
+
128
+ // Main element ID
129
+ if (typeof elem === "object") {
130
+ this._el.container = elem;
131
+ this.options.id = unique_ID(6, "vco");
132
+ } else {
133
+ this.options.id = elem;
134
+ this._el.container = Dom.get(elem);
135
+ }
136
+
137
+ if (!this._el.container.id) {
138
+ this._el.container.id = this.options.id;
139
+ }
140
+
141
+ // Animation Object
142
+ this.animator = null;
143
+ this.animator_background = null;
144
+
145
+ // Merge Data and Options
146
+ mergeData(this.options, options);
147
+ mergeData(this.data, data);
148
+
149
+ if (init) {
150
+ this.init();
151
+ }
152
+ }
153
+
154
+ init() {
155
+ this._initLayout();
156
+ this._initEvents();
157
+ this._initData();
158
+ this._updateDisplay();
159
+
160
+ // Go to initial slide
161
+ this.goTo(this.options.start_at_slide);
162
+
163
+ this._onLoaded();
164
+ this._introInterface();
165
+ }
166
+
167
+ /* Public
168
+ ================================================== */
169
+ updateDisplay(w?: number, h?: number, a?: unknown, l?: string) {
170
+ this._updateDisplay(w, h, a, l);
171
+ }
172
+
173
+ // Create a slide
174
+ createSlide(d: StorymapSlide) {
175
+ this._createSlide(d);
176
+ }
177
+
178
+ // Create Many Slides from an array
179
+ createSlides(array: StorymapData["slides"]) {
180
+ this._createSlides(array);
181
+ }
182
+
183
+ /* Create Slides
184
+ ================================================== */
185
+ _createSlides(array: StorymapData["slides"]) {
186
+ for (let i = 0; i < array.length; i++) {
187
+ if (array[i].uniqueid === "") {
188
+ array[i].uniqueid = unique_ID(6, "vco-slide");
189
+ }
190
+ if (i === 0) {
191
+ this._createSlide(array[i], true);
192
+ } else {
193
+ this._createSlide(array[i], false);
194
+ }
195
+ }
196
+ }
197
+
198
+ _createSlide(d: StorymapSlide, title_slide?: boolean) {
199
+ const slide = new Slide(d, this.options, title_slide);
200
+ this._addSlide(slide);
201
+ this._slides.push(slide);
202
+ }
203
+
204
+ _addSlide(slide: Slide) {
205
+ slide.addTo(this._el.slider_item_container);
206
+ slide.on("added", this._onSlideAdded, this);
207
+ slide.on("background_change", this._onBackgroundChange, this);
208
+ }
209
+
210
+ /* Message
211
+ ================================================== */
212
+
213
+ /* Navigation
214
+ ================================================== */
215
+ goToId(n: string | number, fast?: boolean, displayupdate?: boolean) {
216
+ let _n;
217
+ if (typeof n == "string" || (n as unknown) instanceof String) {
218
+ _n = findArrayNumberByUniqueID(String(n), this._slides, "uniqueid");
219
+ } else {
220
+ _n = n;
221
+ }
222
+ this.goTo(_n, fast, displayupdate);
223
+ }
224
+
225
+ goTo(n: number, fast?: boolean, displayupdate?: boolean) {
226
+ this.changeBackground({ color_value: "", image: false });
227
+
228
+ // Clear Preloader Timer (covers both the setTimeout fallback and
229
+ // the requestIdleCallback handle below — both are numbers)
230
+ if (this.preloadTimer) {
231
+ clearTimeout(this.preloadTimer);
232
+ (
233
+ window as unknown as { cancelIdleCallback?: (handle: number) => void }
234
+ ).cancelIdleCallback?.(this.preloadTimer as unknown as number);
235
+ }
236
+
237
+ // Set Slide Active State
238
+ for (let i = 0; i < this._slides.length; i++) {
239
+ this._slides[i].setActive(false);
240
+ }
241
+
242
+ if (n < this._slides.length && n >= 0) {
243
+ // Scale the transition duration with the jump distance so that
244
+ // out-of-order navigation glides instead of flicking; the map
245
+ // computes the very same value to keep both in sync
246
+ const previous_slide = this.current_slide;
247
+ this.current_slide = n;
248
+ const transition_duration = slideTransitionDuration(previous_slide, n);
249
+
250
+ // Stop animation
251
+ if (this.animator) {
252
+ this.animator.stop();
253
+ }
254
+ if (this._swipable) {
255
+ this._swipable.stopMomentum();
256
+ }
257
+
258
+ if (fast) {
259
+ this._el.slider_container.style.left = -(this.slide_spacing * n) + "px";
260
+ this._onSlideChange(displayupdate);
261
+ } else {
262
+ // fire the change event at animation start so the map and the
263
+ // slider animate simultaneously
264
+ this._onSlideChange(displayupdate);
265
+ this.animator = Animate(this._el.slider_container, {
266
+ left: -(this.slide_spacing * n) + "px",
267
+ duration: transition_duration,
268
+ easing: this.options.ease,
269
+ });
270
+ }
271
+
272
+ // Set Slide Active State
273
+ if (this._slides.length > 0) {
274
+ this._slides[this.current_slide].setActive(true);
275
+ }
276
+
277
+ // Preload the next slide's media right away so its load clock,
278
+ // network and iframe build elapse during this transition (and the
279
+ // dwell time) instead of starting after arrival
280
+ if (this._slides[this.current_slide + 1]) {
281
+ this._slides[this.current_slide + 1].loadMedia();
282
+ this._slides[this.current_slide + 1].scrollToTop();
283
+ }
284
+
285
+ // Update Navigation and Info
286
+ if (this._slides[this.current_slide + 1]) {
287
+ this.showNav(this._nav.next, true);
288
+ this._nav.next.update(this.getNavInfo(this._slides[this.current_slide + 1]));
289
+ } else {
290
+ this.showNav(this._nav.next, false);
291
+ }
292
+ if (this._slides[this.current_slide - 1]) {
293
+ this.showNav(this._nav.previous, true);
294
+ this._nav.previous.update(this.getNavInfo(this._slides[this.current_slide - 1]));
295
+ } else {
296
+ this.showNav(this._nav.previous, false);
297
+ }
298
+
299
+ // Preload the surrounding slides once this transition settles,
300
+ // preferably while the browser is idle so the burst of iframe
301
+ // builds and script injections doesn't compete with animations;
302
+ // the timeout caps the wait at the base transition duration
303
+ const w = window as unknown as {
304
+ requestIdleCallback?: (cb: () => void, opts?: { timeout: number }) => number;
305
+ };
306
+ if (w.requestIdleCallback) {
307
+ this.preloadTimer = w.requestIdleCallback(() => this.preloadSlides(), {
308
+ timeout: this.options.duration,
309
+ }) as unknown as ReturnType<typeof setTimeout>;
310
+ } else {
311
+ this.preloadTimer = setTimeout(() => {
312
+ this.preloadSlides();
313
+ }, this.options.duration);
314
+ }
315
+ }
316
+ }
317
+
318
+ preloadSlides() {
319
+ // NOTE: current_slide + 1 is preloaded eagerly in goTo(); the guard
320
+ // in Slide.loadMedia() makes a repeated call here harmless
321
+ if (this._slides[this.current_slide + 1]) {
322
+ this._slides[this.current_slide + 1].loadMedia();
323
+ this._slides[this.current_slide + 1].scrollToTop();
324
+ }
325
+ if (this._slides[this.current_slide + 2]) {
326
+ this._slides[this.current_slide + 2].loadMedia();
327
+ this._slides[this.current_slide + 2].scrollToTop();
328
+ }
329
+ if (this._slides[this.current_slide - 1]) {
330
+ this._slides[this.current_slide - 1].loadMedia();
331
+ this._slides[this.current_slide - 1].scrollToTop();
332
+ }
333
+ if (this._slides[this.current_slide - 2]) {
334
+ this._slides[this.current_slide - 2].loadMedia();
335
+ this._slides[this.current_slide - 2].scrollToTop();
336
+ }
337
+ }
338
+
339
+ getNavInfo(slide: Slide) {
340
+ const n = {
341
+ title: "",
342
+ description: "",
343
+ };
344
+
345
+ if (slide.data.text) {
346
+ if (slide.data.text.headline) {
347
+ n.title = slide.data.text.headline;
348
+ }
349
+ }
350
+
351
+ return n;
352
+ }
353
+
354
+ next() {
355
+ if (this.current_slide + 1 < this._slides.length) {
356
+ this.goTo(this.current_slide + 1);
357
+ } else {
358
+ this.goTo(this.current_slide);
359
+ }
360
+ }
361
+
362
+ previous() {
363
+ if (this.current_slide - 1 >= 0) {
364
+ this.goTo(this.current_slide - 1);
365
+ } else {
366
+ this.goTo(this.current_slide);
367
+ }
368
+ }
369
+
370
+ showNav(nav_obj: SlideNav, show: boolean) {
371
+ if (this.options.width <= 500 && Browser.mobile) {
372
+ // hidden on small mobile screens
373
+ } else {
374
+ if (show) {
375
+ nav_obj.show();
376
+ } else {
377
+ nav_obj.hide();
378
+ }
379
+ }
380
+ }
381
+
382
+ changeBackground(bg: SlideBackgroundChange) {
383
+ let do_animation = false;
384
+
385
+ let bg_color,
386
+ bg_percent_start = this.options.slide_default_fade,
387
+ bg_css = "";
388
+ const bg_percent_end = "15%";
389
+ const bg_alpha_end = "0.87";
390
+ const _bg_old = this._el.background.getAttribute("style");
391
+
392
+ if (bg.color_value) {
393
+ // any CSS color; unparseable values fall back to the default
394
+ bg_color = parseCssColor(bg.color_value) || this.options.default_bg_color;
395
+ } else {
396
+ bg_color = this.options.default_bg_color;
397
+ }
398
+
399
+ // Stop animation
400
+ if (this.animator_background) {
401
+ this.animator_background.stop();
402
+ }
403
+
404
+ const bg_color_rgb = bg_color.r + "," + bg_color.g + "," + bg_color.b;
405
+
406
+ if (!this.current_bg_color || this.current_bg_color !== bg_color_rgb) {
407
+ this.current_bg_color = bg_color_rgb;
408
+ do_animation = true;
409
+ }
410
+
411
+ if (do_animation) {
412
+ // Figure out CSS
413
+ if (this.options.layout === "landscape") {
414
+ this._nav.next.setColor(false);
415
+ this._nav.previous.setColor(false);
416
+
417
+ // If background is not white, less fade is better
418
+ if (bg_color.r < 255 && bg_color.g < 255 && bg_color.b < 255) {
419
+ bg_percent_start = "15%";
420
+ }
421
+
422
+ if (bg.image) {
423
+ bg_percent_start = "0%";
424
+ }
425
+ bg_css += "opacity:0;";
426
+ bg_css +=
427
+ "background-image: linear-gradient(to right, rgba(" +
428
+ bg_color_rgb +
429
+ ",0.0001 ) " +
430
+ bg_percent_start +
431
+ ", rgba(" +
432
+ bg_color_rgb +
433
+ "," +
434
+ bg_alpha_end +
435
+ ") " +
436
+ bg_percent_end +
437
+ ");";
438
+ bg_css += "background-repeat: repeat-x;";
439
+ } else {
440
+ if (bg.color_value) {
441
+ bg_css += "background-color:" + bg.color_value + ";";
442
+ } else {
443
+ bg_css += "background-color:#FFF;";
444
+ }
445
+
446
+ if ((bg_color.r < 255 && bg_color.g < 255 && bg_color.b < 255) || bg.image) {
447
+ this._nav.next.setColor(true);
448
+ this._nav.previous.setColor(true);
449
+ } else {
450
+ this._nav.next.setColor(false);
451
+ this._nav.previous.setColor(false);
452
+ }
453
+ }
454
+
455
+ // FADE OUT IN
456
+ this.animator_background = Animate(this._el.background, {
457
+ opacity: 0,
458
+ duration: this.options.duration / 2,
459
+ easing: this.options.ease,
460
+ complete: () => {
461
+ this.fadeInBackground(bg_css);
462
+ },
463
+ });
464
+ }
465
+ }
466
+
467
+ fadeInBackground(bg_css: string) {
468
+ if (this.animator_background) {
469
+ this.animator_background.stop();
470
+ }
471
+
472
+ if (bg_css) {
473
+ this._el.background.setAttribute("style", bg_css);
474
+ }
475
+
476
+ this.animator_background = Animate(this._el.background, {
477
+ opacity: 1,
478
+ duration: this.options.duration / 2,
479
+ easing: this.options.ease,
480
+ });
481
+ }
482
+
483
+ /* Private Methods
484
+ ================================================== */
485
+
486
+ // Update Display
487
+ _updateDisplay(width?: number, height?: number, animate?: unknown, layout?: string) {
488
+ let _layout;
489
+
490
+ if (typeof layout === "undefined") {
491
+ _layout = this.options.layout;
492
+ } else {
493
+ _layout = layout;
494
+ }
495
+
496
+ this.options.layout = _layout;
497
+
498
+ this.slide_spacing = this.options.width * 2;
499
+
500
+ if (width) {
501
+ this.options.width = width;
502
+ } else {
503
+ this.options.width = this._el.container.offsetWidth;
504
+ }
505
+
506
+ if (height) {
507
+ this.options.height = height;
508
+ } else {
509
+ this.options.height = this._el.container.offsetHeight;
510
+ }
511
+
512
+ // position navigation
513
+ const nav_pos = this.options.height / 2;
514
+ this._nav.next.setPosition({ top: nav_pos });
515
+ this._nav.previous.setPosition({ top: nav_pos });
516
+
517
+ // Position slides
518
+ for (let i = 0; i < this._slides.length; i++) {
519
+ this._slides[i].updateDisplay(this.options.width, this.options.height, _layout);
520
+ this._slides[i].setPosition({ left: this.slide_spacing * i, top: 0 });
521
+ }
522
+
523
+ // Go to the current slide
524
+ this.goTo(this.current_slide, true, true);
525
+ }
526
+
527
+ _introInterface() {
528
+ if (this.options.call_to_action) {
529
+ let _str = Language.messages.start;
530
+ if (this.options.call_to_action_text !== "") {
531
+ _str = this.options.call_to_action_text;
532
+ }
533
+ this._slides[0].addCallToAction(_str);
534
+ this._slides[0].on("call_to_action", this.next, this);
535
+ }
536
+
537
+ if (this.options.width <= this.options.skinny_size) {
538
+ // hidden when skinny
539
+ } else {
540
+ this._nav.next.updatePosition(
541
+ { right: "130" },
542
+ false,
543
+ this.options.duration * 3,
544
+ this.options.ease,
545
+ -100,
546
+ true,
547
+ );
548
+ this._nav.previous.updatePosition(
549
+ { left: "-100" },
550
+ true,
551
+ this.options.duration * 3,
552
+ this.options.ease,
553
+ -200,
554
+ true,
555
+ );
556
+ }
557
+ }
558
+
559
+ /* Init
560
+ ================================================== */
561
+ _initLayout() {
562
+ this._el.container.className += " vco-storyslider";
563
+
564
+ // Create Layout
565
+ this._el.slider_container_mask = Dom.create(
566
+ "div",
567
+ "vco-slider-container-mask",
568
+ this._el.container,
569
+ );
570
+ this._el.background = Dom.create("div", "vco-slider-background", this._el.container);
571
+ this._el.slider_container = Dom.create(
572
+ "div",
573
+ "vco-slider-container",
574
+ this._el.slider_container_mask,
575
+ );
576
+ this._el.slider_item_container = Dom.create(
577
+ "div",
578
+ "vco-slider-item-container",
579
+ this._el.slider_container,
580
+ );
581
+
582
+ // Update Size
583
+ this.options.width = this._el.container.offsetWidth;
584
+ this.options.height = this._el.container.offsetHeight;
585
+
586
+ // Create Navigation
587
+ this._nav.previous = new SlideNav(
588
+ { title: "Previous", description: "description" },
589
+ { direction: "previous" },
590
+ );
591
+ this._nav.next = new SlideNav(
592
+ { title: "Next", description: "description" },
593
+ { direction: "next" },
594
+ );
595
+
596
+ // add the navigation to the dom
597
+ this._nav.next.addTo(this._el.container);
598
+ this._nav.previous.addTo(this._el.container);
599
+
600
+ this._el.slider_container.style.left = "0px";
601
+
602
+ if (Browser.touch) {
603
+ this._swipable = new Swipable(
604
+ this._el.slider_container_mask,
605
+ this._el.slider_container,
606
+ {
607
+ enable: { x: true, y: false },
608
+ snap: true,
609
+ },
610
+ );
611
+ this._swipable.enable();
612
+
613
+ // Message
614
+ this._message = new Message(
615
+ {},
616
+ {
617
+ message_class: "vco-message-full",
618
+ message_icon_class: "vco-icon-swipe-left",
619
+ },
620
+ );
621
+ this._message.updateMessage(Language.buttons.swipe_to_navigate);
622
+ this._message.addTo(this._el.container);
623
+ }
624
+ }
625
+
626
+ _initEvents() {
627
+ this._nav.next.on("clicked", this._onNavigation, this);
628
+ this._nav.previous.on("clicked", this._onNavigation, this);
629
+
630
+ if (this._message) {
631
+ this._message.on("clicked", this._onMessageClick, this);
632
+ }
633
+
634
+ if (this._swipable) {
635
+ this._swipable.on("swipe_left", this._onNavigation, this);
636
+ this._swipable.on("swipe_right", this._onNavigation, this);
637
+ this._swipable.on("swipe_nodirection", this._onSwipeNoDirection, this);
638
+ }
639
+
640
+ // issue #472: keyboard navigation (the container is focusable)
641
+ this._el.container.setAttribute("tabindex", "0");
642
+ DomEvent.addListener(this._el.container, "keydown", this._onKeyDown, this);
643
+ }
644
+
645
+ _onKeyDown(e: Event) {
646
+ const key = (e as KeyboardEvent).key;
647
+ // don't hijack keys while typing in form fields or media embeds
648
+ const target = e.target as HTMLElement | null;
649
+ const tag = target?.tagName?.toLowerCase();
650
+ if (
651
+ tag === "input" ||
652
+ tag === "textarea" ||
653
+ tag === "select" ||
654
+ target?.isContentEditable
655
+ ) {
656
+ return;
657
+ }
658
+ if (key === "ArrowRight" || key === "ArrowDown") {
659
+ DomEvent.preventDefault(e);
660
+ this.next();
661
+ } else if (key === "ArrowLeft" || key === "ArrowUp") {
662
+ DomEvent.preventDefault(e);
663
+ this.previous();
664
+ }
665
+ }
666
+
667
+ _initData() {
668
+ // Create Slides and then add them
669
+ this._createSlides(this.data.slides);
670
+ }
671
+
672
+ /* Events
673
+ ================================================== */
674
+ _onBackgroundChange(e: SlideBackgroundChange) {
675
+ const slide_background = this._slides[this.current_slide].getBackground();
676
+ this.changeBackground(e);
677
+ this.fire("colorchange", slide_background);
678
+ }
679
+
680
+ _onMessageClick(e?: unknown) {
681
+ this._message.hide();
682
+ }
683
+
684
+ _onSwipeNoDirection(e?: unknown) {
685
+ this.goTo(this.current_slide);
686
+ }
687
+
688
+ _onNavigation(e: { direction: string }) {
689
+ if (e.direction === "next" || e.direction === "left") {
690
+ this.next();
691
+ } else if (e.direction === "previous" || e.direction === "right") {
692
+ this.previous();
693
+ }
694
+ this.fire("nav_" + e.direction, this.data);
695
+ }
696
+
697
+ _onSlideAdded(e?: unknown) {
698
+ this.fire("slideAdded", this.data);
699
+ }
700
+
701
+ _onSlideChange(displayupdate?: boolean) {
702
+ if (!displayupdate) {
703
+ this.fire("change", {
704
+ current_slide: this.current_slide,
705
+ uniqueid: this._slides[this.current_slide].data.uniqueid,
706
+ });
707
+ }
708
+ }
709
+
710
+ _onLoaded() {
711
+ this.fire("loaded", this.data);
712
+ if (this._slides.length > 0) {
713
+ this.fire("title", { title: this._slides[0].title });
714
+ }
715
+ }
716
+ }
717
+
718
+ export default class StorySlider extends Evented(StorySliderBase) {
719
+ constructor(...args: ConstructorParameters<typeof StorySliderBase>) {
720
+ super(...args);
721
+ }
722
+ }