@inappstory/slide-api 0.0.21 → 0.0.23

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/dist/index.cjs CHANGED
@@ -575,8 +575,8 @@ const getWinWidth = function (env) {
575
575
  const getWinHeight = function (env) {
576
576
  return env.innerHeight || env.document.documentElement.clientHeight || env.document.body.clientHeight;
577
577
  };
578
- const sendStatisticEventToApp = function (sdkApi, name, data, devPayload) {
579
- sdkApi.sendStatisticEvent(name, data, devPayload);
578
+ const sendStatisticEventToApp = function (sdkApi, name, data, devPayload, options) {
579
+ sdkApi.sendStatisticEvent(name, data, devPayload, options?.forceEnableStatisticV2 ?? false);
580
580
  };
581
581
  const getValueOrException = function (value, message) {
582
582
  if (value == null) {
@@ -672,6 +672,37 @@ const Clipboard = (function (window, document, navigator) {
672
672
  copy,
673
673
  };
674
674
  })(window, document, navigator);
675
+ function FilterNumber(x) {
676
+ return typeof x === "number";
677
+ }
678
+ function determineLocale() {
679
+ // All modern browsers support this. Should match what's used by localeCompare() etc.
680
+ const intl = window.Intl;
681
+ if (intl !== undefined) {
682
+ return intl.NumberFormat().resolvedOptions().locale;
683
+ }
684
+ // Fall back to ranked choice locales, which are configured in the browser but aren't necessarily
685
+ // what's used in functions like localeCompare().
686
+ const languages = navigator.languages;
687
+ if (languages !== undefined && languages.length > 0) {
688
+ return languages[0];
689
+ }
690
+ // Old standard.
691
+ return navigator.language ?? "en-US";
692
+ }
693
+ function isScreenSupportsTouch(env) {
694
+ let supportsTouch = false;
695
+ if ("ontouchstart" in env) {
696
+ supportsTouch = true;
697
+ }
698
+ else if (env.navigator.msPointerEnabled) {
699
+ supportsTouch = true;
700
+ }
701
+ else if ("ontouchstart" in env.document.documentElement) {
702
+ supportsTouch = true;
703
+ }
704
+ return supportsTouch;
705
+ }
675
706
 
676
707
  var supportAnimate = document.documentElement.animate !== undefined;
677
708
  supportAnimate = false; // tmp off
@@ -1069,8 +1100,8 @@ class EsModuleSdkApi {
1069
1100
  showNextSlide(duration) {
1070
1101
  this.sdkBinding().showNextSlide(duration);
1071
1102
  }
1072
- sendStatisticEvent(name, data, devPayload) {
1073
- this.sdkBinding().sendStatisticEvent(name, data, devPayload);
1103
+ sendStatisticEvent(name, data, devPayload, forceEnableStatisticV2) {
1104
+ this.sdkBinding().sendStatisticEvent(name, data, devPayload, forceEnableStatisticV2);
1074
1105
  }
1075
1106
  getCardLocalData() {
1076
1107
  return this.sdkBinding().getCardLocalData();
@@ -1171,6 +1202,14 @@ class EsModuleSdkApi {
1171
1202
  getCardFonts() {
1172
1203
  return this.sdkBinding().getCardFonts();
1173
1204
  }
1205
+ disableVerticalSwipeGesture() {
1206
+ this.sdkBinding().disableVerticalSwipeGesture();
1207
+ }
1208
+ enableVerticalSwipeGesture() {
1209
+ this.sdkBinding().enableVerticalSwipeGesture();
1210
+ }
1211
+ disableBackpress() { }
1212
+ enableBackpress() { }
1174
1213
  static get [Symbol.for("___CTOR_ARGS___")]() { return [`() => SDKInterface`]; }
1175
1214
  }
1176
1215
 
@@ -1202,6 +1241,8 @@ class WidgetBase {
1202
1241
  localData = null;
1203
1242
  firstOpenTime = 0;
1204
1243
  id;
1244
+ startReadyPromise = null;
1245
+ startReadyResolve = null;
1205
1246
  constructor(element, options, elementIdGetter, slideGetter) {
1206
1247
  this.options = extend({}, this.constructor.DEFAULTS, options);
1207
1248
  this.element = element;
@@ -1253,12 +1294,32 @@ class WidgetBase {
1253
1294
  this.localData = extend({}, this.savedData ?? {}, this.options.localData ?? {});
1254
1295
  this.id = `w_${this.elementId}_${WidgetBase.widgetIndex}`;
1255
1296
  ++WidgetBase.widgetIndex;
1297
+ this.resetStartReadyPromise();
1298
+ }
1299
+ resetStartReadyPromise() {
1300
+ this.startReadyPromise = new Promise(resolve => {
1301
+ this.startReadyResolve = resolve;
1302
+ });
1256
1303
  }
1257
1304
  /**
1258
1305
  * Start or restart widget
1259
1306
  * @param localData
1260
1307
  */
1261
- onRefreshUserData(localData) { }
1308
+ onRefreshUserData(localData) {
1309
+ this.savedData = this.sdkApi.getCardServerData(this.cardId);
1310
+ this.localData = extend({}, this.savedData ?? {}, localData);
1311
+ }
1312
+ onStart() {
1313
+ // add active class for enable animation
1314
+ this.element.classList.add("active");
1315
+ this.startReadyResolve();
1316
+ }
1317
+ onStop() {
1318
+ this.element.classList.remove("active");
1319
+ this.resetStartReadyPromise();
1320
+ }
1321
+ onPause() { }
1322
+ onResume() { }
1262
1323
  static widgetCacheKey = "ias.story-element";
1263
1324
  static widgetClassName = "";
1264
1325
  static getInstance(element) {
@@ -1403,16 +1464,16 @@ class WidgetBase {
1403
1464
  }
1404
1465
  return data;
1405
1466
  }
1406
- static sendStatisticEventToApp(name, data, devPayload) {
1407
- sendStatisticEventToApp(this.widgetsService.sdkApi, name, data, devPayload);
1467
+ static sendStatisticEventToApp(name, data, devPayload, options) {
1468
+ sendStatisticEventToApp(this.widgetsService.sdkApi, name, data, devPayload, options);
1408
1469
  }
1409
- sendStatisticEventToApp(name, data, devPayload) {
1410
- this.constructor.sendStatisticEventToApp(name, data, devPayload);
1470
+ sendStatisticEventToApp(name, data, devPayload, options) {
1471
+ this.constructor.sendStatisticEventToApp(name, data, devPayload, options);
1411
1472
  }
1412
1473
  startDisabledTimeline() {
1413
1474
  this.sdkApi.startDisabledTimeline(this.cardId, this.slideIndex);
1414
1475
  }
1415
- _showLayout(layers, selectIndex, withStatEvent = false) {
1476
+ _showLayer(layers, selectIndex, withStatEvent = false) {
1416
1477
  if (this.sdkApi.isExistsShowLayer()) {
1417
1478
  this.sdkApi.showLayer(selectIndex);
1418
1479
  }
@@ -1555,9 +1616,21 @@ class WidgetCopy extends WidgetBase {
1555
1616
  * @param localData
1556
1617
  */
1557
1618
  onRefreshUserData(localData) {
1558
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
1559
- this.localData = extend({}, this.savedData ?? {}, localData);
1619
+ super.onRefreshUserData(localData);
1620
+ // return DOM to init state (ready to copy)
1621
+ this.element.classList.remove("done");
1622
+ if (this.resultLayer) {
1623
+ this.resultLayer.classList.remove("done");
1624
+ }
1560
1625
  this.state = null;
1626
+ if (this.isPromotionalCode) {
1627
+ this.initPromotionalCodeFromLocalData();
1628
+ }
1629
+ }
1630
+ onStart() {
1631
+ super.onStart();
1632
+ // add active class for enable animation
1633
+ this.resultLayer?.classList.add("active");
1561
1634
  if (this.isPromotionalCode) {
1562
1635
  this.fetchPromoCode();
1563
1636
  }
@@ -1581,16 +1654,22 @@ class WidgetCopy extends WidgetBase {
1581
1654
  this.button.textContent = newText;
1582
1655
  }
1583
1656
  }
1584
- fetchPromoCode() {
1585
- this.state = 0;
1586
- if (this.localData["_cp_g_" + this.elementId + "_pc"] !== undefined) {
1657
+ getPromotionalCodeFromLocalData() {
1658
+ return this.localData["_cp_g_" + this.elementId + "_pc"];
1659
+ }
1660
+ initPromotionalCodeFromLocalData() {
1661
+ if (this.getPromotionalCodeFromLocalData() !== undefined) {
1587
1662
  this.state = 1;
1588
- this.clipboardTarget = this.localData["_cp_g_" + this.elementId + "_pc"];
1663
+ this.clipboardTarget = this.getPromotionalCodeFromLocalData();
1589
1664
  if (this.clipboardTarget != null) {
1590
1665
  this.changeText(this.clipboardTarget);
1591
1666
  }
1592
1667
  removeClass(this.element, "loader");
1593
1668
  }
1669
+ }
1670
+ fetchPromoCode() {
1671
+ this.state = 0;
1672
+ this.initPromotionalCodeFromLocalData();
1594
1673
  if (this.state === 0) {
1595
1674
  if (!this.isTransparentElement()) {
1596
1675
  // for transparent element
@@ -1678,12 +1757,14 @@ class WidgetCopy extends WidgetBase {
1678
1757
  if (this.resultLayer) {
1679
1758
  this.resultLayer.classList.add("done");
1680
1759
  }
1681
- if (this.disableTimer) {
1682
- // флаг - что таймер уже стартанул (в layout или добавить объект sharedMemory)
1683
- // смотрим что прозрачный текст - тогда и лоадер прозрачный
1684
- // _log("_showNarrativeNextSlide: " + getSlideDuration(this.narrativeId, this.slideIndex), true);
1685
- this.startDisabledTimeline();
1686
- }
1760
+ this.startReadyPromise.then(() => {
1761
+ if (this.disableTimer) {
1762
+ // флаг - что таймер уже стартанул layout или добавить объект sharedMemory)
1763
+ // смотрим что прозрачный текст - тогда и лоадер прозрачный
1764
+ // _log("_showNarrativeNextSlide: " + getSlideDuration(this.narrativeId, this.slideIndex), true);
1765
+ this.startDisabledTimeline();
1766
+ }
1767
+ });
1687
1768
  }
1688
1769
  copyToClipboard(element) {
1689
1770
  this._select();
@@ -1717,6 +1798,13 @@ class WidgetCopy extends WidgetBase {
1717
1798
  // prevent initWidget for result layer
1718
1799
  const elements = slice.call(nodeList).filter(element => !element.classList.contains("narrative-element-copy-result-variant"));
1719
1800
  WidgetCopy.initWidgets((element, options) => new WidgetCopy(element, options), elements, localData);
1801
+ elements.forEach(element => WidgetCopy.getInstance(element)?.onStart());
1802
+ },
1803
+ onStart: function (element) {
1804
+ WidgetCopy.getInstance(element)?.onStart();
1805
+ },
1806
+ onStop: function (element) {
1807
+ WidgetCopy.getInstance(element)?.onStop();
1720
1808
  },
1721
1809
  click: function (element) {
1722
1810
  const widgetElement = element.closest(`.${WidgetCopy.widgetClassName}`);
@@ -1772,17 +1860,21 @@ class WidgetDataInput extends WidgetBase {
1772
1860
  * @param localData
1773
1861
  */
1774
1862
  onRefreshUserData(localData) {
1775
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
1776
- this.localData = extend({}, this.savedData ?? {}, localData);
1777
- const text = this.localData["_di_g_" + this.elementId + "_t"];
1863
+ super.onRefreshUserData(localData);
1864
+ const text = this.getTextFromLocalData();
1778
1865
  this._fillUserText(text);
1779
- if (text) {
1866
+ if (text != null) {
1780
1867
  this.element.classList.add("done");
1781
- if (this.disableTimer) {
1782
- this.startDisabledTimeline();
1783
- }
1868
+ this.startReadyPromise.then(() => {
1869
+ if (this.disableTimer) {
1870
+ this.startDisabledTimeline();
1871
+ }
1872
+ });
1784
1873
  }
1785
1874
  }
1875
+ getTextFromLocalData() {
1876
+ return this.localData["_di_g_" + this.elementId + "_t"];
1877
+ }
1786
1878
  _statEventFocusIn() {
1787
1879
  try {
1788
1880
  const labelText = this.label ? this.label.textContent ?? "" : "";
@@ -1860,7 +1952,7 @@ class WidgetDataInput extends WidgetBase {
1860
1952
  }
1861
1953
  _fillUserText(text) {
1862
1954
  if (this.inputElement && this.textElement) {
1863
- if (text) {
1955
+ if (text != null) {
1864
1956
  this.inputElement.classList.remove("_is-placeholder");
1865
1957
  text = text.replace(new RegExp("\r?\n", "g"), "<br />");
1866
1958
  this.textElement.innerHTML = text;
@@ -1910,7 +2002,15 @@ class WidgetDataInput extends WidgetBase {
1910
2002
  },
1911
2003
  /** @deprecated */
1912
2004
  initWidget: function (nodeList, localData) {
2005
+ const elements = slice.call(nodeList);
1913
2006
  WidgetDataInput.initWidgets((element, options) => new WidgetDataInput(element, options), slice.call(nodeList), localData);
2007
+ elements.forEach(element => WidgetDataInput.getInstance(element)?.onStart());
2008
+ },
2009
+ onStart: function (element) {
2010
+ WidgetDataInput.getInstance(element)?.onStart();
2011
+ },
2012
+ onStop: function (element) {
2013
+ WidgetDataInput.getInstance(element)?.onStop();
1914
2014
  },
1915
2015
  click: function (element) {
1916
2016
  const widgetElement = element.closest(`.${WidgetDataInput.widgetClassName}`);
@@ -1941,7 +2041,7 @@ class WidgetDateCountdown extends WidgetBase {
1941
2041
  label;
1942
2042
  layers;
1943
2043
  messages;
1944
- timestampSeconds;
2044
+ timestampMs;
1945
2045
  diff;
1946
2046
  timerInit;
1947
2047
  pendingUpdate;
@@ -1963,58 +2063,58 @@ class WidgetDateCountdown extends WidgetBase {
1963
2063
  minutes: getTagData(this.element, "tMinutes") ?? "",
1964
2064
  seconds: getTagData(this.element, "tSeconds") ?? "",
1965
2065
  };
1966
- this.timestampSeconds = getValueOrException(getTagDataAsNumber(this.element, "timestampSeconds"), "Empty timestampSeconds");
2066
+ this.timestampMs = getValueOrException(getTagDataAsNumber(this.element, "timestampSeconds"), "Empty timestampSeconds") * 1000;
1967
2067
  this.diff = 0;
1968
2068
  this.timerInit = false;
1969
2069
  this.pendingUpdate = true;
1970
2070
  this.layers = this.options.layers;
1971
- // if (false) {
1972
- // // if (sendApiRequestSupported()) {
1973
- // // fetch project time
1974
- // var path = "story/" + this.storyId + "/widget/" + this.elementId + "/timestamp";
1975
- // var profileKey = "fetch-story-timestamp";
1976
- // this.sdkApi
1977
- // .sendApiRequest<{ timestamp: number }>(path, "GET", null, null, null, profileKey)
1978
- // .then(response => {
1979
- // var status = response.status;
1980
- // var timestamp = null;
1981
- // if (status === 200) {
1982
- // if (response.data) timestamp = response.data.timestamp;
1983
- // if (timestamp) {
1984
- // this.diff = new Date().getTime() - timestamp * 1000;
1985
- // }
1986
- // }
1987
- //
1988
- // this.initTimer();
1989
- // })
1990
- // .catch( (reason)=> {
1991
- // console.error(reason);
1992
- // this.initTimer();
1993
- // });
1994
- // } else {
1995
- this.initTimer();
1996
- // }
1997
2071
  }
1998
2072
  /**
1999
2073
  * Start or restart widget
2000
2074
  * @param localData
2001
2075
  */
2002
2076
  onRefreshUserData(localData) {
2003
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
2004
- this.localData = extend({}, this.savedData ?? {}, localData);
2077
+ super.onRefreshUserData(localData);
2078
+ const value = this.timestampMs - (new Date().getTime() - this.diff);
2079
+ if (value > 0) {
2080
+ this._showLayer(this.layers, 0);
2081
+ }
2082
+ else {
2083
+ if (this.layers[1] != null) {
2084
+ this._showLayer(this.layers, 1);
2085
+ }
2086
+ }
2005
2087
  }
2006
- pause() {
2088
+ onPause() {
2089
+ super.onPause();
2007
2090
  if (this.timerInit) {
2008
2091
  this.pendingUpdate = false;
2009
2092
  }
2010
2093
  }
2011
- resume() {
2012
- if (this.timerInit) {
2094
+ onResume() {
2095
+ super.onResume();
2096
+ if (this.timerInit && !this.pendingUpdate) {
2013
2097
  this.pendingUpdate = true;
2014
2098
  this.updateTimer();
2015
2099
  }
2016
2100
  }
2101
+ onStart() {
2102
+ super.onStart();
2103
+ if (!this.timerInit) {
2104
+ this.initTimer();
2105
+ }
2106
+ }
2107
+ onStop() {
2108
+ super.onStop();
2109
+ if (this.timerInit) {
2110
+ this.pendingUpdate = false;
2111
+ this.timerInit = false;
2112
+ }
2113
+ }
2017
2114
  initTimer() {
2115
+ if (this.timerInit) {
2116
+ return;
2117
+ }
2018
2118
  // find groups
2019
2119
  this.firstGroup1 = getValueOrException(this.element.querySelector(".date-item-view-group-1 .date-output-label-1"), "Empty firstGroup1");
2020
2120
  this.firstGroup2 = getValueOrException(this.element.querySelector(".date-item-view-group-1 .date-output-label-2"), "Empty firstGroup2");
@@ -2025,16 +2125,18 @@ class WidgetDateCountdown extends WidgetBase {
2025
2125
  this.thirdGroup1 = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-output-label-1"), "Empty thirdGroup1");
2026
2126
  this.thirdGroup2 = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-output-label-2"), "Empty thirdGroup2");
2027
2127
  this.thirdGroupCaption = getValueOrException(this.element.querySelector(".date-item-view-group-3 .date-item-caption"), "Empty thirdGroupCaption");
2028
- this.timestampSeconds *= 1000;
2029
2128
  this.timerInit = true;
2030
- const value = this.timestampSeconds - (new Date().getTime() - this.diff);
2129
+ const value = this.timestampMs - (new Date().getTime() - this.diff);
2031
2130
  if (value > 0) {
2032
- this._showLayout(this.layers, 0);
2131
+ this._showLayer(this.layers, 0);
2033
2132
  }
2034
2133
  this.updateTimer();
2035
2134
  }
2036
2135
  updateTimer() {
2037
- const value = this.timestampSeconds - (new Date().getTime() - this.diff);
2136
+ if (!this.timerInit) {
2137
+ return;
2138
+ }
2139
+ const value = this.timestampMs - (new Date().getTime() - this.diff);
2038
2140
  if (value > 0) {
2039
2141
  const result = this._asDuration(Math.round(value / 1000));
2040
2142
  if (result.days) {
@@ -2063,7 +2165,9 @@ class WidgetDateCountdown extends WidgetBase {
2063
2165
  }
2064
2166
  else {
2065
2167
  this.pendingUpdate = false;
2066
- this._showLayout(this.layers, 1);
2168
+ if (this.layers[1] != null) {
2169
+ this._showLayer(this.layers, 1);
2170
+ }
2067
2171
  }
2068
2172
  if (this.pendingUpdate) {
2069
2173
  this.env.requestAnimationFrame(() => this.updateTimer());
@@ -2136,24 +2240,32 @@ class WidgetDateCountdown extends WidgetBase {
2136
2240
  },
2137
2241
  /** @deprecated */
2138
2242
  initWidget: function (nodeList, layers, localData) {
2139
- WidgetDateCountdown.initWidgets((element, options) => new WidgetDateCountdown(element, { ...options, layers }), slice.call(nodeList), localData);
2243
+ const elements = slice.call(nodeList);
2244
+ WidgetDateCountdown.initWidgets((element, options) => new WidgetDateCountdown(element, { ...options, layers }), elements, localData);
2245
+ elements.forEach(element => WidgetDateCountdown.getInstance(element)?.onStart());
2246
+ },
2247
+ onStart: function (element) {
2248
+ WidgetDateCountdown.getInstance(element)?.onStart();
2249
+ },
2250
+ onStop: function (element) {
2251
+ WidgetDateCountdown.getInstance(element)?.onStop();
2140
2252
  },
2141
2253
  onPause: function (element) {
2142
- WidgetDateCountdown.getInstance(element)?.pause();
2254
+ WidgetDateCountdown.getInstance(element)?.onPause();
2143
2255
  },
2144
2256
  onResume: function (element) {
2145
- WidgetDateCountdown.getInstance(element)?.resume();
2257
+ WidgetDateCountdown.getInstance(element)?.onResume();
2146
2258
  },
2147
2259
  /** @deprecated */
2148
2260
  pause: function (nodeList) {
2149
2261
  forEach(slice.call(nodeList), function (el, index) {
2150
- WidgetDateCountdown.getInstance(el)?.pause();
2262
+ WidgetDateCountdown.getInstance(el)?.onPause();
2151
2263
  });
2152
2264
  },
2153
2265
  /** @deprecated */
2154
2266
  resume: function (nodeList) {
2155
2267
  forEach(slice.call(nodeList), function (el, index) {
2156
- WidgetDateCountdown.getInstance(el)?.resume();
2268
+ WidgetDateCountdown.getInstance(el)?.onResume();
2157
2269
  });
2158
2270
  },
2159
2271
  };
@@ -2345,8 +2457,7 @@ class WidgetPoll extends WidgetBase {
2345
2457
  * @param localData
2346
2458
  */
2347
2459
  onRefreshUserData(localData) {
2348
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
2349
- this.localData = extend({}, this.savedData ?? {}, localData);
2460
+ super.onRefreshUserData(localData);
2350
2461
  this.selectedVariant = undefined;
2351
2462
  if (this.localData) {
2352
2463
  if (this.localData["_p_g_" + this.elementId + "_sa"] !== undefined) {
@@ -2429,14 +2540,11 @@ class WidgetPoll extends WidgetBase {
2429
2540
  this.element.classList.add("with-total-result");
2430
2541
  this.displayPercents(index, filled);
2431
2542
  }
2432
- if (this.disableTimer) {
2433
- this.env.setTimeout(() => {
2434
- // todo poll - если виджет на первом слайде то при повторном заходе автоматически не стартует таймлайн слайда
2435
- // только в web sdk такое
2436
- // если поставить через setTimeout то все ок
2543
+ this.startReadyPromise.then(() => {
2544
+ if (this.disableTimer) {
2437
2545
  this.startDisabledTimeline();
2438
- });
2439
- }
2546
+ }
2547
+ });
2440
2548
  }
2441
2549
  _clearVariantSelection() {
2442
2550
  forEach(this.variants, function (variant) {
@@ -2783,6 +2891,13 @@ class WidgetPoll extends WidgetBase {
2783
2891
  /** @deprecated */
2784
2892
  initWidget: function (element, localData) {
2785
2893
  WidgetPoll.initWidgets((element, options) => new WidgetPoll(element, options), [element], localData);
2894
+ WidgetPoll.getInstance(element)?.onStart();
2895
+ },
2896
+ onStart: function (element) {
2897
+ WidgetPoll.getInstance(element)?.onStart();
2898
+ },
2899
+ onStop: function (element) {
2900
+ WidgetPoll.getInstance(element)?.onStop();
2786
2901
  },
2787
2902
  /**
2788
2903
  * click
@@ -2857,14 +2972,13 @@ class WidgetPollLayers extends WidgetBase {
2857
2972
  * @param localData
2858
2973
  */
2859
2974
  onRefreshUserData(localData) {
2860
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
2861
- this.localData = extend({}, this.savedData ?? {}, localData);
2975
+ super.onRefreshUserData(localData);
2862
2976
  this.selectedVariant = undefined;
2863
2977
  if (this.slidePollIsDone()) {
2864
2978
  this._selectVariant(this.localData["_pl_g_" + this.elementId + "_sa"]);
2865
2979
  }
2866
2980
  else {
2867
- this._showLayout(this.layers, 0);
2981
+ this._showLayer(this.layers, 0);
2868
2982
  }
2869
2983
  this.firstOpenTime = new Date().getTime();
2870
2984
  }
@@ -2910,10 +3024,12 @@ class WidgetPollLayers extends WidgetBase {
2910
3024
  else if (index === 1) {
2911
3025
  layerIndex = 2;
2912
3026
  }
2913
- this._showLayout(this.layers, layerIndex, userAction);
2914
- if (this.disableTimer) {
2915
- this.startDisabledTimeline();
2916
- }
3027
+ this._showLayer(this.layers, layerIndex, userAction);
3028
+ this.startReadyPromise.then(() => {
3029
+ if (this.disableTimer) {
3030
+ this.startDisabledTimeline();
3031
+ }
3032
+ });
2917
3033
  }
2918
3034
  selectVariant(variant) {
2919
3035
  if (this.selectedVariant !== undefined) {
@@ -2970,6 +3086,13 @@ class WidgetPollLayers extends WidgetBase {
2970
3086
  localData = undefined;
2971
3087
  }
2972
3088
  WidgetPollLayers.initWidgets((element, options) => new WidgetPollLayers(element, { ...options, layers }), [element], localData);
3089
+ WidgetPollLayers.getInstance(element)?.onStart();
3090
+ },
3091
+ onStart: function (element) {
3092
+ WidgetPollLayers.getInstance(element)?.onStart();
3093
+ },
3094
+ onStop: function (element) {
3095
+ WidgetPollLayers.getInstance(element)?.onStop();
2973
3096
  },
2974
3097
  /**
2975
3098
  * click on poll variant
@@ -3004,6 +3127,7 @@ class WidgetQuest extends WidgetBase {
3004
3127
  isWidget;
3005
3128
  slideCount;
3006
3129
  nonFinalSlide;
3130
+ slideDisabledNavigation;
3007
3131
  finalSlide;
3008
3132
  constructor(element, options) {
3009
3133
  const isWidget = !hasClass(element, "narrative-slide");
@@ -3016,6 +3140,7 @@ class WidgetQuest extends WidgetBase {
3016
3140
  this.finalSlide = !this.isWidget && !this.nonFinalSlide;
3017
3141
  this.label = this.element.querySelector(".label-view .label");
3018
3142
  this.variants = slice.call(this.element.querySelectorAll(".variants-box .variant-view"));
3143
+ this.slideDisabledNavigation = Boolean(getTagDataAsNumber(this.slide, "disableNavigation") ?? 0);
3019
3144
  this.selectedAnswer = undefined;
3020
3145
  }
3021
3146
  /**
@@ -3023,8 +3148,7 @@ class WidgetQuest extends WidgetBase {
3023
3148
  * @param localData
3024
3149
  */
3025
3150
  onRefreshUserData(localData) {
3026
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
3027
- this.localData = extend({}, this.savedData ?? {}, localData);
3151
+ super.onRefreshUserData(localData);
3028
3152
  }
3029
3153
  setCardSessionValue(name, value) {
3030
3154
  this.sdkApi.setCardSessionValue(this.element, name, value);
@@ -3161,6 +3285,10 @@ class WidgetQuest extends WidgetBase {
3161
3285
  const directionForward = event.direction === "forward";
3162
3286
  event.direction === "backward";
3163
3287
  if (this.isWidget) {
3288
+ // like in web-sdk - simple block tap navigation at all
3289
+ if (this.slideDisabledNavigation) {
3290
+ return;
3291
+ }
3164
3292
  if (directionForward) {
3165
3293
  return;
3166
3294
  }
@@ -3184,6 +3312,10 @@ class WidgetQuest extends WidgetBase {
3184
3312
  }
3185
3313
  }
3186
3314
  else {
3315
+ // like in web-sdk - simple block tap navigation at all
3316
+ if (this.slideDisabledNavigation) {
3317
+ return;
3318
+ }
3187
3319
  // slides without quest form
3188
3320
  // simple slide case
3189
3321
  if (this.nonFinalSlide || event.slideIndex < this.firstSlideWithQuestIndex()) {
@@ -3277,8 +3409,15 @@ class WidgetQuest extends WidgetBase {
3277
3409
  resolve(true);
3278
3410
  }
3279
3411
  });
3412
+ WidgetQuest.getInstance(element)?.onStart();
3280
3413
  });
3281
3414
  },
3415
+ onStart: function (element) {
3416
+ WidgetQuest.getInstance(element)?.onStart();
3417
+ },
3418
+ onStop: function (element) {
3419
+ WidgetQuest.getInstance(element)?.onStop();
3420
+ },
3282
3421
  select: function (element) {
3283
3422
  const widgetElement = element.closest(`.${WidgetQuest.widgetClassName}`);
3284
3423
  if (widgetElement) {
@@ -3329,8 +3468,7 @@ class WidgetQuiz extends WidgetBase {
3329
3468
  * @param localData
3330
3469
  */
3331
3470
  onRefreshUserData(localData) {
3332
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
3333
- this.localData = extend({}, this.savedData ?? {}, localData);
3471
+ super.onRefreshUserData(localData);
3334
3472
  this.selectedAnswer = undefined;
3335
3473
  if (this.localData) {
3336
3474
  if (this.localData["_q_g_" + this.elementId + "_sa"] !== undefined) {
@@ -3373,9 +3511,11 @@ class WidgetQuiz extends WidgetBase {
3373
3511
  // })
3374
3512
  // })
3375
3513
  // }
3376
- if (this.disableTimer) {
3377
- this.startDisabledTimeline();
3378
- }
3514
+ this.startReadyPromise.then(() => {
3515
+ if (this.disableTimer) {
3516
+ this.startDisabledTimeline();
3517
+ }
3518
+ });
3379
3519
  }
3380
3520
  _clearAnswerSelection() {
3381
3521
  forEach(this.answers, function (answer) {
@@ -3474,6 +3614,13 @@ class WidgetQuiz extends WidgetBase {
3474
3614
  /** @deprecated */
3475
3615
  initWidget: function (element, localData) {
3476
3616
  WidgetQuiz.initWidgets((element, options) => new WidgetQuiz(element, options), [element], localData);
3617
+ WidgetQuiz.getInstance(element)?.onStart();
3618
+ },
3619
+ onStart: function (element) {
3620
+ WidgetQuiz.getInstance(element)?.onStart();
3621
+ },
3622
+ onStop: function (element) {
3623
+ WidgetQuiz.getInstance(element)?.onStop();
3477
3624
  },
3478
3625
  /**
3479
3626
  * click on quiz answer
@@ -3527,8 +3674,7 @@ class WidgetQuizGrouped extends WidgetBase {
3527
3674
  * @param localData
3528
3675
  */
3529
3676
  onRefreshUserData(localData) {
3530
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
3531
- this.localData = extend({}, this.savedData ?? {}, localData);
3677
+ super.onRefreshUserData(localData);
3532
3678
  this.selectedAnswer = undefined;
3533
3679
  if (this.localData) {
3534
3680
  if (this.localData["_q_gg_" + this.elementId + "_sa"] !== undefined) {
@@ -3558,9 +3704,11 @@ class WidgetQuizGrouped extends WidgetBase {
3558
3704
  this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
3559
3705
  }
3560
3706
  });
3561
- if (this.disableTimer) {
3562
- this.startDisabledTimeline();
3563
- }
3707
+ this.startReadyPromise.then(() => {
3708
+ if (this.disableTimer) {
3709
+ this.startDisabledTimeline();
3710
+ }
3711
+ });
3564
3712
  }
3565
3713
  _clearAnswerSelection() {
3566
3714
  forEach(this.answers, function (answer) {
@@ -3676,6 +3824,13 @@ class WidgetQuizGrouped extends WidgetBase {
3676
3824
  /** @deprecated */
3677
3825
  initWidget: function (element, localData) {
3678
3826
  WidgetQuizGrouped.initWidgets((element, options) => new WidgetQuizGrouped(element, options), [element], localData);
3827
+ WidgetQuizGrouped.getInstance(element)?.onStart();
3828
+ },
3829
+ onStart: function (element) {
3830
+ WidgetQuizGrouped.getInstance(element)?.onStart();
3831
+ },
3832
+ onStop: function (element) {
3833
+ WidgetQuizGrouped.getInstance(element)?.onStop();
3679
3834
  },
3680
3835
  /**
3681
3836
  * click on quiz answer
@@ -3921,15 +4076,16 @@ class WidgetRangeSlider extends WidgetBase {
3921
4076
  * @param localData
3922
4077
  */
3923
4078
  onRefreshUserData(localData) {
3924
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
3925
- this.localData = extend({}, this.savedData ?? {}, localData);
4079
+ super.onRefreshUserData(localData);
3926
4080
  if (this.localData["_rs_g_" + this.elementId + "_v"] !== undefined) {
3927
4081
  this.elementSlider.value = String(tryParseFloat(this.localData["_rs_g_" + this.elementId + "_v"], 0));
3928
4082
  this.element.classList.add("done");
3929
4083
  this.displayAverageAnswer();
3930
- if (this.disableTimer) {
3931
- this.startDisabledTimeline();
3932
- }
4084
+ this.startReadyPromise.then(() => {
4085
+ if (this.disableTimer) {
4086
+ this.startDisabledTimeline();
4087
+ }
4088
+ });
3933
4089
  }
3934
4090
  else {
3935
4091
  this.elementSlider.value = String(this.startValue);
@@ -3938,6 +4094,10 @@ class WidgetRangeSlider extends WidgetBase {
3938
4094
  }
3939
4095
  this.init();
3940
4096
  }
4097
+ onStop() {
4098
+ super.onStop();
4099
+ this.destroy();
4100
+ }
3941
4101
  _statEventInputSave(val) {
3942
4102
  try {
3943
4103
  const labelText = this.label?.textContent ?? "";
@@ -4114,10 +4274,10 @@ class WidgetRangeSlider extends WidgetBase {
4114
4274
  if (!this.maxHandlePos) {
4115
4275
  this.update(true, false);
4116
4276
  }
4117
- document.addEventListener("touchmove", this.handleMove);
4118
- document.addEventListener("touchend", this.handleEnd);
4119
- document.addEventListener("mousemove", this.handleMove);
4120
- document.addEventListener("mouseup", this.handleEnd);
4277
+ this.env.document.addEventListener("touchmove", this.handleMove);
4278
+ this.env.document.addEventListener("touchend", this.handleEnd);
4279
+ this.env.document.addEventListener("mousemove", this.handleMove);
4280
+ this.env.document.addEventListener("mouseup", this.handleEnd);
4121
4281
  // add active class because Firefox is ignoring
4122
4282
  // the handle:active pseudo selector because of `e.preventDefault();`
4123
4283
  this.range.classList.add(this.options.activeClass);
@@ -4142,10 +4302,10 @@ class WidgetRangeSlider extends WidgetBase {
4142
4302
  this.isClickCapturedBySlider = false;
4143
4303
  });
4144
4304
  // e.preventDefault();
4145
- document.removeEventListener("touchmove", this.handleMove);
4146
- document.removeEventListener("touchend", this.handleEnd);
4147
- document.removeEventListener("mousemove", this.handleMove);
4148
- document.removeEventListener("mouseup", this.handleEnd);
4305
+ this.env.document.removeEventListener("touchmove", this.handleMove);
4306
+ this.env.document.removeEventListener("touchend", this.handleEnd);
4307
+ this.env.document.removeEventListener("mousemove", this.handleMove);
4308
+ this.env.document.removeEventListener("mouseup", this.handleEnd);
4149
4309
  this.range.classList.remove(this.options.activeClass);
4150
4310
  this.element.classList.add("input-done");
4151
4311
  if (!this.hasSubmitButton) {
@@ -4289,11 +4449,18 @@ class WidgetRangeSlider extends WidgetBase {
4289
4449
  onRefreshUserData: WidgetRangeSlider.onRefreshUserData,
4290
4450
  init: function (element, localData) {
4291
4451
  WidgetRangeSlider.initWidget(element, localData, (element, options) => new WidgetRangeSlider(element, options));
4452
+ WidgetRangeSlider.getInstance(element)?.onStart();
4292
4453
  },
4293
4454
  /** @deprecated */
4294
4455
  initWidget: function (element, localData) {
4295
4456
  WidgetRangeSlider.initWidgets((element, options) => new WidgetRangeSlider(element, options), [element], localData);
4296
4457
  },
4458
+ onStart: function (element) {
4459
+ WidgetRangeSlider.getInstance(element)?.onStart();
4460
+ },
4461
+ onStop: function (element) {
4462
+ WidgetRangeSlider.getInstance(element)?.onStop();
4463
+ },
4297
4464
  click: function (element) {
4298
4465
  const widgetElement = element.closest(`.${WidgetRangeSlider.widgetClassName}`);
4299
4466
  if (widgetElement) {
@@ -4354,8 +4521,7 @@ class WidgetRate extends WidgetBase {
4354
4521
  * @param localData
4355
4522
  */
4356
4523
  onRefreshUserData(localData) {
4357
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
4358
- this.localData = extend({}, this.savedData ?? {}, localData);
4524
+ super.onRefreshUserData(localData);
4359
4525
  this.selectedStar = undefined;
4360
4526
  if (this.localData) {
4361
4527
  if (this.localData["_r_g_" + this.elementId + "_ss"] !== undefined) {
@@ -4413,9 +4579,11 @@ class WidgetRate extends WidgetBase {
4413
4579
  this.selectedStar = value;
4414
4580
  this.localData["_r_g_" + this.elementId + "_ss"] = value;
4415
4581
  this.element.classList.add("done");
4416
- if (this.disableTimer && runTimer) {
4417
- this.startDisabledTimeline();
4418
- }
4582
+ this.startReadyPromise.then(() => {
4583
+ if (this.disableTimer && runTimer) {
4584
+ this.startDisabledTimeline();
4585
+ }
4586
+ });
4419
4587
  }
4420
4588
  _clearSelectedStar() {
4421
4589
  forEach(this.stars, function (element) {
@@ -4548,7 +4716,15 @@ class WidgetRate extends WidgetBase {
4548
4716
  },
4549
4717
  /** @deprecated */
4550
4718
  initWidget: function (nodeList, localData) {
4551
- WidgetRate.initWidgets((element, options) => new WidgetRate(element, options), slice.call(nodeList), localData);
4719
+ const elements = slice.call(nodeList);
4720
+ WidgetRate.initWidgets((element, options) => new WidgetRate(element, options), elements, localData);
4721
+ elements.forEach(element => WidgetRate.getInstance(element)?.onStart());
4722
+ },
4723
+ onStart: function (element) {
4724
+ WidgetRate.getInstance(element)?.onStart();
4725
+ },
4726
+ onStop: function (element) {
4727
+ WidgetRate.getInstance(element)?.onStop();
4552
4728
  },
4553
4729
  select: function (element) {
4554
4730
  const widgetElement = element.closest(`.${WidgetRate.widgetClassName}`);
@@ -4600,19 +4776,20 @@ class WidgetShare extends WidgetBase {
4600
4776
  * @param localData
4601
4777
  */
4602
4778
  onRefreshUserData(localData) {
4603
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
4604
- this.localData = extend({}, this.savedData ?? {}, localData);
4779
+ super.onRefreshUserData(localData);
4605
4780
  if (this.withLayer) {
4606
4781
  if (this.isDone()) {
4607
- this._showLayout(this.layers, 1);
4782
+ this._showLayer(this.layers, 1);
4608
4783
  }
4609
4784
  else {
4610
- this._showLayout(this.layers, 0);
4785
+ this._showLayer(this.layers, 0);
4611
4786
  }
4612
4787
  }
4613
- if (this.isDone() && this.disableTimer) {
4614
- this.startDisabledTimeline();
4615
- }
4788
+ this.startReadyPromise.then(() => {
4789
+ if (this.isDone() && this.disableTimer) {
4790
+ this.startDisabledTimeline();
4791
+ }
4792
+ });
4616
4793
  this.btnDisabled = false;
4617
4794
  }
4618
4795
  _statEventShare(result, via) {
@@ -4667,7 +4844,7 @@ class WidgetShare extends WidgetBase {
4667
4844
  }
4668
4845
  this._statEventShare(isSuccess, null);
4669
4846
  if (isSuccess && this.withLayer) {
4670
- this._showLayout(this.layers, 1, true);
4847
+ this._showLayer(this.layers, 1, true);
4671
4848
  }
4672
4849
  if (this.disableTimer) {
4673
4850
  this.startDisabledTimeline();
@@ -4683,7 +4860,10 @@ class WidgetShare extends WidgetBase {
4683
4860
  refreshUserData: WidgetShare.refreshUserData,
4684
4861
  onRefreshUserData: WidgetShare.onRefreshUserData,
4685
4862
  init: function (element, layers, localData) {
4686
- WidgetShare.initWidget(element, localData, (element, options) => new WidgetShare(element, { ...options, layers }));
4863
+ WidgetShare.initWidget(element, localData, (element, options) => new WidgetShare(element, {
4864
+ ...options,
4865
+ layers,
4866
+ }));
4687
4867
  },
4688
4868
  /** @deprecated
4689
4869
  * signature variants
@@ -4697,7 +4877,15 @@ class WidgetShare extends WidgetBase {
4697
4877
  layers = localData;
4698
4878
  localData = undefined;
4699
4879
  }
4700
- WidgetShare.initWidgets((element, options) => new WidgetShare(element, { ...options, layers }), slice.call(nodeList), localData);
4880
+ const elements = slice.call(nodeList);
4881
+ WidgetShare.initWidgets((element, options) => new WidgetShare(element, { ...options, layers }), elements, localData);
4882
+ elements.forEach(element => WidgetShare.getInstance(element)?.onStart());
4883
+ },
4884
+ onStart: function (element) {
4885
+ WidgetShare.getInstance(element)?.onStart();
4886
+ },
4887
+ onStop: function (element) {
4888
+ WidgetShare.getInstance(element)?.onStop();
4701
4889
  },
4702
4890
  click: function (element) {
4703
4891
  const widgetElement = element.closest(`.${WidgetShare.widgetClassName}`);
@@ -4777,8 +4965,7 @@ class WidgetTest extends WidgetBase {
4777
4965
  * @param localData
4778
4966
  */
4779
4967
  onRefreshUserData(localData) {
4780
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
4781
- this.localData = extend({}, this.savedData ?? {}, localData);
4968
+ super.onRefreshUserData(localData);
4782
4969
  this.selectedAnswer = undefined;
4783
4970
  if (this.localData) {
4784
4971
  if (this.localData["_t_g_" + this.elementId + "_sa"] !== undefined) {
@@ -4802,7 +4989,9 @@ class WidgetTest extends WidgetBase {
4802
4989
  this.timeLeft = this.timeLeftDefault;
4803
4990
  this.animationFrameId = null;
4804
4991
  this.startTimerAt = new Date().getTime();
4805
- this.tick();
4992
+ this.startReadyPromise.then(() => {
4993
+ this.tick();
4994
+ });
4806
4995
  // set answer - unanswered (for close and run again)
4807
4996
  this.localData["_t_g_" + this.elementId + "_sa"] = -1;
4808
4997
  this.setLocalData(this.localData, true);
@@ -4822,6 +5011,15 @@ class WidgetTest extends WidgetBase {
4822
5011
  }
4823
5012
  }
4824
5013
  }
5014
+ onStart() {
5015
+ super.onStart();
5016
+ }
5017
+ onStop() {
5018
+ super.onStop();
5019
+ if (this.slideTestWithTimer()) {
5020
+ this.cancelTick();
5021
+ }
5022
+ }
4825
5023
  _statEventVoteAnswer(answerScore) {
4826
5024
  try {
4827
5025
  if (this.selectedAnswer != null) {
@@ -4869,9 +5067,11 @@ class WidgetTest extends WidgetBase {
4869
5067
  this.submitButtonAnimatedView.style.maxHeight = this.submitButtonViewHeight + "px";
4870
5068
  }
4871
5069
  });
4872
- if (this.disableTimer) {
4873
- this.startDisabledTimeline();
4874
- }
5070
+ this.startReadyPromise.then(() => {
5071
+ if (this.disableTimer) {
5072
+ this.startDisabledTimeline();
5073
+ }
5074
+ });
4875
5075
  }
4876
5076
  selectAnswer(answer) {
4877
5077
  if (this.selectedAnswer !== undefined) {
@@ -4950,6 +5150,13 @@ class WidgetTest extends WidgetBase {
4950
5150
  /** @deprecated */
4951
5151
  initWidget: function (element, localData) {
4952
5152
  WidgetTest.initWidgets((element, options) => new WidgetTest(element, options), [element], localData);
5153
+ WidgetTest.getInstance(element)?.onStart();
5154
+ },
5155
+ onStart: function (element) {
5156
+ WidgetTest.getInstance(element)?.onStart();
5157
+ },
5158
+ onStop: function (element) {
5159
+ WidgetTest.getInstance(element)?.onStop();
4953
5160
  },
4954
5161
  /**
4955
5162
  * click on quiz answer
@@ -5059,8 +5266,7 @@ class WidgetVote extends WidgetBase {
5059
5266
  * @param localData
5060
5267
  */
5061
5268
  onRefreshUserData(localData) {
5062
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
5063
- this.localData = extend({}, this.savedData ?? {}, localData);
5269
+ super.onRefreshUserData(localData);
5064
5270
  this.selectedVariant = undefined;
5065
5271
  if (this.localData) {
5066
5272
  if (this.localData["_v_g_" + this.elementId + "_sa"] != null) {
@@ -5190,9 +5396,11 @@ class WidgetVote extends WidgetBase {
5190
5396
  this._removeInputDone();
5191
5397
  this._hideSubmitBtn();
5192
5398
  }
5193
- if (this.disableTimer) {
5194
- this.startDisabledTimeline();
5195
- }
5399
+ this.startReadyPromise.then(() => {
5400
+ if (this.disableTimer) {
5401
+ this.startDisabledTimeline();
5402
+ }
5403
+ });
5196
5404
  }
5197
5405
  _showSubmitBtn() {
5198
5406
  this.env.requestAnimationFrame(() => {
@@ -5423,6 +5631,13 @@ class WidgetVote extends WidgetBase {
5423
5631
  WidgetVote.initWidgets((element, options) => new WidgetVote(element, options), [element], localData).then(localData => {
5424
5632
  WidgetVote.api.fallbackInitOnMultiSlide(element, localData);
5425
5633
  });
5634
+ WidgetVote.getInstance(element)?.onStart();
5635
+ },
5636
+ onStart: function (element) {
5637
+ WidgetVote.getInstance(element)?.onStart();
5638
+ },
5639
+ onStop: function (element) {
5640
+ WidgetVote.getInstance(element)?.onStop();
5426
5641
  },
5427
5642
  select: function (element) {
5428
5643
  const widgetElement = element.closest(`.${WidgetVote.widgetClassName}`);
@@ -14851,17 +15066,22 @@ class WidgetBarcode extends WidgetBase {
14851
15066
  * @param localData
14852
15067
  */
14853
15068
  onRefreshUserData(localData) {
14854
- this.savedData = this.sdkApi.getCardServerData(this.cardId);
14855
- this.localData = extend({}, this.savedData ?? {}, localData);
15069
+ super.onRefreshUserData(localData);
14856
15070
  this.state = null;
14857
15071
  if (this.isPromotionalCode) {
14858
- this.fetchPromoCode();
15072
+ this.initPromotionalCodeFromLocalData();
14859
15073
  }
14860
15074
  else {
14861
15075
  this.renderCodeView();
14862
15076
  this.renderCaptionView();
14863
15077
  }
14864
15078
  }
15079
+ onStart() {
15080
+ super.onStart();
15081
+ if (this.isPromotionalCode) {
15082
+ this.fetchPromoCode();
15083
+ }
15084
+ }
14865
15085
  isTransparentElement() {
14866
15086
  if (this.element) {
14867
15087
  try {
@@ -14943,17 +15163,23 @@ class WidgetBarcode extends WidgetBase {
14943
15163
  this.captionView.textContent = text;
14944
15164
  }
14945
15165
  }
14946
- fetchPromoCode() {
14947
- this.state = 0;
14948
- if (this.localData["_bc_g_" + this.elementId + "_pc"] !== undefined) {
15166
+ getPromotionalCodeFromLocalData() {
15167
+ return this.localData["_bc_g_" + this.elementId + "_pc"];
15168
+ }
15169
+ initPromotionalCodeFromLocalData() {
15170
+ if (this.getPromotionalCodeFromLocalData() !== undefined) {
14949
15171
  this.state = 1;
14950
- this.clipboardTarget = this.localData["_bc_g_" + this.elementId + "_pc"];
15172
+ this.clipboardTarget = this.getPromotionalCodeFromLocalData();
14951
15173
  if (this.clipboardTarget != null) {
14952
15174
  this.renderCaptionView();
14953
15175
  this.renderCodeView();
14954
15176
  }
14955
15177
  removeClass(this.element, "loader");
14956
15178
  }
15179
+ }
15180
+ fetchPromoCode() {
15181
+ this.state = 0;
15182
+ this.initPromotionalCodeFromLocalData();
14957
15183
  if (this.state === 0) {
14958
15184
  if (!this.isTransparentElement()) {
14959
15185
  // for transparent element
@@ -15039,12 +15265,14 @@ class WidgetBarcode extends WidgetBase {
15039
15265
  }
15040
15266
  _select() {
15041
15267
  this.element.classList.add("done");
15042
- if (this.disableTimer) {
15043
- // флаг - что таймер уже стартанул (в layout или добавить объект sharedMemory)
15044
- // смотрим что прозрачный текст - тогда и лоадер прозрачный
15045
- // _log("_showNarrativeNextSlide: " + getSlideDuration(this.narrativeId, this.slideIndex), true);
15046
- this.startDisabledTimeline();
15047
- }
15268
+ this.startReadyPromise.then(() => {
15269
+ if (this.disableTimer) {
15270
+ // флаг - что таймер уже стартанул layout или добавить объект sharedMemory)
15271
+ // смотрим что прозрачный текст - тогда и лоадер прозрачный
15272
+ // _log("_showNarrativeNextSlide: " + getSlideDuration(this.narrativeId, this.slideIndex), true);
15273
+ this.startDisabledTimeline();
15274
+ }
15275
+ });
15048
15276
  if (this.copiedText) {
15049
15277
  this.sdkApi.showToast(this.copiedText);
15050
15278
  }
@@ -15075,7 +15303,15 @@ class WidgetBarcode extends WidgetBase {
15075
15303
  },
15076
15304
  /** @deprecated */
15077
15305
  initWidget: function (nodeList, localData) {
15078
- WidgetBarcode.initWidgets((element, options) => new WidgetBarcode(element, options), slice.call(nodeList), localData);
15306
+ const elements = slice.call(nodeList);
15307
+ WidgetBarcode.initWidgets((element, options) => new WidgetBarcode(element, options), elements, localData);
15308
+ elements.forEach(element => WidgetBarcode.getInstance(element)?.onStart());
15309
+ },
15310
+ onStart: function (element) {
15311
+ WidgetBarcode.getInstance(element)?.onStart();
15312
+ },
15313
+ onStop: function (element) {
15314
+ WidgetBarcode.getInstance(element)?.onStop();
15079
15315
  },
15080
15316
  click: function (element) {
15081
15317
  const widgetElement = element.closest(`.${WidgetBarcode.widgetClassName}`);
@@ -15099,6 +15335,1045 @@ class WidgetBarcode extends WidgetBase {
15099
15335
  static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
15100
15336
  }
15101
15337
 
15338
+ class Formatter {
15339
+ intlSupport = false;
15340
+ defaultTimeFormat = "medium";
15341
+ defaultDatetimeFormat = "medium";
15342
+ defaultDateFormat = "medium";
15343
+ decimalSeparator = ".";
15344
+ thousandSeparator = "&thinsp;";
15345
+ spaceSeparator = "&thinsp;";
15346
+ static Second = 1000;
15347
+ static Minute = 60 * Formatter.Second;
15348
+ static Hour = 60 * Formatter.Minute;
15349
+ static Day = 24 * Formatter.Hour;
15350
+ datetimeFormatOptions = {
15351
+ short: {
15352
+ year: "numeric",
15353
+ month: "2-digit",
15354
+ day: "2-digit",
15355
+ hour: "2-digit",
15356
+ minute: "2-digit",
15357
+ },
15358
+ medium: {
15359
+ year: "numeric",
15360
+ month: "2-digit",
15361
+ day: "2-digit",
15362
+ hour: "2-digit",
15363
+ minute: "2-digit",
15364
+ second: "2-digit",
15365
+ },
15366
+ long: {
15367
+ year: "numeric",
15368
+ month: "long",
15369
+ day: "2-digit",
15370
+ hour: "2-digit",
15371
+ minute: "2-digit",
15372
+ second: "2-digit",
15373
+ timeZoneName: "short",
15374
+ },
15375
+ full: {
15376
+ weekday: "long",
15377
+ year: "numeric",
15378
+ month: "long",
15379
+ day: "2-digit",
15380
+ hour: "2-digit",
15381
+ minute: "2-digit",
15382
+ second: "2-digit",
15383
+ timeZoneName: "long",
15384
+ },
15385
+ };
15386
+ dateFormatOptions = {
15387
+ short: {
15388
+ year: "2-digit",
15389
+ month: "2-digit",
15390
+ day: "2-digit",
15391
+ },
15392
+ medium: {
15393
+ year: "numeric",
15394
+ month: "2-digit",
15395
+ day: "2-digit",
15396
+ },
15397
+ long: {
15398
+ year: "numeric",
15399
+ month: "long",
15400
+ day: "2-digit",
15401
+ },
15402
+ full: {
15403
+ weekday: "long",
15404
+ year: "numeric",
15405
+ month: "long",
15406
+ day: "2-digit",
15407
+ },
15408
+ };
15409
+ timeFormatOptions = {
15410
+ short: {
15411
+ hour: "2-digit",
15412
+ minute: "2-digit",
15413
+ },
15414
+ medium: {
15415
+ hour: "2-digit",
15416
+ minute: "2-digit",
15417
+ second: "2-digit",
15418
+ },
15419
+ long: {
15420
+ hour: "2-digit",
15421
+ minute: "2-digit",
15422
+ second: "2-digit",
15423
+ timeZoneName: "short",
15424
+ },
15425
+ full: {
15426
+ hour: "2-digit",
15427
+ minute: "2-digit",
15428
+ second: "2-digit",
15429
+ timeZoneName: "long",
15430
+ },
15431
+ };
15432
+ context;
15433
+ constructor(context) {
15434
+ this.intlSupport = typeof Intl === "object" && Intl !== null;
15435
+ this.context = context;
15436
+ }
15437
+ asDate(value, format = undefined, options = {}) {
15438
+ if (!format) {
15439
+ format = this.defaultDateFormat;
15440
+ }
15441
+ return this.formatDateTimeValue(value, format, "date", options);
15442
+ }
15443
+ asTime(value, format = undefined, options = {}) {
15444
+ if (!format) {
15445
+ format = this.defaultTimeFormat;
15446
+ }
15447
+ return this.formatDateTimeValue(value, format, "time", options);
15448
+ }
15449
+ asDatetime(value, format = undefined, options = {}) {
15450
+ if (!format) {
15451
+ format = this.defaultTimeFormat;
15452
+ }
15453
+ return this.formatDateTimeValue(value, format, "datetime", options);
15454
+ }
15455
+ formatDateTimeValue(value, format = undefined, type = undefined, options = {}) {
15456
+ const normalizedValue = Formatter.normalizeDatetimeValue(value);
15457
+ if (normalizedValue === null) {
15458
+ return "";
15459
+ }
15460
+ if (this.intlSupport) {
15461
+ let formatterOptions = {};
15462
+ if (type === "date") {
15463
+ if (typeof format === "undefined") {
15464
+ format = this.defaultDateFormat;
15465
+ }
15466
+ if (typeof format === "object") {
15467
+ formatterOptions = format;
15468
+ }
15469
+ else {
15470
+ if (format in this.dateFormatOptions) {
15471
+ formatterOptions = this.dateFormatOptions[format];
15472
+ }
15473
+ else {
15474
+ return this.momentFallback(normalizedValue, format, options);
15475
+ }
15476
+ }
15477
+ }
15478
+ else if (type === "time") {
15479
+ if (typeof format === "undefined") {
15480
+ format = this.defaultTimeFormat;
15481
+ }
15482
+ if (typeof format === "object") {
15483
+ formatterOptions = format;
15484
+ }
15485
+ else {
15486
+ if (format in this.timeFormatOptions) {
15487
+ formatterOptions = this.timeFormatOptions[format];
15488
+ }
15489
+ else {
15490
+ return this.momentFallback(normalizedValue, format, options);
15491
+ }
15492
+ }
15493
+ }
15494
+ else if (type === "datetime") {
15495
+ if (typeof format === "undefined") {
15496
+ format = this.defaultDatetimeFormat;
15497
+ }
15498
+ if (typeof format === "object") {
15499
+ formatterOptions = format;
15500
+ }
15501
+ else {
15502
+ if (format in this.datetimeFormatOptions) {
15503
+ formatterOptions = this.datetimeFormatOptions[format];
15504
+ }
15505
+ else {
15506
+ return this.momentFallback(normalizedValue, format, options);
15507
+ }
15508
+ }
15509
+ }
15510
+ if (options.timezone) {
15511
+ formatterOptions.timeZone = options.timezone;
15512
+ }
15513
+ Intl.DateTimeFormat(this.locale, formatterOptions).format(normalizedValue);
15514
+ return Intl.DateTimeFormat(this.locale, formatterOptions).format(normalizedValue);
15515
+ }
15516
+ return "";
15517
+ }
15518
+ momentFallback(value, format, options = {}) {
15519
+ return value.toLocaleString(this.locale);
15520
+ // return this.context.$moment(value).format(format);
15521
+ }
15522
+ asInteger(value) {
15523
+ if (value === undefined || value === null) {
15524
+ return this.nullDisplay;
15525
+ }
15526
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15527
+ if (this.intlSupport) {
15528
+ return Intl.NumberFormat(this.locale, {
15529
+ maximumFractionDigits: 0,
15530
+ useGrouping: true,
15531
+ }).format(normalizedValue);
15532
+ }
15533
+ return Formatter.numberFormat(normalizedValue, 0, this.decimalSeparator, this.thousandSeparator);
15534
+ }
15535
+ asDecimal(value, decimals = 2) {
15536
+ if (value == null) {
15537
+ return this.nullDisplay;
15538
+ }
15539
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15540
+ if (this.intlSupport) {
15541
+ return Intl.NumberFormat(this.locale, {
15542
+ maximumFractionDigits: decimals,
15543
+ minimumFractionDigits: decimals,
15544
+ useGrouping: true,
15545
+ }).format(normalizedValue);
15546
+ }
15547
+ return Formatter.numberFormat(normalizedValue, decimals, this.decimalSeparator, this.thousandSeparator);
15548
+ }
15549
+ asDecimalMax(value, decimals = 2) {
15550
+ if (value === undefined || value === null) {
15551
+ return this.nullDisplay;
15552
+ }
15553
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15554
+ if (this.intlSupport) {
15555
+ return Intl.NumberFormat(this.locale, {
15556
+ maximumFractionDigits: decimals,
15557
+ minimumFractionDigits: 0,
15558
+ useGrouping: true,
15559
+ }).format(normalizedValue);
15560
+ }
15561
+ return Formatter.numberFormat(normalizedValue, decimals, this.decimalSeparator, this.thousandSeparator);
15562
+ }
15563
+ asPercent(value, decimals = 0) {
15564
+ if (value === undefined || value === null) {
15565
+ return this.nullDisplay;
15566
+ }
15567
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15568
+ if (this.intlSupport) {
15569
+ return Intl.NumberFormat(this.locale, {
15570
+ style: "percent",
15571
+ maximumFractionDigits: decimals,
15572
+ minimumFractionDigits: decimals,
15573
+ }).format(normalizedValue);
15574
+ }
15575
+ return Formatter.numberFormat(normalizedValue * 100, decimals, this.decimalSeparator, this.thousandSeparator);
15576
+ }
15577
+ asPercentMax(value, decimals = 0) {
15578
+ if (value === undefined || value === null) {
15579
+ return this.nullDisplay;
15580
+ }
15581
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15582
+ if (this.intlSupport) {
15583
+ return Intl.NumberFormat(this.locale, {
15584
+ style: "percent",
15585
+ maximumFractionDigits: decimals,
15586
+ minimumFractionDigits: 0,
15587
+ }).format(normalizedValue);
15588
+ }
15589
+ return Formatter.numberFormat(normalizedValue * 100, decimals, this.decimalSeparator, this.thousandSeparator);
15590
+ }
15591
+ asRelativeTime(value, referenceTime = undefined) {
15592
+ if (value === undefined || value === null) {
15593
+ return this.nullDisplay;
15594
+ }
15595
+ const normalizedValue = Formatter.normalizeDatetimeValue(value);
15596
+ if (normalizedValue == null) {
15597
+ return this.nullDisplay;
15598
+ }
15599
+ if (referenceTime === undefined || referenceTime === null) {
15600
+ referenceTime = new Date();
15601
+ }
15602
+ else {
15603
+ referenceTime = Formatter.normalizeDatetimeValue(value);
15604
+ }
15605
+ const dt = referenceTime.getTime() - normalizedValue.getTime();
15606
+ const absDt = Math.abs(dt);
15607
+ const invert = dt < 0;
15608
+ if (absDt < Formatter.Second) {
15609
+ return this.context.i18n?.t("format.relativeTime.justNow").toString() ?? "";
15610
+ }
15611
+ const seconds = absDt / 1000;
15612
+ let interval = seconds / 31536000;
15613
+ if (interval > 1) {
15614
+ return this.context.i18n?.tc("format.relativeTime.year" + (invert ? "In" : "Ago"), Math.floor(interval)).toString() ?? "";
15615
+ }
15616
+ interval = seconds / 2592000;
15617
+ if (interval > 1) {
15618
+ return this.context.i18n?.tc("format.relativeTime.month" + (invert ? "In" : "Ago"), Math.floor(interval)).toString() ?? "";
15619
+ }
15620
+ interval = seconds / 86400;
15621
+ if (interval > 1) {
15622
+ return this.context.i18n?.tc("format.relativeTime.day" + (invert ? "In" : "Ago"), Math.floor(interval)).toString() ?? "";
15623
+ }
15624
+ interval = seconds / 3600;
15625
+ if (interval > 1) {
15626
+ return this.context.i18n?.tc("format.relativeTime.hour" + (invert ? "In" : "Ago"), Math.floor(interval)).toString() ?? "";
15627
+ }
15628
+ interval = seconds / 60;
15629
+ if (interval > 1) {
15630
+ return this.context.i18n?.tc("format.relativeTime.minute" + (invert ? "In" : "Ago"), Math.floor(interval)).toString() ?? "";
15631
+ }
15632
+ return this.context.i18n?.tc("format.relativeTime.second" + (invert ? "In" : "Ago"), Math.floor(seconds)).toString() ?? "";
15633
+ }
15634
+ asDuration(value) {
15635
+ if (value === undefined || value === null) {
15636
+ return "00:00";
15637
+ }
15638
+ const normalizedValue = Formatter.normalizeDatetimeValue(value);
15639
+ if (normalizedValue === undefined || normalizedValue === null) {
15640
+ return "00:00";
15641
+ }
15642
+ const hours = Math.floor(value / 3600);
15643
+ const minutes = Math.floor((value / 60) % 60);
15644
+ const seconds = value % 60;
15645
+ if (hours > 0) {
15646
+ return `${hours}:${minutes < 10 ? 0 : ""}${minutes}:${seconds < 10 ? 0 : ""}${seconds}`;
15647
+ }
15648
+ else {
15649
+ return `${minutes < 10 ? 0 : ""}${minutes}:${seconds < 10 ? 0 : ""}${seconds}`;
15650
+ }
15651
+ }
15652
+ asCurrency(value, currency = undefined) {
15653
+ if (value === undefined || value === null) {
15654
+ return this.nullDisplay;
15655
+ }
15656
+ if (currency === undefined || currency === null) {
15657
+ currency = "USD";
15658
+ }
15659
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15660
+ if (normalizedValue == null) {
15661
+ return this.nullDisplay;
15662
+ }
15663
+ let decimals = 2;
15664
+ if (Number.isInteger(normalizedValue)) {
15665
+ decimals = 0;
15666
+ }
15667
+ if (currency === "RUR" || currency === "RUB") {
15668
+ return `${this.asDecimal(normalizedValue, decimals)}${this.spaceSeparator}₽`;
15669
+ }
15670
+ if (this.intlSupport) {
15671
+ try {
15672
+ return Intl.NumberFormat(this.locale, {
15673
+ style: "currency",
15674
+ currency,
15675
+ currencyDisplay: "symbol",
15676
+ maximumFractionDigits: decimals,
15677
+ minimumFractionDigits: decimals,
15678
+ }).format(normalizedValue);
15679
+ }
15680
+ catch (e) {
15681
+ console.error(e);
15682
+ return String(normalizedValue);
15683
+ }
15684
+ }
15685
+ return currency + "&thinsp;" + this.asDecimal(normalizedValue, 2);
15686
+ }
15687
+ asShortSizeCasual(value, dp = 1) {
15688
+ if (value === undefined || value === null) {
15689
+ return this.nullDisplay;
15690
+ }
15691
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15692
+ if (normalizedValue === undefined || normalizedValue === null) {
15693
+ return this.nullDisplay;
15694
+ }
15695
+ const thresh = 1024;
15696
+ if (Math.abs(value) < thresh) {
15697
+ return value + " B";
15698
+ }
15699
+ const units = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
15700
+ let u = -1;
15701
+ const r = 10 ** dp;
15702
+ do {
15703
+ value /= thresh;
15704
+ ++u;
15705
+ } while (Math.round(Math.abs(value) * r) / r >= thresh && u < units.length - 1);
15706
+ return value.toFixed(dp) + " " + units[u];
15707
+ }
15708
+ asShortSize(value, si = false, dp = 1) {
15709
+ if (value === undefined || value === null) {
15710
+ return this.nullDisplay;
15711
+ }
15712
+ const normalizedValue = Formatter.normalizeNumericValue(value);
15713
+ if (normalizedValue === undefined || normalizedValue === null) {
15714
+ return this.nullDisplay;
15715
+ }
15716
+ const thresh = si ? 1000 : 1024;
15717
+ if (Math.abs(value) < thresh) {
15718
+ return value + " B";
15719
+ }
15720
+ const units = si ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
15721
+ let u = -1;
15722
+ const r = 10 ** dp;
15723
+ do {
15724
+ value /= thresh;
15725
+ ++u;
15726
+ } while (Math.round(Math.abs(value) * r) / r >= thresh && u < units.length - 1);
15727
+ return value.toFixed(dp) + " " + units[u];
15728
+ }
15729
+ static numberFormat(value, decimals = 0, decimalSeparator = ".", thousandsSeparator) {
15730
+ const sign = value < 0 ? "-" : "";
15731
+ const sNumber = Math.abs(parseInt((+value || 0).toFixed(decimals))) + "";
15732
+ const len = sNumber.length;
15733
+ const tchunk = len > 3 ? len % 3 : 0;
15734
+ const chFirst = tchunk ? sNumber.substr(0, tchunk) + thousandsSeparator : "";
15735
+ const chRest = sNumber.substr(tchunk).replace(/(\d\d\d)(?=\d)/g, "$1" + thousandsSeparator);
15736
+ const chLast = decimals ? decimalSeparator + (Math.abs(value) - parseFloat(sNumber)).toFixed(decimals).slice(2) : "";
15737
+ return sign + chFirst + chRest + chLast;
15738
+ }
15739
+ get nullDisplay() {
15740
+ return "";
15741
+ // if (this.context && this.context.i18n) {
15742
+ // return this.context.i18n.t("notSet").toString();
15743
+ // }
15744
+ //
15745
+ // return "not set";
15746
+ }
15747
+ static normalizeDatetimeValue(value) {
15748
+ const type = typeof value;
15749
+ if (type === "object" && value instanceof Date) {
15750
+ return value;
15751
+ }
15752
+ else if (type === "number") {
15753
+ return new Date(value);
15754
+ }
15755
+ else if (type === "string") {
15756
+ if (isNaN(value)) {
15757
+ return new Date(parseInt(value));
15758
+ }
15759
+ else {
15760
+ const d = Date.parse(value);
15761
+ if (isNaN(d)) {
15762
+ return null;
15763
+ }
15764
+ return new Date(d);
15765
+ }
15766
+ }
15767
+ return null;
15768
+ }
15769
+ static normalizeNumericValue(value) {
15770
+ const type = typeof value;
15771
+ if ((type === "object" && value === null) || type === "undefined") {
15772
+ return 0;
15773
+ }
15774
+ else if (type === "number") {
15775
+ return value;
15776
+ }
15777
+ return parseFloat(value);
15778
+ }
15779
+ get locale() {
15780
+ return this.context.determineLocale();
15781
+ }
15782
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`{\n determineLocale: () => string;\n i18n: { t: (key: string) => string; tc: (key: string, value: string | number) => string } | undefined;\n }`]; }
15783
+ }
15784
+ const formatter = new Formatter({ determineLocale, i18n: undefined });
15785
+
15786
+ class SwipeGestureDetector {
15787
+ env;
15788
+ isScreenSupportsTouch;
15789
+ canContinueHandleDown;
15790
+ onStart;
15791
+ onUpdate;
15792
+ onEnd;
15793
+ constructor(env, isScreenSupportsTouch, canContinueHandleDown, onStart, onUpdate, onEnd) {
15794
+ this.env = env;
15795
+ this.isScreenSupportsTouch = isScreenSupportsTouch;
15796
+ this.canContinueHandleDown = canContinueHandleDown;
15797
+ this.onStart = onStart;
15798
+ this.onUpdate = onUpdate;
15799
+ this.onEnd = onEnd;
15800
+ // Store context
15801
+ this.handleDown = this.handleDown.bind(this);
15802
+ this.handleMove = this.handleMove.bind(this);
15803
+ this.handleEnd = this.handleEnd.bind(this);
15804
+ this.supportsTouch = false;
15805
+ if (this.isScreenSupportsTouch) {
15806
+ this.env.document.addEventListener("touchstart", this.handleDown, false);
15807
+ }
15808
+ else {
15809
+ this.env.document.addEventListener("mousedown", this.handleDown, false);
15810
+ }
15811
+ }
15812
+ startPageCoordinate = [0, 0];
15813
+ limit = Math.tan(((45 * 1.5) / 180) * Math.PI);
15814
+ pageWidth = window.innerWidth || document.body.clientWidth;
15815
+ threshold = Math.max(1, Math.floor(0.01 * this.pageWidth));
15816
+ supportsTouch = false;
15817
+ handleDown(e) {
15818
+ if (!this.canContinueHandleDown(e)) {
15819
+ return;
15820
+ }
15821
+ this.startPageCoordinate = this.getPageCoordinate(e);
15822
+ if (this.isScreenSupportsTouch) {
15823
+ this.env.document.addEventListener("touchmove", this.handleMove, false);
15824
+ this.env.document.addEventListener("touchend", this.handleEnd, false);
15825
+ }
15826
+ else {
15827
+ this.env.document.addEventListener("mousemove", this.handleMove, false);
15828
+ this.env.document.addEventListener("mouseup", this.handleEnd, false);
15829
+ }
15830
+ this.onStart(e);
15831
+ }
15832
+ handleMove(e) {
15833
+ // console.log("handleMove", { startPageCoordinate: this.startPageCoordinate})
15834
+ // this.currentPageCoordinate = this.getPageCoordinate(e);
15835
+ this.onUpdate(e);
15836
+ }
15837
+ handleEnd(e) {
15838
+ if (this.isScreenSupportsTouch) {
15839
+ this.env.document.removeEventListener("touchmove", this.handleMove);
15840
+ this.env.document.removeEventListener("touchend", this.handleEnd);
15841
+ }
15842
+ else {
15843
+ this.env.document.removeEventListener("mousemove", this.handleMove);
15844
+ this.env.document.removeEventListener("mouseup", this.handleEnd);
15845
+ }
15846
+ const currentPageCoordinate = this.getPageCoordinate(e);
15847
+ let gesture = 0 /* SwipeGesture.undefined */;
15848
+ const x = currentPageCoordinate[0] - this.startPageCoordinate[0];
15849
+ const y = currentPageCoordinate[1] - this.startPageCoordinate[1];
15850
+ // console.log("handleEnd", {currentPageCoordinate, startPageCoordinate: this.startPageCoordinate})
15851
+ let xy = Math.abs(x / y);
15852
+ let yx = Math.abs(y / x);
15853
+ if (Math.abs(x) > this.threshold || Math.abs(y) > this.threshold) {
15854
+ if (yx <= this.limit) {
15855
+ if (x < 0) {
15856
+ gesture = 4 /* SwipeGesture.SwipeLeft */;
15857
+ // @ts-ignore
15858
+ // _log(JSON.stringify({t: "SwipeLeft", yx, x, threshold: this.threshold}), true);
15859
+ }
15860
+ else {
15861
+ // @ts-ignore
15862
+ // _log(JSON.stringify({t: "SwipeRight", yx, x, threshold: this.threshold}), true);
15863
+ gesture = 5 /* SwipeGesture.SwipeRight */;
15864
+ }
15865
+ }
15866
+ if (xy <= this.limit) {
15867
+ if (y < 0) {
15868
+ // @ts-ignore
15869
+ // _log(JSON.stringify({t: "SwipeUp", xy, y, threshold: this.threshold}), true);
15870
+ gesture = 2 /* SwipeGesture.SwipeUp */;
15871
+ }
15872
+ else {
15873
+ // @ts-ignore
15874
+ // _log(JSON.stringify({t: "SwipeDown", xy, y, threshold: this.threshold}), true);
15875
+ gesture = 3 /* SwipeGesture.SwipeDown */;
15876
+ }
15877
+ }
15878
+ }
15879
+ else {
15880
+ // @ts-ignore
15881
+ // _log(JSON.stringify({t: "Tap", x, y, threshold: this.threshold}), true);
15882
+ gesture = 1 /* SwipeGesture.Tap */;
15883
+ }
15884
+ this.onEnd(e, gesture);
15885
+ }
15886
+ destroy() {
15887
+ if (this.isScreenSupportsTouch) {
15888
+ this.env.document.removeEventListener("touchstart", this.handleDown);
15889
+ }
15890
+ else {
15891
+ this.env.document.removeEventListener("mousedown", this.handleDown);
15892
+ }
15893
+ }
15894
+ getPageCoordinate(e) {
15895
+ let x = 0;
15896
+ let y = 0;
15897
+ if (e["clientX"] != null && e["clientY"] != null) {
15898
+ x = e["clientX"];
15899
+ y = e["clientY"];
15900
+ }
15901
+ else if (e.touches &&
15902
+ e.touches[0] &&
15903
+ e.touches[0]["clientX"] != null &&
15904
+ e.touches[0]["clientY"] != null) {
15905
+ x = e.touches[0]["clientX"];
15906
+ y = e.touches[0]["clientY"];
15907
+ }
15908
+ else if (e.changedTouches &&
15909
+ e.changedTouches[0] &&
15910
+ e.changedTouches[0]["clientX"] != null &&
15911
+ e.changedTouches[0]["clientY"] != null) {
15912
+ x = e.changedTouches[0]["clientX"];
15913
+ y = e.changedTouches[0]["clientY"];
15914
+ }
15915
+ // @ts-ignore
15916
+ else if (e.currentPoint && e.currentPoint["x"] != null && e.currentPoint["y"] != null) {
15917
+ // @ts-ignore
15918
+ x = e.currentPoint["x"];
15919
+ // @ts-ignore
15920
+ y = e.currentPoint["y"];
15921
+ }
15922
+ return [x, y];
15923
+ }
15924
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`Window`, `boolean`, `(e: MouseEvent | TouchEvent) => boolean`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent, gesture: SwipeGesture) => void`]; }
15925
+ }
15926
+
15927
+ /**
15928
+ * adult: null
15929
+ * availability: 1
15930
+ * coverUrl: "https://cdn.test.inappstory.com/np/file/cf/wb/wc/vcaji5clqon3nkwdwle3cjz63x.jpg?k=KgAAAAAAAAACAQ"
15931
+ * currency: "RUR"
15932
+ * description: "Непромокаемый комбинезон - дождевик детский Муссон"
15933
+ * id: 204
15934
+ * name: "Непромокаемый комбинезон - дождевик детский \"Муссон\""
15935
+ * offerId: "10125"
15936
+ * oldPrice: null
15937
+ * price: "2690.0000"
15938
+ * url: "http://www.songnomik.ru/products/detskaya-odezhda-optom-dlya-novorozhdennyh/detskie-kombinezony-optom/2166483.html"
15939
+ */
15940
+ class WidgetProducts extends WidgetBase {
15941
+ static DEFAULTS = {
15942
+ slide: null,
15943
+ activateAfterCreate: false,
15944
+ create: false,
15945
+ localData: {},
15946
+ };
15947
+ static widgetClassName = "narrative-element-products";
15948
+ captionView;
15949
+ linkTarget = [];
15950
+ msgNetworkError;
15951
+ msgServiceError;
15952
+ swipeGestureDetector = null;
15953
+ isClickCapturedByWidget = false;
15954
+ isScreenSupportsTouch = false;
15955
+ constructor(element, options) {
15956
+ super(element, options);
15957
+ this.captionView = this.element.querySelector(".narrative-element-text-lines");
15958
+ const linkTarget = decodeURIComponent(getTagData(element, "linkTarget") ?? "[]");
15959
+ try {
15960
+ let parsed = JSON.parse(linkTarget);
15961
+ if (Array.isArray(parsed)) {
15962
+ this.linkTarget = parsed.filter(FilterNumber);
15963
+ }
15964
+ }
15965
+ catch (e) {
15966
+ console.error(e);
15967
+ }
15968
+ this.isScreenSupportsTouch = isScreenSupportsTouch(this.env);
15969
+ this.msgNetworkError = getTagData(this.element, "msgNetworkError");
15970
+ this.msgServiceError = getTagData(this.element, "msgServiceError");
15971
+ }
15972
+ /**
15973
+ * Start or restart widget
15974
+ * @param localData
15975
+ */
15976
+ onRefreshUserData(localData) {
15977
+ super.onRefreshUserData(localData);
15978
+ }
15979
+ onStart() {
15980
+ super.onStart();
15981
+ // reinit for case when we returned to slide from other slide and onStop destroyed SwipeGestureDetector
15982
+ this.initSwipeGestureDetector();
15983
+ }
15984
+ isTransparentElement() {
15985
+ if (this.element) {
15986
+ try {
15987
+ const color = window.getComputedStyle(this.element).color;
15988
+ if (color === "transparent" || color === "rgba(0, 0, 0, 0)" || color === "rgba(0,0,0,0)") {
15989
+ return true;
15990
+ }
15991
+ }
15992
+ catch (err) {
15993
+ console.error(err);
15994
+ }
15995
+ }
15996
+ return false;
15997
+ }
15998
+ _statEventWidgetClick() {
15999
+ try {
16000
+ const captionViewText = this.captionView?.textContent ?? "";
16001
+ this.sendStatisticEventToApp("w-products-click", {
16002
+ ...this.statisticEventBaseFieldsShortForm,
16003
+ wi: this.elementId,
16004
+ wl: captionViewText,
16005
+ wv: this.linkTarget,
16006
+ }, {
16007
+ ...this.statisticEventBaseFieldsShortForm,
16008
+ widget_id: this.elementId,
16009
+ widget_label: captionViewText,
16010
+ widget_value: this.linkTarget,
16011
+ }, {
16012
+ forceEnableStatisticV2: true,
16013
+ });
16014
+ }
16015
+ catch (error) {
16016
+ console.error(error);
16017
+ }
16018
+ }
16019
+ _statEventWidgetOpen(offers) {
16020
+ try {
16021
+ const captionViewText = this.captionView?.textContent ?? "";
16022
+ this.sendStatisticEventToApp("w-products-open", {
16023
+ ...this.statisticEventBaseFieldsShortForm,
16024
+ wi: this.elementId,
16025
+ wl: captionViewText,
16026
+ wv: this.linkTarget,
16027
+ wit: offers.map(item => item.offerId),
16028
+ }, {
16029
+ ...this.statisticEventBaseFieldsShortForm,
16030
+ widget_id: this.elementId,
16031
+ widget_label: captionViewText,
16032
+ widget_value: this.linkTarget,
16033
+ widget_items: offers.map(item => item.offerId),
16034
+ }, {
16035
+ forceEnableStatisticV2: true,
16036
+ });
16037
+ }
16038
+ catch (error) {
16039
+ console.error(error);
16040
+ }
16041
+ }
16042
+ _statEventWidgetCardClick(offer) {
16043
+ try {
16044
+ const captionViewText = this.captionView?.textContent ?? "";
16045
+ this.sendStatisticEventToApp("w-products-card-click", {
16046
+ ...this.statisticEventBaseFieldsShortForm,
16047
+ wi: this.elementId,
16048
+ wl: captionViewText,
16049
+ wv: offer.offerId,
16050
+ wvi: offer.id,
16051
+ }, {
16052
+ ...this.statisticEventBaseFieldsShortForm,
16053
+ widget_id: this.elementId,
16054
+ widget_label: captionViewText,
16055
+ widget_value: offer.offerId,
16056
+ widget_value_id: offer.id,
16057
+ }, {
16058
+ forceEnableStatisticV2: true,
16059
+ });
16060
+ }
16061
+ catch (error) {
16062
+ console.error(error);
16063
+ }
16064
+ }
16065
+ async fetchProducts() {
16066
+ const fetchAndCacheMedia = async () => {
16067
+ if (!this.linkTarget.length) {
16068
+ return { message: this.msgServiceError ?? "", models: [] };
16069
+ }
16070
+ const path = `product/offer?id=${this.linkTarget.join(",")}`;
16071
+ const headers = {
16072
+ accept: "application/json",
16073
+ "Content-Type": "application/json",
16074
+ };
16075
+ const profileKey = "fetch-products";
16076
+ try {
16077
+ const response = await this.sdkApi.sendApiRequest(path, "GET", null, headers, null, profileKey);
16078
+ // console.log({response});
16079
+ const status = response.status;
16080
+ if (status === 200 || status === 201) {
16081
+ if (response.data && Array.isArray(response.data) && response.data.length > 0) {
16082
+ try {
16083
+ await this.cacheOffersMediaResources(response.data);
16084
+ }
16085
+ catch (error) {
16086
+ console.error(error);
16087
+ }
16088
+ return { message: "", models: response.data };
16089
+ }
16090
+ else {
16091
+ return { message: this.msgServiceError ?? "", models: [] };
16092
+ }
16093
+ }
16094
+ else if (status === 12163 || status === 12002) {
16095
+ return { message: this.msgNetworkError ?? "", models: [] };
16096
+ }
16097
+ else {
16098
+ return { message: this.msgServiceError ?? "", models: [] };
16099
+ }
16100
+ }
16101
+ catch (error) {
16102
+ console.error(error);
16103
+ return { message: this.msgServiceError ?? "", models: [] };
16104
+ }
16105
+ };
16106
+ return Promise.all([
16107
+ fetchAndCacheMedia(),
16108
+ new Promise(t => {
16109
+ return setTimeout(t, 200);
16110
+ }),
16111
+ ]).then(([result]) => result);
16112
+ }
16113
+ cacheOffersMediaResources(offers) {
16114
+ const cacheItem = (offer) => {
16115
+ return new Promise(resolve => {
16116
+ if (offer.coverUrl != null) {
16117
+ this.env
16118
+ .fetch(offer.coverUrl)
16119
+ .then(response => {
16120
+ if (response != null && response.ok) {
16121
+ response
16122
+ .blob()
16123
+ .then(blob => {
16124
+ offer.coverUrl = URL.createObjectURL(blob);
16125
+ resolve();
16126
+ })
16127
+ .catch(resolve);
16128
+ }
16129
+ else {
16130
+ resolve();
16131
+ }
16132
+ })
16133
+ .catch(resolve);
16134
+ }
16135
+ else {
16136
+ resolve();
16137
+ }
16138
+ });
16139
+ };
16140
+ const promises = offers.map(cacheItem);
16141
+ return Promise.all(promises);
16142
+ }
16143
+ revokeOffersMediaResources(offers) {
16144
+ offers.forEach(offer => {
16145
+ if (offer.coverUrl != null) {
16146
+ // todo check if coverUrl really is object URL
16147
+ URL.revokeObjectURL(offer.coverUrl);
16148
+ }
16149
+ });
16150
+ }
16151
+ initSwipeGestureDetector() {
16152
+ if (this.isOpen) {
16153
+ this.swipeGestureDetector = new SwipeGestureDetector(this.env, this.isScreenSupportsTouch, () => true, e => {
16154
+ // this.isClickCapturedByWidget = true;
16155
+ return;
16156
+ }, e => {
16157
+ return;
16158
+ }, (e, gesture) => {
16159
+ if (gesture === 3 /* SwipeGesture.SwipeDown */) {
16160
+ this.closeProductsView();
16161
+ }
16162
+ // this.env.requestAnimationFrame(() => {
16163
+ // this.isClickCapturedByWidget = false;
16164
+ // });
16165
+ });
16166
+ }
16167
+ }
16168
+ productsView = null;
16169
+ isOpen = false;
16170
+ currentModels = [];
16171
+ async openProductsView() {
16172
+ if (this.isOpen) {
16173
+ return;
16174
+ }
16175
+ this._statEventWidgetClick();
16176
+ if (!this.disableTimer) {
16177
+ this.sdkApi.pauseUI();
16178
+ }
16179
+ if (!this.isTransparentElement()) {
16180
+ this.element.classList.add("loader");
16181
+ }
16182
+ // const start = window.performance.now();
16183
+ const result = await this.fetchProducts();
16184
+ // @ts-ignore
16185
+ // _log(`fetched for ${window.performance.now() - start}ms`, true);
16186
+ // console.log({result})
16187
+ if (result.models.length > 0) {
16188
+ this.currentModels = result.models;
16189
+ this.productsView = this.createProductsView(this.currentModels, this.closeProductsView.bind(this));
16190
+ this.productsView.classList.add("ias-products-container-view--visible");
16191
+ this.slide.appendChild(this.productsView);
16192
+ this.element.classList.add("hidden");
16193
+ this.isOpen = true;
16194
+ // prevent next slide navigation gesture
16195
+ this.isClickCapturedByWidget = true;
16196
+ this.sdkApi.disableVerticalSwipeGesture();
16197
+ this.sdkApi.disableBackpress();
16198
+ this._statEventWidgetOpen(this.currentModels);
16199
+ this.initSwipeGestureDetector();
16200
+ }
16201
+ else {
16202
+ if (result.message) {
16203
+ this.sdkApi.showToast(result.message);
16204
+ }
16205
+ }
16206
+ this.element.classList.remove("loader");
16207
+ }
16208
+ closeProductsView() {
16209
+ if (!this.isOpen) {
16210
+ return;
16211
+ }
16212
+ this.productsView?.classList.add("ias-products-container-view--hidden");
16213
+ this.element.classList.remove("hidden");
16214
+ this.isClickCapturedByWidget = false;
16215
+ if (this.swipeGestureDetector != null) {
16216
+ this.swipeGestureDetector.destroy();
16217
+ }
16218
+ this.sdkApi.enableVerticalSwipeGesture();
16219
+ this.sdkApi.enableBackpress();
16220
+ const onClosed = () => {
16221
+ this.productsView?.removeEventListener("animationend", onClosed);
16222
+ this.productsView?.parentElement?.removeChild(this.productsView);
16223
+ this.revokeOffersMediaResources(this.currentModels);
16224
+ if (!this.disableTimer) {
16225
+ this.sdkApi.resumeUI();
16226
+ }
16227
+ this.isOpen = false;
16228
+ this.currentModels = [];
16229
+ };
16230
+ this.productsView?.addEventListener("animationend", onClosed);
16231
+ }
16232
+ createCardView(offer) {
16233
+ const figure = document.createElement("div");
16234
+ figure.classList.add("ias-products-card-figure");
16235
+ if (offer.coverUrl) {
16236
+ // todo preload coverImage by fetch, save to offer.coverUrl via createUrl (add revoke)
16237
+ // if cannot fetch - skip caching
16238
+ const image = document.createElement("img");
16239
+ image.classList.add("ias-products-card-figure-image");
16240
+ image.alt = offer.name ?? "";
16241
+ image.src = offer.coverUrl;
16242
+ figure.appendChild(image);
16243
+ }
16244
+ // const subTitle = document.createElement("div");
16245
+ // subTitle.classList.add("ias-products-card-subtitle");
16246
+ // subTitle.innerText = offer.description ?? "";
16247
+ const title = document.createElement("div");
16248
+ title.classList.add("ias-products-card-title");
16249
+ title.innerText = offer.name ?? "";
16250
+ let price = null;
16251
+ if (offer.price) {
16252
+ price = document.createElement("div");
16253
+ price.classList.add("ias-products-card-price");
16254
+ price.innerHTML = formatter.asCurrency(offer.price, offer.currency);
16255
+ }
16256
+ let oldPrice = null;
16257
+ if (offer.oldPrice) {
16258
+ oldPrice = document.createElement("div");
16259
+ oldPrice.classList.add("ias-products-card-old-price");
16260
+ oldPrice.innerHTML = formatter.asCurrency(offer.oldPrice, offer.currency);
16261
+ }
16262
+ const prices = document.createElement("div");
16263
+ prices.classList.add("ias-products-card-prices");
16264
+ if (price) {
16265
+ prices.appendChild(price);
16266
+ }
16267
+ if (oldPrice) {
16268
+ prices.appendChild(oldPrice);
16269
+ }
16270
+ const card = document.createElement("div");
16271
+ card.classList.add("ias-products-card");
16272
+ card.onclick = () => {
16273
+ this._statEventWidgetCardClick(offer);
16274
+ if (offer.url) {
16275
+ this.sdkApi.openUrl(offer.url);
16276
+ }
16277
+ };
16278
+ card.appendChild(figure);
16279
+ // card.appendChild(subTitle);
16280
+ card.appendChild(prices);
16281
+ card.appendChild(title);
16282
+ return card;
16283
+ }
16284
+ createScrollView(offers) {
16285
+ const scrollView = document.createElement("div");
16286
+ scrollView.classList.add("ias-products-scroll-view");
16287
+ offers.forEach(offer => scrollView.appendChild(this.createCardView(offer)));
16288
+ return scrollView;
16289
+ }
16290
+ createProductsView(offers, onClose) {
16291
+ const containerView = document.createElement("div");
16292
+ containerView.classList.add("ias-products-container-view");
16293
+ const backdropView = document.createElement("div");
16294
+ backdropView.classList.add("ias-products-container-backdrop-view");
16295
+ backdropView.onclick = e => {
16296
+ e.preventDefault();
16297
+ e.stopPropagation();
16298
+ onClose();
16299
+ };
16300
+ const backgroundView = document.createElement("div");
16301
+ backgroundView.classList.add("ias-products-container-background-view");
16302
+ const scrollView = this.createScrollView(offers);
16303
+ const closeButton = document.createElement("div");
16304
+ closeButton.classList.add("ias-products-container-close-button");
16305
+ // fill=${ProductsWidgetOptionsDefault.productsList.closeBackgroundColor}
16306
+ closeButton.innerHTML = `<svg width="32" height="12.5" viewBox="0 0 64 25" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M56.293 1.23375C58.054 -0.41125 60.846 -0.41125 62.607 1.23375C64.464 2.96775 64.464 5.85675 62.607 7.59075L35.157 23.2288C33.396 24.8738 30.604 24.8738 28.843 23.2288L1.393 7.59075C0.494002 6.75175 0 5.62775 0 4.41275C0 3.19775 0.494002 2.07375 1.393 1.23475C3.154 -0.410251 5.946 -0.410251 7.707 1.23475L32 13.9237L56.293 1.23375Z" fill="currentColor" /></svg>`;
16307
+ closeButton.onclick = e => {
16308
+ e.preventDefault();
16309
+ e.stopPropagation();
16310
+ onClose();
16311
+ };
16312
+ backgroundView.appendChild(scrollView);
16313
+ backgroundView.appendChild(closeButton);
16314
+ containerView.appendChild(backdropView);
16315
+ containerView.appendChild(backgroundView);
16316
+ return containerView;
16317
+ }
16318
+ getIsClickCapturedByWidget() {
16319
+ return this.isClickCapturedByWidget;
16320
+ }
16321
+ destroy() {
16322
+ if (this.swipeGestureDetector != null) {
16323
+ this.swipeGestureDetector.destroy();
16324
+ this.swipeGestureDetector = null;
16325
+ }
16326
+ }
16327
+ onStop() {
16328
+ super.onStop();
16329
+ this.destroy();
16330
+ }
16331
+ static api = {
16332
+ widgetClassName: WidgetProducts.widgetClassName,
16333
+ onRefreshUserData: WidgetProducts.onRefreshUserData,
16334
+ init: function (element, localData) {
16335
+ WidgetProducts.initWidget(element, localData, (element, options) => new WidgetProducts(element, options));
16336
+ },
16337
+ onStart: function (element) {
16338
+ WidgetProducts.getInstance(element)?.onStart();
16339
+ },
16340
+ onStop: function (element) {
16341
+ WidgetProducts.getInstance(element)?.onStop();
16342
+ },
16343
+ click: function (element) {
16344
+ const widgetElement = element.closest(`.${WidgetProducts.widgetClassName}`);
16345
+ if (widgetElement) {
16346
+ const widget = WidgetProducts.getInstance(widgetElement);
16347
+ if (widget) {
16348
+ widget.openProductsView();
16349
+ }
16350
+ }
16351
+ return false;
16352
+ },
16353
+ isClickCapturedByWidget: function (element) {
16354
+ const widgetElement = element.closest(`.${WidgetProducts.widgetClassName}`);
16355
+ if (widgetElement) {
16356
+ const widget = WidgetProducts.getInstance(widgetElement);
16357
+ if (widget) {
16358
+ return widget.getIsClickCapturedByWidget();
16359
+ }
16360
+ }
16361
+ return false;
16362
+ },
16363
+ onHandleBackpress: function (element) {
16364
+ const widgetElement = element.closest(`.${WidgetProducts.widgetClassName}`);
16365
+ if (widgetElement) {
16366
+ const widget = WidgetProducts.getInstance(widgetElement);
16367
+ if (widget) {
16368
+ widget.closeProductsView();
16369
+ }
16370
+ }
16371
+ return false;
16372
+ },
16373
+ };
16374
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `Partial`]; }
16375
+ }
16376
+
15102
16377
  let sdkInterface;
15103
16378
  const getSlideApi = (_sdkInterface) => {
15104
16379
  sdkInterface = _sdkInterface;
@@ -15119,6 +16394,7 @@ const getSlideApi = (_sdkInterface) => {
15119
16394
  WidgetTest: WidgetTest.api,
15120
16395
  WidgetVote: WidgetVote.api,
15121
16396
  WidgetBarcode: WidgetBarcode.api,
16397
+ WidgetProducts: WidgetProducts.api,
15122
16398
  };
15123
16399
  };
15124
16400