@inappstory/slide-api 0.0.1

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.
package/index.cjs.js ADDED
@@ -0,0 +1,4913 @@
1
+ 'use strict';
2
+
3
+ const arPrototype = Array.prototype;
4
+ const obPrototype = Object.prototype;
5
+ const slice = arPrototype.slice;
6
+ const obKeys = Object.keys;
7
+ const obHasOwnProp = obPrototype.hasOwnProperty;
8
+ const toString = obPrototype.toString;
9
+ const isArray = Array.isArray ||
10
+ function (e) {
11
+ return toString.call(e) === "[object Array]";
12
+ };
13
+ // Matches dashed string for camelizing
14
+ const rmsPrefix = /^-ms-/;
15
+ const rdashAlpha = /-([\da-z])/gi;
16
+ const fcamelCase = function (letter) {
17
+ return letter.toUpperCase();
18
+ };
19
+ // private methods
20
+ const isObject = function (e) {
21
+ var t = typeof e;
22
+ return t === "function" || (t === "object" && !!e);
23
+ };
24
+ const isNumber = function (t) {
25
+ return toString.call(t) === "[object Number]";
26
+ };
27
+ const isNumeric = function (n) {
28
+ return !isNaN(parseFloat(n)) && isFinite(n);
29
+ };
30
+ // isEmpty = function(e) {
31
+ // if (e == null)
32
+ // return !0;
33
+ // if (isArray(e) || isString(e) || isArguments(e))
34
+ // return e.length === 0;
35
+ // for (var t in e)
36
+ // if (p.has(e, t))
37
+ // return !1;
38
+ // return !0
39
+ // },
40
+ const has = function (e, t) {
41
+ return e != null && obHasOwnProp.call(e, t);
42
+ };
43
+ const keys = function (e) {
44
+ if (!isObject(e))
45
+ return [];
46
+ if (obKeys)
47
+ return obKeys(e);
48
+ var t = [];
49
+ for (var n in e)
50
+ has(e, n) && t.push(n);
51
+ return t;
52
+ };
53
+ const d = function (e, t, n) {
54
+ if (t === void 0)
55
+ return e;
56
+ switch (3 ) {
57
+ case 1:
58
+ return function (n) {
59
+ return e.call(t, n);
60
+ };
61
+ case 2:
62
+ return function (n, r) {
63
+ return e.call(t, n, r);
64
+ };
65
+ case 3:
66
+ return function (n, r, i) {
67
+ return e.call(t, n, r, i);
68
+ };
69
+ case 4:
70
+ return function (n, r, i, s) {
71
+ return e.call(t, n, r, i, s);
72
+ };
73
+ }
74
+ return function () {
75
+ return e.apply(t, arguments);
76
+ };
77
+ };
78
+ const each = function (e, t, n) {
79
+ if (e == null)
80
+ return e;
81
+ t = d(t, n);
82
+ var r, i = e.length;
83
+ if (i === +i)
84
+ for (r = 0; r < i; ++r)
85
+ t(e[r], r, e);
86
+ else {
87
+ var s = keys(e);
88
+ for (r = 0, i = s.length; r < i; ++r)
89
+ t(e[s[r]], s[r], e);
90
+ }
91
+ return e;
92
+ };
93
+ const forEach = each;
94
+ const extend = function (e, ...args) {
95
+ var t, n;
96
+ for (var r = 1, i = arguments.length; r < i; r++) {
97
+ t = arguments[r];
98
+ for (n in t)
99
+ obHasOwnProp.call(t, n) && (e[n] = t[n]);
100
+ }
101
+ return e;
102
+ };
103
+ const isEmptyObject = function (obj) {
104
+ var name;
105
+ for (name in obj) {
106
+ return false;
107
+ }
108
+ return true;
109
+ };
110
+ const expando = function () {
111
+ return "app" + ("" + Math.random()).replace(/\D/g, "");
112
+ };
113
+ // Convert dashed to camelCase; used by the css and data modules
114
+ // Support: IE9-11+
115
+ // Microsoft forgot to hump their vendor prefix (#9572)
116
+ const camelCase = function (string) {
117
+ return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
118
+ };
119
+ const proxy = function (func, obj) {
120
+ if (typeof func != "function") {
121
+ return func;
122
+ }
123
+ // If obj is empty or another set another object
124
+ if (!obj) {
125
+ // @ts-ignore
126
+ obj = this;
127
+ }
128
+ return function () {
129
+ return func.apply(obj, arguments);
130
+ };
131
+ };
132
+ /*
133
+ hasData: function( elem ) {
134
+ return data_user.hasData( elem ) || data_priv.hasData( elem );
135
+ },
136
+
137
+ data: function( elem, name, data ) {
138
+ return data_user.access( elem, name, data );
139
+ },
140
+
141
+ removeData: function( elem, name ) {
142
+ data_user.remove( elem, name );
143
+ },
144
+ */
145
+ const data = function (elem, name, data) {
146
+ return data_user.access(elem, name, data);
147
+ };
148
+ const getTagData = function (element, key) {
149
+ return element.dataset[key];
150
+ };
151
+ const getTagDataAsNumber = function (element, key) {
152
+ const data = element.dataset[key];
153
+ if (data == null) {
154
+ return undefined;
155
+ }
156
+ return parseInt(data);
157
+ };
158
+ var rnotwhite = /\S+/g;
159
+ class Data {
160
+ static uid = 1;
161
+ static accepts(owner) {
162
+ // Accepts only:
163
+ // - Node
164
+ // - Node.ELEMENT_NODE
165
+ // - Node.DOCUMENT_NODE
166
+ // - Object
167
+ // - Any
168
+ /* jshint -W018 */
169
+ return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType;
170
+ }
171
+ expando;
172
+ cache;
173
+ constructor() {
174
+ // Support: Android<4,
175
+ // Old WebKit does not have Object.preventExtensions/freeze method,
176
+ // return new empty object instead with no [[set]] accessor
177
+ Object.defineProperty((this.cache = {}), 0, {
178
+ get: function () {
179
+ return {};
180
+ },
181
+ });
182
+ this.expando = expando() + String(Data.uid++);
183
+ }
184
+ key(owner) {
185
+ const _owner = owner;
186
+ // We can accept data for non-element nodes in modern browsers,
187
+ // but we should not, see #8335.
188
+ // Always return the key for a frozen object.
189
+ if (!Data.accepts(_owner)) {
190
+ return 0;
191
+ }
192
+ var descriptor = {},
193
+ // Check if the owner object already has a cache key
194
+ unlock = _owner[this.expando];
195
+ // If not, create one
196
+ if (!unlock) {
197
+ unlock = Data.uid++;
198
+ // Secure it in a non-enumerable, non-writable property
199
+ try {
200
+ descriptor[this.expando] = { value: unlock };
201
+ Object.defineProperties(_owner, descriptor);
202
+ // Support: Android<4
203
+ // Fallback to a less secure definition
204
+ }
205
+ catch (e) {
206
+ descriptor[this.expando] = unlock;
207
+ extend(_owner, descriptor);
208
+ }
209
+ }
210
+ // Ensure the cache object
211
+ if (!this.cache[unlock]) {
212
+ this.cache[unlock] = {};
213
+ }
214
+ return unlock;
215
+ }
216
+ set(owner, data, value) {
217
+ var prop,
218
+ // There may be an unlock assigned to this node,
219
+ // if there is no entry for this "owner", create one inline
220
+ // and set the unlock as though an owner entry had always existed
221
+ unlock = this.key(owner), cache = this.cache[unlock];
222
+ // Handle: [ owner, key, value ] args
223
+ if (typeof data === "string") {
224
+ cache[data] = value;
225
+ // Handle: [ owner, { properties } ] args
226
+ }
227
+ else {
228
+ // Fresh assignments by object are shallow copied
229
+ if (isEmptyObject(cache)) {
230
+ extend(this.cache[unlock], data);
231
+ // Otherwise, copy the properties one-by-one to the cache object
232
+ }
233
+ else {
234
+ for (prop in data) {
235
+ //@ts-ignore
236
+ cache[prop] = data[prop];
237
+ }
238
+ }
239
+ }
240
+ return cache;
241
+ }
242
+ get(owner, key) {
243
+ // Either a valid cache is found, or will be created.
244
+ // New caches will be created and the unlock returned,
245
+ // allowing direct access to the newly created
246
+ // empty data object. A valid owner object must be provided.
247
+ var cache = this.cache[this.key(owner)];
248
+ return key === undefined ? cache : cache[key];
249
+ }
250
+ access(owner, key, value) {
251
+ var stored;
252
+ // In cases where either:
253
+ //
254
+ // 1. No key was specified
255
+ // 2. A string key was specified, but no value provided
256
+ //
257
+ // Take the "read" path and allow the get method to determine
258
+ // which value to return, respectively either:
259
+ //
260
+ // 1. The entire cache object
261
+ // 2. The data stored at the key
262
+ //
263
+ if (key === undefined || (key && typeof key === "string" && value === undefined)) {
264
+ stored = this.get(owner, key);
265
+ return stored !== undefined ? stored : this.get(owner, camelCase(key));
266
+ }
267
+ // [*]When the key is not a string, or both a key and value
268
+ // are specified, set or extend (existing objects) with either:
269
+ //
270
+ // 1. An object of properties
271
+ // 2. A key and value
272
+ //
273
+ this.set(owner, key, value);
274
+ // Since the "set" path can have two possible entry points
275
+ // return the expected data based on which path was taken[*]
276
+ return value !== undefined ? value : key;
277
+ }
278
+ remove(owner, key) {
279
+ var i, name, camel, unlock = this.key(owner), cache = this.cache[unlock];
280
+ if (key === undefined) {
281
+ this.cache[unlock] = {};
282
+ }
283
+ else {
284
+ // Support array or space separated string of keys
285
+ if (isArray(key)) {
286
+ // If "name" is an array of keys...
287
+ // When data is initially created, via ("key", "val") signature,
288
+ // keys will be converted to camelCase.
289
+ // Since there is no way to tell _how_ a key was added, remove
290
+ // both plain key and camelCase key. #12786
291
+ // This will only penalize the array argument path.
292
+ name = key.concat(key.map(camelCase));
293
+ }
294
+ else {
295
+ camel = camelCase(key);
296
+ // Try the string as a key before any manipulation
297
+ if (key in cache) {
298
+ name = [key, camel];
299
+ }
300
+ else {
301
+ // If a key with the spaces exists, use it.
302
+ // Otherwise, create an array by matching non-whitespace
303
+ name = camel;
304
+ name = name in cache ? [name] : name.match(rnotwhite) || [];
305
+ }
306
+ }
307
+ i = name.length;
308
+ while (i--) {
309
+ delete cache[name[i]];
310
+ }
311
+ }
312
+ }
313
+ hasData(owner) {
314
+ const _owner = owner;
315
+ return !isEmptyObject(this.cache[_owner[this.expando]] || {});
316
+ }
317
+ discard(owner) {
318
+ const _owner = owner;
319
+ if (_owner[this.expando]) {
320
+ delete this.cache[_owner[this.expando]];
321
+ }
322
+ }
323
+ static get [Symbol.for("___CTOR_ARGS___")]() { return []; }
324
+ }
325
+ // var data_priv = new Data();
326
+ const data_user = new Data();
327
+ const getSlideDuration = function (sdkApi, storyId, slideIndex) {
328
+ return sdkApi.getSlideDuration(storyId, slideIndex) ?? 10000;
329
+ };
330
+ const getWinWidth = function (env) {
331
+ return env.innerWidth || env.document.documentElement.clientWidth || env.document.body.clientWidth;
332
+ };
333
+ const getWinHeight = function (env) {
334
+ return env.innerHeight || env.document.documentElement.clientHeight || env.document.body.clientHeight;
335
+ };
336
+ const sendStatisticEventToApp = function (sdkApi, name, data, devPayload) {
337
+ sdkApi.sendStatisticEvent(name, data, devPayload);
338
+ };
339
+ const getValueOrException = function (value, message) {
340
+ if (value == null) {
341
+ throw new Error(message);
342
+ }
343
+ return value;
344
+ };
345
+ const getValueOrDefault = function (value, defaultValue) {
346
+ if (value == null) {
347
+ return defaultValue;
348
+ }
349
+ return value;
350
+ };
351
+ const getElementBounding = (env, rect) => {
352
+ var wWidth = getWinWidth(env);
353
+ var wHeight = getWinHeight(env);
354
+ var bounding = {
355
+ absolute: {
356
+ width: rect.width,
357
+ height: rect.height,
358
+ left: rect.left,
359
+ right: 0,
360
+ center: {
361
+ x: rect.x + rect.width / 2,
362
+ y: rect.y + rect.height / 2,
363
+ },
364
+ },
365
+ width: (rect.width / wWidth) * 100,
366
+ height: (rect.height / wHeight) * 100,
367
+ left: (rect.left / wWidth) * 100,
368
+ right: 0,
369
+ center: {
370
+ x: ((rect.x + rect.width / 2) / wWidth) * 100,
371
+ y: ((rect.y + rect.height / 2) / wHeight) * 100,
372
+ },
373
+ };
374
+ bounding.right = bounding.left + bounding.width;
375
+ bounding.absolute.right = rect.left + rect.width;
376
+ return bounding;
377
+ };
378
+ const toArray = (value) => Array.prototype.slice.call(value);
379
+ const addClass = (target, className) => {
380
+ var arr = target.className.split(" ");
381
+ if (arr.indexOf(className) === -1) {
382
+ target.className += " " + className;
383
+ }
384
+ };
385
+ const removeClass = (target, className) => {
386
+ target.className = target.className.replace(new RegExp("(?:^|\\s)" + className + "(?:\\s|$)"), " ").trim();
387
+ };
388
+ const classList = (target) => {
389
+ if (target.classList !== undefined) {
390
+ return toArray(target.classList);
391
+ }
392
+ return target.className.split(" ");
393
+ };
394
+ const hasClass = (target, className) => classList(target).indexOf(className) !== -1;
395
+ const Clipboard = (function (window, document, navigator) {
396
+ let textArea;
397
+ function isOS() {
398
+ return navigator.userAgent.match(/ipad|iphone/i);
399
+ }
400
+ function createTextArea(text) {
401
+ textArea = document.createElement("textArea");
402
+ textArea.value = text;
403
+ document.body.appendChild(textArea);
404
+ }
405
+ function selectText() {
406
+ if (isOS()) {
407
+ const range = document.createRange();
408
+ range.selectNodeContents(textArea);
409
+ const selection = window.getSelection();
410
+ if (selection) {
411
+ selection.removeAllRanges();
412
+ selection.addRange(range);
413
+ }
414
+ textArea.setSelectionRange(0, 999999);
415
+ }
416
+ else {
417
+ textArea.select();
418
+ }
419
+ }
420
+ function copyToClipboard() {
421
+ document.execCommand("copy");
422
+ document.body.removeChild(textArea);
423
+ }
424
+ const copy = function (text) {
425
+ createTextArea(text);
426
+ selectText();
427
+ copyToClipboard();
428
+ };
429
+ return {
430
+ copy,
431
+ };
432
+ })(window, document, navigator);
433
+
434
+ var supportAnimate = document.documentElement.animate !== undefined;
435
+ supportAnimate = false; // tmp off
436
+ var _intervals = [];
437
+ var _startShakeAnimation = function (element) {
438
+ var step = 0;
439
+ return window.setInterval(function () {
440
+ if (element) {
441
+ switch (step) {
442
+ case 0:
443
+ element.style.setProperty("transform", "translate(1px, 1px) rotate(0deg)");
444
+ break;
445
+ case 10:
446
+ element.style.setProperty("transform", "translate(-1px, -2px) rotate(-1deg)");
447
+ break;
448
+ case 20:
449
+ element.style.setProperty("transform", "translate(-3px, 0px) rotate(1deg)");
450
+ break;
451
+ case 30:
452
+ element.style.setProperty("transform", "translate(3px, 2px) rotate(0deg)");
453
+ break;
454
+ case 40:
455
+ element.style.setProperty("transform", "translate(1px, -1px) rotate(1deg)");
456
+ break;
457
+ case 50:
458
+ element.style.setProperty("transform", "translate(-1px, 2px) rotate(-1deg)");
459
+ break;
460
+ case 60:
461
+ element.style.setProperty("transform", "translate(-3px, 1px) rotate(0deg)");
462
+ break;
463
+ case 70:
464
+ element.style.setProperty("transform", "translate(-3px, 1px) rotate(0deg)");
465
+ break;
466
+ case 80:
467
+ element.style.setProperty("transform", "translate(-1px, -1px) rotate(1deg)");
468
+ break;
469
+ case 90:
470
+ element.style.setProperty("transform", "translate(1px, 2px) rotate(0deg)");
471
+ break;
472
+ case 100:
473
+ element.style.setProperty("transform", "translate(1px, -2px) rotate(-1deg)");
474
+ break;
475
+ }
476
+ step += 10;
477
+ if (step > 100) {
478
+ step = 0;
479
+ }
480
+ }
481
+ }, 100);
482
+ };
483
+ var _startExpandShakeAnimation = function (element) {
484
+ var step = 0;
485
+ return window.setInterval(function () {
486
+ if (element) {
487
+ switch (step) {
488
+ case 0:
489
+ element.style.setProperty("transform", "translate(1px, 1px) rotate(0deg) scale(1.1)");
490
+ break;
491
+ case 10:
492
+ element.style.setProperty("transform", "translate(-1px, -2px) rotate(-1deg) scale(1.1)");
493
+ break;
494
+ case 20:
495
+ element.style.setProperty("transform", "translate(-3px, 0px) rotate(1deg) scale(1.1)");
496
+ break;
497
+ case 30:
498
+ element.style.setProperty("transform", "translate(3px, 2px) rotate(0deg) scale(1.1)");
499
+ break;
500
+ case 40:
501
+ element.style.setProperty("transform", "translate(1px, -1px) rotate(1deg) scale(1.1)");
502
+ break;
503
+ case 50:
504
+ element.style.setProperty("transform", "translate(-1px, 2px) rotate(-1deg) scale(1.1)");
505
+ break;
506
+ case 60:
507
+ element.style.setProperty("transform", "translate(-3px, 1px) rotate(0deg) scale(1.1)");
508
+ break;
509
+ case 70:
510
+ element.style.setProperty("transform", "translate(3px, 1px) rotate(-1deg) scale(1.1)");
511
+ break;
512
+ case 80:
513
+ element.style.setProperty("transform", "translate(-1px, -1px) rotate(1deg) scale(1.1)");
514
+ break;
515
+ case 90:
516
+ element.style.setProperty("transform", "translate(1px, 2px) rotate(0deg) scale(1.1)");
517
+ break;
518
+ case 100:
519
+ element.style.setProperty("transform", "translate(1px, -2px) rotate(-1deg) scale(1.1)");
520
+ break;
521
+ }
522
+ step += 10;
523
+ if (step > 100) {
524
+ step = 0;
525
+ }
526
+ }
527
+ }, 100);
528
+ };
529
+ var _startBlurAnimation = function (element) {
530
+ const listener = (e) => {
531
+ if (e.propertyName === "filter" && e.target != null) {
532
+ const target = e.target;
533
+ if (hasClass(target, "animated")) {
534
+ if (target.style.filter === "blur(0px)" || target.style.filter === "") {
535
+ setTimeout(function () {
536
+ target.style.filter = "blur(5px)";
537
+ }, 10);
538
+ }
539
+ else if (target.style.filter === "blur(5px)") {
540
+ setTimeout(function () {
541
+ target.style.filter = "blur(0px)";
542
+ }, 10);
543
+ }
544
+ }
545
+ else {
546
+ target.style.filter = "";
547
+ target.removeEventListener("transitionend", listener);
548
+ }
549
+ }
550
+ };
551
+ element.addEventListener("transitionend", listener);
552
+ };
553
+ var shortDuration = {
554
+ duration: 1000,
555
+ iterations: 1,
556
+ };
557
+ var longDuration = {
558
+ duration: 10000,
559
+ iterations: 1,
560
+ };
561
+ var extraLongDuration = {
562
+ duration: 20000,
563
+ iterations: 1,
564
+ };
565
+ var longInfinityDuration = {
566
+ duration: 10000,
567
+ iterations: Infinity,
568
+ };
569
+ var getAnimationFunction = function (element) {
570
+ if (!hasClass(element, "animated")) {
571
+ if (hasClass(element, "narrative-element-animation-shake")) {
572
+ if (element.parentElement && hasClass(element.parentElement, "narrative-element-expand")) {
573
+ return function () {
574
+ _intervals.push(_startExpandShakeAnimation(element));
575
+ addClass(element, "animated");
576
+ };
577
+ }
578
+ else {
579
+ return function () {
580
+ _intervals.push(_startShakeAnimation(element));
581
+ addClass(element, "animated");
582
+ };
583
+ }
584
+ }
585
+ else if (hasClass(element, "narrative-element-animation-blur")) {
586
+ return function () {
587
+ _startBlurAnimation(element);
588
+ addClass(element, "animated");
589
+ };
590
+ }
591
+ else {
592
+ return function () {
593
+ addClass(element, "active");
594
+ addClass(element, "animated");
595
+ };
596
+ }
597
+ }
598
+ return function () { };
599
+ };
600
+ const animationApi = {
601
+ start: function (slide, animate = false) {
602
+ if (supportAnimate && animate) {
603
+ // for editor, todo add .reset-animation to narrative-editor-slide && clear that
604
+ if (!hasClass(slide, "narrative-slide")) {
605
+ addClass(slide, "reset-animation");
606
+ }
607
+ const elements = toArray(slide.querySelectorAll(".narrative-element-animation"));
608
+ elements.forEach(element => {
609
+ var width = element.offsetWidth;
610
+ var height = element.offsetHeight;
611
+ var _classList = classList(element);
612
+ if (_classList.indexOf("narrative-element-animation-fade-in-up") !== -1) {
613
+ element.animate({
614
+ transform: ["translateY(" + height + "px)", "translateY(0)"],
615
+ opacity: [0, 1],
616
+ }, shortDuration);
617
+ }
618
+ else if (_classList.indexOf("narrative-element-animation-fade-in-down") !== -1) {
619
+ element.animate({
620
+ transform: ["translateY(" + -1 * height + "px)", "translateY(0)"],
621
+ opacity: [0, 1],
622
+ }, shortDuration);
623
+ }
624
+ else if (_classList.indexOf("narrative-element-animation-fade-in-left") !== -1) {
625
+ element.animate({
626
+ transform: ["translateX(" + -1 * width + "px)", "translateX(0)"],
627
+ opacity: [0, 1],
628
+ }, shortDuration);
629
+ }
630
+ else if (_classList.indexOf("narrative-element-animation-fade-in-right") !== -1) {
631
+ element.animate({
632
+ transform: ["translateX(" + width + "px)", "translateX(0)"],
633
+ opacity: [0, 1],
634
+ }, shortDuration);
635
+ }
636
+ else if (_classList.indexOf("narrative-element-animation-blur") !== -1) {
637
+ element.animate([
638
+ { filter: "blur(5px)", offset: 0 },
639
+ { filter: "blur(0px)", offset: 0.5 },
640
+ { filter: "blur(5px)", offset: 1 },
641
+ ], longInfinityDuration);
642
+ }
643
+ else if (_classList.indexOf("narrative-element-animation-focus-in") !== -1) {
644
+ element.animate({ filter: ["blur(12px)", "blur(0px)"], opacity: [0, 1] }, shortDuration);
645
+ }
646
+ else if (_classList.indexOf("narrative-element-animation-scroll-left") !== -1) {
647
+ element.animate({
648
+ transform: ["scale(1.2) translateX(" + 0.08 * width + "px)", "scale(1.2) translateX(" + -0.08 * width + "px)"],
649
+ }, extraLongDuration);
650
+ }
651
+ else if (_classList.indexOf("narrative-element-animation-scroll-right") !== -1) {
652
+ element.animate({
653
+ transform: ["scale(1.2) translateX(" + -0.08 * width + "px)", "scale(1.2) translateX(" + 0.08 * width + "px)"],
654
+ }, extraLongDuration);
655
+ }
656
+ else if (_classList.indexOf("narrative-element-animation-scroll-up") !== -1) {
657
+ element.animate({
658
+ transform: ["scale(1.2) translateY(" + 0.08 * width + "px)", "scale(1.2) translateY(" + -0.08 * width + "px)"],
659
+ }, extraLongDuration);
660
+ }
661
+ else if (_classList.indexOf("narrative-element-animation-scroll-down") !== -1) {
662
+ element.animate({
663
+ transform: ["scale(1.2) translateY(" + -0.08 * width + "px)", "scale(1.2) translateY(" + 0.08 * width + "px)"],
664
+ }, extraLongDuration);
665
+ }
666
+ else if (_classList.indexOf("narrative-element-animation-zoom") !== -1) {
667
+ element.animate({ transform: ["scale(1)", "scale(1.2)"] }, longDuration);
668
+ }
669
+ else if (_classList.indexOf("narrative-element-animation-zoom-out") !== -1) {
670
+ element.animate({ transform: ["scale(1.2)", "scale(1)"] }, longDuration);
671
+ }
672
+ else if (_classList.indexOf("narrative-element-animation-shake") !== -1) {
673
+ element.animate([
674
+ { transform: "translate(1px, 1px) rotate(0deg)", offset: 0 },
675
+ { transform: "translate(-1px, -2px) rotate(-1deg)", offset: 0.1 },
676
+ { transform: "translate(-3px, 0px) rotate(1deg)", offset: 0.2 },
677
+ { transform: "translate(3px, 2px) rotate(0deg)", offset: 0.3 },
678
+ { transform: "translate(1px, -1px) rotate(1deg)", offset: 0.4 },
679
+ { transform: "translate(-1px, 2px) rotate(-1deg)", offset: 0.5 },
680
+ { transform: "translate(-3px, 1px) rotate(0deg)", offset: 0.6 },
681
+ { transform: "translate(3px, 1px) rotate(-1deg)", offset: 0.7 },
682
+ { transform: "translate(-1px, -1px) rotate(1deg)", offset: 0.8 },
683
+ { transform: "translate(1px, 2px) rotate(0deg)", offset: 0.9 },
684
+ { transform: "translate(1px, -2px) rotate(-1deg)", offset: 1 },
685
+ ], { duration: 1000, iterations: Infinity, composite: "add" });
686
+ }
687
+ });
688
+ if (elements.length > 0) {
689
+ requestAnimationFrame(() => removeClass(slide, "reset-animation"));
690
+ }
691
+ }
692
+ else {
693
+ addClass(slide, "animation-fallback");
694
+ const animations = [];
695
+ // просто Array
696
+ var elements = slide.querySelectorAll(".narrative-element-animation");
697
+ var isEditorSlide = hasClass(slide, "narrative-editor-slide");
698
+ for (var i = 0; i < elements.length; i++) {
699
+ if (!isEditorSlide && !elements[i].style.getPropertyValue("--width")) {
700
+ var rects = elements[i].getBoundingClientRect();
701
+ var width = rects.width;
702
+ var height = rects.height;
703
+ if (width && height) {
704
+ elements[i].style.setProperty("--width", width + "px");
705
+ elements[i].style.setProperty("--height", height + "px");
706
+ }
707
+ }
708
+ (function (element) {
709
+ var timeout = 50;
710
+ if (element.getAttribute("data-animation-timeout") && parseFloat(element.getAttribute("data-animation-timeout") ?? "0")) {
711
+ timeout = parseFloat(element.getAttribute("data-animation-timeout") ?? "0") * 1000;
712
+ }
713
+ const cb = () => {
714
+ getAnimationFunction(element)();
715
+ if (animation) {
716
+ animation.timerId = undefined;
717
+ }
718
+ };
719
+ const animation = {
720
+ cb,
721
+ timeout,
722
+ timerId: window.setTimeout(cb, timeout),
723
+ };
724
+ animations.push(animation);
725
+ })(elements[i]);
726
+ }
727
+ var startAt = new Date().getTime();
728
+ // onstop && onpause
729
+ return function (isStop) {
730
+ for (var animation of animations) {
731
+ if (animation["timerId"] !== undefined) {
732
+ clearTimeout(animation["timerId"]);
733
+ animation["timerId"] = undefined;
734
+ animation["timeout"] -= new Date().getTime() - startAt;
735
+ animation["needResume"] = !isStop;
736
+ }
737
+ }
738
+ // resume
739
+ return function () {
740
+ startAt = new Date().getTime();
741
+ for (const animation of animations) {
742
+ if (animation["timerId"] === undefined && animation["needResume"] === true) {
743
+ animation["timerId"] = window.setTimeout(animation["cb"], animation["timeout"]);
744
+ }
745
+ }
746
+ };
747
+ };
748
+ }
749
+ },
750
+ stop: function (slide, animate) {
751
+ if (supportAnimate && animate) {
752
+ /** @type {HTMLElement[]} */
753
+ var elements = toArray(slide.querySelectorAll(".narrative-element-animation"));
754
+ elements.forEach(function (el) {
755
+ el.getAnimations().forEach(function (animation) {
756
+ animation.cancel();
757
+ });
758
+ });
759
+ }
760
+ else {
761
+ for (var i = 0; i < _intervals.length; i++) {
762
+ clearInterval(_intervals[i]);
763
+ }
764
+ if (slide) {
765
+ var elements = toArray(slide.querySelectorAll(".narrative-element-animation"));
766
+ for (var i = 0; i < elements.length; i++) {
767
+ removeClass(elements[i], "active");
768
+ removeClass(elements[i], "animated");
769
+ elements[i].style.setProperty("transform", "");
770
+ elements[i].style.setProperty("filter", "");
771
+ }
772
+ }
773
+ }
774
+ },
775
+ pause: function (slide) {
776
+ if (supportAnimate) {
777
+ /* var elements = document.querySelectorAll('.narrative-element-animation');
778
+ elements = _toArray(elements);
779
+
780
+ elements.forEach(function(el) {
781
+ el.playState = "paused";
782
+ // el.currentTime = 0;
783
+ });*/
784
+ var elements = toArray(slide.querySelectorAll(".narrative-element-animation"));
785
+ elements.forEach(function (el) {
786
+ el.getAnimations().forEach(function (animation) {
787
+ if (animation.playState !== "finished" && animation.playState === "running") {
788
+ animation.pause();
789
+ }
790
+ });
791
+ });
792
+ // slide.getAnimations().forEach(function (animation) {
793
+ // if (animation.playState !== 'finished' && animation.playState === 'running') {
794
+ // animation.pause();
795
+ // }
796
+ // });
797
+ }
798
+ },
799
+ resume: function (slide) {
800
+ if (supportAnimate) {
801
+ var elements = toArray(slide.querySelectorAll(".narrative-element-animation"));
802
+ elements.forEach(function (el) {
803
+ el.getAnimations().forEach(function (animation) {
804
+ if (animation.playState === "paused") {
805
+ animation.play();
806
+ }
807
+ });
808
+ });
809
+ }
810
+ },
811
+ reset: function (slide) {
812
+ // _addClass(slide, 'reset-animation');
813
+ },
814
+ };
815
+
816
+ const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = `___CTOR_ARGS___`;
817
+ const CONSTRUCTOR_ARGUMENTS_SYMBOL = Symbol.for(CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER);
818
+
819
+ /**
820
+ * A Dependency-Injection container that holds services and can produce instances of them as required.
821
+ * It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
822
+ * @author Frederik Wessberg
823
+ */
824
+ class DIContainer {
825
+ /**
826
+ * A map between interface names and the services that should be dependency injected
827
+ */
828
+ constructorArguments = new Map();
829
+ /**
830
+ * A Map between identifying names for services and their IRegistrationRecords.
831
+ */
832
+ serviceRegistry = new Map();
833
+ /**
834
+ * A map between identifying names for services and concrete instances of their implementation.
835
+ */
836
+ instances = new Map();
837
+ registerSingleton(newExpression, options) {
838
+ if (options == null) {
839
+ throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
840
+ }
841
+ if (newExpression == null) {
842
+ return this.register("SINGLETON", newExpression, options);
843
+ }
844
+ else {
845
+ return this.register("SINGLETON", newExpression, options);
846
+ }
847
+ }
848
+ registerTransient(newExpression, options) {
849
+ if (options == null) {
850
+ throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
851
+ }
852
+ if (newExpression == null) {
853
+ return this.register("TRANSIENT", newExpression, options);
854
+ }
855
+ else {
856
+ return this.register("TRANSIENT", newExpression, options);
857
+ }
858
+ }
859
+ /**
860
+ * Gets an instance of the service matching the interface given as a generic type parameter.
861
+ * For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
862
+ * generic interface name.
863
+ *
864
+ * You should not pass any options to the method if using the compiler. It will do that automatically.
865
+ */
866
+ get(options) {
867
+ if (options == null) {
868
+ throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
869
+ }
870
+ return this.constructInstance(options);
871
+ }
872
+ /**
873
+ * Returns true if a service has been registered matching the interface given as a generic type parameter.
874
+ * For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
875
+ * generic interface name.
876
+ *
877
+ * You should not pass any options to the method if using the compiler. It will do that automatically.
878
+ */
879
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
880
+ has(options) {
881
+ if (options == null) {
882
+ throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
883
+ }
884
+ return this.serviceRegistry.has(options.identifier);
885
+ }
886
+ register(kind, newExpression, options) {
887
+ // Take all of the constructor arguments for the implementation
888
+ const implementationArguments = "implementation" in options &&
889
+ options.implementation != null &&
890
+ options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL] != null
891
+ ? options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL]
892
+ : [];
893
+ this.constructorArguments.set(options.identifier, implementationArguments);
894
+ this.serviceRegistry.set(options.identifier, "implementation" in options && options.implementation != null
895
+ ? { ...options, kind }
896
+ : { ...options, kind, newExpression: newExpression });
897
+ }
898
+ /**
899
+ * Returns true if an instance exists that matches the given identifier.
900
+ */
901
+ hasInstance(identifier) {
902
+ return this.getInstance(identifier) != null;
903
+ }
904
+ /**
905
+ * Gets the cached instance, if any, associated with the given identifier.
906
+ */
907
+ getInstance(identifier) {
908
+ const instance = this.instances.get(identifier);
909
+ return instance == null ? null : instance;
910
+ }
911
+ /**
912
+ * Gets an IRegistrationRecord associated with the given identifier.
913
+ */
914
+ getRegistrationRecord({ identifier, parentChain, }) {
915
+ const record = this.serviceRegistry.get(identifier);
916
+ if (record == null) {
917
+ throw new ReferenceError(`${this.constructor.name} could not find a service for identifier: "${identifier}". ${parentChain == null || parentChain.length < 1
918
+ ? ""
919
+ : `It is required by the service: '${parentChain
920
+ .map((parent) => parent.identifier)
921
+ .join(" -> ")}'.`} Remember to register it as a service!`);
922
+ }
923
+ return record;
924
+ }
925
+ /**
926
+ * Caches the given instance so that it can be retrieved in the future.
927
+ */
928
+ setInstance(identifier, instance) {
929
+ this.instances.set(identifier, instance);
930
+ return instance;
931
+ }
932
+ /**
933
+ * Gets a lazy reference to another service
934
+ */
935
+ getLazyIdentifier(lazyPointer) {
936
+ return (new Proxy({}, { get: (_, key) => lazyPointer()[key] }));
937
+ }
938
+ /**
939
+ * Constructs a new instance of the given identifier and returns it.
940
+ * It checks the constructor arguments and injects any services it might depend on recursively.
941
+ */
942
+ constructInstance({ identifier, parentChain = [], }) {
943
+ const registrationRecord = this.getRegistrationRecord({
944
+ identifier,
945
+ parentChain,
946
+ });
947
+ // If an instance already exists (and it is a singleton), return that one
948
+ if (this.hasInstance(identifier) &&
949
+ registrationRecord.kind === "SINGLETON") {
950
+ return this.getInstance(identifier);
951
+ }
952
+ // Otherwise, instantiate a new one
953
+ let instance;
954
+ const me = {
955
+ identifier,
956
+ ref: this.getLazyIdentifier(() => instance),
957
+ };
958
+ // If a user-provided new-expression has been provided, invoke that to get an instance.
959
+ if ("newExpression" in registrationRecord) {
960
+ if (typeof registrationRecord.newExpression !== "function") {
961
+ throw new TypeError(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': You provided a custom instantiation argument, but it wasn't of type function. It has to be a function that returns whatever should be used as an instance of the Service!`);
962
+ }
963
+ try {
964
+ instance = registrationRecord.newExpression();
965
+ }
966
+ catch (ex) {
967
+ throw new Error(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': When you registered the service, you provided a custom instantiation function, but it threw an exception when it was run!`);
968
+ }
969
+ }
970
+ else {
971
+ // Find the arguments for the identifier
972
+ const mappedArgs = this.constructorArguments.get(identifier);
973
+ if (mappedArgs == null) {
974
+ throw new ReferenceError(`${this.constructor.name} could not find constructor arguments for the service: '${identifier}'. Have you registered it as a service?`);
975
+ }
976
+ // Instantiate all of the argument services (or re-use them if they were registered as singletons)
977
+ const instanceArgs = mappedArgs.map((dep) => {
978
+ if (dep === undefined)
979
+ return undefined;
980
+ const matchedParent = parentChain.find((parent) => parent.identifier === dep);
981
+ if (matchedParent != null)
982
+ return matchedParent.ref;
983
+ return this.constructInstance({
984
+ identifier: dep,
985
+ parentChain: [...parentChain, me],
986
+ });
987
+ });
988
+ try {
989
+ // Try to construct an instance with 'new' and if it fails, call the implementation directly.
990
+ const newable = registrationRecord.implementation;
991
+ instance = new newable(...instanceArgs);
992
+ }
993
+ catch (ex) {
994
+ if (registrationRecord.implementation == null) {
995
+ throw new ReferenceError(`${this.constructor.name} could not construct a new service of kind: ${identifier}. Reason: No implementation was given!`);
996
+ }
997
+ const constructable = registrationRecord.implementation;
998
+ // Try without 'new' and call the implementation as a function.
999
+ instance = constructable(...instanceArgs);
1000
+ }
1001
+ }
1002
+ return registrationRecord.kind === "SINGLETON"
1003
+ ? this.setInstance(identifier, instance)
1004
+ : instance;
1005
+ }
1006
+ }
1007
+ const DI_COMPILER_ERROR_HINT = `Note: You must use DI-Compiler (https://github.com/wessberg/di-compiler) for this library to work correctly. Please consult the readme for instructions on how to install and configure it for your project.`;
1008
+
1009
+ const container = new DIContainer();
1010
+
1011
+ class WidgetsService {
1012
+ _env;
1013
+ _sdkApi;
1014
+ constructor(_env, _sdkApi) {
1015
+ this._env = _env;
1016
+ this._sdkApi = _sdkApi;
1017
+ }
1018
+ get env() {
1019
+ return this._env;
1020
+ }
1021
+ get sdkApi() {
1022
+ return this._sdkApi;
1023
+ }
1024
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`Window`, `SDKApi`]; }
1025
+ }
1026
+
1027
+ container.registerSingleton(undefined, { identifier: `WidgetsService`, implementation: WidgetsService });
1028
+
1029
+ // import '../adapters/dateTimeSource/composition';
1030
+ // import '../adapters/uuidGenerator/composition';
1031
+ // import '../effects/eventHandler/composition';
1032
+ // import '../effects/logger/composition';
1033
+ // import '../effects/timer/composition';
1034
+ container.registerSingleton(() => window, { identifier: `Window` });
1035
+
1036
+ class WidgetBase {
1037
+ /**
1038
+ * @see https://github.com/Microsoft/TypeScript/issues/3841#issuecomment-337560146
1039
+ */
1040
+ ["constructor"];
1041
+ static DEFAULTS = {
1042
+ slide: null,
1043
+ activateAfterCreate: false,
1044
+ create: false,
1045
+ localData: {},
1046
+ };
1047
+ static widgetIndex = 0;
1048
+ env = WidgetBase.widgetsService.env;
1049
+ sdkApi = WidgetBase.widgetsService.sdkApi;
1050
+ options = null;
1051
+ element = null;
1052
+ elementId = null;
1053
+ slide = null;
1054
+ slideIndex = null;
1055
+ disableTimer = null;
1056
+ layoutDirection = "ltr";
1057
+ storyId = null;
1058
+ widgetDone = null;
1059
+ showWidgetCompleteToast = null;
1060
+ submitButtonAnimatedView = null;
1061
+ submitButtonView = null;
1062
+ submitButtonViewHeight = 0;
1063
+ savedData = null;
1064
+ localData = null;
1065
+ firstOpenTime = 0;
1066
+ id;
1067
+ constructor(element, options, elementIdGetter, slideGetter) {
1068
+ this.options = extend({}, this.constructor.DEFAULTS, options);
1069
+ this.element = element;
1070
+ if (elementIdGetter) {
1071
+ this.elementId = elementIdGetter(this.element);
1072
+ }
1073
+ else {
1074
+ this.elementId = getValueOrException(getTagData(this.element, "elementId"), "Empty elementId");
1075
+ }
1076
+ if (slideGetter) {
1077
+ this.slide = slideGetter(this.element);
1078
+ }
1079
+ else {
1080
+ this.slide = getValueOrException(this.element.closest(".narrative-slide"), "Empty slide");
1081
+ }
1082
+ this.slideIndex = getValueOrException(getTagDataAsNumber(this.slide, "index"), "Empty slideIndex");
1083
+ this.disableTimer = getTagData(this.slide, "disableTimer") === "1";
1084
+ this.storyId = getValueOrException(getTagDataAsNumber(this.slide, "id"), "Empty storyId");
1085
+ if (this.env.getComputedStyle(this.element).direction === "rtl") {
1086
+ this.layoutDirection = "rtl";
1087
+ }
1088
+ else {
1089
+ this.layoutDirection = "ltr";
1090
+ }
1091
+ this.element.dir = this.layoutDirection;
1092
+ if (this.element.parentElement != null) {
1093
+ this.widgetDone = this.element.parentElement?.nextElementSibling; // geometry + .widget-sent-toast
1094
+ if (this.widgetDone) {
1095
+ if (!this.widgetDone.classList.contains("widget-sent-toast")) {
1096
+ this.widgetDone = null;
1097
+ }
1098
+ }
1099
+ }
1100
+ this.showWidgetCompleteToast = Boolean(getValueOrDefault(getTagDataAsNumber(this.element, "showWidgetCompleteToast"), 0));
1101
+ if (!this.showWidgetCompleteToast) {
1102
+ this.widgetDone = null;
1103
+ }
1104
+ if (this.element != null) {
1105
+ this.submitButtonAnimatedView = this.element.querySelector(".submit-button-animated-view");
1106
+ if (this.submitButtonAnimatedView != null) {
1107
+ this.submitButtonView = this.submitButtonAnimatedView.querySelector(".submit-button-view");
1108
+ if (this.submitButtonView != null) {
1109
+ this.submitButtonViewHeight = this.submitButtonView.clientHeight;
1110
+ }
1111
+ }
1112
+ }
1113
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
1114
+ this.localData = extend({}, this.savedData ?? {}, this.options.localData ?? {});
1115
+ this.id = `w_${this.elementId}_${WidgetBase.widgetIndex}`;
1116
+ ++WidgetBase.widgetIndex;
1117
+ }
1118
+ refreshUserData(localData) { }
1119
+ static widgetCacheKey = "ias.story-element";
1120
+ static widgetClassName = "";
1121
+ static getInstance(element) {
1122
+ return data(element, this.widgetCacheKey);
1123
+ }
1124
+ static getInstanceById(id) {
1125
+ const widgetsElements = slice.call(this.widgetsService.env.document.querySelectorAll(`.${this.widgetClassName}`));
1126
+ let widget;
1127
+ forEach(widgetsElements, (element, index) => {
1128
+ const localWidget = data(element, this.widgetCacheKey);
1129
+ if (localWidget && localWidget.id === id) {
1130
+ widget = localWidget;
1131
+ }
1132
+ });
1133
+ return widget;
1134
+ }
1135
+ static createInstance(instantiate, element, options) {
1136
+ // get from objects cache (just Map<key, data> where key assigned to HTMLElement)
1137
+ let instance = WidgetBase.getInstance(element);
1138
+ if (instance == null) {
1139
+ // can throw Error
1140
+ instance = instantiate(element, options);
1141
+ // save object in cache by key associated with HTMLElement
1142
+ data(element, WidgetBase.widgetCacheKey, instance);
1143
+ }
1144
+ return instance;
1145
+ }
1146
+ static initWidgets(instantiate, elements, localData) {
1147
+ if (localData != null) {
1148
+ forEach(elements, element => {
1149
+ this.createInstance(instantiate, element, {
1150
+ slide: null,
1151
+ localData,
1152
+ });
1153
+ });
1154
+ return Promise.resolve(localData);
1155
+ }
1156
+ else {
1157
+ return new Promise(resolve => {
1158
+ this.getLocalData().then(localData => {
1159
+ forEach(elements, element => {
1160
+ this.createInstance(instantiate, element, {
1161
+ slide: null,
1162
+ localData,
1163
+ });
1164
+ });
1165
+ resolve(localData);
1166
+ });
1167
+ });
1168
+ }
1169
+ }
1170
+ static get widgetsService() {
1171
+ return container.get({ identifier: "WidgetsService" });
1172
+ }
1173
+ static getLocalData() {
1174
+ return this.widgetsService.sdkApi.getStoryLocalData();
1175
+ }
1176
+ getLocalData() {
1177
+ return this.constructor.getLocalData();
1178
+ }
1179
+ static setLocalData(keyValue, sendToServer, syncWithRuntimeLocalData) {
1180
+ // push json object as string
1181
+ if (sendToServer === undefined) {
1182
+ sendToServer = true;
1183
+ }
1184
+ else {
1185
+ sendToServer = Boolean(sendToServer);
1186
+ }
1187
+ if (syncWithRuntimeLocalData === undefined) {
1188
+ syncWithRuntimeLocalData = true;
1189
+ }
1190
+ else {
1191
+ syncWithRuntimeLocalData = Boolean(syncWithRuntimeLocalData);
1192
+ }
1193
+ if (syncWithRuntimeLocalData) {
1194
+ this.getLocalData().then(localData => {
1195
+ // 1 - old values, 2 - new values
1196
+ keyValue = extend({}, localData, keyValue);
1197
+ // todo make async via promise or async
1198
+ this.widgetsService.sdkApi.setStoryLocalData(keyValue, sendToServer);
1199
+ });
1200
+ }
1201
+ else {
1202
+ // todo make async via promise or async
1203
+ this.widgetsService.sdkApi.setStoryLocalData(keyValue, sendToServer);
1204
+ }
1205
+ }
1206
+ setLocalData(keyValue, sendToServer, syncWithRuntimeLocalData) {
1207
+ return this.constructor.setLocalData(keyValue, sendToServer, syncWithRuntimeLocalData);
1208
+ }
1209
+ static sendStatisticEventToApp(name, data, devPayload) {
1210
+ sendStatisticEventToApp(this.widgetsService.sdkApi, name, data, devPayload);
1211
+ }
1212
+ sendStatisticEventToApp(name, data, devPayload) {
1213
+ this.constructor.sendStatisticEventToApp(name, data, devPayload);
1214
+ }
1215
+ showNextSlide() {
1216
+ this.sdkApi.showNextSlide(getSlideDuration(this.sdkApi, this.storyId, this.slideIndex));
1217
+ }
1218
+ _showLayout(layers, selectIndex, withStatEvent = false) {
1219
+ if (this.sdkApi.isExistsShowLayer()) {
1220
+ this.sdkApi.showLayer(selectIndex);
1221
+ }
1222
+ else {
1223
+ forEach(layers, (layer, index) => {
1224
+ if (index === selectIndex) {
1225
+ layer.classList.remove("hidden");
1226
+ this.sdkApi.storyAnimation?.start(layer);
1227
+ }
1228
+ else {
1229
+ layer.classList.add("hidden");
1230
+ }
1231
+ });
1232
+ }
1233
+ if (withStatEvent) {
1234
+ this._statEventLayoutShow(selectIndex);
1235
+ }
1236
+ }
1237
+ _statEventLayoutShow(layoutIndex) {
1238
+ try {
1239
+ this.sendStatisticEventToApp("layout-show", {
1240
+ i: this.storyId,
1241
+ si: this.slideIndex,
1242
+ li: layoutIndex,
1243
+ }, {
1244
+ story_id: this.storyId,
1245
+ slide_index: this.slideIndex,
1246
+ layout_index: layoutIndex,
1247
+ });
1248
+ }
1249
+ catch (error) {
1250
+ console.error(error);
1251
+ }
1252
+ }
1253
+ static api = {
1254
+ refreshUserData: function (nodes, localData) {
1255
+ const cb = (el, localData) => {
1256
+ var widgetElement = el.closest(`.${WidgetBase.widgetClassName}`);
1257
+ if (widgetElement) {
1258
+ const widget = WidgetBase.getInstance(widgetElement);
1259
+ if (widget) {
1260
+ widget.refreshUserData(localData);
1261
+ }
1262
+ }
1263
+ };
1264
+ if (localData != null) {
1265
+ const elements = slice.call(nodes);
1266
+ forEach(elements, el => cb(el, localData));
1267
+ }
1268
+ else {
1269
+ WidgetBase.getLocalData().then(localData => {
1270
+ const elements = slice.call(nodes);
1271
+ forEach(elements, el => cb(el, localData));
1272
+ });
1273
+ }
1274
+ },
1275
+ };
1276
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`, `(element: HTMLElement) => string`, `(element: HTMLElement) => HTMLElement`]; }
1277
+ }
1278
+
1279
+ class WidgetCopy extends WidgetBase {
1280
+ static DEFAULTS = {
1281
+ slide: null,
1282
+ activateAfterCreate: false,
1283
+ create: false,
1284
+ localData: {},
1285
+ };
1286
+ static widgetClassName = "narrative-element-copy";
1287
+ button;
1288
+ clipboardTarget;
1289
+ isPromotionalCode;
1290
+ state;
1291
+ msgNetworkError;
1292
+ msgServiceError;
1293
+ msgNoMoreCodes;
1294
+ msgTryAgain;
1295
+ geometry;
1296
+ resultLayer;
1297
+ resultLayerGeometry;
1298
+ constructor(element, options) {
1299
+ super(element, options);
1300
+ this.button = this.element.querySelector(".narrative-element-text-lines");
1301
+ this.clipboardTarget = getTagData(element, "clipboardTarget");
1302
+ this.isPromotionalCode = getTagData(element, "clipboardType") === "promocode";
1303
+ this.state = null;
1304
+ this.msgNetworkError = getTagData(this.element, "msgNetworkError");
1305
+ this.msgServiceError = getTagData(this.element, "msgServiceError");
1306
+ this.msgNoMoreCodes = getTagData(this.element, "msgNoMoreCodes");
1307
+ this.msgTryAgain = getTagData(this.element, "msgTryAgain");
1308
+ this.geometry = this.element.closest(".narrative-element-geometry");
1309
+ this.resultLayer = this.slide.querySelector(".narrative-element-copy-result-variant");
1310
+ if (this.resultLayer && this.geometry) {
1311
+ this.resultLayerGeometry = this.resultLayer.closest(".narrative-element-geometry");
1312
+ // create align center
1313
+ if (this.resultLayerGeometry) {
1314
+ var baseComputedGeometry = window.getComputedStyle(this.geometry);
1315
+ var resultComputedGeometry = window.getComputedStyle(this.resultLayerGeometry);
1316
+ if (parseFloat(resultComputedGeometry.width) < parseFloat(baseComputedGeometry.width)) {
1317
+ // prevent resultLayer shrinking
1318
+ this.resultLayerGeometry.style.setProperty("width", parseFloat(baseComputedGeometry.width) + "px");
1319
+ resultComputedGeometry = window.getComputedStyle(this.resultLayerGeometry);
1320
+ }
1321
+ var geometryCenter = parseFloat(baseComputedGeometry.left) + parseFloat(baseComputedGeometry.width) / 2;
1322
+ var resultLayerGeometryWidth = parseFloat(resultComputedGeometry.width);
1323
+ var newResultLayerGeometryLeft = geometryCenter - resultLayerGeometryWidth / 2;
1324
+ this.resultLayerGeometry.style.setProperty("left", newResultLayerGeometryLeft + "px");
1325
+ }
1326
+ }
1327
+ if (this.isPromotionalCode) {
1328
+ this.fetchPromoCode();
1329
+ }
1330
+ // this.refreshUserData(this.options.localData);
1331
+ }
1332
+ refreshUserData(localData) { }
1333
+ isTransparentElement() {
1334
+ if (this.element) {
1335
+ try {
1336
+ var color = window.getComputedStyle(this.element).color;
1337
+ if (color === "transparent" || color === "rgba(0, 0, 0, 0)" || color === "rgba(0,0,0,0)") {
1338
+ return true;
1339
+ }
1340
+ }
1341
+ catch (err) {
1342
+ console.error(err);
1343
+ }
1344
+ }
1345
+ return false;
1346
+ }
1347
+ changeText(newText) {
1348
+ if (this.button) {
1349
+ this.button.textContent = newText;
1350
+ }
1351
+ }
1352
+ fetchPromoCode() {
1353
+ this.state = 0;
1354
+ if (this.localData["_cp_g_" + this.elementId + "_pc"] !== undefined) {
1355
+ this.state = 1;
1356
+ this.clipboardTarget = this.localData["_cp_g_" + this.elementId + "_pc"];
1357
+ if (this.clipboardTarget != null) {
1358
+ this.changeText(this.clipboardTarget);
1359
+ }
1360
+ removeClass(this.element, "loader");
1361
+ }
1362
+ if (this.state === 0) {
1363
+ if (!this.isTransparentElement()) {
1364
+ // for transparent element
1365
+ addClass(this.element, "loader");
1366
+ }
1367
+ // fetch promo code
1368
+ var path = "story/" + this.storyId + "/widget/" + this.elementId + "/promo-code/" + this.clipboardTarget;
1369
+ var headers = {
1370
+ accept: "application/json",
1371
+ "Content-Type": "application/json",
1372
+ };
1373
+ var profileKey = "fetch-promo-code";
1374
+ Promise.all([
1375
+ this.sdkApi.sendApiRequest(path, "POST", null, headers, null, profileKey),
1376
+ new Promise(function (t, e) {
1377
+ return setTimeout(t, 300);
1378
+ }),
1379
+ ]).then(values => {
1380
+ var r = values[0];
1381
+ var status = r.status;
1382
+ var code = null;
1383
+ var success = false;
1384
+ if (status === 200 || status === 201) {
1385
+ if (r.data)
1386
+ code = r.data.code;
1387
+ if (code) {
1388
+ // success case
1389
+ this.clipboardTarget = code;
1390
+ this.changeText(this.clipboardTarget);
1391
+ success = true;
1392
+ this.state = 1;
1393
+ removeClass(this.element, "loader");
1394
+ if (status === 201) {
1395
+ this.localData["_cp_g_" + this.elementId + "_pc_fetched_at"] = Math.round(new Date().getTime() / 1000);
1396
+ this.localData["_&ts_cp_g_" + this.elementId + "_pc_fetched_at"] = Math.round(new Date().getTime() / 1000);
1397
+ }
1398
+ this.localData["_cp_g_" + this.elementId + "_pc"] = code;
1399
+ this.setLocalData(this.localData, true);
1400
+ }
1401
+ else {
1402
+ this.msgNoMoreCodes && this.sdkApi.showToast(this.msgNoMoreCodes);
1403
+ }
1404
+ }
1405
+ else if (status === 12163 || status === 12002) {
1406
+ this.msgNetworkError && this.sdkApi.showToast(this.msgNetworkError);
1407
+ }
1408
+ else {
1409
+ this.msgServiceError && this.sdkApi.showToast(this.msgServiceError);
1410
+ }
1411
+ if (!success) {
1412
+ this.state = 3;
1413
+ this.changeText(this.msgTryAgain ?? "");
1414
+ removeClass(this.element, "loader");
1415
+ }
1416
+ });
1417
+ }
1418
+ }
1419
+ getStateValue() {
1420
+ return this.state;
1421
+ }
1422
+ getIsPromotionalCode() {
1423
+ return this.isPromotionalCode;
1424
+ }
1425
+ _statEventCopyClick(clipboardTarget) {
1426
+ try {
1427
+ var buttonText = this.button?.textContent ?? "";
1428
+ this.sendStatisticEventToApp("w-copy", {
1429
+ i: this.storyId,
1430
+ si: this.slideIndex,
1431
+ wi: this.elementId,
1432
+ wl: buttonText,
1433
+ wt: clipboardTarget,
1434
+ }, {
1435
+ story_id: this.storyId,
1436
+ slide_index: this.slideIndex,
1437
+ widget_id: this.elementId,
1438
+ widget_label: buttonText,
1439
+ widget_value: clipboardTarget,
1440
+ });
1441
+ }
1442
+ catch (error) {
1443
+ console.error(error);
1444
+ }
1445
+ }
1446
+ _select() {
1447
+ this.element.classList.add("done");
1448
+ if (this.resultLayer) {
1449
+ this.resultLayer.classList.add("done");
1450
+ }
1451
+ if (this.disableTimer) {
1452
+ // флаг - что таймер уже стартанул (в layout или добавить объект sharedMemory)
1453
+ // смотрим что прозрачный текст - тогда и лоадер прозрачный
1454
+ // _log("_showNarrativeNextSlide: " + getSlideDuration(this.narrativeId, this.slideIndex), true);
1455
+ this.showNextSlide();
1456
+ }
1457
+ }
1458
+ copyToClipboard(element) {
1459
+ this._select();
1460
+ var text = this.clipboardTarget ?? "";
1461
+ Clipboard.copy(text);
1462
+ this.completeWidget();
1463
+ this._statEventCopyClick(text);
1464
+ }
1465
+ completeWidget() {
1466
+ this.localData["_cp_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
1467
+ // ответ на вопрос
1468
+ this.localData["_&ts_cp_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
1469
+ this.setLocalData(this.localData, true);
1470
+ }
1471
+ isDone() {
1472
+ return this.localData["_cp_g_" + this.elementId + "_done_at"] !== undefined;
1473
+ }
1474
+ static api = {
1475
+ ...WidgetBase.api,
1476
+ initWidget: function (nodeList, localData) {
1477
+ // prevent initWidget for result layer
1478
+ const elements = slice.call(nodeList).filter(element => !element.classList.contains("narrative-element-copy-result-variant"));
1479
+ WidgetCopy.initWidgets((element, options) => new WidgetCopy(element, options), elements, localData);
1480
+ },
1481
+ click: function (element) {
1482
+ const widgetElement = element.closest(`.${WidgetCopy.widgetClassName}`);
1483
+ if (widgetElement) {
1484
+ const widget = WidgetCopy.getInstance(widgetElement);
1485
+ if (widget) {
1486
+ if (!widget.getIsPromotionalCode()) {
1487
+ widget.copyToClipboard(element);
1488
+ }
1489
+ else if (widget.getStateValue() === 1) {
1490
+ widget.copyToClipboard(element);
1491
+ }
1492
+ else if (widget.getStateValue() === 3) {
1493
+ widget.fetchPromoCode();
1494
+ }
1495
+ }
1496
+ }
1497
+ return false;
1498
+ },
1499
+ };
1500
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
1501
+ }
1502
+
1503
+ /** QUIZ */
1504
+ class WidgetDataInput extends WidgetBase {
1505
+ static DEFAULTS = {
1506
+ slide: null,
1507
+ activateAfterCreate: false,
1508
+ create: false,
1509
+ localData: {},
1510
+ };
1511
+ static widgetClassName = "narrative-element-data-input";
1512
+ label;
1513
+ elementRect;
1514
+ inputElement;
1515
+ textElement;
1516
+ inputPlaceholderValue;
1517
+ /**
1518
+ * @throws Error
1519
+ * @param element
1520
+ * @param options
1521
+ */
1522
+ constructor(element, options) {
1523
+ super(element, options);
1524
+ this.label = this.element.querySelector(".label-view .label");
1525
+ this.elementRect = this.element.getBoundingClientRect();
1526
+ this.inputElement = getValueOrException(this.element.querySelector(".input-view .input"), "Empty .input-view .input");
1527
+ this.textElement = getValueOrException(this.inputElement.querySelector(".narrative-element-text-lines"), "Empty .narrative-element-text-lines");
1528
+ this.inputPlaceholderValue = this.textElement.innerHTML;
1529
+ this.refreshUserData(this.options.localData);
1530
+ }
1531
+ refreshUserData(localData) {
1532
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
1533
+ this.localData = extend({}, this.savedData ?? {}, localData);
1534
+ var text = this.localData["_di_g_" + this.elementId + "_t"];
1535
+ this._fillUserText(text);
1536
+ if (text) {
1537
+ this.element.classList.add("done");
1538
+ if (this.disableTimer) {
1539
+ this.showNextSlide();
1540
+ }
1541
+ }
1542
+ }
1543
+ _statEventFocusIn() {
1544
+ try {
1545
+ var labelText = this.label ? this.label.textContent ?? "" : "";
1546
+ WidgetBase.sendStatisticEventToApp("w-data-input-focus", {
1547
+ i: this.storyId,
1548
+ si: this.slideIndex,
1549
+ wi: this.elementId,
1550
+ wl: labelText,
1551
+ }, {
1552
+ story_id: this.storyId,
1553
+ slide_index: this.slideIndex,
1554
+ widget_id: this.elementId,
1555
+ widget_label: labelText,
1556
+ });
1557
+ }
1558
+ catch (error) {
1559
+ console.error(error);
1560
+ }
1561
+ }
1562
+ _statEventInputSave(answerText) {
1563
+ try {
1564
+ const labelText = this.label ? this.label.textContent ?? "" : "";
1565
+ WidgetBase.sendStatisticEventToApp("w-data-input-save", {
1566
+ i: this.storyId,
1567
+ si: this.slideIndex,
1568
+ wi: this.elementId,
1569
+ wl: labelText,
1570
+ wv: answerText,
1571
+ }, {
1572
+ story_id: this.storyId,
1573
+ slide_index: this.slideIndex,
1574
+ widget_id: this.elementId,
1575
+ widget_label: labelText,
1576
+ widget_value: answerText,
1577
+ });
1578
+ }
1579
+ catch (error) {
1580
+ console.error(error);
1581
+ }
1582
+ }
1583
+ isDone() {
1584
+ return Boolean(this.localData["_di_g_" + this.elementId + "_t"]);
1585
+ }
1586
+ click(element) {
1587
+ if (this.isDone()) {
1588
+ return true;
1589
+ }
1590
+ this.elementRect = this.element.getBoundingClientRect();
1591
+ if (this.sdkApi.isAndroid || this.sdkApi.isWeb) {
1592
+ this.slide.classList.add("blured");
1593
+ }
1594
+ this.slide.classList.add("data-input-editing");
1595
+ const dataString = this.element.dataset["clientdialogwidgetconfig"];
1596
+ if (this.sdkApi.isExistsShowStoryTextInput && dataString) {
1597
+ const data = JSON.parse(dataString);
1598
+ data.size = getElementBounding(this.env, this.elementRect);
1599
+ if (!this.disableTimer) {
1600
+ this.sdkApi.pauseUI();
1601
+ }
1602
+ try {
1603
+ data.text.value = data.text.value.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
1604
+ data.input.text.placeholder = data.input.text.placeholder.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
1605
+ data.configV2.main.question.text.value = data.configV2.main.question.text.value
1606
+ .replaceAll("\\n", "\n")
1607
+ .replaceAll("\\r", "\r")
1608
+ .replaceAll("\\t", "\t");
1609
+ data.configV2.main.input.text.placeholder = data.configV2.main.input.text.placeholder
1610
+ .replaceAll("\\n", "\n")
1611
+ .replaceAll("\\r", "\r")
1612
+ .replaceAll("\\t", "\t");
1613
+ }
1614
+ catch (e) {
1615
+ console.error(e);
1616
+ }
1617
+ this.sdkApi.showStoryTextInput(this.id, data);
1618
+ this._statEventFocusIn();
1619
+ }
1620
+ return false;
1621
+ }
1622
+ _fillUserText(text) {
1623
+ if (this.inputElement && this.textElement) {
1624
+ if (text) {
1625
+ this.inputElement.classList.remove("_is-placeholder");
1626
+ text = text.replace(new RegExp("\r?\n", "g"), "<br />");
1627
+ this.textElement.innerHTML = text;
1628
+ }
1629
+ else {
1630
+ this.inputElement.classList.add("_is-placeholder");
1631
+ this.textElement.innerHTML = this.inputPlaceholderValue;
1632
+ }
1633
+ }
1634
+ }
1635
+ setUserText(text) {
1636
+ this.slide.classList.remove("data-input-editing");
1637
+ this.slide.classList.remove("blured");
1638
+ var needResumeUITimer = true;
1639
+ if (text) {
1640
+ this._fillUserText(text);
1641
+ this.localData["_di_g_" + this.elementId + "_t"] = text;
1642
+ // answer to question
1643
+ this.localData["_&ts_di_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
1644
+ if (this.widgetDone) {
1645
+ this.widgetDone.classList.add("active", "opacity-active");
1646
+ setTimeout(() => {
1647
+ this.widgetDone?.classList.remove("active");
1648
+ setTimeout(() => {
1649
+ this.widgetDone?.classList.remove("opacity-active");
1650
+ }, 250);
1651
+ }, 2000);
1652
+ }
1653
+ this.setLocalData(this.localData, true);
1654
+ this._statEventInputSave(text);
1655
+ if (this.disableTimer) {
1656
+ if ("_showNarrativeNextSlide" in window) {
1657
+ this.showNextSlide();
1658
+ needResumeUITimer = false;
1659
+ }
1660
+ }
1661
+ }
1662
+ if (needResumeUITimer && !this.disableTimer) {
1663
+ this.sdkApi.resumeUI();
1664
+ }
1665
+ }
1666
+ static api = {
1667
+ ...WidgetBase.api,
1668
+ initWidget: function (nodeList, localData) {
1669
+ WidgetDataInput.initWidgets((element, options) => new WidgetDataInput(element, options), slice.call(nodeList), localData);
1670
+ },
1671
+ click: function (element) {
1672
+ const widgetElement = element.closest(`.${WidgetDataInput.widgetClassName}`);
1673
+ if (widgetElement) {
1674
+ const widget = WidgetDataInput.getInstance(widgetElement);
1675
+ if (widget) {
1676
+ return widget.click(element);
1677
+ }
1678
+ }
1679
+ return true;
1680
+ },
1681
+ setUserData: function (id, text) {
1682
+ WidgetDataInput.getInstanceById(id)?.setUserText(text);
1683
+ },
1684
+ };
1685
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
1686
+ }
1687
+
1688
+ class WidgetDateCountdown extends WidgetBase {
1689
+ static DEFAULTS = {
1690
+ slide: null,
1691
+ activateAfterCreate: false,
1692
+ create: false,
1693
+ localData: {},
1694
+ layers: [],
1695
+ };
1696
+ static widgetClassName = "narrative-element-date-countdown";
1697
+ label;
1698
+ layers;
1699
+ messages;
1700
+ timestampSeconds;
1701
+ diff;
1702
+ timerInited;
1703
+ pendingUpdate;
1704
+ firstGroup1;
1705
+ firstGroup2;
1706
+ firstGroupCaption;
1707
+ secondGroup1;
1708
+ secondGroup2;
1709
+ secondGroupCaption;
1710
+ thirdGroup1;
1711
+ thirdGroup2;
1712
+ thirdGroupCaption;
1713
+ constructor(element, options) {
1714
+ super(element, options);
1715
+ this.label = this.element.querySelector(".label-view .label");
1716
+ this.messages = {
1717
+ days: getTagData(this.element, "tDays") ?? "",
1718
+ hours: getTagData(this.element, "tHours") ?? "",
1719
+ minutes: getTagData(this.element, "tMinutes") ?? "",
1720
+ seconds: getTagData(this.element, "tSeconds") ?? "",
1721
+ };
1722
+ this.timestampSeconds = getValueOrException(getTagDataAsNumber(this.element, "timestampSeconds"), "Empty timestampSeconds");
1723
+ this.diff = 0;
1724
+ this.timerInited = false;
1725
+ this.pendingUpdate = true;
1726
+ this.layers = this.options.layers;
1727
+ // if (false) {
1728
+ // // if (sendApiRequestSupported()) {
1729
+ // // fetch project time
1730
+ // var path = "story/" + this.storyId + "/widget/" + this.elementId + "/timestamp";
1731
+ // var profileKey = "fetch-story-timestamp";
1732
+ // this.sdkApi
1733
+ // .sendApiRequest<{ timestamp: number }>(path, "GET", null, null, null, profileKey)
1734
+ // .then(response => {
1735
+ // var status = response.status;
1736
+ // var timestamp = null;
1737
+ // if (status === 200) {
1738
+ // if (response.data) timestamp = response.data.timestamp;
1739
+ // if (timestamp) {
1740
+ // this.diff = new Date().getTime() - timestamp * 1000;
1741
+ // }
1742
+ // }
1743
+ //
1744
+ // this.initTimer();
1745
+ // })
1746
+ // .catch( (reason)=> {
1747
+ // console.error(reason);
1748
+ // this.initTimer();
1749
+ // });
1750
+ // } else {
1751
+ this.initTimer();
1752
+ // }
1753
+ // this.refreshUserData(this.options.localData);
1754
+ }
1755
+ refreshUserData(localData) { }
1756
+ pause() {
1757
+ if (this.timerInited) {
1758
+ this.pendingUpdate = false;
1759
+ }
1760
+ }
1761
+ resume() {
1762
+ if (this.timerInited) {
1763
+ this.pendingUpdate = true;
1764
+ this.updateTimer();
1765
+ }
1766
+ }
1767
+ initTimer() {
1768
+ // find groups
1769
+ this.firstGroup1 = getValueOrException(this.element.querySelector(".date-item-view-group-1 .date-output-label-1"), "Empty firstGroup1");
1770
+ this.firstGroup2 = getValueOrException(this.element.querySelector(".date-item-view-group-1 .date-output-label-2"), "Empty firstGroup2");
1771
+ this.firstGroupCaption = getValueOrException(this.element.querySelector(".date-item-view-group-1 .date-item-caption"), "Empty firstGroupCaption");
1772
+ this.secondGroup1 = getValueOrException(this.element.querySelector(".date-item-view-group-2 .date-output-label-1"), "Empty secondGroup1");
1773
+ this.secondGroup2 = getValueOrException(this.element.querySelector(".date-item-view-group-2 .date-output-label-2"), "Empty secondGroup2");
1774
+ this.secondGroupCaption = getValueOrException(this.element.querySelector(".date-item-view-group-2 .date-item-caption"), "Empty secondGroupCaption");
1775
+ this.thirdGroup1 = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-output-label-1"), "Empty thirdGroup1");
1776
+ this.thirdGroup2 = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-output-label-2"), "Empty thirdGroup2");
1777
+ this.thirdGroupCaption = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-item-caption"), "Empty thirdGroupCaption");
1778
+ this.timestampSeconds *= 1000;
1779
+ this.timerInited = true;
1780
+ var value = this.timestampSeconds - (new Date().getTime() - this.diff);
1781
+ if (value > 0) {
1782
+ this._showLayout(this.layers, 0);
1783
+ }
1784
+ this.updateTimer();
1785
+ }
1786
+ updateTimer() {
1787
+ var value = this.timestampSeconds - (new Date().getTime() - this.diff);
1788
+ if (value > 0) {
1789
+ var result = this._asDuration(Math.round(value / 1000));
1790
+ if (result.days) {
1791
+ this.firstGroupCaption.textContent = this.messages.days;
1792
+ this.firstGroup1.textContent = result.day1;
1793
+ this.firstGroup2.textContent = result.day2;
1794
+ this.secondGroupCaption.textContent = this.messages.hours;
1795
+ this.secondGroup1.textContent = result.hour1;
1796
+ this.secondGroup2.textContent = result.hour2;
1797
+ this.thirdGroupCaption.textContent = this.messages.minutes;
1798
+ this.thirdGroup1.textContent = result.minute1;
1799
+ this.thirdGroup2.textContent = result.minute2;
1800
+ }
1801
+ else {
1802
+ this.firstGroupCaption.textContent = this.messages.hours;
1803
+ this.firstGroup1.textContent = result.hour1;
1804
+ this.firstGroup2.textContent = result.hour2;
1805
+ this.secondGroupCaption.textContent = this.messages.minutes;
1806
+ this.secondGroup1.textContent = result.minute1;
1807
+ this.secondGroup2.textContent = result.minute2;
1808
+ this.thirdGroupCaption.textContent = this.messages.seconds;
1809
+ this.thirdGroup1.textContent = result.second1;
1810
+ this.thirdGroup2.textContent = result.second2;
1811
+ }
1812
+ // this.pendingUpdate = true;
1813
+ }
1814
+ else {
1815
+ this.pendingUpdate = false;
1816
+ this._showLayout(this.layers, 1);
1817
+ }
1818
+ if (this.pendingUpdate) {
1819
+ this.env.requestAnimationFrame(() => this.updateTimer());
1820
+ }
1821
+ }
1822
+ _asDuration(value) {
1823
+ var result = {
1824
+ days: false,
1825
+ day1: "0",
1826
+ day2: "0",
1827
+ hour1: "0",
1828
+ hour2: "0",
1829
+ minute1: "0",
1830
+ minute2: "0",
1831
+ second1: "0",
1832
+ second2: "0",
1833
+ };
1834
+ if (value === undefined || value === null) {
1835
+ return result;
1836
+ }
1837
+ if (value < 0) {
1838
+ return result;
1839
+ }
1840
+ value = Math.floor(value);
1841
+ var days = Math.floor((value / 86400) % 365);
1842
+ var hours = Math.floor((value / 3600) % 24);
1843
+ var minutes = Math.floor((value / 60) % 60);
1844
+ var seconds = value % 60;
1845
+ var pair;
1846
+ if (days > 0) {
1847
+ result.days = true;
1848
+ if (days < 10)
1849
+ result.day2 = String(days);
1850
+ else {
1851
+ pair = String(days).split("");
1852
+ result.day1 = pair[0];
1853
+ result.day2 = pair[1];
1854
+ }
1855
+ }
1856
+ if (hours < 10)
1857
+ result.hour2 = String(hours);
1858
+ else {
1859
+ pair = String(hours).split("");
1860
+ result.hour1 = pair[0];
1861
+ result.hour2 = pair[1];
1862
+ }
1863
+ if (minutes < 10)
1864
+ result.minute2 = String(minutes);
1865
+ else {
1866
+ pair = String(minutes).split("");
1867
+ result.minute1 = pair[0];
1868
+ result.minute2 = pair[1];
1869
+ }
1870
+ if (seconds < 10)
1871
+ result.second2 = String(seconds);
1872
+ else {
1873
+ pair = String(seconds).split("");
1874
+ result.second1 = pair[0];
1875
+ result.second2 = pair[1];
1876
+ }
1877
+ return result;
1878
+ }
1879
+ static api = {
1880
+ ...WidgetBase.api,
1881
+ initWidget: function (nodeList, layers, localData) {
1882
+ WidgetDateCountdown.initWidgets((element, options) => new WidgetDateCountdown(element, { ...options, layers }), slice.call(nodeList), localData);
1883
+ },
1884
+ pause: function (nodeList) {
1885
+ forEach(slice.call(nodeList), function (el, index) {
1886
+ WidgetDateCountdown.getInstance(el)?.pause();
1887
+ });
1888
+ },
1889
+ resume: function (nodeList) {
1890
+ forEach(slice.call(nodeList), function (el, index) {
1891
+ WidgetDateCountdown.getInstance(el)?.resume();
1892
+ });
1893
+ },
1894
+ };
1895
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
1896
+ }
1897
+
1898
+ const displaySlide = function (slides, localData) {
1899
+ const multiSlideItem = slides[0];
1900
+ let storyId = undefined;
1901
+ let slideIndex = undefined;
1902
+ if (multiSlideItem != null) {
1903
+ storyId = getTagDataAsNumber(multiSlideItem, "id");
1904
+ slideIndex = getTagDataAsNumber(multiSlideItem, "index");
1905
+ if (multiSlideItem.querySelectorAll(".narrative-element-share[data-with-layer='1'], .narrative-element-poll-layers, .narrative-element-date-countdown, .narrative-element-game").length > 0) {
1906
+ // skip if exists share/poll_layers
1907
+ return;
1908
+ }
1909
+ }
1910
+ // score
1911
+ var score = null;
1912
+ var selectedIndex = undefined;
1913
+ if (localData["q_score"] !== undefined) {
1914
+ score = parseInt(localData["q_score"]);
1915
+ }
1916
+ else if (localData["t_score"] !== undefined) {
1917
+ score = parseInt(localData["t_score"]);
1918
+ }
1919
+ else if (localData["qg_score"] !== undefined) {
1920
+ score = localData["qg_score"]; // array
1921
+ var tmpScore = score;
1922
+ if (isObject(score)) {
1923
+ tmpScore = Object.values(score);
1924
+ }
1925
+ tmpScore.sort();
1926
+ tmpScore.reverse();
1927
+ if (tmpScore[0] === tmpScore[1]) {
1928
+ forEach(slides, function (slide, index) {
1929
+ var minScore = getTagData(slide, "layerMinScore");
1930
+ if (minScore !== undefined) {
1931
+ if (minScore === "uncertain") {
1932
+ selectedIndex = index;
1933
+ }
1934
+ }
1935
+ });
1936
+ }
1937
+ else {
1938
+ var maxCategoryCnt = 0;
1939
+ // find quiz category (selectedCategoryIndex) - chosen most often
1940
+ var selectedCategoryIndex = undefined;
1941
+ forEach(score, function (value, i) {
1942
+ var item = parseInt(value);
1943
+ if (item > maxCategoryCnt) {
1944
+ maxCategoryCnt = item;
1945
+ selectedCategoryIndex = parseInt(i);
1946
+ }
1947
+ });
1948
+ // chose slide with correct result
1949
+ forEach(slides, function (slide, index) {
1950
+ var minScore = getTagData(slide, "layerMinScore");
1951
+ if (minScore !== undefined && isNumeric(minScore) && parseInt(minScore) === selectedCategoryIndex) {
1952
+ selectedIndex = index;
1953
+ }
1954
+ });
1955
+ }
1956
+ }
1957
+ if (score === null) {
1958
+ if (slides.length > 0) {
1959
+ var slide = slides[0];
1960
+ slide.classList.remove("hidden");
1961
+ WidgetBase.widgetsService.sdkApi.storyAnimation?.start(slide);
1962
+ return;
1963
+ }
1964
+ score = 0;
1965
+ }
1966
+ if (selectedIndex === undefined) {
1967
+ var map = [];
1968
+ forEach(slides, function (slide, index) {
1969
+ var minScore = getTagData(slide, "layerMinScore");
1970
+ if (minScore !== undefined) {
1971
+ map.push([index, parseInt(minScore)]);
1972
+ }
1973
+ });
1974
+ map.sort(function (a, b) {
1975
+ return a[1] - b[1];
1976
+ });
1977
+ for (var i = map.length - 1; i >= 0; i--) {
1978
+ if (score >= map[i][1]) {
1979
+ selectedIndex = map[i][0];
1980
+ break;
1981
+ }
1982
+ }
1983
+ }
1984
+ var undefinedResult = true;
1985
+ if (selectedIndex !== undefined) {
1986
+ forEach(slides, function (slide, index) {
1987
+ if (index === selectedIndex) {
1988
+ slide.classList.remove("hidden");
1989
+ undefinedResult = false;
1990
+ WidgetBase.widgetsService.sdkApi.storyAnimation?.start(slide);
1991
+ _sendStatEvent(storyId, slideIndex, selectedIndex);
1992
+ }
1993
+ });
1994
+ }
1995
+ if (undefinedResult) {
1996
+ console.warn("undefinedResult layer index");
1997
+ WidgetBase.widgetsService.sdkApi.showLayer(0);
1998
+ }
1999
+ };
2000
+ const _sendStatEvent = function (storyId, slideIndex, layerIndex) {
2001
+ try {
2002
+ WidgetBase.sendStatisticEventToApp("layout-show", {
2003
+ i: storyId,
2004
+ si: slideIndex,
2005
+ li: layerIndex,
2006
+ });
2007
+ }
2008
+ catch (error) {
2009
+ console.error(error);
2010
+ }
2011
+ };
2012
+ class WidgetMultiSlide {
2013
+ static api = {
2014
+ init: function (slides, localData) {
2015
+ if (localData != null) {
2016
+ displaySlide(slides, localData);
2017
+ }
2018
+ else {
2019
+ WidgetBase.getLocalData().then(function (localData) {
2020
+ displaySlide(slides, localData);
2021
+ });
2022
+ }
2023
+ },
2024
+ };
2025
+ }
2026
+
2027
+ class WidgetPoll extends WidgetBase {
2028
+ static DEFAULTS = {
2029
+ slide: null,
2030
+ activateAfterCreate: false,
2031
+ create: false,
2032
+ localData: {},
2033
+ };
2034
+ static widgetClassName = "narrative-element-poll";
2035
+ elementRect;
2036
+ label;
2037
+ percentFillMask;
2038
+ maskedVariants;
2039
+ variantsViewGroup;
2040
+ variants;
2041
+ variantsTexts;
2042
+ isInvertedPercentFilledMaskDirection;
2043
+ getUseResponseOnFirstButton;
2044
+ getUseResponseOnSecondButton;
2045
+ showClientTotalResult;
2046
+ selectedVariant;
2047
+ nativeDialogueWasOpened = false;
2048
+ answerDuration = 0;
2049
+ /**
2050
+ * @throws Error
2051
+ * @param element
2052
+ * @param options
2053
+ */
2054
+ constructor(element, options) {
2055
+ super(element, options);
2056
+ this.elementRect = this.element.getBoundingClientRect();
2057
+ this.label = this.element.querySelector(".label-view .label");
2058
+ this.percentFillMask = this.element.querySelector(".percent-filled-variants-view-group-mask");
2059
+ this.maskedVariants = slice.call(this.element.querySelectorAll(".variants-box .variants-view-group.percent-filled-variants-view-group .variant-view"));
2060
+ this.variantsViewGroup = getValueOrException(this.element.querySelector(".variants-box .variants-view-group:not(.percent-filled-variants-view-group)"), "Empty variantsViewGroup");
2061
+ this.variants = slice.call(this.variantsViewGroup.querySelectorAll(".variant-view"));
2062
+ this.variantsTexts = [];
2063
+ forEach(this.variants, (element, index) => {
2064
+ const label = element.querySelector(".label");
2065
+ if (label) {
2066
+ this.variantsTexts.push(label.textContent ?? "");
2067
+ }
2068
+ });
2069
+ this.isInvertedPercentFilledMaskDirection =
2070
+ this.element.classList.contains("theme-translucent") || this.element.classList.contains("base-theme-translucent");
2071
+ this.getUseResponseOnFirstButton = Boolean(getTagDataAsNumber(this.element, "getUserResponseOnFirstButton"));
2072
+ this.getUseResponseOnSecondButton = Boolean(getTagDataAsNumber(this.element, "getUserResponseOnSecondButton"));
2073
+ this.showClientTotalResult = Boolean(getTagDataAsNumber(this.element, "showClientTotalResult"));
2074
+ this.refreshUserData(this.options.localData);
2075
+ }
2076
+ refreshUserData(localData) {
2077
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
2078
+ this.localData = extend({}, this.savedData ?? {}, localData);
2079
+ this.selectedVariant = undefined;
2080
+ if (this.localData) {
2081
+ if (this.localData["_p_g_" + this.elementId + "_sa"] !== undefined) {
2082
+ this._selectVariant(this.localData["_p_g_" + this.elementId + "_sa"], true);
2083
+ }
2084
+ else {
2085
+ this._clearVariantSelection();
2086
+ }
2087
+ }
2088
+ this.firstOpenTime = new Date().getTime();
2089
+ this.nativeDialogueWasOpened = false;
2090
+ }
2091
+ _statEventPollAnswer() {
2092
+ this.answerDuration = new Date().getTime() - this.firstOpenTime;
2093
+ try {
2094
+ if (this.selectedVariant !== undefined) {
2095
+ var labelText = this.label?.textContent ?? "";
2096
+ var variantText = this.variantsTexts[this.selectedVariant] ? this.variantsTexts[this.selectedVariant] : "";
2097
+ this.sendStatisticEventToApp("w-poll-answer", {
2098
+ i: this.storyId,
2099
+ si: this.slideIndex,
2100
+ wi: this.elementId,
2101
+ wl: labelText,
2102
+ wa: this.selectedVariant,
2103
+ wal: variantText,
2104
+ d: this.answerDuration,
2105
+ }, {
2106
+ story_id: this.storyId,
2107
+ slide_index: this.slideIndex,
2108
+ widget_id: this.elementId,
2109
+ widget_label: labelText,
2110
+ widget_answer: this.selectedVariant,
2111
+ widget_answer_label: variantText,
2112
+ duration_ms: this.answerDuration,
2113
+ });
2114
+ }
2115
+ }
2116
+ catch (error) {
2117
+ console.error(error);
2118
+ }
2119
+ }
2120
+ _statEventInputSave(responseText) {
2121
+ try {
2122
+ if (this.selectedVariant !== undefined) {
2123
+ var labelText = this.label?.textContent ?? "";
2124
+ var variantText = this.variantsTexts[this.selectedVariant] ? this.variantsTexts[this.selectedVariant] : "";
2125
+ this.sendStatisticEventToApp("w-poll-clarification", {
2126
+ i: this.storyId,
2127
+ si: this.slideIndex,
2128
+ wi: this.elementId,
2129
+ wl: labelText,
2130
+ wa: this.selectedVariant,
2131
+ wal: variantText,
2132
+ wv: responseText,
2133
+ d: this.answerDuration,
2134
+ }, {
2135
+ story_id: this.storyId,
2136
+ slide_index: this.slideIndex,
2137
+ widget_id: this.elementId,
2138
+ widget_label: labelText,
2139
+ widget_answer: this.selectedVariant,
2140
+ widget_answer_label: variantText,
2141
+ widget_value: responseText,
2142
+ duration_ms: this.answerDuration,
2143
+ });
2144
+ }
2145
+ }
2146
+ catch (error) {
2147
+ console.error(error);
2148
+ }
2149
+ }
2150
+ _selectVariant(index, filled = false) {
2151
+ if (this.variants[index]) {
2152
+ this.variants[index].classList.add("selected");
2153
+ }
2154
+ this.selectedVariant = index;
2155
+ this.localData["_p_g_" + this.elementId + "_sa"] = index;
2156
+ this.element.classList.add("done");
2157
+ this.element.classList.add("selected-" + this.selectedVariant);
2158
+ if (filled) {
2159
+ this.element.classList.add("filled");
2160
+ }
2161
+ if (this.showClientTotalResult) {
2162
+ this.element.classList.add("with-total-result");
2163
+ this.displayPercents(index, filled);
2164
+ }
2165
+ if (this.disableTimer) {
2166
+ this.env.setTimeout(() => {
2167
+ // todo poll - если виджет на первом слайде то при повторном заходе автоматически не стартует таймлайн слайда
2168
+ // только в web sdk такое
2169
+ // если поставить через setTimeout то все ок
2170
+ this.showNextSlide();
2171
+ });
2172
+ }
2173
+ }
2174
+ _clearVariantSelection() {
2175
+ forEach(this.variants, function (variant) {
2176
+ variant.classList.remove("selected");
2177
+ });
2178
+ this.element.classList.remove("done");
2179
+ this.element.classList.remove("selected-" + this.selectedVariant);
2180
+ this.element.classList.remove("filled");
2181
+ this.selectedVariant = undefined;
2182
+ this.element.classList.remove("with-total-result");
2183
+ // this.displayPercents(index, filled);
2184
+ }
2185
+ selectVariant(variantView) {
2186
+ this.nativeDialogueWasOpened = false;
2187
+ if (this.selectedVariant !== undefined) {
2188
+ return true;
2189
+ }
2190
+ var index = this.variants.indexOf(variantView);
2191
+ if (index !== -1) {
2192
+ if (this.getUseResponseOnFirstButton && index === 0) {
2193
+ if (this.sdkApi.isAndroid) {
2194
+ this.slide.classList.add("blured");
2195
+ }
2196
+ this.slide.classList.add("data-input-editing");
2197
+ const dataString = this.element.dataset["clientdialogwidgetconfig"];
2198
+ this.selectedVariant = index;
2199
+ if (this.sdkApi.isExistsShowStoryTextInput && dataString) {
2200
+ const data = JSON.parse(dataString);
2201
+ data.size = getElementBounding(this.env, this.elementRect);
2202
+ if (!this.disableTimer) {
2203
+ this.sdkApi.pauseUI();
2204
+ }
2205
+ this.nativeDialogueWasOpened = false;
2206
+ try {
2207
+ data.text.value = data.text.value.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
2208
+ data.input.text.placeholder = data.input.text.placeholder.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
2209
+ data.configV2.main.question.text.value = data.configV2.main.question.text.value
2210
+ .replaceAll("\\n", "\n")
2211
+ .replaceAll("\\r", "\r")
2212
+ .replaceAll("\\t", "\t");
2213
+ data.configV2.main.input.text.placeholder = data.configV2.main.input.text.placeholder
2214
+ .replaceAll("\\n", "\n")
2215
+ .replaceAll("\\r", "\r")
2216
+ .replaceAll("\\t", "\t");
2217
+ }
2218
+ catch (e) {
2219
+ console.error(e);
2220
+ }
2221
+ this.sdkApi.showStoryTextInput(`${this.id}_first`, data);
2222
+ }
2223
+ this._statEventPollAnswer();
2224
+ return false;
2225
+ }
2226
+ else if (this.getUseResponseOnSecondButton && index === 1) {
2227
+ if (this.sdkApi.isAndroid) {
2228
+ this.slide.classList.add("blured");
2229
+ }
2230
+ this.slide.classList.add("data-input-editing");
2231
+ const dataString = this.element.dataset["clientdialogwidgetconfig"];
2232
+ this.selectedVariant = index;
2233
+ if (this.sdkApi.isExistsShowStoryTextInput && dataString) {
2234
+ const data = JSON.parse(dataString);
2235
+ data.size = getElementBounding(this.env, this.elementRect);
2236
+ if (!this.disableTimer) {
2237
+ this.sdkApi.pauseUI();
2238
+ }
2239
+ try {
2240
+ data.text.value = data.text.value.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
2241
+ data.input.text.placeholder = data.input.text.placeholder.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
2242
+ data.configV2.main.question.text.value = data.configV2.main.question.text.value
2243
+ .replaceAll("\\n", "\n")
2244
+ .replaceAll("\\r", "\r")
2245
+ .replaceAll("\\t", "\t");
2246
+ data.configV2.main.input.text.placeholder = data.configV2.main.input.text.placeholder
2247
+ .replaceAll("\\n", "\n")
2248
+ .replaceAll("\\r", "\r")
2249
+ .replaceAll("\\t", "\t");
2250
+ }
2251
+ catch (e) {
2252
+ console.error(e);
2253
+ }
2254
+ this.sdkApi.showStoryTextInput(`${this.id}_second`, data);
2255
+ }
2256
+ this._statEventPollAnswer();
2257
+ return false;
2258
+ }
2259
+ else {
2260
+ this._selectVariant(index);
2261
+ this._statEventPollAnswer();
2262
+ }
2263
+ this.completeWidget();
2264
+ }
2265
+ return false;
2266
+ }
2267
+ _getVariantBoxInPercent(variantIndex) {
2268
+ var box = {
2269
+ sideOffset: 0,
2270
+ width: 0,
2271
+ };
2272
+ if (this.variantsViewGroup != null && variantIndex != null && this.variants[0] != null && this.variants[1] != null) {
2273
+ var viewGroupWidth = this.variantsViewGroup.clientWidth;
2274
+ if (viewGroupWidth > 0) {
2275
+ var offset = 0;
2276
+ var variantViewMinWidth = 0;
2277
+ // get min offset for variantView from variants-view-group
2278
+ var variantView = this.variants[variantIndex];
2279
+ var label = variantView.querySelector(".label");
2280
+ var percentLabel = variantView.querySelector(".percent-label");
2281
+ if (label != null && percentLabel != null) {
2282
+ var variantViewWidth = variantView.clientWidth;
2283
+ var labelOffset = (variantViewWidth - label.clientWidth) / 2;
2284
+ var percentLabelOffset = (variantViewWidth - percentLabel.clientWidth) / 2;
2285
+ offset = Math.min(labelOffset, percentLabelOffset);
2286
+ variantViewMinWidth = Math.max(label.clientWidth, percentLabel.clientWidth);
2287
+ }
2288
+ box.sideOffset = (offset / viewGroupWidth) * 100;
2289
+ box.width = (variantViewMinWidth / viewGroupWidth) * 100;
2290
+ }
2291
+ }
2292
+ return box;
2293
+ }
2294
+ displayPercents(selectedVariantIndex, filled = false) {
2295
+ let pollAllocation = [0, 0];
2296
+ let pollAllocationTs = undefined;
2297
+ const sharedData = this.sdkApi.getWidgetsSharedData(this.storyId, "poll" /* Widgets.Poll */);
2298
+ if (sharedData && sharedData[this.elementId] != null && (isObject(sharedData[this.elementId]) || isArray(sharedData[this.elementId]))) {
2299
+ pollAllocation = sharedData[this.elementId];
2300
+ if (isObject(sharedData[this.elementId])) {
2301
+ pollAllocation = slice.call(Object.values(sharedData[this.elementId]));
2302
+ }
2303
+ pollAllocationTs = sharedData.ts;
2304
+ }
2305
+ // todo debug
2306
+ // pollAllocation[0] = 10;
2307
+ // pollAllocation[1] = 20;
2308
+ var pollDoneAt = this.localData["_p_g_" + this.elementId + "_done_at"];
2309
+ if (pollAllocationTs === undefined || pollDoneAt === undefined || pollDoneAt > pollAllocationTs) {
2310
+ forEach(this.variants, (element, index) => {
2311
+ const key = index;
2312
+ if (pollAllocation[key] === undefined || !isNumber(pollAllocation[key])) {
2313
+ pollAllocation[key] = 0;
2314
+ }
2315
+ if (selectedVariantIndex === key) {
2316
+ ++pollAllocation[key];
2317
+ }
2318
+ });
2319
+ }
2320
+ // calc percents
2321
+ var percents = [], total = 0;
2322
+ forEach(this.variants, (element, index) => {
2323
+ const key = index;
2324
+ if (pollAllocation[key] !== undefined) {
2325
+ if (!isNumber(pollAllocation[key])) {
2326
+ percents[key] = parseInt(String(pollAllocation[key]));
2327
+ }
2328
+ else {
2329
+ percents[key] = pollAllocation[key];
2330
+ }
2331
+ if (!isNumber(percents[key]) || isNaN(percents[key])) {
2332
+ percents[key] = 0;
2333
+ }
2334
+ }
2335
+ else {
2336
+ percents[key] = 0;
2337
+ }
2338
+ total += percents[key];
2339
+ });
2340
+ for (var i = 0; i < percents.length; i++) {
2341
+ if (total !== 0) {
2342
+ percents[i] = Math.round((percents[i] / total) * 100);
2343
+ if (percents[i] > 100) {
2344
+ percents[i] = 100;
2345
+ }
2346
+ }
2347
+ else {
2348
+ percents[i] = 0;
2349
+ }
2350
+ }
2351
+ var percentsTotal = function () {
2352
+ var acc = 0;
2353
+ for (var i = 0; i < percents.length; i++) {
2354
+ acc += percents[i];
2355
+ }
2356
+ return acc;
2357
+ };
2358
+ var start = new Date().getTime();
2359
+ while (percentsTotal() > 100) {
2360
+ percents[percents.length - 1]--;
2361
+ if (new Date().getTime() - start >= 1000) {
2362
+ break;
2363
+ }
2364
+ }
2365
+ var variantWithMinPercentsRelativeWidth = 0;
2366
+ var variantWithMinPercentsIndex = null;
2367
+ forEach(this.variants, (element, index) => {
2368
+ const key = index;
2369
+ var percent = percents[key];
2370
+ var variant = element;
2371
+ var maskedVariant = this.maskedVariants[key];
2372
+ if (this.selectedVariant === key) {
2373
+ variant.classList.add("selected");
2374
+ if (maskedVariant != null) {
2375
+ maskedVariant.classList.add("selected");
2376
+ }
2377
+ }
2378
+ var percentLabel = variant.querySelector(".percent-label");
2379
+ if (percentLabel != null) {
2380
+ percentLabel.innerHTML = percent + "%";
2381
+ }
2382
+ var maskedPercentLabel = maskedVariant?.querySelector(".percent-label");
2383
+ if (maskedPercentLabel != null) {
2384
+ maskedPercentLabel.innerHTML = percent + "%";
2385
+ }
2386
+ });
2387
+ const cb = () => {
2388
+ if (this.percentFillMask != null &&
2389
+ this.variants[0] != null &&
2390
+ this.variants[1] != null &&
2391
+ this.selectedVariant != null &&
2392
+ percents[this.selectedVariant] != null) {
2393
+ var selectedVariantPercent = percents[this.selectedVariant];
2394
+ var limit = 0;
2395
+ var percent = 0;
2396
+ variantWithMinPercentsIndex = 0;
2397
+ if (percents[1] < percents[0]) {
2398
+ variantWithMinPercentsIndex = 1;
2399
+ }
2400
+ var boxPercents = this._getVariantBoxInPercent(variantWithMinPercentsIndex);
2401
+ variantWithMinPercentsRelativeWidth = boxPercents.width;
2402
+ var offset = 0;
2403
+ if (this.selectedVariant === 0) {
2404
+ if (this.isInvertedPercentFilledMaskDirection) {
2405
+ if (variantWithMinPercentsIndex === 1) {
2406
+ percent = Math.max(variantWithMinPercentsRelativeWidth, 100 - selectedVariantPercent);
2407
+ }
2408
+ else {
2409
+ limit = 100 - variantWithMinPercentsRelativeWidth;
2410
+ percent = Math.min(limit, 100 - selectedVariantPercent);
2411
+ }
2412
+ offset = (50 - percent) / 2;
2413
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-start", String(0));
2414
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-end", String(percent));
2415
+ this.element.style.setProperty("--variants-view-group-offset", String(offset));
2416
+ }
2417
+ else {
2418
+ if (variantWithMinPercentsIndex === 0) {
2419
+ // real variant percent or variantView min width
2420
+ percent = Math.max(selectedVariantPercent, variantWithMinPercentsRelativeWidth);
2421
+ }
2422
+ else {
2423
+ limit = 100 - variantWithMinPercentsRelativeWidth;
2424
+ percent = Math.min(limit, selectedVariantPercent);
2425
+ }
2426
+ offset = (50 - percent) / -2;
2427
+ // decrease alt color from start to firstVariant percents
2428
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-start", String(percent));
2429
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-end", String(0));
2430
+ this.element.style.setProperty("--variants-view-group-offset", String(offset));
2431
+ }
2432
+ }
2433
+ else if (this.selectedVariant === 1) {
2434
+ if (this.isInvertedPercentFilledMaskDirection) {
2435
+ if (variantWithMinPercentsIndex === 0) {
2436
+ percent = Math.max(variantWithMinPercentsRelativeWidth, 100 - selectedVariantPercent);
2437
+ }
2438
+ else {
2439
+ limit = 100 - variantWithMinPercentsRelativeWidth;
2440
+ percent = Math.min(limit, 100 - selectedVariantPercent);
2441
+ }
2442
+ offset = (50 - percent) / -2;
2443
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-start", String(percent));
2444
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-end", String(0));
2445
+ this.element.style.setProperty("--variants-view-group-offset", String(offset));
2446
+ }
2447
+ else {
2448
+ // decrease alt color from end to secondVariant percents
2449
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-start", String(0));
2450
+ if (variantWithMinPercentsIndex === 1) {
2451
+ // real variant percent or variantView min width
2452
+ percent = Math.max(selectedVariantPercent, variantWithMinPercentsRelativeWidth);
2453
+ }
2454
+ else {
2455
+ limit = 100 - variantWithMinPercentsRelativeWidth;
2456
+ percent = Math.min(limit, selectedVariantPercent);
2457
+ }
2458
+ offset = (50 - percent) / 2;
2459
+ this.percentFillMask.style.setProperty("--selected-variant-view-clip-area-end", String(percent));
2460
+ this.element.style.setProperty("--variants-view-group-offset", String(offset));
2461
+ }
2462
+ }
2463
+ }
2464
+ };
2465
+ // if (filled) {
2466
+ // cb();
2467
+ // } else {
2468
+ // wait for percent render done (for calc correct variantView width)
2469
+ this.env.requestAnimationFrame(cb);
2470
+ // }
2471
+ }
2472
+ setUserText(text, buttonPosition) {
2473
+ this.slide.classList.remove("data-input-editing");
2474
+ this.slide.classList.remove("blured");
2475
+ if (this.selectedVariant != null) {
2476
+ this._selectVariant(this.selectedVariant);
2477
+ }
2478
+ if (!this.disableTimer && this.nativeDialogueWasOpened) {
2479
+ this.sdkApi.resumeUI();
2480
+ this.nativeDialogueWasOpened = false;
2481
+ }
2482
+ this.localData["_p_g_" + this.elementId + "_user_response_on_" + buttonPosition] = text;
2483
+ this.completeWidget();
2484
+ this._statEventInputSave(text);
2485
+ }
2486
+ completeWidget() {
2487
+ if (this.widgetDone) {
2488
+ this.widgetDone.classList.add("active", "opacity-active");
2489
+ setTimeout(() => {
2490
+ this.widgetDone?.classList.remove("active");
2491
+ setTimeout(() => {
2492
+ this.widgetDone?.classList.remove("opacity-active");
2493
+ }, 250);
2494
+ }, 2000);
2495
+ }
2496
+ this.localData["_p_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
2497
+ // ответ на вопрос
2498
+ this.localData["_&ts_p_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
2499
+ this.setLocalData(this.localData, true);
2500
+ }
2501
+ isDone() {
2502
+ return this.localData["_p_g_" + this.elementId + "_done_at"] !== undefined;
2503
+ }
2504
+ slidePollIsDone() {
2505
+ return this.localData["_p_g_" + this.elementId + "_sa"] !== undefined;
2506
+ }
2507
+ static api = {
2508
+ ...WidgetBase.api,
2509
+ initWidget: function (element, localData) {
2510
+ WidgetPoll.initWidgets((element, options) => new WidgetPoll(element, options), [element], localData);
2511
+ },
2512
+ /**
2513
+ * click
2514
+ */
2515
+ select: function (element) {
2516
+ const widgetElement = element.closest(`.${WidgetPoll.widgetClassName}`);
2517
+ if (widgetElement) {
2518
+ const widget = WidgetPoll.getInstance(widgetElement);
2519
+ if (widget) {
2520
+ return widget.selectVariant(element);
2521
+ }
2522
+ }
2523
+ return false;
2524
+ },
2525
+ slidePollIsDone: function (element) {
2526
+ const widget = WidgetPoll.getInstance(element);
2527
+ if (widget) {
2528
+ return widget.slidePollIsDone();
2529
+ }
2530
+ return true;
2531
+ },
2532
+ setUserData: function (id, text) {
2533
+ // id = widgetId_first || widgetId_second
2534
+ let correctWidgetId = id;
2535
+ let buttonPosition;
2536
+ if (id.endsWith("_first")) {
2537
+ buttonPosition = "first_button";
2538
+ correctWidgetId = id.replace(/_first$/, "");
2539
+ }
2540
+ else if (id.endsWith("_second")) {
2541
+ buttonPosition = "second_button";
2542
+ correctWidgetId = id.replace(/_second$/, "");
2543
+ }
2544
+ const widget = WidgetPoll.getInstanceById(correctWidgetId);
2545
+ if (widget && buttonPosition) {
2546
+ widget.setUserText(text, buttonPosition);
2547
+ }
2548
+ },
2549
+ };
2550
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
2551
+ }
2552
+
2553
+ class WidgetPollLayers extends WidgetBase {
2554
+ static DEFAULTS = {
2555
+ slide: null,
2556
+ activateAfterCreate: false,
2557
+ create: false,
2558
+ localData: {},
2559
+ layers: [],
2560
+ };
2561
+ static widgetClassName = "narrative-element-poll-layers";
2562
+ label;
2563
+ variants;
2564
+ variantsTexts;
2565
+ selectedVariant;
2566
+ layers;
2567
+ constructor(element, options) {
2568
+ super(element, options);
2569
+ this.layers = this.options.layers;
2570
+ this.label = this.element.querySelector(".label-view .label");
2571
+ this.variants = slice.call(this.element.querySelectorAll(".variants-box .variant-view"));
2572
+ this.variantsTexts = [];
2573
+ forEach(this.variants, (element, index) => {
2574
+ const label = element.querySelector(".label");
2575
+ if (label) {
2576
+ this.variantsTexts.push(label.textContent ?? "");
2577
+ }
2578
+ });
2579
+ this.selectedVariant = undefined;
2580
+ if (this.slidePollIsDone()) {
2581
+ this._selectVariant(this.localData["_pl_g_" + this.elementId + "_sa"]);
2582
+ }
2583
+ else {
2584
+ this._showLayout(this.layers, 0);
2585
+ }
2586
+ this.firstOpenTime = new Date().getTime();
2587
+ this.refreshUserData(this.options.localData);
2588
+ }
2589
+ refreshUserData(localData) { }
2590
+ _statEventPollVariant() {
2591
+ try {
2592
+ if (this.selectedVariant != null) {
2593
+ var labelText = this.label?.textContent ?? "";
2594
+ var variantText = this.variants[this.selectedVariant]?.textContent ?? "";
2595
+ var duration = new Date().getTime() - this.firstOpenTime;
2596
+ this.sendStatisticEventToApp("w-poll-layers-answer", {
2597
+ i: this.storyId,
2598
+ si: this.slideIndex,
2599
+ wi: this.elementId,
2600
+ wl: labelText,
2601
+ wa: this.selectedVariant,
2602
+ wal: variantText,
2603
+ d: duration,
2604
+ }, {
2605
+ story_id: this.storyId,
2606
+ slide_index: this.slideIndex,
2607
+ widget_id: this.elementId,
2608
+ widget_label: labelText,
2609
+ widget_variant: this.selectedVariant,
2610
+ widget_answer_label: variantText,
2611
+ duration_ms: duration,
2612
+ });
2613
+ }
2614
+ }
2615
+ catch (error) {
2616
+ console.error(error);
2617
+ }
2618
+ }
2619
+ _selectVariant(index, userAction = false) {
2620
+ if (this.variants[index]) {
2621
+ this.variants[index].classList.add("selected");
2622
+ }
2623
+ this.selectedVariant = index;
2624
+ this.localData["_pl_g_" + this.elementId + "_sa"] = index;
2625
+ this.element.classList.add("done");
2626
+ // main
2627
+ var layerIndex = 0;
2628
+ if (index === 0) {
2629
+ layerIndex = 1;
2630
+ }
2631
+ else if (index === 1) {
2632
+ layerIndex = 2;
2633
+ }
2634
+ this._showLayout(this.layers, layerIndex, userAction);
2635
+ if (this.disableTimer) {
2636
+ this.showNextSlide();
2637
+ }
2638
+ }
2639
+ selectVariant(variant) {
2640
+ if (this.selectedVariant !== undefined) {
2641
+ return true;
2642
+ }
2643
+ var index = this.variants.indexOf(variant);
2644
+ if (index !== -1) {
2645
+ this._selectVariant(index, true);
2646
+ this.completeWidget();
2647
+ this._statEventPollVariant();
2648
+ }
2649
+ return false;
2650
+ }
2651
+ completeWidget() {
2652
+ if (this.widgetDone) {
2653
+ this.widgetDone.classList.add("active", "opacity-active");
2654
+ setTimeout(() => {
2655
+ this.widgetDone?.classList.remove("active");
2656
+ setTimeout(() => {
2657
+ this.widgetDone?.classList.remove("opacity-active");
2658
+ }, 250);
2659
+ }, 2000);
2660
+ }
2661
+ this.localData["_pl_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
2662
+ // ответ на вопрос
2663
+ this.localData["_&ts_pl_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
2664
+ this.setLocalData(this.localData, true);
2665
+ }
2666
+ isDone() {
2667
+ return this.localData != null && this.localData["_pl_g_" + this.elementId + "_done_at"] !== undefined;
2668
+ }
2669
+ slidePollIsDone() {
2670
+ return this.localData != null && this.localData["_pl_g_" + this.elementId + "_sa"] !== undefined;
2671
+ }
2672
+ static api = {
2673
+ ...WidgetBase.api,
2674
+ // signature variants
2675
+ // (widget, layers, undefined) - modern web sdk
2676
+ // (widget, undefined, layers) - old web sdk and rn
2677
+ // (widget, layers, localData) - native sdk
2678
+ initWidget: function (element, layers, localData) {
2679
+ if (layers === undefined && localData !== undefined) {
2680
+ // @ts-ignore
2681
+ layers = localData;
2682
+ localData = undefined;
2683
+ }
2684
+ WidgetPollLayers.initWidgets((element, options) => new WidgetPollLayers(element, { ...options, layers }), [element], localData);
2685
+ },
2686
+ /**
2687
+ * click on poll variant
2688
+ * @param element
2689
+ * @returns {boolean}
2690
+ */
2691
+ select: function (element) {
2692
+ const widgetElement = element.closest(`.${WidgetPollLayers.widgetClassName}`);
2693
+ if (widgetElement) {
2694
+ const widget = WidgetPollLayers.getInstance(widgetElement);
2695
+ if (widget) {
2696
+ return widget.selectVariant(element);
2697
+ }
2698
+ }
2699
+ return false;
2700
+ },
2701
+ };
2702
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
2703
+ }
2704
+
2705
+ class WidgetQuest extends WidgetBase {
2706
+ static DEFAULTS = {
2707
+ slide: null,
2708
+ activateAfterCreate: false,
2709
+ create: false,
2710
+ localData: {},
2711
+ };
2712
+ static widgetClassName = "narrative-element-quest";
2713
+ selectedAnswer;
2714
+ label;
2715
+ variants;
2716
+ isWidget;
2717
+ slideCount;
2718
+ nonFinalSlide;
2719
+ finalSlide;
2720
+ constructor(element, options) {
2721
+ const isWidget = !hasClass(element, "narrative-slide");
2722
+ const elementIdGetter = (element) => getValueOrDefault(getTagData(element, "elementId"), "");
2723
+ const slideGetter = (element) => isWidget ? getValueOrException(element.closest(".narrative-slide"), "Empty slide") : element;
2724
+ super(element, options, elementIdGetter, slideGetter);
2725
+ this.isWidget = isWidget;
2726
+ this.slideCount = getTagDataAsNumber(this.slide, "slideCount") ?? 0;
2727
+ this.nonFinalSlide = Boolean(getTagDataAsNumber(this.slide, "nonFinalSlide") ?? 0);
2728
+ this.finalSlide = !this.isWidget && !this.nonFinalSlide;
2729
+ this.label = this.element.querySelector(".label-view .label");
2730
+ this.variants = slice.call(this.element.querySelectorAll(".variants-box .variant-view"));
2731
+ this.selectedAnswer = undefined;
2732
+ // this.refreshUserData(this.options.localData);
2733
+ }
2734
+ refreshUserData(localData) { }
2735
+ setStorySessionValue(name, value) {
2736
+ try {
2737
+ var parent = this.element.closest(".stories-item");
2738
+ if (parent) {
2739
+ parent.dataset[name] = value;
2740
+ }
2741
+ else {
2742
+ //@ts-ignore
2743
+ this.env[name] = value;
2744
+ }
2745
+ }
2746
+ catch (e) {
2747
+ console.error(e);
2748
+ }
2749
+ }
2750
+ getStorySessionValue(name) {
2751
+ try {
2752
+ var parent = this.element.closest(".stories-item");
2753
+ if (parent) {
2754
+ return parent.dataset[name];
2755
+ }
2756
+ else {
2757
+ // @ts-ignore
2758
+ return this.env[name];
2759
+ }
2760
+ }
2761
+ catch (e) {
2762
+ console.error(e);
2763
+ return undefined;
2764
+ }
2765
+ }
2766
+ init() {
2767
+ if (this.localData) {
2768
+ if (this.localData["_qt_g_" + this.elementId + "_sa"] !== undefined) ;
2769
+ if (this.localData["_qt_fo_at"] === undefined) {
2770
+ this.localData["_qt_fo_at"] = Math.round(new Date().getTime() / 1000);
2771
+ this.setLocalData(this.localData, false);
2772
+ }
2773
+ var lastSlideIdx = this.localData["_qt_last_slide_idx"];
2774
+ if (lastSlideIdx !== undefined) {
2775
+ lastSlideIdx = parseInt(lastSlideIdx);
2776
+ if (lastSlideIdx >= 0 &&
2777
+ lastSlideIdx < this.slideCount &&
2778
+ lastSlideIdx !== this.slideIndex /*&& this.slideIndex === this.firstSlideWithQuestIndex()*/) {
2779
+ if (this.getStorySessionValue("__storyQuestSlideChanged") === undefined) {
2780
+ // global flag - был сделан переход на нужный слайд, больше не нужно повторять за эту сессию
2781
+ this.setStorySessionValue("__storyQuestSlideChanged", "1");
2782
+ if (this.sdkApi.isExistsShowStorySlide) {
2783
+ this.sdkApi.showStorySlide(lastSlideIdx);
2784
+ return false;
2785
+ }
2786
+ }
2787
+ }
2788
+ }
2789
+ // если этого слайда нет в роутинге (сработал переход по таймеру в app)
2790
+ var routes = this._getRoutes();
2791
+ if (routes[0].indexOf(this.slideIndex) === -1 && this.finalSlide) {
2792
+ if (this.sdkApi.isExistsShowNextStory) {
2793
+ this.sdkApi.storyShowNext();
2794
+ return false;
2795
+ }
2796
+ }
2797
+ // сбор роутинга - все же в selectAnswer
2798
+ // + pointer - set in select answer and in simple history back naviation
2799
+ // Общее поле в сторис - latest slide with viewed quest item
2800
+ // только если находимся в диапазоне квеста
2801
+ this.localData["_qt_last_slide_idx"] = this.slideIndex;
2802
+ // global flag - был сделан переход на нужный слайд, больше не нужно повторять за эту сессию
2803
+ this.setStorySessionValue("__storyQuestSlideChanged", "1");
2804
+ // если перешли на слайд (через кнопку - на слайд например) то не будет истории в роутере
2805
+ // добавляем сами
2806
+ if (this.getLastSlideIndexFromRouteHistory() !== this.slideIndex) {
2807
+ this._addNewRouteHistory(this.slideIndex);
2808
+ }
2809
+ this.setLocalData(this.localData, true);
2810
+ }
2811
+ this.firstOpenTime = new Date().getTime();
2812
+ return true;
2813
+ }
2814
+ _selectAnswer(index, slideIndex) {
2815
+ // if (this.answers[index]) {
2816
+ // this.answers[index].classList.add('selected');
2817
+ // }
2818
+ this.selectedAnswer = index;
2819
+ if (this.localData["_qt_g_" + this.elementId + "_sa"] === undefined || !Array.isArray(this.localData["_qt_g_" + this.elementId + "_sa"])) {
2820
+ this.localData["_qt_g_" + this.elementId + "_sa"] = [];
2821
+ }
2822
+ this.localData["_qt_g_" + this.elementId + "_sa"].push([index, slideIndex, Math.round(new Date().getTime() / 1000)]);
2823
+ // ответ на вопрос
2824
+ this.localData["_&ts_qt_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
2825
+ this.element.classList.add("done");
2826
+ this._addNewRouteHistory(slideIndex);
2827
+ }
2828
+ selectAnswer(answer) {
2829
+ // if (this.selectedAnswer !== undefined) {
2830
+ // return true;
2831
+ // }
2832
+ var index = this.variants.indexOf(answer);
2833
+ if (index !== -1) {
2834
+ var slideIndex = getValueOrDefault(getTagDataAsNumber(this.variants[index], "score"), 0) - 1;
2835
+ this._selectAnswer(index, slideIndex);
2836
+ this.setLocalData(this.localData, true);
2837
+ this.env.setTimeout(() => {
2838
+ if (slideIndex >= 0 && slideIndex < this.slideCount && this.sdkApi.isExistsShowStorySlide) {
2839
+ // global flag - был сделан переход на нужный слайд, больше не нужно повторять за эту сессию
2840
+ this.setStorySessionValue("__storyQuestSlideChanged", "1");
2841
+ this.sdkApi.showStorySlide(slideIndex);
2842
+ }
2843
+ }, 100);
2844
+ }
2845
+ return true;
2846
+ }
2847
+ isDone() {
2848
+ return this.localData["_qt_done_at"] !== undefined && this.selectedAnswer !== undefined;
2849
+ }
2850
+ slideQuestIsDone() {
2851
+ return this.localData["_qt_g_" + this.elementId + "_sa"] !== undefined && this.selectedAnswer !== undefined;
2852
+ }
2853
+ firstSlideWithQuestIndex() {
2854
+ return getTagDataAsNumber(this.slide, "firstSlideWithQuest") ?? 0;
2855
+ }
2856
+ lastSlideWithQuestIndex() {
2857
+ return getTagDataAsNumber(this.slide, "lastSlideWithQuest") ?? 0;
2858
+ }
2859
+ _getRoutes() {
2860
+ var routes = this.localData["_qt_routes"];
2861
+ if (!Array.isArray(routes)) {
2862
+ routes = [[0], 0];
2863
+ }
2864
+ return routes;
2865
+ }
2866
+ _addNewRouteHistory(route) {
2867
+ var routes = this._getRoutes();
2868
+ var _routes = routes[0].slice(0, routes[1] + 1);
2869
+ routes[0] = _routes.concat([route]);
2870
+ routes[1] = routes[0].length - 1;
2871
+ this.localData["_qt_routes"] = routes;
2872
+ }
2873
+ _routeMvPtrBack() {
2874
+ var routes = this._getRoutes();
2875
+ var newPtr = routes[1] - 1;
2876
+ if (newPtr >= 0 && routes[0][newPtr] !== undefined) {
2877
+ routes[1] = newPtr;
2878
+ this.localData["_qt_routes"] = routes;
2879
+ this.setLocalData(this.localData, true);
2880
+ return routes[0][newPtr];
2881
+ }
2882
+ return false;
2883
+ }
2884
+ getLastSlideIndexFromRouteHistory() {
2885
+ var routes = this._getRoutes();
2886
+ return routes[0][routes[1]];
2887
+ }
2888
+ handleRouteClick(event) {
2889
+ // event: direction ('backward', 'forward') slideIndex, slideCount
2890
+ var directionForward = event.direction === "forward";
2891
+ event.direction === "backward";
2892
+ if (this.isWidget) {
2893
+ if (directionForward) {
2894
+ return;
2895
+ }
2896
+ else {
2897
+ if (event.slideIndex === 0) {
2898
+ // can click back
2899
+ event.click();
2900
+ }
2901
+ else {
2902
+ // by routing - move back
2903
+ var moveTo = this._routeMvPtrBack();
2904
+ if (moveTo !== false && moveTo >= 0 && moveTo < event.slideCount && this.sdkApi.isExistsShowStorySlide) {
2905
+ this.sdkApi.showStorySlide(moveTo);
2906
+ }
2907
+ if (moveTo === false && this.sdkApi.isExistsShowStorySlide) {
2908
+ // allow move to start - for broken route history
2909
+ this.sdkApi.showStorySlide(0);
2910
+ }
2911
+ }
2912
+ return;
2913
+ }
2914
+ }
2915
+ else {
2916
+ // slides without quest form
2917
+ // simple slide case
2918
+ if (this.nonFinalSlide || event.slideIndex < this.firstSlideWithQuestIndex()) {
2919
+ if (directionForward) {
2920
+ var nextSlideIndex = event.slideIndex + 1;
2921
+ if (nextSlideIndex < this.slideCount) {
2922
+ this._addNewRouteHistory(nextSlideIndex);
2923
+ this.setLocalData(this.localData, true);
2924
+ this.sdkApi.showStorySlide(nextSlideIndex);
2925
+ }
2926
+ else {
2927
+ if (this.sdkApi.isExistsShowNextStory) {
2928
+ this.sdkApi.storyShowNext();
2929
+ }
2930
+ }
2931
+ }
2932
+ else {
2933
+ if (event.slideIndex === 0) {
2934
+ // move to prev slide
2935
+ event.click();
2936
+ }
2937
+ else {
2938
+ // by routing - move back
2939
+ var moveTo = this._routeMvPtrBack();
2940
+ if (moveTo !== false && moveTo >= 0 && moveTo < event.slideCount && this.sdkApi.isExistsShowStorySlide) {
2941
+ this.sdkApi.showStorySlide(moveTo);
2942
+ }
2943
+ if (moveTo === false && this.sdkApi.isExistsShowStorySlide) {
2944
+ // allow move to start - for broken route history
2945
+ this.sdkApi.showStorySlide(0);
2946
+ }
2947
+ }
2948
+ }
2949
+ }
2950
+ else {
2951
+ // quest final slide
2952
+ if (directionForward) {
2953
+ // если клик вперед по финальному слайду из любой ветки - то выходим из сторис
2954
+ // var nextSlideIndex = this.lastSlideWithQuestIndex() + 1;
2955
+ // if (nextSlideIndex < this.slideCount) {
2956
+ // this._addNewRouteHistory(nextSlideIndex);
2957
+ // setLocalData(this.localData, true);
2958
+ // window._showNarrativeSlide(nextSlideIndex);
2959
+ // } else {
2960
+ if (this.sdkApi.isExistsShowNextStory) {
2961
+ this.sdkApi.storyShowNext();
2962
+ }
2963
+ // }
2964
+ }
2965
+ else {
2966
+ // by routing - move back
2967
+ var moveTo = this._routeMvPtrBack();
2968
+ if (moveTo !== false && moveTo >= 0 && moveTo < event.slideCount && this.sdkApi.isExistsShowStorySlide) {
2969
+ this.sdkApi.showStorySlide(moveTo);
2970
+ }
2971
+ if (moveTo === false && this.sdkApi.isExistsShowStorySlide) {
2972
+ // allow move to start - for broken route history
2973
+ this.sdkApi.showStorySlide(0);
2974
+ }
2975
+ }
2976
+ }
2977
+ }
2978
+ }
2979
+ static api = {
2980
+ ...WidgetBase.api,
2981
+ initWidget: function (element, localData) {
2982
+ return new Promise(function (resolve, reject) {
2983
+ WidgetQuest.initWidgets((element, options) => new WidgetQuest(element, options), [element], localData).then(localData => {
2984
+ const widget = WidgetQuest.getInstance(element);
2985
+ if (widget) {
2986
+ resolve(widget.init());
2987
+ }
2988
+ else {
2989
+ resolve(true);
2990
+ }
2991
+ });
2992
+ });
2993
+ },
2994
+ select: function (element) {
2995
+ const widgetElement = element.closest(`.${WidgetQuest.widgetClassName}`);
2996
+ if (widgetElement) {
2997
+ const widget = WidgetQuest.getInstance(widgetElement);
2998
+ if (widget) {
2999
+ return widget.selectAnswer(element);
3000
+ }
3001
+ }
3002
+ return false;
3003
+ },
3004
+ slideTestIsDone: function (element) {
3005
+ const widget = WidgetQuest.getInstance(element);
3006
+ if (widget) {
3007
+ return widget.slideQuestIsDone();
3008
+ }
3009
+ return true;
3010
+ },
3011
+ handleRouteClick: function (element, event) {
3012
+ const widget = WidgetQuest.getInstance(element);
3013
+ if (widget) {
3014
+ widget.handleRouteClick(event);
3015
+ }
3016
+ },
3017
+ };
3018
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
3019
+ }
3020
+
3021
+ class WidgetQuiz extends WidgetBase {
3022
+ static DEFAULTS = {
3023
+ slide: null,
3024
+ activateAfterCreate: false,
3025
+ create: false,
3026
+ localData: {},
3027
+ };
3028
+ static widgetClassName = "narrative-element-quiz";
3029
+ question;
3030
+ answers;
3031
+ questionCount;
3032
+ selectedAnswer;
3033
+ constructor(element, options) {
3034
+ super(element, options);
3035
+ this.question = this.element.querySelector(".label-view .label");
3036
+ this.answers = slice.call(this.element.querySelectorAll(".variants-box .variant-view-group"));
3037
+ this.questionCount = getValueOrException(getTagDataAsNumber(this.slide, "quizCount"), "Empty quizCount");
3038
+ this.refreshUserData(this.options.localData);
3039
+ }
3040
+ refreshUserData(localData) {
3041
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
3042
+ this.localData = extend({}, this.savedData ?? {}, localData);
3043
+ this.selectedAnswer = undefined;
3044
+ if (this.localData) {
3045
+ if (this.localData["_q_g_" + this.elementId + "_sa"] !== undefined) {
3046
+ this._selectAnswer(this.localData["_q_g_" + this.elementId + "_sa"]);
3047
+ this.constructor.setLocalData(this.localData, false);
3048
+ }
3049
+ else {
3050
+ this._clearAnswerSelection();
3051
+ }
3052
+ if (this.localData["_q_fo_at"] === undefined) {
3053
+ this.localData["_q_fo_at"] = Math.round(new Date().getTime() / 1000);
3054
+ this.constructor.setLocalData(this.localData, false);
3055
+ }
3056
+ }
3057
+ this.firstOpenTime = new Date().getTime();
3058
+ }
3059
+ _selectAnswer(index) {
3060
+ // var hintContainer = null;
3061
+ // var hintContainerHeight = null;
3062
+ if (this.answers[index]) {
3063
+ this.answers[index].classList.add("selected");
3064
+ // hintContainer = this.answers[index].nextSibling;
3065
+ // if (hintContainer && hintContainer.classList.contains('narrative-element-quiz-answer-hint-container')) {
3066
+ // hintContainerHeight = hintContainer.getBoundingClientRect().height;
3067
+ // hintContainer.style.height = 0;
3068
+ // }
3069
+ }
3070
+ this.selectedAnswer = index;
3071
+ this.localData["_q_g_" + this.elementId + "_sa"] = index;
3072
+ this.element.classList.add("done");
3073
+ this.env.requestAnimationFrame(() => {
3074
+ if (this.submitButtonAnimatedView != null && this.submitButtonViewHeight != null) {
3075
+ this.submitButtonAnimatedView.style.maxHeight = `${this.submitButtonViewHeight}px`;
3076
+ }
3077
+ });
3078
+ // if (hintContainer && hintContainerHeight && window.requestAnimationFrame) {
3079
+ // requestAnimationFrame(function() {
3080
+ // requestAnimationFrame(function() {
3081
+ // hintContainer.style.height = hintContainerHeight + 'px';
3082
+ // })
3083
+ // })
3084
+ // }
3085
+ if (this.disableTimer) {
3086
+ this.showNextSlide();
3087
+ }
3088
+ }
3089
+ _clearAnswerSelection() {
3090
+ forEach(this.answers, function (answer) {
3091
+ answer.classList.remove("selected");
3092
+ });
3093
+ this.selectedAnswer = undefined;
3094
+ this.element.classList.remove("done");
3095
+ this.env.requestAnimationFrame(() => {
3096
+ if (this.submitButtonAnimatedView != null) {
3097
+ this.submitButtonAnimatedView.style.maxHeight = "0px";
3098
+ }
3099
+ });
3100
+ }
3101
+ selectAnswer(answer) {
3102
+ if (this.selectedAnswer !== undefined) {
3103
+ return true;
3104
+ }
3105
+ const selectedAnswerIndex = this.answers.indexOf(answer);
3106
+ if (selectedAnswerIndex !== -1) {
3107
+ this._selectAnswer(selectedAnswerIndex);
3108
+ var isCorrect = this.answers[selectedAnswerIndex].classList.contains("check");
3109
+ this.localData["q_score"] = (this.localData["q_score"] === undefined ? 0 : this.localData["q_score"]) + (isCorrect ? 1 : 0);
3110
+ var answeredQuestion = 0;
3111
+ for (var key in this.localData) {
3112
+ if (this.localData.hasOwnProperty(key)) {
3113
+ if (/^_q_g_[A-z0-9-_]+_sa$/.test(key)) {
3114
+ answeredQuestion++;
3115
+ }
3116
+ }
3117
+ }
3118
+ if (this.localData["_q_fa_at"] === undefined) {
3119
+ this.localData["_q_fa_at"] = Math.round(new Date().getTime() / 1000);
3120
+ }
3121
+ if (answeredQuestion === this.questionCount) {
3122
+ this.localData["_q_done_at"] = Math.round(new Date().getTime() / 1000);
3123
+ }
3124
+ // ответ на вопрос
3125
+ this.localData["_&ts_q_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
3126
+ this.setLocalData(this.localData, true);
3127
+ if (this.widgetDone) {
3128
+ this.widgetDone.classList.add("active", "opacity-active");
3129
+ const self = this;
3130
+ setTimeout(function () {
3131
+ self.widgetDone?.classList.remove("active");
3132
+ setTimeout(function () {
3133
+ self.widgetDone?.classList.remove("opacity-active");
3134
+ }, 250);
3135
+ }, 2000);
3136
+ }
3137
+ try {
3138
+ var questionText = this.question ? this.question.textContent ?? "" : "";
3139
+ let answerText = "";
3140
+ if (this.answers[selectedAnswerIndex]) {
3141
+ const answerLabel = this.answers[selectedAnswerIndex].querySelector(".variant-view .label");
3142
+ if (answerLabel != null && answerLabel.textContent != null) {
3143
+ answerText = answerLabel.textContent;
3144
+ }
3145
+ }
3146
+ var duration = new Date().getTime() - this.firstOpenTime;
3147
+ WidgetBase.sendStatisticEventToApp("w-quiz-answer", {
3148
+ i: this.storyId,
3149
+ si: this.slideIndex,
3150
+ wi: this.elementId,
3151
+ wl: questionText,
3152
+ wa: selectedAnswerIndex,
3153
+ wal: answerText,
3154
+ d: duration,
3155
+ }, {
3156
+ story_id: this.storyId,
3157
+ slide_index: this.slideIndex,
3158
+ widget_id: this.elementId,
3159
+ widget_label: questionText,
3160
+ widget_answer: selectedAnswerIndex,
3161
+ widget_answer_label: answerText,
3162
+ duration_ms: duration,
3163
+ });
3164
+ }
3165
+ catch (error) {
3166
+ console.error(error);
3167
+ }
3168
+ }
3169
+ return false;
3170
+ }
3171
+ isDone() {
3172
+ return this.localData["_q_done_at"] !== undefined;
3173
+ }
3174
+ slideQuizIsDone() {
3175
+ return this.localData["_q_g_" + this.elementId + "_sa"] !== undefined;
3176
+ }
3177
+ static api = {
3178
+ ...WidgetBase.api,
3179
+ initWidget: function (element, localData) {
3180
+ WidgetQuiz.initWidgets((element, options) => new WidgetQuiz(element, options), [element], localData);
3181
+ },
3182
+ /**
3183
+ * click on quiz answer
3184
+ */
3185
+ select: function (element) {
3186
+ const widgetElement = element.closest(`.${WidgetQuiz.widgetClassName}`);
3187
+ if (widgetElement) {
3188
+ const widget = WidgetQuiz.getInstance(widgetElement);
3189
+ if (widget) {
3190
+ return widget.selectAnswer(element);
3191
+ }
3192
+ }
3193
+ return false;
3194
+ },
3195
+ slideQuizIsDone: function (element) {
3196
+ const widget = WidgetQuiz.getInstance(element);
3197
+ if (widget) {
3198
+ return widget.slideQuizIsDone();
3199
+ }
3200
+ return true;
3201
+ },
3202
+ };
3203
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
3204
+ }
3205
+
3206
+ class WidgetQuizGrouped extends WidgetBase {
3207
+ static DEFAULTS = {
3208
+ slide: null,
3209
+ activateAfterCreate: false,
3210
+ create: false,
3211
+ localData: {},
3212
+ };
3213
+ static widgetClassName = "narrative-element-quiz-grouped";
3214
+ question;
3215
+ answers;
3216
+ questionCount;
3217
+ selectedAnswer;
3218
+ /**
3219
+ * @throws Error
3220
+ * @param element
3221
+ * @param options
3222
+ */
3223
+ constructor(element, options) {
3224
+ super(element, options);
3225
+ this.question = this.element.querySelector(".label-view .label");
3226
+ this.answers = slice.call(this.element.querySelectorAll(".variants-box .variant-view-group"));
3227
+ this.questionCount = getValueOrException(getTagDataAsNumber(this.slide, "quizCount"), "Empty quizCount");
3228
+ this.refreshUserData(this.options.localData);
3229
+ }
3230
+ refreshUserData(localData) {
3231
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
3232
+ this.localData = extend({}, this.savedData ?? {}, localData);
3233
+ this.selectedAnswer = undefined;
3234
+ if (this.localData) {
3235
+ if (this.localData["_q_gg_" + this.elementId + "_sa"] !== undefined) {
3236
+ this._selectAnswer(this.localData["_q_gg_" + this.elementId + "_sa"]);
3237
+ // this._updateScore(this.localData['_q_gg_' + this.elementId + '_sa']);
3238
+ this.setLocalData(this.localData, false);
3239
+ }
3240
+ else {
3241
+ this._clearAnswerSelection();
3242
+ }
3243
+ if (this.localData["_qg_fo_at"] === undefined) {
3244
+ this.localData["_qg_fo_at"] = Math.round(new Date().getTime() / 1000);
3245
+ this.setLocalData(this.localData, false);
3246
+ }
3247
+ }
3248
+ this.firstOpenTime = new Date().getTime();
3249
+ }
3250
+ _selectAnswer(index) {
3251
+ if (this.answers[index]) {
3252
+ this.answers[index].classList.add("selected");
3253
+ }
3254
+ this.selectedAnswer = index;
3255
+ this.localData["_q_gg_" + this.elementId + "_sa"] = index;
3256
+ this.element.classList.add("done");
3257
+ this.env.requestAnimationFrame(() => {
3258
+ if (this.submitButtonAnimatedView != null && this.submitButtonViewHeight != null) {
3259
+ this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
3260
+ }
3261
+ });
3262
+ if (this.disableTimer) {
3263
+ this.showNextSlide();
3264
+ }
3265
+ }
3266
+ _clearAnswerSelection() {
3267
+ forEach(this.answers, function (answer) {
3268
+ answer.classList.remove("selected");
3269
+ });
3270
+ this.selectedAnswer = undefined;
3271
+ this.element.classList.remove("done");
3272
+ this.env.requestAnimationFrame(() => {
3273
+ if (this.submitButtonAnimatedView != null) {
3274
+ this.submitButtonAnimatedView.style.maxHeight = "0px";
3275
+ }
3276
+ });
3277
+ }
3278
+ _updateScore(index) {
3279
+ const answerValue = getValueOrDefault(getTagDataAsNumber(this.answers[index], "value"), index);
3280
+ if (this.localData["qg_score"] == null) {
3281
+ this.localData["qg_score"] = {};
3282
+ }
3283
+ var sum = 0;
3284
+ for (var i = 0; i < this.answers.length; i++) {
3285
+ if (this.localData["qg_score"][i] == null) {
3286
+ this.localData["qg_score"][i] = 0;
3287
+ }
3288
+ sum += this.localData["qg_score"][i];
3289
+ }
3290
+ // если еще не ответили на все
3291
+ if (sum < this.questionCount) {
3292
+ this.localData["qg_score"][answerValue] += 1;
3293
+ var answeredQuestion = 0;
3294
+ for (var key in this.localData) {
3295
+ if (this.localData.hasOwnProperty(key)) {
3296
+ if (/^_q_gg_[A-z0-9-_]+_sa$/.test(key)) {
3297
+ answeredQuestion++;
3298
+ }
3299
+ }
3300
+ }
3301
+ if (this.localData["_qg_fa_at"] === undefined) {
3302
+ this.localData["_qg_fa_at"] = Math.round(new Date().getTime() / 1000);
3303
+ }
3304
+ if (this.localData["_qg_done_at"] === undefined) {
3305
+ if (answeredQuestion === this.questionCount) {
3306
+ this.localData["_qg_done_at"] = Math.round(new Date().getTime() / 1000);
3307
+ }
3308
+ }
3309
+ // ответ на вопрос
3310
+ this.localData["_&ts_qg_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
3311
+ this.setLocalData(this.localData, true);
3312
+ }
3313
+ }
3314
+ selectAnswer(answer) {
3315
+ if (this.selectedAnswer != null) {
3316
+ return true;
3317
+ }
3318
+ const selectedAnswerIndex = this.answers.indexOf(answer);
3319
+ if (selectedAnswerIndex !== -1) {
3320
+ this._selectAnswer(selectedAnswerIndex);
3321
+ this._updateScore(selectedAnswerIndex);
3322
+ if (this.widgetDone) {
3323
+ this.widgetDone.classList.add("active", "opacity-active");
3324
+ setTimeout(() => {
3325
+ this.widgetDone?.classList.remove("active");
3326
+ setTimeout(() => {
3327
+ this.widgetDone?.classList.remove("opacity-active");
3328
+ }, 250);
3329
+ }, 2000);
3330
+ }
3331
+ try {
3332
+ var questionText = this.question ? this.question.textContent ?? "" : "";
3333
+ var answerText = "";
3334
+ if (this.answers[selectedAnswerIndex]) {
3335
+ var answerLabel = this.answers[selectedAnswerIndex].querySelector(".variant-view .label");
3336
+ if (answerLabel != null) {
3337
+ answerText = answerLabel.textContent ?? "";
3338
+ }
3339
+ }
3340
+ var duration = new Date().getTime() - this.firstOpenTime;
3341
+ WidgetBase.sendStatisticEventToApp("w-quiz-grouped-answer", {
3342
+ i: this.storyId,
3343
+ si: this.slideIndex,
3344
+ wi: this.elementId,
3345
+ wl: questionText,
3346
+ wa: selectedAnswerIndex,
3347
+ wal: answerText,
3348
+ d: duration,
3349
+ }, {
3350
+ story_id: this.storyId,
3351
+ slide_index: this.slideIndex,
3352
+ widget_id: this.elementId,
3353
+ widget_label: questionText,
3354
+ widget_answer: selectedAnswerIndex,
3355
+ widget_answer_label: answerText,
3356
+ duration_ms: duration,
3357
+ });
3358
+ }
3359
+ catch (error) {
3360
+ console.error(error);
3361
+ }
3362
+ }
3363
+ return false;
3364
+ }
3365
+ isDone() {
3366
+ return this.localData["_qg_done_at"] !== undefined;
3367
+ }
3368
+ slideQuizIsDone() {
3369
+ return this.localData["_q_gg_" + this.elementId + "_sa"] !== undefined;
3370
+ }
3371
+ static api = {
3372
+ ...WidgetBase.api,
3373
+ initWidget: function (element, localData) {
3374
+ WidgetQuizGrouped.initWidgets((element, options) => new WidgetQuizGrouped(element, options), [element], localData);
3375
+ },
3376
+ /**
3377
+ * click on quiz answer
3378
+ */
3379
+ select: function (element) {
3380
+ const widgetElement = element.closest(`.${WidgetQuizGrouped.widgetClassName}`);
3381
+ if (widgetElement) {
3382
+ const widget = WidgetQuizGrouped.getInstance(widgetElement);
3383
+ if (widget) {
3384
+ return widget.selectAnswer(element);
3385
+ }
3386
+ }
3387
+ return false;
3388
+ },
3389
+ slideQuizIsDone: function (element) {
3390
+ const widget = WidgetQuizGrouped.getInstance(element);
3391
+ if (widget) {
3392
+ return widget.slideQuizIsDone();
3393
+ }
3394
+ return true;
3395
+ },
3396
+ };
3397
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
3398
+ }
3399
+
3400
+ // Polyfill Number.isNaN(value)
3401
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
3402
+ Number.isNaN =
3403
+ Number.isNaN ||
3404
+ function (value) {
3405
+ return typeof value === "number" && value !== value;
3406
+ };
3407
+ const constants = {
3408
+ orientation: {
3409
+ horizontal: {
3410
+ dimension: "width",
3411
+ direction: "left",
3412
+ directionStyle: {
3413
+ ltr: "left",
3414
+ rtl: "right",
3415
+ },
3416
+ coordinate: "x",
3417
+ },
3418
+ vertical: {
3419
+ dimension: "height",
3420
+ direction: "top",
3421
+ directionStyle: {
3422
+ ltr: "bottom",
3423
+ rtl: "bottom",
3424
+ },
3425
+ coordinate: "y",
3426
+ },
3427
+ },
3428
+ };
3429
+ /**
3430
+ * Check if a `element` is visible in the DOM
3431
+ *
3432
+ * @param {Element} element
3433
+ * @return {Boolean}
3434
+ */
3435
+ function isHidden(element) {
3436
+ return Boolean(element &&
3437
+ (element.offsetWidth === 0 ||
3438
+ element.offsetHeight === 0 ||
3439
+ // Also Consider native `<details>` elements.
3440
+ element.open === false));
3441
+ }
3442
+ /**
3443
+ * Get hidden parentNodes of an `element`
3444
+ *
3445
+ * @param {Element} element
3446
+ * @return {[type]}
3447
+ */
3448
+ function getHiddenParentNodes(element) {
3449
+ var parents = [], node = element.parentNode;
3450
+ while (isHidden(node)) {
3451
+ parents.push(node);
3452
+ node = node.parentNode;
3453
+ }
3454
+ return parents;
3455
+ }
3456
+ /**
3457
+ * Returns dimensions for an element even if it is not visible in the DOM.
3458
+ *
3459
+ * @param {Element} element
3460
+ * @param {String} key (e.g. offsetWidth …)
3461
+ * @return {Number}
3462
+ */
3463
+ function getDimension(element, key) {
3464
+ getHiddenParentNodes(element);
3465
+ // if (hiddenParentNodesLength) {
3466
+ // for (var i = 0; i < hiddenParentNodesLength; i++) {
3467
+ //
3468
+ // // Cache style attribute to restore it later.
3469
+ // inlineStyle[i] = hiddenParentNodes[i].style.cssText;
3470
+ //
3471
+ // // visually hide
3472
+ // if (hiddenParentNodes[i].style.setProperty) {
3473
+ // hiddenParentNodes[i].style.setProperty('display', 'block', 'important');
3474
+ // } else {
3475
+ // hiddenParentNodes[i].style.cssText += ';display: block !important';
3476
+ // }
3477
+ // hiddenParentNodes[i].style.height = '0';
3478
+ // hiddenParentNodes[i].style.overflow = 'hidden';
3479
+ // hiddenParentNodes[i].style.visibility = 'hidden';
3480
+ // toggleOpenProperty(hiddenParentNodes[i]);
3481
+ // }
3482
+ //
3483
+ // // Update dimension
3484
+ // dimension = element[key];
3485
+ //
3486
+ // for (var j = 0; j < hiddenParentNodesLength; j++) {
3487
+ //
3488
+ // // Restore the style attribute
3489
+ // hiddenParentNodes[j].style.cssText = inlineStyle[j];
3490
+ // toggleOpenProperty(hiddenParentNodes[j]);
3491
+ // }
3492
+ // }
3493
+ return element[key];
3494
+ }
3495
+ /**
3496
+ * Returns the parsed float or the default if it failed.
3497
+ *
3498
+ * @param {String} str
3499
+ * @param {Number} defaultValue
3500
+ * @return {Number}
3501
+ */
3502
+ function tryParseFloat(str, defaultValue) {
3503
+ if (str == null) {
3504
+ return defaultValue;
3505
+ }
3506
+ var value = parseFloat(str);
3507
+ return Number.isNaN(value) ? defaultValue : value;
3508
+ }
3509
+ /**
3510
+ * Capitalize the first letter of string
3511
+ *
3512
+ * @param {String} str
3513
+ * @return {String}
3514
+ */
3515
+ function ucfirst(str) {
3516
+ return str.charAt(0).toUpperCase() + str.substr(1);
3517
+ }
3518
+ class WidgetRangeSlider extends WidgetBase {
3519
+ static DEFAULTS = {
3520
+ slide: null,
3521
+ activateAfterCreate: false,
3522
+ create: false,
3523
+ localData: {},
3524
+ rangeClass: "slider-view",
3525
+ activeClass: "rangeslider--active",
3526
+ horizontalClass: "rangeslider--horizontal",
3527
+ verticalClass: "rangeslider--vertical",
3528
+ fillClass: "slider-fill-view",
3529
+ handleClass: "slider-handle-view",
3530
+ };
3531
+ static widgetClassName = "narrative-element-range-slider";
3532
+ label;
3533
+ topScale;
3534
+ startValue;
3535
+ snapPosition;
3536
+ hasSubmitButton;
3537
+ elementSlider;
3538
+ elementAverageResult;
3539
+ elementAverageResultTooltip;
3540
+ elementAverageResultTooltipLabelView;
3541
+ orientation;
3542
+ min;
3543
+ max;
3544
+ value;
3545
+ step;
3546
+ toFixed;
3547
+ fill;
3548
+ handle;
3549
+ range;
3550
+ DIMENSION;
3551
+ DIRECTION;
3552
+ DIRECTION_STYLE;
3553
+ COORDINATE;
3554
+ isClickCapturedBySlider = false;
3555
+ handleDimension;
3556
+ rangeDimension;
3557
+ maxHandlePos;
3558
+ grabPos;
3559
+ position;
3560
+ prevSnapValue;
3561
+ /**
3562
+ * @throws Error
3563
+ * @param element
3564
+ * @param options
3565
+ */
3566
+ constructor(element, options) {
3567
+ super(element, options);
3568
+ this.hasSubmitButton = Boolean(this.element.querySelector(".submit-button-view"));
3569
+ this.topScale = this.element.querySelector(".top-scale-bar-view-group");
3570
+ this.snapPosition = false;
3571
+ try {
3572
+ this.snapPosition = this.topScale != null && this.topScale.getBoundingClientRect().height > 0;
3573
+ }
3574
+ catch (e) {
3575
+ console.error(e);
3576
+ }
3577
+ this.startValue = tryParseFloat(getTagData(this.element, "startValue"), 0);
3578
+ this.label = this.element.querySelector(".label-view .label");
3579
+ this.elementSlider = getValueOrException(this.element.querySelector('input[type="range"]'), "Empty elementSlider");
3580
+ this.elementAverageResult = this.element.querySelector(".slider-average-result-view");
3581
+ if (this.elementAverageResult != null) {
3582
+ this.elementAverageResultTooltip = this.elementAverageResult.querySelector(".tooltip-view");
3583
+ if (this.elementAverageResultTooltip != null) {
3584
+ this.elementAverageResultTooltipLabelView = this.elementAverageResult.querySelector(".average-result-label-view");
3585
+ }
3586
+ }
3587
+ this.toFixed = (this.step + "").replace(".", "").length - 1;
3588
+ this.fill = getValueOrException(this.element.querySelector(`.${this.options.fillClass}`), `Empty .${this.options.fillClass}`);
3589
+ this.handle = getValueOrException(this.element.querySelector(`.${this.options.handleClass}`), `Empty .${this.options.handleClass}`);
3590
+ this.range = getValueOrException(this.element.querySelector(`.${this.options.rangeClass}`), `Empty .${this.options.rangeClass}`);
3591
+ this.range.id = this.id;
3592
+ // if (this.range.classList.contains(this.options['horizontalClass'])) {
3593
+ this.orientation = "horizontal";
3594
+ // } else if (this.range.classList.contains(this.options['verticalClass'])) {
3595
+ // this.orientation = 'vertical';
3596
+ // }
3597
+ this.DIMENSION = constants.orientation[this.orientation].dimension;
3598
+ this.DIRECTION = constants.orientation[this.orientation].direction;
3599
+ this.DIRECTION_STYLE = constants.orientation[this.orientation].directionStyle[this.layoutDirection];
3600
+ this.COORDINATE = constants.orientation[this.orientation].coordinate;
3601
+ // Store context
3602
+ this.handleDown = proxy(this.handleDown, this);
3603
+ this.handleMove = proxy(this.handleMove, this);
3604
+ this.handleEnd = proxy(this.handleEnd, this);
3605
+ this.refreshUserData(this.options.localData);
3606
+ // Attach Events
3607
+ // window.addEventListener('resize.' + this.identifier, debounce(function() {
3608
+ // // Simulate resizeEnd event.
3609
+ // delay(function() {
3610
+ // _this.update(false, false);
3611
+ // }, 300);
3612
+ // }, 20));
3613
+ this.env.document.addEventListener("touchstart", this.handleDown);
3614
+ this.env.document.addEventListener("mousedown", this.handleDown);
3615
+ }
3616
+ refreshUserData(localData) {
3617
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
3618
+ this.localData = extend({}, this.savedData ?? {}, localData);
3619
+ if (this.localData["_rs_g_" + this.elementId + "_v"] !== undefined) {
3620
+ this.elementSlider.value = String(tryParseFloat(this.localData["_rs_g_" + this.elementId + "_v"], 0));
3621
+ this.element.classList.add("done");
3622
+ this.displayAverageAnswer();
3623
+ if (this.disableTimer) {
3624
+ this.showNextSlide();
3625
+ }
3626
+ }
3627
+ else {
3628
+ this.elementSlider.value = String(this.startValue);
3629
+ this.element.classList.remove("done");
3630
+ this.element.classList.remove("input-done");
3631
+ }
3632
+ this.init();
3633
+ }
3634
+ _statEventInputSave(val) {
3635
+ try {
3636
+ const labelText = this.label?.textContent ?? "";
3637
+ this.sendStatisticEventToApp("w-range-slider-answer", {
3638
+ i: this.storyId,
3639
+ si: this.slideIndex,
3640
+ wi: this.elementId,
3641
+ wl: labelText,
3642
+ wa: val,
3643
+ }, {
3644
+ story_id: this.storyId,
3645
+ slide_index: this.slideIndex,
3646
+ widget_id: this.elementId,
3647
+ widget_label: labelText,
3648
+ widget_answer: val,
3649
+ });
3650
+ }
3651
+ catch (error) {
3652
+ console.error(error);
3653
+ }
3654
+ }
3655
+ click() {
3656
+ if (this.isDone()) {
3657
+ return true;
3658
+ }
3659
+ this.completeWidget();
3660
+ return false;
3661
+ }
3662
+ completeWidget() {
3663
+ if (this.widgetDone) {
3664
+ this.widgetDone.classList.add("active", "opacity-active");
3665
+ setTimeout(() => {
3666
+ this.widgetDone?.classList.remove("active");
3667
+ setTimeout(() => {
3668
+ this.widgetDone?.classList.remove("opacity-active");
3669
+ }, 250);
3670
+ }, 2000);
3671
+ }
3672
+ this.localData["_rs_g_" + this.elementId + "_v"] = tryParseFloat(this.elementSlider.value, 0);
3673
+ this.localData["_rs_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
3674
+ // answer for question
3675
+ this.localData["_&ts_rs_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
3676
+ // hide submit button
3677
+ this.env.requestAnimationFrame(() => {
3678
+ if (this.submitButtonAnimatedView != null) {
3679
+ this.submitButtonAnimatedView.style.maxHeight = "0px";
3680
+ setTimeout(() => {
3681
+ // important, displayAverageAnswer need .done at element
3682
+ this.element.classList.add("done");
3683
+ this.displayAverageAnswer(true);
3684
+ }, 200);
3685
+ }
3686
+ else {
3687
+ // important, displayAverageAnswer need .done at element
3688
+ this.element.classList.add("done");
3689
+ this.displayAverageAnswer(true);
3690
+ }
3691
+ });
3692
+ // if (this.disableTimer) {
3693
+ this.showNextSlide();
3694
+ // }
3695
+ this.setLocalData(this.localData, true);
3696
+ this._statEventInputSave(this.localData["_rs_g_" + this.elementId + "_v"]);
3697
+ }
3698
+ isDone() {
3699
+ return this.localData["_rs_g_" + this.elementId + "_v"] != null;
3700
+ }
3701
+ getIsClickCapturedBySlider() {
3702
+ return this.isClickCapturedBySlider;
3703
+ }
3704
+ displayAverageAnswer(withTooltip = false) {
3705
+ let answerAllocation = {
3706
+ total_value: 0,
3707
+ total_user: 0,
3708
+ };
3709
+ let answerAllocationTs = undefined;
3710
+ const sharedData = this.sdkApi.getWidgetsSharedData(this.storyId, "rangeSlider" /* Widgets.RangeSlider */);
3711
+ if (sharedData && sharedData[this.elementId] != null && (isObject(sharedData[this.elementId]) || isArray(sharedData[this.elementId]))) {
3712
+ answerAllocation = sharedData[this.elementId];
3713
+ answerAllocationTs = sharedData.ts;
3714
+ }
3715
+ const rangeSliderDoneAt = this.localData["_rs_g_" + this.elementId + "_done_at"];
3716
+ if (answerAllocationTs === undefined || rangeSliderDoneAt === undefined || rangeSliderDoneAt > answerAllocationTs) {
3717
+ answerAllocation["total_value"] += this.localData["_rs_g_" + this.elementId + "_v"];
3718
+ ++answerAllocation["total_user"];
3719
+ }
3720
+ let averageValue = null;
3721
+ if (answerAllocation["total_user"] !== undefined &&
3722
+ isNumber(answerAllocation["total_user"]) &&
3723
+ answerAllocation["total_value"] !== undefined &&
3724
+ isNumber(answerAllocation["total_value"])) {
3725
+ averageValue = Math.round((answerAllocation["total_value"] / answerAllocation["total_user"]) * 10) / 10;
3726
+ }
3727
+ if (this.elementAverageResult != null && averageValue !== null) {
3728
+ this.update(true, false);
3729
+ const positionDimension = this.env.document.documentElement.dir === "rtl" ? "right" : "left";
3730
+ const position = this.getPositionFromValue(averageValue) + this.handleDimension / 2;
3731
+ this.elementAverageResult.style[positionDimension] = position + "px";
3732
+ // this.elementAverageResult.style.display = 'block';
3733
+ if (withTooltip && this.elementAverageResultTooltipLabelView != null && this.element != null) {
3734
+ if (!this.elementAverageResultTooltip?.classList.contains("visible")) {
3735
+ this.elementAverageResultTooltip?.classList.add("visible");
3736
+ setTimeout(() => {
3737
+ if (this.elementAverageResultTooltip && this.elementAverageResultTooltip.classList) {
3738
+ this.elementAverageResultTooltip.classList.remove("visible");
3739
+ }
3740
+ }, 3000);
3741
+ }
3742
+ this.env.requestAnimationFrame(() => {
3743
+ var elementBox = this.element.getBoundingClientRect();
3744
+ var labelViewBox = this.elementAverageResultTooltipLabelView?.getBoundingClientRect();
3745
+ var offset = 0;
3746
+ // console.log({labelViewBox, elementBox})
3747
+ if (labelViewBox && labelViewBox.width !== 0) {
3748
+ if (labelViewBox.right > elementBox.right) {
3749
+ // get -x for translateX with offset to left
3750
+ offset = elementBox.right - labelViewBox.right;
3751
+ }
3752
+ else if (labelViewBox.left < elementBox.left) {
3753
+ // get +x for translateX with offset to right
3754
+ offset = elementBox.left - labelViewBox.left;
3755
+ }
3756
+ }
3757
+ if (offset !== 0) {
3758
+ this.elementAverageResultTooltipLabelView?.style.setProperty("transform", "translateX(" + offset + "px)");
3759
+ }
3760
+ });
3761
+ }
3762
+ }
3763
+ }
3764
+ init() {
3765
+ if (!this.maxHandlePos) {
3766
+ this.env.setTimeout(() => {
3767
+ this.update(true, false);
3768
+ }, 10);
3769
+ }
3770
+ else {
3771
+ this.update(true, false);
3772
+ }
3773
+ }
3774
+ update(updateAttributes, triggerSlide) {
3775
+ updateAttributes = updateAttributes || false;
3776
+ if (updateAttributes) {
3777
+ this.min = tryParseFloat(this.elementSlider.getAttribute("min"), 0);
3778
+ this.max = tryParseFloat(this.elementSlider.getAttribute("max"), 100);
3779
+ this.value = tryParseFloat(this.elementSlider.value, Math.round(this.min + (this.max - this.min) / 2));
3780
+ this.step = tryParseFloat(this.elementSlider.getAttribute("step"), 1);
3781
+ }
3782
+ this.handleDimension = getDimension(this.handle, ("offset" + ucfirst(this.DIMENSION)));
3783
+ this.rangeDimension = getDimension(this.range, ("offset" + ucfirst(this.DIMENSION)));
3784
+ this.maxHandlePos = this.rangeDimension - this.handleDimension;
3785
+ this.grabPos = this.handleDimension / 2;
3786
+ this.position = this.getPositionFromValue(this.value);
3787
+ if (updateAttributes) {
3788
+ // Snapping steps
3789
+ this.prevSnapValue = this.getValueFromPosition(this.cap(this.position, 0, this.maxHandlePos));
3790
+ }
3791
+ this.setPosition(this.position, triggerSlide);
3792
+ }
3793
+ handleDown(e) {
3794
+ if (this.isDone()) {
3795
+ return;
3796
+ }
3797
+ let rangeslider = e.target;
3798
+ if (!rangeslider.classList.contains("slider-view")) {
3799
+ rangeslider = rangeslider.closest(".slider-view");
3800
+ }
3801
+ if (!rangeslider) {
3802
+ return;
3803
+ }
3804
+ if (rangeslider.id !== this.id) {
3805
+ return;
3806
+ }
3807
+ e.preventDefault();
3808
+ this.isClickCapturedBySlider = true;
3809
+ if (!this.maxHandlePos) {
3810
+ this.update(true, false);
3811
+ }
3812
+ document.addEventListener("touchmove", this.handleMove);
3813
+ document.addEventListener("touchend", this.handleEnd);
3814
+ document.addEventListener("mousemove", this.handleMove);
3815
+ document.addEventListener("mouseup", this.handleEnd);
3816
+ // add active class because Firefox is ignoring
3817
+ // the handle:active pseudo selector because of `e.preventDefault();`
3818
+ this.range.classList.add(this.options.activeClass);
3819
+ // If we click on the handle don't set the new position
3820
+ if ((" " + e.target.className + " ").replace(/[\n\t]/g, " ").indexOf(this.options.handleClass) > -1) {
3821
+ return;
3822
+ }
3823
+ var pos = this.getRelativePosition(e), rangePos = this.range.getBoundingClientRect()[this.DIRECTION], handlePos = this.getPositionFromNode(this.handle) - rangePos, setPos = this.orientation === "vertical" ? this.maxHandlePos - (pos - this.grabPos) : pos - this.grabPos;
3824
+ this.setPosition(setPos);
3825
+ if (pos >= handlePos && pos < handlePos + this.handleDimension) {
3826
+ this.grabPos = pos - handlePos;
3827
+ }
3828
+ }
3829
+ handleMove(e) {
3830
+ e.preventDefault();
3831
+ var pos = this.getRelativePosition(e);
3832
+ var setPos = this.orientation === "vertical" ? this.maxHandlePos - (pos - this.grabPos) : pos - this.grabPos;
3833
+ this.setPosition(setPos);
3834
+ }
3835
+ handleEnd(e) {
3836
+ this.env.requestAnimationFrame(() => {
3837
+ this.isClickCapturedBySlider = false;
3838
+ });
3839
+ // e.preventDefault();
3840
+ document.removeEventListener("touchmove", this.handleMove);
3841
+ document.removeEventListener("touchend", this.handleEnd);
3842
+ document.removeEventListener("mousemove", this.handleMove);
3843
+ document.removeEventListener("mouseup", this.handleEnd);
3844
+ this.range.classList.remove(this.options.activeClass);
3845
+ this.element.classList.add("input-done");
3846
+ if (!this.hasSubmitButton) {
3847
+ this.completeWidget();
3848
+ }
3849
+ else {
3850
+ this.env.requestAnimationFrame(() => {
3851
+ if (this.submitButtonAnimatedView != null && this.submitButtonViewHeight != null) {
3852
+ this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
3853
+ }
3854
+ });
3855
+ }
3856
+ // Ok we're done fire the change event
3857
+ // this.$element.trigger('change', {origin: this.identifier});
3858
+ }
3859
+ cap = function (pos, min, max) {
3860
+ if (pos < min) {
3861
+ return min;
3862
+ }
3863
+ if (pos > max) {
3864
+ return max;
3865
+ }
3866
+ return pos;
3867
+ };
3868
+ setPosition(pos, triggerSlide) {
3869
+ var value, newPos;
3870
+ // Snapping steps
3871
+ value = this.getValueFromPosition(this.cap(pos, 0, this.maxHandlePos));
3872
+ newPos = this.getPositionFromValue(value);
3873
+ // Update ui
3874
+ var uiPos = newPos;
3875
+ // invert pos for rtl
3876
+ if (this.orientation === "horizontal" && this.layoutDirection === "rtl") {
3877
+ uiPos = this.maxHandlePos - uiPos;
3878
+ }
3879
+ // this.rangeDimension - slider width
3880
+ this.fill.style.transform = "translateX(" + (uiPos + this.grabPos - this.rangeDimension) + "px)";
3881
+ // this.fill.style[this.DIMENSION] = (uiPos + this.grabPos) + 'px';
3882
+ var percentage = this.getPercentageFromValue(value);
3883
+ // 1 + (scale - 1) * percentage
3884
+ this.handle.style.transform = "translateY(-50%) translateX(" + uiPos + "px) scale(calc(1 + (var(--scale-factor, 1) - 1) * " + percentage + "))";
3885
+ // this.handle.style[this.DIRECTION_STYLE] = uiPos + 'px';
3886
+ this.setValue(value);
3887
+ // Update globals
3888
+ this.position = newPos;
3889
+ this.value = value;
3890
+ if (this.snapPosition) {
3891
+ const stepItem = String(Math.round(this.value / this.step));
3892
+ this.fill.setAttribute("data-step-item", stepItem);
3893
+ if (this.value !== this.prevSnapValue) {
3894
+ this.prevSnapValue = this.value;
3895
+ try {
3896
+ this.sdkApi.vibrate(20);
3897
+ }
3898
+ catch (e) {
3899
+ console.error(e);
3900
+ }
3901
+ }
3902
+ }
3903
+ }
3904
+ // Returns element position relative to the parent
3905
+ getPositionFromNode(node) {
3906
+ var i = 0;
3907
+ while (node !== null) {
3908
+ i += node.offsetLeft;
3909
+ node = node.offsetParent;
3910
+ }
3911
+ return i;
3912
+ }
3913
+ getRelativePosition(e) {
3914
+ // Get the offset DIRECTION relative to the viewport
3915
+ const ucCoordinate = ucfirst(this.COORDINATE);
3916
+ const ucCoordinateClient = `client${ucCoordinate}`;
3917
+ const rangePos = this.range.getBoundingClientRect()[this.DIRECTION];
3918
+ let pageCoordinate = 0;
3919
+ if (typeof e[ucCoordinateClient] !== "undefined") {
3920
+ pageCoordinate = e[ucCoordinateClient];
3921
+ }
3922
+ else if (e.touches && e.touches[0] && typeof e.touches[0][ucCoordinateClient] !== "undefined") {
3923
+ pageCoordinate = e.touches[0][ucCoordinateClient];
3924
+ // @ts-ignore
3925
+ }
3926
+ else if (e.currentPoint && typeof e.currentPoint[this.COORDINATE] !== "undefined") {
3927
+ // @ts-ignore
3928
+ pageCoordinate = e.currentPoint[this.COORDINATE];
3929
+ }
3930
+ return pageCoordinate - rangePos;
3931
+ }
3932
+ getPercentageFromValue(value) {
3933
+ var percentage;
3934
+ percentage = (value - this.min) / (this.max - this.min);
3935
+ // invert pos for rtl
3936
+ if (this.orientation === "horizontal" && this.layoutDirection === "rtl") {
3937
+ percentage = 1 - percentage;
3938
+ }
3939
+ return percentage;
3940
+ }
3941
+ getPositionFromValue(value) {
3942
+ var percentage, pos;
3943
+ percentage = (value - this.min) / (this.max - this.min);
3944
+ // invert pos for rtl
3945
+ if (this.orientation === "horizontal" && this.layoutDirection === "rtl") {
3946
+ percentage = 1 - percentage;
3947
+ }
3948
+ pos = !Number.isNaN(percentage) ? percentage * this.maxHandlePos : 0;
3949
+ return pos;
3950
+ }
3951
+ getValueFromPosition(pos) {
3952
+ var percentage, value;
3953
+ percentage = pos / (this.maxHandlePos || 1);
3954
+ // invert pos for rtl
3955
+ if (this.orientation === "horizontal" && this.layoutDirection === "rtl") {
3956
+ percentage = 1 - percentage;
3957
+ }
3958
+ value = this.step * Math.round((percentage * (this.max - this.min)) / this.step) + this.min;
3959
+ return Number(value.toFixed(this.toFixed));
3960
+ }
3961
+ setValue(value) {
3962
+ if (value === this.value && this.elementSlider.value !== "") {
3963
+ return;
3964
+ }
3965
+ // Set the new value and fire the `input` event
3966
+ this.elementSlider.value = String(value);
3967
+ // .val(value)
3968
+ // .trigger('input', {origin: this.identifier});
3969
+ }
3970
+ destroy() {
3971
+ this.env.document.removeEventListener("touchstart", this.handleDown);
3972
+ this.env.document.removeEventListener("mousedown", this.handleDown);
3973
+ // off resize event
3974
+ // this.$window.off('.' + this.identifier);
3975
+ // this.$element
3976
+ // .off('.' + this.identifier)
3977
+ // .removeAttr('style')
3978
+ // .removeData('plugin_' + pluginName);
3979
+ }
3980
+ static api = {
3981
+ ...WidgetBase.api,
3982
+ initWidget: function (element, localData) {
3983
+ WidgetRangeSlider.initWidgets((element, options) => new WidgetRangeSlider(element, options), [element], localData);
3984
+ },
3985
+ click: function (element) {
3986
+ const widgetElement = element.closest(`.${WidgetRangeSlider.widgetClassName}`);
3987
+ if (widgetElement) {
3988
+ const widget = WidgetRangeSlider.getInstance(widgetElement);
3989
+ if (widget) {
3990
+ return widget.click();
3991
+ }
3992
+ }
3993
+ return true;
3994
+ },
3995
+ isClickCapturedBySlider: function (element) {
3996
+ const widgetElement = element.closest(`.${WidgetRangeSlider.widgetClassName}`);
3997
+ if (widgetElement) {
3998
+ const widget = WidgetRangeSlider.getInstance(widgetElement);
3999
+ if (widget) {
4000
+ return widget.getIsClickCapturedBySlider();
4001
+ }
4002
+ }
4003
+ return false;
4004
+ },
4005
+ };
4006
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
4007
+ }
4008
+
4009
+ class WidgetRate extends WidgetBase {
4010
+ static DEFAULTS = {
4011
+ slide: null,
4012
+ activateAfterCreate: false,
4013
+ create: false,
4014
+ localData: {},
4015
+ };
4016
+ static widgetClassName = "narrative-element-rate";
4017
+ elementRect;
4018
+ label;
4019
+ nativeDialogueWasOpened = false;
4020
+ stars;
4021
+ submitToStores;
4022
+ submitToStoresMin;
4023
+ submitToStoresMax;
4024
+ showDialogOnLowRate;
4025
+ showDialogueMin;
4026
+ showDialogueMax;
4027
+ selectedStar;
4028
+ answerSelectDuration;
4029
+ constructor(element, options) {
4030
+ super(element, options);
4031
+ this.elementRect = this.element.getBoundingClientRect();
4032
+ this.label = this.element.querySelector(".label-view .label");
4033
+ this.stars = slice.call(this.element.querySelectorAll(".input-view"));
4034
+ this.submitToStores = Boolean(getValueOrDefault(getTagDataAsNumber(this.element, "submitToStores"), 0));
4035
+ this.submitToStoresMin = getValueOrDefault(getTagDataAsNumber(this.element, "submitToStoresMin"), 4);
4036
+ this.submitToStoresMax = getValueOrDefault(getTagDataAsNumber(this.element, "submitToStoresMax"), 5);
4037
+ this.showDialogOnLowRate = Boolean(getValueOrDefault(getTagDataAsNumber(this.element, "showDialogOnLowRate"), 0));
4038
+ this.showDialogueMin = getValueOrDefault(getTagDataAsNumber(this.element, "showDialogueMin"), 1);
4039
+ this.showDialogueMax = getValueOrDefault(getTagDataAsNumber(this.element, "showDialogueMax"), 3);
4040
+ this.refreshUserData(this.options.localData);
4041
+ }
4042
+ refreshUserData(localData) {
4043
+ this.savedData = this.sdkApi.getStoryServerData(this.storyId);
4044
+ this.localData = extend({}, this.savedData ?? {}, localData);
4045
+ this.selectedStar = undefined;
4046
+ if (this.localData) {
4047
+ if (this.localData["_r_g_" + this.elementId + "_ss"] !== undefined) {
4048
+ this._selectStar(this.localData["_r_g_" + this.elementId + "_ss"], true);
4049
+ }
4050
+ else {
4051
+ this._clearSelectedStar();
4052
+ }
4053
+ }
4054
+ this.firstOpenTime = new Date().getTime();
4055
+ this.answerSelectDuration = 0;
4056
+ this.nativeDialogueWasOpened = false;
4057
+ }
4058
+ _statEventRateUsAnswer(answerText) {
4059
+ try {
4060
+ var labelText = this.label?.textContent ?? "";
4061
+ if (this.selectedStar != null) {
4062
+ var selectedAnswer = this.selectedStar + 1;
4063
+ this.sendStatisticEventToApp("w-rate-answer", {
4064
+ i: this.storyId,
4065
+ si: this.slideIndex,
4066
+ wi: this.elementId,
4067
+ wl: labelText,
4068
+ wa: selectedAnswer,
4069
+ wv: answerText,
4070
+ d: this.answerSelectDuration,
4071
+ }, {
4072
+ story_id: this.storyId,
4073
+ slide_index: this.slideIndex,
4074
+ widget_id: this.elementId,
4075
+ widget_label: labelText,
4076
+ widget_answer: selectedAnswer,
4077
+ widget_value: answerText,
4078
+ duration_ms: this.answerSelectDuration,
4079
+ });
4080
+ }
4081
+ }
4082
+ catch (error) {
4083
+ console.error(error);
4084
+ }
4085
+ }
4086
+ _selectStar(value, runTimer) {
4087
+ var list = [];
4088
+ var i;
4089
+ for (i = 0; i < this.stars.length; i++) {
4090
+ list[i] = this.stars[i];
4091
+ }
4092
+ forEach(list, (element, idx) => {
4093
+ const key = idx;
4094
+ if (key <= value) {
4095
+ element.classList.add("fill");
4096
+ }
4097
+ });
4098
+ if (list[value]) {
4099
+ list[value].classList.add("selected");
4100
+ }
4101
+ this.selectedStar = value;
4102
+ this.localData["_r_g_" + this.elementId + "_ss"] = value;
4103
+ this.element.classList.add("done");
4104
+ if (this.disableTimer && runTimer) {
4105
+ this.showNextSlide();
4106
+ }
4107
+ }
4108
+ _clearSelectedStar() {
4109
+ forEach(this.stars, function (element) {
4110
+ element.classList.remove("fill");
4111
+ element.classList.remove("selected");
4112
+ });
4113
+ this.element.classList.remove("done");
4114
+ }
4115
+ selectStar(starElement) {
4116
+ if (this.selectedStar !== undefined) {
4117
+ return true;
4118
+ }
4119
+ var index = this.stars.indexOf(starElement);
4120
+ this.stars.length;
4121
+ var value = index;
4122
+ // if (this.layoutDirection === 'rtl') {
4123
+ // value = length - index + 1;
4124
+ // }
4125
+ this.nativeDialogueWasOpened = false;
4126
+ if (value !== -1) {
4127
+ this.answerSelectDuration = new Date().getTime() - this.firstOpenTime;
4128
+ // 1-3 stars (default)
4129
+ if (value + 1 >= this.showDialogueMin && value + 1 <= this.showDialogueMax) {
4130
+ this.selectedStar = value;
4131
+ this._selectStar(this.selectedStar, false);
4132
+ if (this.showDialogOnLowRate) {
4133
+ if (this.sdkApi.isAndroid) {
4134
+ this.slide.classList.add("blured");
4135
+ }
4136
+ this.slide.classList.add("data-input-editing");
4137
+ const dataString = this.element.dataset["clientdialogwidgetconfig"];
4138
+ if (this.sdkApi.isExistsShowStoryTextInput && dataString) {
4139
+ const data = JSON.parse(dataString);
4140
+ data.size = getElementBounding(this.env, this.elementRect);
4141
+ if (!this.disableTimer) {
4142
+ this.sdkApi.pauseUI();
4143
+ }
4144
+ this.nativeDialogueWasOpened = true;
4145
+ try {
4146
+ data.text.value = data.text.value.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
4147
+ data.input.text.placeholder = data.input.text.placeholder.replaceAll("\\n", "\n").replaceAll("\\r", "\r").replaceAll("\\t", "\t");
4148
+ data.configV2.main.question.text.value = data.configV2.main.question.text.value
4149
+ .replaceAll("\\n", "\n")
4150
+ .replaceAll("\\r", "\r")
4151
+ .replaceAll("\\t", "\t");
4152
+ data.configV2.main.input.text.placeholder = data.configV2.main.input.text.placeholder
4153
+ .replaceAll("\\n", "\n")
4154
+ .replaceAll("\\r", "\r")
4155
+ .replaceAll("\\t", "\t");
4156
+ }
4157
+ catch (e) {
4158
+ console.error(e);
4159
+ }
4160
+ this.sdkApi.showStoryTextInput(this.id, data);
4161
+ }
4162
+ }
4163
+ else {
4164
+ this.completeWidget();
4165
+ this._statEventRateUsAnswer("");
4166
+ }
4167
+ return false;
4168
+ }
4169
+ else if (value + 1 >= this.submitToStoresMin && value + 1 <= this.submitToStoresMax) {
4170
+ var target = null;
4171
+ if (this.sdkApi.isAndroid) {
4172
+ target = getTagData(this.element, "androidLink");
4173
+ }
4174
+ else if (this.sdkApi.isIOS) {
4175
+ target = getTagData(this.element, "appleLink");
4176
+ }
4177
+ this._selectStar(value, false);
4178
+ this.completeWidget();
4179
+ this._statEventRateUsAnswer("");
4180
+ if (this.submitToStores && target) {
4181
+ this.sdkApi.openUrl(target);
4182
+ }
4183
+ }
4184
+ else {
4185
+ this._selectStar(value, false);
4186
+ this.completeWidget();
4187
+ this._statEventRateUsAnswer("");
4188
+ }
4189
+ }
4190
+ return false;
4191
+ }
4192
+ setUserText(text) {
4193
+ this.slide.classList.remove("data-input-editing");
4194
+ this.slide.classList.remove("blured");
4195
+ if (this.selectedStar != null) {
4196
+ this._selectStar(this.selectedStar, true);
4197
+ }
4198
+ if (!this.disableTimer && this.nativeDialogueWasOpened) {
4199
+ this.sdkApi.resumeUI();
4200
+ this.nativeDialogueWasOpened = false;
4201
+ }
4202
+ this.localData["_r_g_" + this.elementId + "_user_response"] = text;
4203
+ this.completeWidget();
4204
+ this._statEventRateUsAnswer(text);
4205
+ }
4206
+ completeWidget() {
4207
+ if (this.widgetDone) {
4208
+ this.widgetDone.classList.add("active", "opacity-active");
4209
+ setTimeout(() => {
4210
+ this.widgetDone?.classList.remove("active");
4211
+ setTimeout(() => {
4212
+ this.widgetDone?.classList.remove("opacity-active");
4213
+ }, 250);
4214
+ }, 2000);
4215
+ }
4216
+ this.localData["_r_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
4217
+ // ответ на вопрос
4218
+ this.localData["_&ts_r_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
4219
+ this.setLocalData(this.localData, true);
4220
+ }
4221
+ isDone() {
4222
+ return this.localData["_r_g_" + this.elementId + "_done_at"] !== undefined;
4223
+ }
4224
+ slideRateIsDone() {
4225
+ return this.localData["_r_g_" + this.elementId + "_sa"] !== undefined;
4226
+ }
4227
+ static api = {
4228
+ ...WidgetBase.api,
4229
+ initWidget: function (nodeList, localData) {
4230
+ WidgetRate.initWidgets((element, options) => new WidgetRate(element, options), slice.call(nodeList), localData);
4231
+ },
4232
+ select: function (element) {
4233
+ const widgetElement = element.closest(`.${WidgetRate.widgetClassName}`);
4234
+ if (widgetElement) {
4235
+ const widget = WidgetRate.getInstance(widgetElement);
4236
+ if (widget) {
4237
+ return widget.selectStar(element);
4238
+ }
4239
+ }
4240
+ return false;
4241
+ },
4242
+ slidePollIsDone: function (element) {
4243
+ const widget = WidgetRate.getInstance(element);
4244
+ if (widget) {
4245
+ return widget.slideRateIsDone();
4246
+ }
4247
+ return true;
4248
+ },
4249
+ setUserData: function (id, text) {
4250
+ WidgetRate.getInstanceById(id)?.setUserText(text);
4251
+ },
4252
+ };
4253
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
4254
+ }
4255
+
4256
+ class WidgetShare extends WidgetBase {
4257
+ static DEFAULTS = {
4258
+ slide: null,
4259
+ activateAfterCreate: false,
4260
+ create: false,
4261
+ localData: {},
4262
+ layers: [],
4263
+ };
4264
+ static widgetClassName = "narrative-element-share";
4265
+ layers;
4266
+ shareType;
4267
+ shareTarget;
4268
+ withLayer;
4269
+ btnDisabled;
4270
+ constructor(element, options) {
4271
+ super(element, options);
4272
+ this.shareType = getTagData(this.element, "shareType");
4273
+ this.shareTarget = getTagData(this.element, "shareTarget");
4274
+ this.layers = this.options.layers;
4275
+ this.withLayer = Boolean(getValueOrDefault(getTagDataAsNumber(this.element, "withLayer"), 0));
4276
+ if (this.withLayer) {
4277
+ if (this.isDone()) {
4278
+ this._showLayout(this.layers, 1);
4279
+ }
4280
+ else {
4281
+ this._showLayout(this.layers, 0);
4282
+ }
4283
+ }
4284
+ this.btnDisabled = false;
4285
+ // this.refreshUserData(this.options.localData);
4286
+ }
4287
+ refreshUserData(localData) { }
4288
+ _statEventShare(result, via) {
4289
+ try {
4290
+ var buttonText = this.element.textContent ?? "";
4291
+ this.sendStatisticEventToApp("w-share", {
4292
+ i: this.storyId,
4293
+ si: this.slideIndex,
4294
+ wi: this.elementId,
4295
+ wl: buttonText,
4296
+ wt: this.shareTarget ?? "",
4297
+ wa: result ? 1 : 0,
4298
+ wal: via ?? "",
4299
+ }, {
4300
+ story_id: this.storyId,
4301
+ slide_index: this.slideIndex,
4302
+ widget_id: this.elementId,
4303
+ widget_label: buttonText,
4304
+ widget_value: this.shareTarget ?? "",
4305
+ widget_answer: result ? 1 : 0,
4306
+ widget_answer_label: via ?? "",
4307
+ });
4308
+ }
4309
+ catch (error) {
4310
+ console.error(error);
4311
+ }
4312
+ }
4313
+ share() {
4314
+ if (!this.btnDisabled) {
4315
+ if (this.sdkApi.isExistsShare) {
4316
+ if (this.sdkApi.sdkCanSendShareComplete) {
4317
+ this.btnDisabled = true;
4318
+ }
4319
+ if (this.shareType === "url" || this.shareType === "story") {
4320
+ this.sdkApi.share(this.id, {
4321
+ url: this.shareTarget, // sdk old versions
4322
+ text: this.shareTarget,
4323
+ title: null,
4324
+ files: null,
4325
+ });
4326
+ }
4327
+ else if (this.shareType === "slide") {
4328
+ this.sdkApi.shareSlideScreenshot(this.id, "[data-element-id='" + this.elementId + "']");
4329
+ }
4330
+ }
4331
+ }
4332
+ }
4333
+ _complete(isSuccess) {
4334
+ if (!this.localData["_s_" + this.elementId + "_ts"] && isSuccess) {
4335
+ this.localData["_s_" + this.elementId + "_ts"] = Math.round(new Date().getTime() / 1000);
4336
+ // `answer_at` time
4337
+ this.localData["_&ts_s_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
4338
+ this.setLocalData(this.localData, true);
4339
+ }
4340
+ this._statEventShare(isSuccess, null);
4341
+ if (isSuccess && this.withLayer) {
4342
+ this._showLayout(this.layers, 1, true);
4343
+ }
4344
+ this.btnDisabled = false;
4345
+ }
4346
+ isDone() {
4347
+ return Boolean(this.localData["_s_" + this.elementId + "_ts"]);
4348
+ }
4349
+ static api = {
4350
+ ...WidgetBase.api,
4351
+ // signature variants
4352
+ // (widget, layers, undefined) - modern web sdk
4353
+ // (widget, undefined, layers) - old web sdk and rn
4354
+ // (widget, layers, localData) - native sdk
4355
+ initWidget: function (nodeList, layers, localData) {
4356
+ if (layers === undefined && localData !== undefined) {
4357
+ // @ts-ignore
4358
+ layers = localData;
4359
+ localData = undefined;
4360
+ }
4361
+ WidgetShare.initWidgets((element, options) => new WidgetShare(element, { ...options, layers }), slice.call(nodeList), localData);
4362
+ },
4363
+ click: function (element) {
4364
+ const widgetElement = element.closest(`.${WidgetShare.widgetClassName}`);
4365
+ if (widgetElement) {
4366
+ const widget = WidgetShare.getInstance(widgetElement);
4367
+ if (widget) {
4368
+ widget.share();
4369
+ }
4370
+ }
4371
+ },
4372
+ complete: function (id, isSuccess) {
4373
+ WidgetShare.getInstanceById(id)?._complete(isSuccess);
4374
+ },
4375
+ };
4376
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
4377
+ }
4378
+
4379
+ class WidgetTest extends WidgetBase {
4380
+ static DEFAULTS = {
4381
+ slide: null,
4382
+ activateAfterCreate: false,
4383
+ create: false,
4384
+ localData: {},
4385
+ };
4386
+ static widgetClassName = "narrative-element-test";
4387
+ label;
4388
+ variants;
4389
+ testCount;
4390
+ selectedAnswer;
4391
+ withTimeToAnswer;
4392
+ answerTimeout;
4393
+ tick;
4394
+ cancelTick;
4395
+ animationFrameId;
4396
+ startTimerAt;
4397
+ timeLeft;
4398
+ timeLeftDefault;
4399
+ timeline;
4400
+ constructor(element, options) {
4401
+ super(element, options);
4402
+ this.label = this.element.querySelector(".label-view .label");
4403
+ this.variants = slice.call(this.element.querySelectorAll(".variants-box .variant-view"));
4404
+ this.testCount = getValueOrException(getTagDataAsNumber(this.slide, "testCount"), "Empty testCount");
4405
+ this.withTimeToAnswer = Boolean(getValueOrDefault(getTagDataAsNumber(this.element, "withTimeToAnswer"), 0));
4406
+ this.answerTimeout = getValueOrDefault(getTagDataAsNumber(this.element, "answerTimeout"), 0);
4407
+ this.selectedAnswer = undefined;
4408
+ if (this.localData) {
4409
+ if (this.localData["_t_g_" + this.elementId + "_sa"] !== undefined) {
4410
+ this._selectAnswer(this.localData["_t_g_" + this.elementId + "_sa"]);
4411
+ this.setLocalData(this.localData, false);
4412
+ }
4413
+ if (this.localData["_t_fo_at"] === undefined) {
4414
+ this.localData["_t_fo_at"] = Math.round(new Date().getTime() / 1000);
4415
+ this.setLocalData(this.localData, false);
4416
+ }
4417
+ }
4418
+ this.firstOpenTime = new Date().getTime();
4419
+ this.tick = () => {
4420
+ this.animationFrameId = this.env.requestAnimationFrame(() => {
4421
+ this.tick();
4422
+ });
4423
+ // update timer
4424
+ // update timeline position
4425
+ if (this.startTimerAt) {
4426
+ // if (this.state.timeLeft - this.timeLeft >= 950) {
4427
+ // this.setState({timeLeft: this.timeLeft});
4428
+ // }
4429
+ var timeNow = new Date().getTime();
4430
+ this.timeLeft -= timeNow - this.startTimerAt;
4431
+ this.startTimerAt = timeNow;
4432
+ if (this.timeLeft <= 0) {
4433
+ this.timeLeft = 0;
4434
+ this.cancelTick();
4435
+ this.doneWithoutAnswer();
4436
+ }
4437
+ if (this.timeline) {
4438
+ this.timeline.style.transform = "translateX(" + String((1 - this.timeLeft / this.timeLeftDefault) * 100) + "%)";
4439
+ }
4440
+ }
4441
+ };
4442
+ this.cancelTick = () => {
4443
+ if (this.animationFrameId != null) {
4444
+ this.env.cancelAnimationFrame(this.animationFrameId);
4445
+ }
4446
+ };
4447
+ if (this.slideTestWithTimer()) {
4448
+ this.timeline = this.element.querySelector(".timeline");
4449
+ if (this.selectedAnswer === undefined) {
4450
+ // find timer element
4451
+ // start raf
4452
+ // pause raf on pauseUI (actually don`t need)
4453
+ this.timeLeftDefault = (this.answerTimeout ? this.answerTimeout : 0) * 1000;
4454
+ this.timeLeft = this.timeLeftDefault;
4455
+ this.animationFrameId = null;
4456
+ this.startTimerAt = new Date().getTime();
4457
+ this.tick();
4458
+ // set answer - unanswered (for close and run again)
4459
+ this.localData["_t_g_" + this.elementId + "_sa"] = -1;
4460
+ this.setLocalData(this.localData, true);
4461
+ }
4462
+ else {
4463
+ // animate 100%
4464
+ if (this.selectedAnswer === -1) {
4465
+ if (this.timeline) {
4466
+ this.timeline.style.transform = "translateX(100%)";
4467
+ }
4468
+ }
4469
+ }
4470
+ }
4471
+ // this.refreshUserData(this.options.localData);
4472
+ }
4473
+ refreshUserData(localData) { }
4474
+ _statEventVoteAnswer(answerScore) {
4475
+ try {
4476
+ if (this.selectedAnswer != null) {
4477
+ const labelText = this.label?.textContent ?? "";
4478
+ var answerText = "";
4479
+ if (this.variants[this.selectedAnswer]) {
4480
+ var answerLabel = this.variants[this.selectedAnswer].querySelector(".label");
4481
+ if (answerLabel != null) {
4482
+ answerText = answerLabel.textContent ?? "";
4483
+ }
4484
+ }
4485
+ var duration = new Date().getTime() - this.firstOpenTime;
4486
+ this.sendStatisticEventToApp("w-test-answer", {
4487
+ i: this.storyId,
4488
+ si: this.slideIndex,
4489
+ wi: this.elementId,
4490
+ wl: labelText,
4491
+ wa: this.selectedAnswer,
4492
+ wal: answerText,
4493
+ was: answerScore,
4494
+ d: duration,
4495
+ }, {
4496
+ story_id: this.storyId,
4497
+ slide_index: this.slideIndex,
4498
+ widget_id: this.elementId,
4499
+ widget_label: labelText,
4500
+ widget_answer: this.selectedAnswer,
4501
+ widget_answer_label: answerText,
4502
+ widget_answer_score: answerScore,
4503
+ duration_ms: duration,
4504
+ });
4505
+ }
4506
+ }
4507
+ catch (error) {
4508
+ console.error(error);
4509
+ }
4510
+ }
4511
+ _selectAnswer(index) {
4512
+ if (this.variants[index]) {
4513
+ this.variants[index].classList.add("selected");
4514
+ }
4515
+ this.selectedAnswer = index;
4516
+ this.localData["_t_g_" + this.elementId + "_sa"] = index;
4517
+ this.element.classList.add("done");
4518
+ this.env.requestAnimationFrame(() => {
4519
+ if (this.submitButtonAnimatedView != null && this.submitButtonViewHeight != null) {
4520
+ this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
4521
+ }
4522
+ });
4523
+ if (this.disableTimer) {
4524
+ this.showNextSlide();
4525
+ }
4526
+ }
4527
+ selectAnswer(answer) {
4528
+ if (this.selectedAnswer !== undefined) {
4529
+ return true;
4530
+ }
4531
+ var index = this.variants.indexOf(answer);
4532
+ if (index !== -1) {
4533
+ var answerScore = getValueOrDefault(getTagDataAsNumber(this.variants[index], "score"), 0);
4534
+ this._completeWidget(index, answerScore);
4535
+ }
4536
+ if (Boolean(this.withTimeToAnswer && this.answerTimeout)) {
4537
+ this.cancelTick();
4538
+ }
4539
+ return false;
4540
+ }
4541
+ doneWithoutAnswer() {
4542
+ if (this.selectedAnswer !== undefined) {
4543
+ return;
4544
+ }
4545
+ var index = -1, answerScore = 0;
4546
+ this._completeWidget(index, answerScore);
4547
+ }
4548
+ // complete answer select and save local data + stat event
4549
+ _completeWidget(index, answerScore) {
4550
+ this._selectAnswer(index);
4551
+ this.localData["t_score"] = (this.localData["t_score"] === undefined ? 0 : this.localData["t_score"]) + answerScore;
4552
+ var answeredQuestion = 0;
4553
+ for (var key in this.localData) {
4554
+ if (this.localData.hasOwnProperty(key)) {
4555
+ if (/^_t_g_[A-z0-9-_]+_sa$/.test(key)) {
4556
+ answeredQuestion++;
4557
+ }
4558
+ }
4559
+ }
4560
+ if (this.localData["_t_fa_at"] === undefined) {
4561
+ this.localData["_t_fa_at"] = Math.round(new Date().getTime() / 1000);
4562
+ }
4563
+ if (answeredQuestion === this.testCount) {
4564
+ this.localData["_t_done_at"] = Math.round(new Date().getTime() / 1000);
4565
+ }
4566
+ // answer on question
4567
+ this.localData["_&ts_t_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
4568
+ if (this.widgetDone) {
4569
+ this.widgetDone.classList.add("active", "opacity-active");
4570
+ setTimeout(() => {
4571
+ this.widgetDone?.classList.remove("active");
4572
+ setTimeout(() => {
4573
+ this.widgetDone?.classList.remove("opacity-active");
4574
+ }, 250);
4575
+ }, 2000);
4576
+ }
4577
+ this.setLocalData(this.localData, true);
4578
+ this._statEventVoteAnswer(answerScore);
4579
+ }
4580
+ isDone() {
4581
+ return this.localData["_t_done_at"] !== undefined && this.selectedAnswer !== undefined;
4582
+ }
4583
+ slideTestIsDone() {
4584
+ return this.localData["_t_g_" + this.elementId + "_sa"] !== undefined && this.selectedAnswer !== undefined;
4585
+ }
4586
+ slideTestWithTimer() {
4587
+ return Boolean(this.withTimeToAnswer && this.answerTimeout);
4588
+ }
4589
+ static api = {
4590
+ ...WidgetBase.api,
4591
+ initWidget: function (element, localData) {
4592
+ WidgetTest.initWidgets((element, options) => new WidgetTest(element, options), [element], localData);
4593
+ },
4594
+ /**
4595
+ * click on quiz answer
4596
+ */
4597
+ select: function (element) {
4598
+ const widgetElement = element.closest(`.${WidgetTest.widgetClassName}`);
4599
+ if (widgetElement) {
4600
+ const widget = WidgetTest.getInstance(widgetElement);
4601
+ if (widget) {
4602
+ return widget.selectAnswer(element);
4603
+ }
4604
+ }
4605
+ return false;
4606
+ },
4607
+ slideTestIsDone: function (element) {
4608
+ const widget = WidgetTest.getInstance(element);
4609
+ if (widget) {
4610
+ return widget.slideTestIsDone();
4611
+ }
4612
+ return true;
4613
+ },
4614
+ slideTestWithTimer: function (element) {
4615
+ const widget = WidgetTest.getInstance(element);
4616
+ if (widget) {
4617
+ return widget.slideTestWithTimer();
4618
+ }
4619
+ return true;
4620
+ },
4621
+ };
4622
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
4623
+ }
4624
+
4625
+ class WidgetVote extends WidgetBase {
4626
+ static DEFAULTS = {
4627
+ slide: null,
4628
+ activateAfterCreate: false,
4629
+ create: false,
4630
+ localData: {},
4631
+ };
4632
+ static widgetClassName = "narrative-element-vote";
4633
+ question = null;
4634
+ answers = null;
4635
+ questionCount = null;
4636
+ selectedAnswer = undefined;
4637
+ label;
4638
+ variants;
4639
+ variantsTexts;
4640
+ selectedVariant;
4641
+ voteAllocation;
4642
+ hideClientTotalResult;
4643
+ /**
4644
+ * @throws Error
4645
+ * @param element
4646
+ * @param options
4647
+ */
4648
+ constructor(element, options) {
4649
+ super(element, options);
4650
+ this.voteAllocation = getTagData(this.slide, "voteAllocation");
4651
+ this.label = this.element.querySelector(".label-view .label");
4652
+ this.variants = slice.call(this.element.querySelectorAll(".variants-box .variant-view-group"));
4653
+ this.variantsTexts = [];
4654
+ forEach(this.variants, (element, index) => {
4655
+ const variantView = element.querySelector(".variant-view .label");
4656
+ if (variantView) {
4657
+ this.variantsTexts.push(variantView.textContent ?? "");
4658
+ }
4659
+ });
4660
+ this.hideClientTotalResult = getValueOrDefault(Boolean(getTagDataAsNumber(this.element, "hideClientTotalResult")), false);
4661
+ this.selectedVariant = undefined;
4662
+ if (this.localData) {
4663
+ if (this.localData["_v_g_" + this.elementId + "_sa"] !== undefined) {
4664
+ this._selectVariant(this.localData["_v_g_" + this.elementId + "_sa"], true);
4665
+ }
4666
+ }
4667
+ this.firstOpenTime = new Date().getTime();
4668
+ // this.refreshUserData(this.options.localData);
4669
+ }
4670
+ refreshUserData(localData) { }
4671
+ _statEventVoteVariant() {
4672
+ try {
4673
+ if (this.selectedVariant != null) {
4674
+ var labelText = this.label?.textContent ?? "";
4675
+ var variantText = this.variantsTexts[this.selectedVariant] ? this.variantsTexts[this.selectedVariant] : "";
4676
+ var duration = new Date().getTime() - this.firstOpenTime;
4677
+ this.sendStatisticEventToApp("w-vote-answer", {
4678
+ i: this.storyId,
4679
+ si: this.slideIndex,
4680
+ wi: this.elementId,
4681
+ wl: labelText,
4682
+ wa: this.selectedVariant,
4683
+ wv: variantText,
4684
+ d: duration,
4685
+ }, {
4686
+ story_id: this.storyId,
4687
+ slide_index: this.slideIndex,
4688
+ widget_id: this.elementId,
4689
+ widget_label: labelText,
4690
+ widget_answer: this.selectedVariant,
4691
+ widget_value: variantText,
4692
+ duration_ms: duration,
4693
+ });
4694
+ }
4695
+ }
4696
+ catch (error) {
4697
+ console.error(error);
4698
+ }
4699
+ }
4700
+ _selectVariant(index, filled = false) {
4701
+ if (this.variants[index]) {
4702
+ this.variants[index].classList.add("selected");
4703
+ }
4704
+ this.selectedVariant = index;
4705
+ this.localData["_v_g_" + this.elementId + "_sa"] = index;
4706
+ this.element.classList.add("done");
4707
+ if (filled) {
4708
+ this.element.classList.add("filled");
4709
+ }
4710
+ if (this.hideClientTotalResult) {
4711
+ const cb = () => {
4712
+ if (this.variants[index]) {
4713
+ this.variants[index].style.setProperty("--selected-variant-view-clip-area", String(0));
4714
+ }
4715
+ };
4716
+ if (filled) {
4717
+ cb();
4718
+ }
4719
+ else {
4720
+ this.env.requestAnimationFrame(cb);
4721
+ }
4722
+ }
4723
+ else {
4724
+ this.displayPercents(index, filled);
4725
+ }
4726
+ this.env.requestAnimationFrame(() => {
4727
+ if (this.submitButtonAnimatedView != null && this.submitButtonViewHeight != null) {
4728
+ this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
4729
+ }
4730
+ });
4731
+ if (this.disableTimer) {
4732
+ this.showNextSlide();
4733
+ }
4734
+ }
4735
+ selectVariant(variant) {
4736
+ if (this.selectedVariant !== undefined) {
4737
+ return true;
4738
+ }
4739
+ var selectedVariantIndex = this.variants.indexOf(variant);
4740
+ if (selectedVariantIndex !== -1) {
4741
+ this._selectVariant(selectedVariantIndex);
4742
+ this.localData["_v_g_" + this.elementId + "_done_at"] = Math.round(new Date().getTime() / 1000);
4743
+ // ответ на вопрос
4744
+ this.localData["_&ts_v_g_" + this.elementId + "_a_at"] = Math.round(new Date().getTime() / 1000);
4745
+ if (this.widgetDone) {
4746
+ this.widgetDone.classList.add("active", "opacity-active");
4747
+ setTimeout(() => {
4748
+ this.widgetDone?.classList.remove("active");
4749
+ setTimeout(() => {
4750
+ this.widgetDone?.classList.remove("opacity-active");
4751
+ }, 250);
4752
+ }, 2000);
4753
+ }
4754
+ this.setLocalData(this.localData, true);
4755
+ this._statEventVoteVariant();
4756
+ }
4757
+ return false;
4758
+ }
4759
+ displayPercents(selectedVariantIndex, filled = false) {
4760
+ // voteAllocation[0] - variant total count allocation
4761
+ // voteAllocation[1]
4762
+ // ...
4763
+ // voteAllocation[7]
4764
+ let voteAllocation = [];
4765
+ let voteAllocationTs = undefined;
4766
+ const sharedData = this.sdkApi.getWidgetsSharedData(this.storyId, "vote" /* Widgets.Vote */);
4767
+ if (sharedData && sharedData[this.elementId] != null && (isObject(sharedData[this.elementId]) || isArray(sharedData[this.elementId]))) {
4768
+ voteAllocation = sharedData[this.elementId];
4769
+ if (isObject(sharedData[this.elementId])) {
4770
+ voteAllocation = slice.call(Object.values(sharedData[this.elementId]));
4771
+ }
4772
+ voteAllocationTs = sharedData.ts;
4773
+ }
4774
+ var voteDoneAt = this.localData["_v_g_" + this.elementId + "_done_at"];
4775
+ if (voteAllocationTs === undefined || voteDoneAt === undefined || voteDoneAt > voteAllocationTs) {
4776
+ forEach(this.variants, function (element, index) {
4777
+ const key = index;
4778
+ if (voteAllocation[key] === undefined || !isNumber(voteAllocation[key])) {
4779
+ voteAllocation[key] = 0;
4780
+ }
4781
+ if (selectedVariantIndex === key) {
4782
+ ++voteAllocation[key];
4783
+ }
4784
+ });
4785
+ }
4786
+ // calc percents
4787
+ var percents = [], total = 0;
4788
+ forEach(this.variants, (element, index) => {
4789
+ const key = index;
4790
+ if (voteAllocation[key] !== undefined) {
4791
+ percents[key] = isNumber(voteAllocation[key]) ? voteAllocation[key] : parseInt(String(voteAllocation[key]));
4792
+ if (!isNumber(percents[key]) || isNaN(percents[key])) {
4793
+ percents[key] = 0;
4794
+ }
4795
+ }
4796
+ else {
4797
+ percents[key] = 0;
4798
+ }
4799
+ total += percents[key];
4800
+ });
4801
+ for (let i = 0; i < percents.length; ++i) {
4802
+ if (total !== 0) {
4803
+ percents[i] = Math.round((percents[i] / total) * 100 * 10) / 10;
4804
+ if (percents[i] > 100) {
4805
+ percents[i] = 100;
4806
+ }
4807
+ // percents[i] += '%';
4808
+ }
4809
+ }
4810
+ var self = this;
4811
+ forEach(this.variants, (element, index) => {
4812
+ const key = index;
4813
+ var percentLabels = slice.call(element.querySelectorAll(".percent-label"));
4814
+ forEach(percentLabels, label => {
4815
+ if (percents[key] != null) {
4816
+ label.textContent = percents[key] + "%";
4817
+ }
4818
+ });
4819
+ element.classList.add("selected");
4820
+ });
4821
+ var cb = function () {
4822
+ forEach(self.variants, function (element, index) {
4823
+ const key = index;
4824
+ if (percents[key] != null) {
4825
+ element.style.setProperty("--selected-variant-view-clip-area", String(100 - percents[key]));
4826
+ }
4827
+ });
4828
+ };
4829
+ if (filled) {
4830
+ cb();
4831
+ }
4832
+ else {
4833
+ this.env.requestAnimationFrame(cb);
4834
+ }
4835
+ }
4836
+ isDone() {
4837
+ return this.localData["_v_g_" + this.elementId + "_done_at"] !== undefined;
4838
+ }
4839
+ slideVoteIsDone() {
4840
+ return this.localData["_v_g_" + this.elementId + "_sa"] !== undefined;
4841
+ }
4842
+ static api = {
4843
+ ...WidgetBase.api,
4844
+ // fix for WidgetVote on every layer of multilayers story
4845
+ fallbackInitOnMultiSlide: function (element, localData) {
4846
+ if (element.dataset.fallbackInitOnMultiSlide) {
4847
+ return;
4848
+ }
4849
+ var multiSlide = element.closest(".narrative-multi-slide");
4850
+ if (multiSlide != null) {
4851
+ var container = multiSlide.parentElement;
4852
+ var widgetElements = container?.querySelectorAll(`.${WidgetVote.widgetClassName}`);
4853
+ if (widgetElements != null) {
4854
+ for (var i = 0; i < widgetElements.length; ++i) {
4855
+ var widgetElement = widgetElements[i];
4856
+ const widget = WidgetVote.getInstance(widgetElement);
4857
+ if (!widget) {
4858
+ WidgetVote.initWidgets((element, options) => new WidgetVote(element, options), [widgetElement], localData);
4859
+ }
4860
+ }
4861
+ }
4862
+ }
4863
+ element.dataset.fallbackInitOnMultiSlide = "1";
4864
+ },
4865
+ initWidget: function (element, localData) {
4866
+ WidgetVote.initWidgets((element, options) => new WidgetVote(element, options), [element], localData).then(localData => {
4867
+ WidgetVote.api.fallbackInitOnMultiSlide(element, localData);
4868
+ });
4869
+ },
4870
+ select: function (element) {
4871
+ const widgetElement = element.closest(`.${WidgetVote.widgetClassName}`);
4872
+ if (widgetElement) {
4873
+ const widget = WidgetVote.getInstance(widgetElement);
4874
+ if (widget) {
4875
+ return widget.selectVariant(element);
4876
+ }
4877
+ }
4878
+ return false;
4879
+ },
4880
+ slideVoteIsDone: function (element) {
4881
+ const widget = WidgetVote.getInstance(element);
4882
+ if (widget) {
4883
+ return widget.slideVoteIsDone();
4884
+ }
4885
+ return true;
4886
+ },
4887
+ };
4888
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
4889
+ }
4890
+
4891
+ exports.sdkInterface = void 0;
4892
+ const getSlideApi = (_sdkInterface) => {
4893
+ exports.sdkInterface = _sdkInterface;
4894
+ return {
4895
+ Animation: animationApi,
4896
+ WidgetCopy: WidgetCopy.api,
4897
+ WidgetDataInput: WidgetDataInput.api,
4898
+ WidgetDateCountdown: WidgetDateCountdown.api,
4899
+ WidgetMultiSlide: WidgetMultiSlide.api,
4900
+ WidgetPoll: WidgetPoll.api,
4901
+ WidgetPollLayers: WidgetPollLayers.api,
4902
+ WidgetQuest: WidgetQuest.api,
4903
+ WidgetQuiz: WidgetQuiz.api,
4904
+ WidgetQuizGrouped: WidgetQuizGrouped.api,
4905
+ WidgetRangeSlider: WidgetRangeSlider.api,
4906
+ WidgetRate: WidgetRate.api,
4907
+ WidgetShare: WidgetShare.api,
4908
+ WidgetTest: WidgetTest.api,
4909
+ WidgetVote: WidgetVote.api,
4910
+ };
4911
+ };
4912
+
4913
+ exports.getSlideApi = getSlideApi;