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