@inappstory/slide-api 0.1.25 → 0.1.27
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 +1269 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -6
- package/dist/index.d.ts +95 -6
- package/dist/index.js +1269 -159
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1043,6 +1043,12 @@ class EsModuleSdkApi {
|
|
|
1043
1043
|
constructor(sdkBinding) {
|
|
1044
1044
|
this.sdkBinding = sdkBinding;
|
|
1045
1045
|
}
|
|
1046
|
+
onWidgetRequirePauseUI() {
|
|
1047
|
+
return this.sdkBinding.onWidgetRequirePauseUI();
|
|
1048
|
+
}
|
|
1049
|
+
onWidgetRequireResumeUI() {
|
|
1050
|
+
return this.sdkBinding.onWidgetRequireResumeUI();
|
|
1051
|
+
}
|
|
1046
1052
|
getCardServerData(cardId) {
|
|
1047
1053
|
return this.sdkBinding.getCardServerData(cardId);
|
|
1048
1054
|
}
|
|
@@ -1133,8 +1139,11 @@ class EsModuleSdkApi {
|
|
|
1133
1139
|
getCardSessionValue(element, key) {
|
|
1134
1140
|
return this.sdkBinding.getCardSessionValue(key);
|
|
1135
1141
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1142
|
+
isSdkSupportUpdateTimeline() {
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
|
|
1146
|
+
await this.sdkBinding.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
|
|
1138
1147
|
}
|
|
1139
1148
|
cardPausedCallback(currentTime) { }
|
|
1140
1149
|
cardResumedCallback(currentTime) { }
|
|
@@ -1177,12 +1186,87 @@ class EsModuleSdkApi {
|
|
|
1177
1186
|
this.sdkBinding.onEvent(name, event);
|
|
1178
1187
|
}
|
|
1179
1188
|
onCardLoadingStateChange(state, reason) {
|
|
1180
|
-
console.log("onCardLoadingStateChange", { state });
|
|
1189
|
+
// console.log("onCardLoadingStateChange", { state });
|
|
1181
1190
|
this.sdkBinding.onCardLoadingStateChange(state, reason);
|
|
1182
1191
|
}
|
|
1192
|
+
get isSdkSupportProductCart() {
|
|
1193
|
+
return true;
|
|
1194
|
+
}
|
|
1195
|
+
productCartUpdate(data) {
|
|
1196
|
+
return this.sdkBinding.productCartUpdate(data);
|
|
1197
|
+
}
|
|
1198
|
+
productCartGetState() {
|
|
1199
|
+
return this.sdkBinding.productCartGetState();
|
|
1200
|
+
}
|
|
1201
|
+
productCartClicked() {
|
|
1202
|
+
this.sdkBinding.productCartClicked();
|
|
1203
|
+
}
|
|
1183
1204
|
static get [Symbol.for("___CTOR_ARGS___")]() { return [`SDKInterface`]; }
|
|
1184
1205
|
}
|
|
1185
1206
|
|
|
1207
|
+
class CardLoadingStateController {
|
|
1208
|
+
onCardLoadingStateChange;
|
|
1209
|
+
constructor(onCardLoadingStateChange) {
|
|
1210
|
+
this.onCardLoadingStateChange = onCardLoadingStateChange;
|
|
1211
|
+
}
|
|
1212
|
+
timeout = 300;
|
|
1213
|
+
onSetLoadStartState() {
|
|
1214
|
+
this.onBeforeStateChanged();
|
|
1215
|
+
// prevent micro loaders in UI
|
|
1216
|
+
if (this.currentState === 1 /* CARD_LOADING_STATE.LOADED */) {
|
|
1217
|
+
this.deferredDataWaitingStateTimerId = window.setTimeout(() => {
|
|
1218
|
+
this.onCardLoadingStateChange(0 /* CARD_LOADING_STATE.LOADING */);
|
|
1219
|
+
this.dataWaitingStartedAt = Date.now();
|
|
1220
|
+
}, this.timeout);
|
|
1221
|
+
}
|
|
1222
|
+
else {
|
|
1223
|
+
this.onCardLoadingStateChange(0 /* CARD_LOADING_STATE.LOADING */);
|
|
1224
|
+
this.dataWaitingStartedAt = Date.now();
|
|
1225
|
+
}
|
|
1226
|
+
this.currentState = 0 /* CARD_LOADING_STATE.LOADING */;
|
|
1227
|
+
}
|
|
1228
|
+
onSetLoadEndState() {
|
|
1229
|
+
this.onBeforeStateChanged();
|
|
1230
|
+
// prevent micro loaders in UI
|
|
1231
|
+
const delay = this.timeout;
|
|
1232
|
+
let dataWaitingLoaderSpent = delay;
|
|
1233
|
+
if (this.dataWaitingStartedAt != null) {
|
|
1234
|
+
dataWaitingLoaderSpent = Date.now() - this.dataWaitingStartedAt;
|
|
1235
|
+
}
|
|
1236
|
+
if (dataWaitingLoaderSpent < delay) {
|
|
1237
|
+
this.deferredResumeStateTimerId = window.setTimeout(() => this.onCardLoadingStateChange(1 /* CARD_LOADING_STATE.LOADED */), dataWaitingLoaderSpent - delay);
|
|
1238
|
+
}
|
|
1239
|
+
else {
|
|
1240
|
+
this.onCardLoadingStateChange(1 /* CARD_LOADING_STATE.LOADED */);
|
|
1241
|
+
}
|
|
1242
|
+
this.currentState = 1 /* CARD_LOADING_STATE.LOADED */;
|
|
1243
|
+
}
|
|
1244
|
+
onSetLoadErrorState(reason) {
|
|
1245
|
+
this.onBeforeStateChanged();
|
|
1246
|
+
this.onCardLoadingStateChange(2 /* CARD_LOADING_STATE.LOADING_ERROR */, reason);
|
|
1247
|
+
this.currentState = 2 /* CARD_LOADING_STATE.LOADING_ERROR */;
|
|
1248
|
+
}
|
|
1249
|
+
currentState = 0 /* CARD_LOADING_STATE.LOADING */;
|
|
1250
|
+
deferredDataWaitingStateTimerId = null;
|
|
1251
|
+
deferredResumeStateTimerId = null;
|
|
1252
|
+
dataWaitingStartedAt = null;
|
|
1253
|
+
clearDeferredDataWaitingStateTimerId() {
|
|
1254
|
+
if (this.deferredDataWaitingStateTimerId != null) {
|
|
1255
|
+
window.clearTimeout(this.deferredDataWaitingStateTimerId);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
clearDeferredResumeStateTimerId() {
|
|
1259
|
+
if (this.deferredResumeStateTimerId != null) {
|
|
1260
|
+
window.clearTimeout(this.deferredResumeStateTimerId);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
onBeforeStateChanged() {
|
|
1264
|
+
this.clearDeferredDataWaitingStateTimerId();
|
|
1265
|
+
this.clearDeferredResumeStateTimerId();
|
|
1266
|
+
}
|
|
1267
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`(state: CARD_LOADING_STATE, reason?: string) => void`]; }
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1186
1270
|
const DEFAULT_SLIDE_DURATION = 10000;
|
|
1187
1271
|
|
|
1188
1272
|
class DataInput {
|
|
@@ -3301,19 +3385,7 @@ class SlideTimeline {
|
|
|
3301
3385
|
return SlideTimeline.layoutService;
|
|
3302
3386
|
}
|
|
3303
3387
|
get isSDKSupportUpdateTimeline() {
|
|
3304
|
-
|
|
3305
|
-
return Boolean(SlideTimeline.layoutService.env.Android && "updateTimeline" in SlideTimeline.layoutService.env.Android);
|
|
3306
|
-
}
|
|
3307
|
-
else if (this.slideApiDeps.isIOS) {
|
|
3308
|
-
const mh = SlideTimeline.layoutService.env?.webkit?.messageHandlers ?? {};
|
|
3309
|
-
return "updateTimeline" in mh;
|
|
3310
|
-
}
|
|
3311
|
-
else if (this.slideApiDeps.isWeb) {
|
|
3312
|
-
return true;
|
|
3313
|
-
}
|
|
3314
|
-
else {
|
|
3315
|
-
return false;
|
|
3316
|
-
}
|
|
3388
|
+
return this.slideApiDeps.isSdkSupportUpdateTimeline();
|
|
3317
3389
|
}
|
|
3318
3390
|
get isSdkSupportTimelineOnBeforeStart() {
|
|
3319
3391
|
return this.slideApiDeps.isSdkSupportTimelineOnBeforeStart();
|
|
@@ -3357,7 +3429,7 @@ class SlideTimeline {
|
|
|
3357
3429
|
await this.slideReady.then();
|
|
3358
3430
|
// window._log(`updateTimeline, a: ${action} ct: ${currentTime} d: ${duration} tds: ${this.timelineDisabledState}`, true);
|
|
3359
3431
|
// console.trace(`updateTimeline ${action} slideIndex: ${this.slideIndex} currentTime:${currentTime} duration:${duration} tds: ${this.timelineDisabledState} showLoader: ${showLoader} showError: ${showError}`);
|
|
3360
|
-
this.slideApiDeps.updateTimeline(this.slideIndex, action, currentTime, duration, showLoader, showError);
|
|
3432
|
+
await this.slideApiDeps.updateTimeline(this.slideIndex, action, currentTime, duration, showLoader, showError);
|
|
3361
3433
|
if (action === "pause" /* TIMELINE_ACTION.PAUSE */ && showLoader) {
|
|
3362
3434
|
this.dataWaitingStartedAt = Date.now();
|
|
3363
3435
|
}
|
|
@@ -3383,13 +3455,13 @@ class SlideTimeline {
|
|
|
3383
3455
|
* Start timeline after slide started
|
|
3384
3456
|
* Nothing do if old sdk
|
|
3385
3457
|
*/
|
|
3386
|
-
slideStarted() {
|
|
3458
|
+
async slideStarted() {
|
|
3387
3459
|
// console.trace("slideStarted");
|
|
3388
3460
|
this.onBeforeStateChanged();
|
|
3389
3461
|
if (this.isSDKSupportUpdateTimeline) {
|
|
3390
3462
|
this.resumedAt = new Date().getTime();
|
|
3391
3463
|
this.timeSpent = 0; // for case when instance exists, but we return to slide again
|
|
3392
|
-
this.updateTimeline("start" /* TIMELINE_ACTION.START */);
|
|
3464
|
+
await this.updateTimeline("start" /* TIMELINE_ACTION.START */);
|
|
3393
3465
|
}
|
|
3394
3466
|
}
|
|
3395
3467
|
slideRestarted() {
|
|
@@ -3458,6 +3530,7 @@ class SlideTimeline {
|
|
|
3458
3530
|
this.onBeforeStateChanged();
|
|
3459
3531
|
if (this.isSDKSupportUpdateTimeline) {
|
|
3460
3532
|
this.updateTimeline("stop" /* TIMELINE_ACTION.STOP */);
|
|
3533
|
+
// console.log(`TIMELINE_ACTION -> slideStopped, index: ${this.slideIndex}`);
|
|
3461
3534
|
}
|
|
3462
3535
|
}
|
|
3463
3536
|
/**
|
|
@@ -3594,10 +3667,20 @@ class Layer {
|
|
|
3594
3667
|
});
|
|
3595
3668
|
};
|
|
3596
3669
|
const onWidgetRequirePauseUI = (cardId, slideIndex) => {
|
|
3597
|
-
this.
|
|
3670
|
+
if (this.slideApiDeps.isWeb) {
|
|
3671
|
+
this.slideApiDeps.onWidgetRequirePauseUI();
|
|
3672
|
+
}
|
|
3673
|
+
else {
|
|
3674
|
+
this._slidePauseUI();
|
|
3675
|
+
}
|
|
3598
3676
|
};
|
|
3599
3677
|
const onWidgetRequireResumeUI = (cardId, slideIndex) => {
|
|
3600
|
-
this.
|
|
3678
|
+
if (this.slideApiDeps.isWeb) {
|
|
3679
|
+
this.slideApiDeps.onWidgetRequireResumeUI();
|
|
3680
|
+
}
|
|
3681
|
+
else {
|
|
3682
|
+
this._slideResumeUI();
|
|
3683
|
+
}
|
|
3601
3684
|
};
|
|
3602
3685
|
const _elementsNodes = this._nodeRef.querySelectorAll(".narrative-slide-elements .narrative-element:not(.narrative-element-child-element)");
|
|
3603
3686
|
let layerWithWidgetQuest = false;
|
|
@@ -3836,7 +3919,7 @@ class Layer {
|
|
|
3836
3919
|
}
|
|
3837
3920
|
// skip start timeline if we returned to slide with enabled timer and opened WidgetProducts modal
|
|
3838
3921
|
if (!this.isLayerForcePaused) {
|
|
3839
|
-
this.timeline.slideStarted();
|
|
3922
|
+
await this.timeline.slideStarted();
|
|
3840
3923
|
}
|
|
3841
3924
|
return { currentTime };
|
|
3842
3925
|
}
|
|
@@ -4689,7 +4772,9 @@ let SlideApi$1 = class SlideApi {
|
|
|
4689
4772
|
this._state = 5 /* STATE.RESUMED */;
|
|
4690
4773
|
}
|
|
4691
4774
|
async slideStop(options) {
|
|
4692
|
-
|
|
4775
|
+
// console.log(`TIMELINE_ACTION -> STOP, index: ${this.slide.slideIndex}, state: ${this._state}`);
|
|
4776
|
+
// из состояния START (слайд (например с видео) еще не стартовал) тоже позволяем прерывать - чтобы был правильный LC при быстром пролистывании слайдера
|
|
4777
|
+
if (!(this._state === 2 /* STATE.START */ || this._state === 3 /* STATE.STARTED */ || this._state === 5 /* STATE.RESUMED */ || this._state === 9 /* STATE.USER_PAUSED */)) {
|
|
4693
4778
|
return;
|
|
4694
4779
|
}
|
|
4695
4780
|
this._state = 11 /* STATE.STOP */;
|
|
@@ -5429,6 +5514,12 @@ class SlideApiDepsMultiSlideMode {
|
|
|
5429
5514
|
this.sdkApi = sdkApi;
|
|
5430
5515
|
this.slider = slider;
|
|
5431
5516
|
}
|
|
5517
|
+
onWidgetRequirePauseUI() {
|
|
5518
|
+
return this.sdkApi.onWidgetRequirePauseUI();
|
|
5519
|
+
}
|
|
5520
|
+
onWidgetRequireResumeUI() {
|
|
5521
|
+
return this.sdkApi.onWidgetRequireResumeUI();
|
|
5522
|
+
}
|
|
5432
5523
|
getWidgetsSharedData(cardId, widget) {
|
|
5433
5524
|
return this.sdkApi.getWidgetsSharedData(cardId, widget);
|
|
5434
5525
|
}
|
|
@@ -5528,7 +5619,9 @@ class SlideApiDepsMultiSlideMode {
|
|
|
5528
5619
|
return this.sdkApi.isExistsShowNextCard;
|
|
5529
5620
|
}
|
|
5530
5621
|
cardShowNext() {
|
|
5531
|
-
|
|
5622
|
+
return;
|
|
5623
|
+
// skip action in multislide mode (business logic)
|
|
5624
|
+
// this.sdkApi.cardShowNext();
|
|
5532
5625
|
}
|
|
5533
5626
|
/** @deprecated, used only in native sdk **/
|
|
5534
5627
|
cardPausedCallback(currentTime) {
|
|
@@ -5550,6 +5643,18 @@ class SlideApiDepsMultiSlideMode {
|
|
|
5550
5643
|
showLayer(index) {
|
|
5551
5644
|
this.sdkApi.showLayer(index);
|
|
5552
5645
|
}
|
|
5646
|
+
get isSdkSupportProductCart() {
|
|
5647
|
+
return this.sdkApi.isSdkSupportProductCart;
|
|
5648
|
+
}
|
|
5649
|
+
productCartUpdate(data) {
|
|
5650
|
+
return this.sdkApi.productCartUpdate(data);
|
|
5651
|
+
}
|
|
5652
|
+
productCartGetState() {
|
|
5653
|
+
return this.sdkApi.productCartGetState();
|
|
5654
|
+
}
|
|
5655
|
+
productCartClicked() {
|
|
5656
|
+
this.sdkApi.productCartClicked();
|
|
5657
|
+
}
|
|
5553
5658
|
/**
|
|
5554
5659
|
* For single slide mode - proxy these methods via SDKApi
|
|
5555
5660
|
* =================================================================================================================
|
|
@@ -5560,8 +5665,11 @@ class SlideApiDepsMultiSlideMode {
|
|
|
5560
5665
|
showCardSlide(index) {
|
|
5561
5666
|
this.slider.showByIndex(index);
|
|
5562
5667
|
}
|
|
5563
|
-
|
|
5564
|
-
|
|
5668
|
+
isSdkSupportUpdateTimeline() {
|
|
5669
|
+
return true;
|
|
5670
|
+
}
|
|
5671
|
+
async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
|
|
5672
|
+
await this.slider.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
|
|
5565
5673
|
}
|
|
5566
5674
|
isSdkSupportTimelineOnBeforeStart() {
|
|
5567
5675
|
return true;
|
|
@@ -5580,6 +5688,12 @@ class SlideApiDepsSingleSlideMode {
|
|
|
5580
5688
|
constructor(sdkApi) {
|
|
5581
5689
|
this.sdkApi = sdkApi;
|
|
5582
5690
|
}
|
|
5691
|
+
onWidgetRequirePauseUI() {
|
|
5692
|
+
return this.sdkApi.onWidgetRequirePauseUI();
|
|
5693
|
+
}
|
|
5694
|
+
onWidgetRequireResumeUI() {
|
|
5695
|
+
return this.sdkApi.onWidgetRequireResumeUI();
|
|
5696
|
+
}
|
|
5583
5697
|
getWidgetsSharedData(cardId, widget) {
|
|
5584
5698
|
return this.sdkApi.getWidgetsSharedData(cardId, widget);
|
|
5585
5699
|
}
|
|
@@ -5701,6 +5815,18 @@ class SlideApiDepsSingleSlideMode {
|
|
|
5701
5815
|
showLayer(index) {
|
|
5702
5816
|
this.sdkApi.showLayer(index);
|
|
5703
5817
|
}
|
|
5818
|
+
get isSdkSupportProductCart() {
|
|
5819
|
+
return this.sdkApi.isSdkSupportProductCart;
|
|
5820
|
+
}
|
|
5821
|
+
productCartUpdate(data) {
|
|
5822
|
+
return this.sdkApi.productCartUpdate(data);
|
|
5823
|
+
}
|
|
5824
|
+
productCartGetState() {
|
|
5825
|
+
return this.sdkApi.productCartGetState();
|
|
5826
|
+
}
|
|
5827
|
+
productCartClicked() {
|
|
5828
|
+
this.sdkApi.productCartClicked();
|
|
5829
|
+
}
|
|
5704
5830
|
/**
|
|
5705
5831
|
* For single slide mode - proxy these methods via SDKApi
|
|
5706
5832
|
*/
|
|
@@ -5710,8 +5836,11 @@ class SlideApiDepsSingleSlideMode {
|
|
|
5710
5836
|
showCardSlide(index) {
|
|
5711
5837
|
this.sdkApi.showCardSlide(index);
|
|
5712
5838
|
}
|
|
5713
|
-
|
|
5714
|
-
this.sdkApi.
|
|
5839
|
+
isSdkSupportUpdateTimeline() {
|
|
5840
|
+
return this.sdkApi.isSdkSupportUpdateTimeline();
|
|
5841
|
+
}
|
|
5842
|
+
async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
|
|
5843
|
+
await this.sdkApi.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
|
|
5715
5844
|
}
|
|
5716
5845
|
isSdkSupportTimelineOnBeforeStart() {
|
|
5717
5846
|
return this.sdkApi.isSdkSupportTimelineOnBeforeStart();
|
|
@@ -5766,12 +5895,16 @@ class SlideTimer {
|
|
|
5766
5895
|
this.timerId = null;
|
|
5767
5896
|
}
|
|
5768
5897
|
}
|
|
5769
|
-
resume(duration = 0) {
|
|
5898
|
+
resume(currentTime = undefined, duration = 0) {
|
|
5770
5899
|
this._pause = false;
|
|
5771
5900
|
if (!this._started) {
|
|
5772
5901
|
this.start(duration);
|
|
5773
5902
|
}
|
|
5774
5903
|
else {
|
|
5904
|
+
if (currentTime != null) {
|
|
5905
|
+
// timeLeft correction
|
|
5906
|
+
this.timeLeft = this.duration - currentTime;
|
|
5907
|
+
}
|
|
5775
5908
|
this.tick();
|
|
5776
5909
|
}
|
|
5777
5910
|
}
|
|
@@ -5787,12 +5920,12 @@ class SlideTimer {
|
|
|
5787
5920
|
}
|
|
5788
5921
|
const dtDiff = new Date().getTime() - rafStartTime;
|
|
5789
5922
|
this.timeLeft -= dtDiff;
|
|
5790
|
-
let
|
|
5791
|
-
if (
|
|
5792
|
-
|
|
5923
|
+
let progressPercent = Math.round(((this.duration - this.timeLeft) / this.duration) * 100 * 10000) / 10000;
|
|
5924
|
+
if (progressPercent > 100) {
|
|
5925
|
+
progressPercent = 100;
|
|
5793
5926
|
}
|
|
5794
|
-
this.updateCb(
|
|
5795
|
-
if (
|
|
5927
|
+
this.updateCb(progressPercent);
|
|
5928
|
+
if (progressPercent < 100) {
|
|
5796
5929
|
if (this._pause !== true) {
|
|
5797
5930
|
this.tick();
|
|
5798
5931
|
}
|
|
@@ -5802,7 +5935,43 @@ class SlideTimer {
|
|
|
5802
5935
|
}
|
|
5803
5936
|
});
|
|
5804
5937
|
}
|
|
5805
|
-
static get [Symbol.for("___CTOR_ARGS___")]() { return [`(callback: () => void) => number`, `(timerId: number) => void`, `(
|
|
5938
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`(callback: () => void) => number`, `(timerId: number) => void`, `(progressPercent: number) => void`, `() => void`]; }
|
|
5939
|
+
}
|
|
5940
|
+
|
|
5941
|
+
/**
|
|
5942
|
+
* usage TS interface with ctor
|
|
5943
|
+
* https://blog.logrocket.com/writing-constructor-typescript/
|
|
5944
|
+
*
|
|
5945
|
+
* @param ctor
|
|
5946
|
+
* @param slides
|
|
5947
|
+
* @param getLayoutDirection
|
|
5948
|
+
*/
|
|
5949
|
+
function createTimelineController(ctor, slides, getLayoutDirection) {
|
|
5950
|
+
return new ctor(slides, getLayoutDirection);
|
|
5951
|
+
}
|
|
5952
|
+
class TimelineController {
|
|
5953
|
+
slides;
|
|
5954
|
+
getLayoutDirection;
|
|
5955
|
+
constructor(slides, getLayoutDirection) {
|
|
5956
|
+
this.slides = slides;
|
|
5957
|
+
this.getLayoutDirection = getLayoutDirection;
|
|
5958
|
+
}
|
|
5959
|
+
onSlideTimerUpdate(index, progressPercent) {
|
|
5960
|
+
this.slides[index]?.updateTimelineProgress(progressPercent, true);
|
|
5961
|
+
}
|
|
5962
|
+
onSlideBeforeStart(index) {
|
|
5963
|
+
// fill to 100% all previous slides
|
|
5964
|
+
for (let i = 0; i < index; ++i) {
|
|
5965
|
+
this.slides[i]?.updateTimelineProgress(100, false);
|
|
5966
|
+
}
|
|
5967
|
+
// fill to 0% all next slides (for user revert direction)
|
|
5968
|
+
for (let i = index + 1; i < this.slides.length; ++i) {
|
|
5969
|
+
this.slides[i]?.updateTimelineProgress(0, false);
|
|
5970
|
+
}
|
|
5971
|
+
// activate current slide
|
|
5972
|
+
this.slides[index]?.updateTimelineProgress(0, true);
|
|
5973
|
+
}
|
|
5974
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`Array`, `GetLayoutDirection`]; }
|
|
5806
5975
|
}
|
|
5807
5976
|
|
|
5808
5977
|
class Slider {
|
|
@@ -5824,15 +5993,19 @@ class Slider {
|
|
|
5824
5993
|
slides: config.slides,
|
|
5825
5994
|
nonce: config.nonce,
|
|
5826
5995
|
slideRender: config.slideRender,
|
|
5996
|
+
navbarAppearance: config.navbarAppearance,
|
|
5827
5997
|
});
|
|
5828
5998
|
config.root.appendChild(slideWrapper);
|
|
5829
5999
|
this.slideWrapperElement = slideWrapper;
|
|
6000
|
+
this.timelineController = createTimelineController(TimelineController, this.slides, this.config.getLayoutDirection.bind(this));
|
|
5830
6001
|
// cardMounted: (card: HTMLElement) => Promise<void>
|
|
5831
6002
|
requestAnimationFrame(async () => {
|
|
5832
6003
|
await Promise.all(this.slides.map((slide, index) => config.onSlideMounted(slide.element, index)));
|
|
5833
6004
|
});
|
|
5834
6005
|
}
|
|
5835
6006
|
isAnimating = false;
|
|
6007
|
+
// block click while slide loading and starting (prevent several timeline starting)
|
|
6008
|
+
isSlideStarting = false;
|
|
5836
6009
|
activeIndex = -1;
|
|
5837
6010
|
get activeSlide() {
|
|
5838
6011
|
return this.slides[this.activeIndex];
|
|
@@ -5842,133 +6015,192 @@ class Slider {
|
|
|
5842
6015
|
bulletsContainer = null;
|
|
5843
6016
|
slidesFirstRenders = [];
|
|
5844
6017
|
slideWrapperElement;
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
6018
|
+
timelineController;
|
|
6019
|
+
assembleNavbarCssVariables(navbarAppearance) {
|
|
6020
|
+
let css = "";
|
|
6021
|
+
if (navbarAppearance.edge_offset != null) {
|
|
6022
|
+
css += `--navbar-edge-offset: ${navbarAppearance.edge_offset};`;
|
|
6023
|
+
}
|
|
6024
|
+
if (navbarAppearance.active_timeline_width != null) {
|
|
6025
|
+
css += `--navbar-active-timeline-width: ${navbarAppearance.active_timeline_width};`;
|
|
6026
|
+
}
|
|
6027
|
+
if (navbarAppearance.background_color != null) {
|
|
6028
|
+
css += `--navbar-background-color: ${navbarAppearance.background_color};`;
|
|
6029
|
+
}
|
|
6030
|
+
if (navbarAppearance.border_radius != null) {
|
|
6031
|
+
css += `--navbar-border-radius: ${navbarAppearance.border_radius};`;
|
|
6032
|
+
}
|
|
6033
|
+
if (navbarAppearance.drop_shadow_blur != null) {
|
|
6034
|
+
css += `--navbar-drop-shadow-blur: ${navbarAppearance.drop_shadow_blur};`;
|
|
6035
|
+
}
|
|
6036
|
+
if (navbarAppearance.drop_shadow_color != null) {
|
|
6037
|
+
css += `--navbar-drop-shadow-color: ${navbarAppearance.drop_shadow_color};`;
|
|
6038
|
+
}
|
|
6039
|
+
if (navbarAppearance.drop_shadow_x_offset != null) {
|
|
6040
|
+
css += `--navbar-drop-shadow-x-offset: ${navbarAppearance.drop_shadow_x_offset};`;
|
|
6041
|
+
}
|
|
6042
|
+
if (navbarAppearance.drop_shadow_y_offset != null) {
|
|
6043
|
+
css += `--navbar-drop-shadow-y-offset: ${navbarAppearance.drop_shadow_y_offset};`;
|
|
6044
|
+
}
|
|
6045
|
+
if (navbarAppearance.timeline_background_color != null) {
|
|
6046
|
+
css += `--navbar-timeline-background-color: ${navbarAppearance.timeline_background_color};`;
|
|
6047
|
+
}
|
|
6048
|
+
if (navbarAppearance.timeline_fill_color != null) {
|
|
6049
|
+
css += `--navbar-timeline-fill-color: ${navbarAppearance.timeline_fill_color};`;
|
|
6050
|
+
}
|
|
6051
|
+
if (navbarAppearance.timeline_size != null) {
|
|
6052
|
+
css += `--navbar-timeline-size: ${navbarAppearance.timeline_size};`;
|
|
6053
|
+
}
|
|
6054
|
+
if (navbarAppearance.timelines_gap != null) {
|
|
6055
|
+
css += `--navbar-timelines-gap: ${navbarAppearance.timelines_gap};`;
|
|
6056
|
+
}
|
|
6057
|
+
if (navbarAppearance.vertical_padding != null) {
|
|
6058
|
+
css += `--navbar-vertical-padding: ${navbarAppearance.vertical_padding};`;
|
|
6059
|
+
}
|
|
6060
|
+
if (navbarAppearance.horizontal_padding != null) {
|
|
6061
|
+
css += `--navbar-horizontal-padding: ${navbarAppearance.horizontal_padding};`;
|
|
6062
|
+
}
|
|
6063
|
+
return `.cards-slider {${css}`;
|
|
6064
|
+
}
|
|
6065
|
+
createSliderElement = ({ slides, nonce, slideRender, navbarAppearance, }) => {
|
|
5848
6066
|
const style = document.createElement("style");
|
|
5849
6067
|
if (nonce != null) {
|
|
5850
6068
|
style.nonce = nonce;
|
|
5851
6069
|
}
|
|
6070
|
+
style.innerText = this.assembleNavbarCssVariables(navbarAppearance);
|
|
5852
6071
|
const slider = document.createElement("div");
|
|
5853
6072
|
slider.classList.add("cards-slider");
|
|
5854
6073
|
const track = document.createElement("div");
|
|
5855
6074
|
track.classList.add("cards-slider__track");
|
|
5856
6075
|
this.sliderTrack = track;
|
|
5857
|
-
|
|
5858
|
-
const slide = document.createElement("div");
|
|
5859
|
-
slide.classList.add("cards-slider__slide");
|
|
5860
|
-
slide.setAttribute("data-index", String(i));
|
|
5861
|
-
this.slides[i] = {
|
|
5862
|
-
element: slideRender(slides[i], i, this.slidesFirstRenders[i].firstRenderCallPromise),
|
|
5863
|
-
timer: new SlideTimer(cb => window.requestAnimationFrame(cb), handle => window.cancelAnimationFrame(handle), this.onSlideTimerUpdate.bind(this), this.onSlideTimerEnd.bind(this)),
|
|
5864
|
-
};
|
|
5865
|
-
slide.appendChild(this.slides[i].element);
|
|
5866
|
-
track.appendChild(slide);
|
|
5867
|
-
}
|
|
5868
|
-
const [bullets, updateBulletActiveIndex, updateTimelineProgress] = this.createBulletPoints(slides.length);
|
|
6076
|
+
const [bullets, updateTimelineProgress] = this.createBulletPoints(slides.length, this.config.getLayoutDirection.bind(this), navbarAppearance.position);
|
|
5869
6077
|
this.bulletsContainer = bullets;
|
|
5870
|
-
this.
|
|
5871
|
-
|
|
6078
|
+
this.slides = slides.map((slide, i) => ({
|
|
6079
|
+
element: slideRender(slide, i, this.slidesFirstRenders[i].firstRenderCallPromise),
|
|
6080
|
+
timer: new SlideTimer(cb => window.requestAnimationFrame(cb), handle => window.cancelAnimationFrame(handle), progressPercent => this.timelineController.onSlideTimerUpdate(i, progressPercent), this.onSlideTimerEnd.bind(this)),
|
|
6081
|
+
updateTimelineProgress: (progressPercent, isActive) => updateTimelineProgress(i, progressPercent, isActive),
|
|
6082
|
+
}));
|
|
6083
|
+
for (let i = 0; i < this.slides.length; ++i) {
|
|
6084
|
+
const slideElement = document.createElement("div");
|
|
6085
|
+
slideElement.classList.add("cards-slider__slide");
|
|
6086
|
+
slideElement.setAttribute("data-index", String(i));
|
|
6087
|
+
slideElement.appendChild(this.slides[i].element);
|
|
6088
|
+
track.appendChild(slideElement);
|
|
6089
|
+
}
|
|
5872
6090
|
slider.appendChild(track);
|
|
5873
|
-
|
|
6091
|
+
const safeAreaView = document.createElement("div");
|
|
6092
|
+
safeAreaView.classList.add("safe-area-view", "inset-0", "non-touchable");
|
|
6093
|
+
const safeAreaRelativeZoneView = document.createElement("div");
|
|
6094
|
+
safeAreaRelativeZoneView.classList.add("safe-area-relative-zone-view");
|
|
6095
|
+
safeAreaRelativeZoneView.appendChild(bullets);
|
|
6096
|
+
safeAreaView.appendChild(safeAreaRelativeZoneView);
|
|
6097
|
+
slider.appendChild(safeAreaView);
|
|
5874
6098
|
slider.appendChild(style);
|
|
5875
6099
|
return slider;
|
|
5876
6100
|
};
|
|
5877
|
-
createBulletPoints(count) {
|
|
6101
|
+
createBulletPoints(count, getLayoutDirection, position) {
|
|
5878
6102
|
const bullets = document.createElement("div");
|
|
5879
|
-
bullets.classList.
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
6103
|
+
bullets.classList.add("cards-slider__navbar");
|
|
6104
|
+
if (position === 0) {
|
|
6105
|
+
bullets.classList.add("cards-slider__navbar--position-none");
|
|
6106
|
+
}
|
|
6107
|
+
else if (position === 1) {
|
|
6108
|
+
bullets.classList.add("cards-slider__navbar--position-top");
|
|
6109
|
+
}
|
|
6110
|
+
else if (position === 2) {
|
|
6111
|
+
bullets.classList.add("cards-slider__navbar--position-bottom");
|
|
6112
|
+
}
|
|
6113
|
+
else {
|
|
6114
|
+
// default
|
|
6115
|
+
bullets.classList.add("cards-slider__navbar--position-bottom");
|
|
6116
|
+
}
|
|
6117
|
+
bullets.dir = getLayoutDirection();
|
|
6118
|
+
// skip creating view elements for single slide
|
|
6119
|
+
if (count > 1) {
|
|
6120
|
+
for (let i = 0; i < count; ++i) {
|
|
6121
|
+
const bullet = document.createElement("div");
|
|
6122
|
+
bullet.classList.add("cards-slider__timeline", "touchable");
|
|
6123
|
+
bullet.setAttribute("data-index", String(i));
|
|
6124
|
+
bullet.onclick = (e) => {
|
|
6125
|
+
e.stopPropagation();
|
|
6126
|
+
e.preventDefault();
|
|
6127
|
+
const bullet = e.target;
|
|
6128
|
+
if (bullet != null) {
|
|
6129
|
+
const index = bullet.dataset.index;
|
|
6130
|
+
if (index != null) {
|
|
6131
|
+
this.showByIndex(parseInt(index));
|
|
6132
|
+
}
|
|
5892
6133
|
}
|
|
5893
|
-
}
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
}
|
|
5900
|
-
const onUpdateActiveIndex = (activeIndex) => {
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
};
|
|
5908
|
-
const onUpdateTimelineProgress = (index, progress) => {
|
|
6134
|
+
};
|
|
6135
|
+
const bulletFill = document.createElement("div");
|
|
6136
|
+
bulletFill.classList.add("cards-slider__timeline-fill");
|
|
6137
|
+
bullet.append(bulletFill);
|
|
6138
|
+
bullets.appendChild(bullet);
|
|
6139
|
+
}
|
|
6140
|
+
}
|
|
6141
|
+
// const onUpdateActiveIndex = (activeIndex: number) => {
|
|
6142
|
+
// if (activeIndex >= 0 && activeIndex < count) {
|
|
6143
|
+
// for (const bullet of bullets.querySelectorAll(".cards-slider__bullet--active")) {
|
|
6144
|
+
// bullet.classList.toggle("cards-slider__bullet--active");
|
|
6145
|
+
// }
|
|
6146
|
+
// bullets.querySelector(`.cards-slider__bullet[data-index="${activeIndex}"]`)?.classList.toggle("cards-slider__bullet--active");
|
|
6147
|
+
// }
|
|
6148
|
+
// };
|
|
6149
|
+
const onUpdateTimelineProgress = (index, progress, isActive) => {
|
|
5909
6150
|
if (index >= 0 && index < count) {
|
|
5910
|
-
const bullet = bullets.querySelector(`.cards-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
6151
|
+
const bullet = bullets.querySelector(`.cards-slider__timeline:nth-child(${index + 1})`);
|
|
6152
|
+
const bulletFill = bullet?.querySelector(".cards-slider__timeline-fill");
|
|
6153
|
+
bullet?.classList[isActive ? "add" : "remove"]("cards-slider__timeline--active");
|
|
6154
|
+
if (bulletFill != null) {
|
|
5914
6155
|
// todo remove progress after slide changed?
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
// : index === this.$props.index
|
|
5920
|
-
// ? `${this.$props.timePercent}%`
|
|
5921
|
-
// : "0%"
|
|
5922
|
-
// })`,
|
|
6156
|
+
if (this.config.getLayoutDirection() === "rtl") {
|
|
6157
|
+
progress = -1 * progress;
|
|
6158
|
+
}
|
|
6159
|
+
bulletFill.style.setProperty("transform", `translateX(${progress}%)`);
|
|
5923
6160
|
}
|
|
5924
6161
|
}
|
|
5925
6162
|
};
|
|
5926
|
-
return [bullets,
|
|
6163
|
+
return [bullets, onUpdateTimelineProgress];
|
|
5927
6164
|
}
|
|
5928
6165
|
async showByIndex(newIndex) {
|
|
5929
6166
|
const prevIndex = this.activeIndex;
|
|
5930
|
-
if (this.isAnimating)
|
|
6167
|
+
if (this.isAnimating) {
|
|
5931
6168
|
return prevIndex;
|
|
5932
|
-
if (prevIndex !== -1) {
|
|
5933
|
-
// skip for slider start
|
|
5934
|
-
this.config.onSlideLeft(this.slides[prevIndex].element, prevIndex);
|
|
5935
|
-
this.config.onSlideStop();
|
|
5936
|
-
}
|
|
5937
|
-
const { index, loadingError } = await this.initAndRenderSlide(newIndex);
|
|
5938
|
-
if (loadingError) {
|
|
5939
|
-
// todo via updateTimeline ????
|
|
5940
|
-
this.config.onSlideLoadingError(index, loadingError);
|
|
5941
6169
|
}
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
6170
|
+
if (this.isSlideStarting) {
|
|
6171
|
+
// block click while slide loading and starting (prevent several timeline starting)
|
|
6172
|
+
return prevIndex;
|
|
5945
6173
|
}
|
|
5946
|
-
|
|
5947
|
-
}
|
|
5948
|
-
async showNextSlide() {
|
|
5949
|
-
const prevIndex = this.activeIndex;
|
|
5950
|
-
if (this.isAnimating)
|
|
6174
|
+
if (newIndex === prevIndex) {
|
|
5951
6175
|
return prevIndex;
|
|
5952
|
-
|
|
6176
|
+
}
|
|
5953
6177
|
if (newIndex < 0 || newIndex >= this.slides.length) {
|
|
5954
|
-
return
|
|
6178
|
+
return prevIndex;
|
|
5955
6179
|
}
|
|
5956
6180
|
if (prevIndex !== -1) {
|
|
5957
6181
|
// skip for slider start
|
|
5958
6182
|
this.config.onSlideLeft(this.slides[prevIndex].element, prevIndex);
|
|
5959
|
-
this.config.onSlideStop();
|
|
6183
|
+
await this.config.onSlideStop();
|
|
5960
6184
|
}
|
|
6185
|
+
this.isSlideStarting = true;
|
|
5961
6186
|
const { index, loadingError } = await this.initAndRenderSlide(newIndex);
|
|
5962
6187
|
if (loadingError) {
|
|
5963
6188
|
// todo via updateTimeline ????
|
|
5964
6189
|
this.config.onSlideLoadingError(index, loadingError);
|
|
5965
6190
|
}
|
|
5966
|
-
await this.slideTo(index);
|
|
5967
6191
|
if (!loadingError) {
|
|
5968
6192
|
this.onShowSlide(index);
|
|
5969
6193
|
}
|
|
6194
|
+
this.config.onSlideChangeActiveIndex(await this.slideTo(index));
|
|
6195
|
+
if (!loadingError) {
|
|
6196
|
+
await this.config.onSlideStart();
|
|
6197
|
+
}
|
|
6198
|
+
this.isSlideStarting = false;
|
|
5970
6199
|
return newIndex;
|
|
5971
6200
|
}
|
|
6201
|
+
async showNextSlide() {
|
|
6202
|
+
return this.showByIndex(this.activeIndex + 1);
|
|
6203
|
+
}
|
|
5972
6204
|
async initAndRenderSlide(index) {
|
|
5973
6205
|
this.config.onBeforeLoadSlide(index);
|
|
5974
6206
|
let showSlidePromise;
|
|
@@ -6001,9 +6233,9 @@ class Slider {
|
|
|
6001
6233
|
}
|
|
6002
6234
|
}
|
|
6003
6235
|
onShowSlide(index) {
|
|
6004
|
-
this.updateBulletActiveIndex(index);
|
|
6236
|
+
// this.updateBulletActiveIndex(index);
|
|
6005
6237
|
this.config.onShowSlide(this.slides[index].element, index);
|
|
6006
|
-
this.config.onSlideStart();
|
|
6238
|
+
// this.config.onSlideStart();
|
|
6007
6239
|
}
|
|
6008
6240
|
onUpdateSizeMetrics(metrics) {
|
|
6009
6241
|
// this.slideTo(this.activeIndex, 0);
|
|
@@ -6016,11 +6248,13 @@ class Slider {
|
|
|
6016
6248
|
return k * index * cardWidth;
|
|
6017
6249
|
}
|
|
6018
6250
|
async slideTo(index, speed = 300) {
|
|
6019
|
-
if (index < 0 || index > this.slides.length - 1 || this.isAnimating)
|
|
6020
|
-
return;
|
|
6251
|
+
if (index < 0 || index > this.slides.length - 1 || this.isAnimating) {
|
|
6252
|
+
return this.activeIndex;
|
|
6253
|
+
}
|
|
6021
6254
|
const cardOffset = this.getSlideOffset(index);
|
|
6022
6255
|
await this.translateTo(cardOffset, speed);
|
|
6023
6256
|
this.activeIndex = index;
|
|
6257
|
+
return this.activeIndex;
|
|
6024
6258
|
}
|
|
6025
6259
|
setTranslate(value) {
|
|
6026
6260
|
this.sliderTrack?.style.setProperty("transform", `translateX(${value}px)`);
|
|
@@ -6059,23 +6293,36 @@ class Slider {
|
|
|
6059
6293
|
this.config.root.removeChild(this.slideWrapperElement);
|
|
6060
6294
|
}
|
|
6061
6295
|
}
|
|
6062
|
-
updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
|
|
6296
|
+
async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
|
|
6063
6297
|
switch (action) {
|
|
6064
6298
|
case "before_start" /* TIMELINE_ACTION.BEFORE_START */: {
|
|
6065
6299
|
// switch timeline to active slide and wait for start (wait VOD loading)
|
|
6066
|
-
console.log("TIMELINE_ACTION.BEFORE_START", { activeSlide: this.activeSlide, duration });
|
|
6300
|
+
// console.log("TIMELINE_ACTION.BEFORE_START", { activeSlide: this.activeSlide, duration });
|
|
6301
|
+
this.timelineController.onSlideBeforeStart(slideIndex);
|
|
6067
6302
|
break;
|
|
6068
6303
|
}
|
|
6069
6304
|
case "start" /* TIMELINE_ACTION.START */: {
|
|
6070
6305
|
this.config.onSlideDataResume();
|
|
6071
6306
|
// also start after data waiting or pause
|
|
6072
|
-
// window.setTimeout(() => {
|
|
6073
|
-
// this.config.onSlideStop();
|
|
6074
|
-
// this.config.onSlideTimerEnd();
|
|
6075
|
-
// }, 10000);
|
|
6076
6307
|
// destroy on IAM closing
|
|
6077
|
-
console.log("TIMELINE_ACTION.START", {
|
|
6078
|
-
this.activeSlide
|
|
6308
|
+
// console.log("TIMELINE_ACTION.START", {
|
|
6309
|
+
// activeSlide: this.activeSlide,
|
|
6310
|
+
// index: this.activeIndex,
|
|
6311
|
+
// duration,
|
|
6312
|
+
// });
|
|
6313
|
+
let resumeTimer = false;
|
|
6314
|
+
if (duration > 0) {
|
|
6315
|
+
// skip timer start for slide/layer with disabled timeline
|
|
6316
|
+
resumeTimer = true;
|
|
6317
|
+
}
|
|
6318
|
+
if (currentTime === duration) {
|
|
6319
|
+
// skip timer start for already ended layer timeline
|
|
6320
|
+
// skip timer start for already ended layer timeline
|
|
6321
|
+
resumeTimer = false;
|
|
6322
|
+
}
|
|
6323
|
+
if (resumeTimer) {
|
|
6324
|
+
this.activeSlide?.timer.resume(currentTime, duration);
|
|
6325
|
+
}
|
|
6079
6326
|
break;
|
|
6080
6327
|
}
|
|
6081
6328
|
case "pause" /* TIMELINE_ACTION.PAUSE */: {
|
|
@@ -6083,7 +6330,7 @@ class Slider {
|
|
|
6083
6330
|
this.config.onSlideDataWaiting();
|
|
6084
6331
|
}
|
|
6085
6332
|
this.activeSlide?.timer.pause();
|
|
6086
|
-
console.log("TIMELINE_ACTION.PAUSE", { activeSlide: this.activeSlide, duration });
|
|
6333
|
+
// console.log("TIMELINE_ACTION.PAUSE", { activeSlide: this.activeSlide, duration });
|
|
6087
6334
|
break;
|
|
6088
6335
|
}
|
|
6089
6336
|
case "stop" /* TIMELINE_ACTION.STOP */: {
|
|
@@ -6093,27 +6340,23 @@ class Slider {
|
|
|
6093
6340
|
}
|
|
6094
6341
|
this.activeSlide?.timer.stop();
|
|
6095
6342
|
// todo нужен STOP когда вручную переключаем слайд на другой
|
|
6096
|
-
console.log("TIMELINE_ACTION.STOP", { activeSlide: this.activeSlide, duration });
|
|
6343
|
+
// console.log("TIMELINE_ACTION.STOP", { activeSlide: this.activeSlide, duration });
|
|
6097
6344
|
break;
|
|
6098
6345
|
}
|
|
6099
6346
|
}
|
|
6100
6347
|
}
|
|
6101
|
-
onSlideTimerUpdate(progress) {
|
|
6102
|
-
|
|
6103
|
-
}
|
|
6104
|
-
onSlideTimerEnd() {
|
|
6105
|
-
this.config.onSlideStop();
|
|
6348
|
+
// private onSlideTimerUpdate(progress: number) {
|
|
6349
|
+
// this.updateTimelineProgress(this.activeIndex, progress);
|
|
6350
|
+
// }
|
|
6351
|
+
async onSlideTimerEnd() {
|
|
6352
|
+
await this.config.onSlideStop();
|
|
6106
6353
|
this.config.onSlideTimerEnd();
|
|
6107
6354
|
}
|
|
6108
6355
|
static get [Symbol.for("___CTOR_ARGS___")]() { return [`{
|
|
6109
6356
|
slides: Array<T>;
|
|
6110
6357
|
root: HTMLElement;
|
|
6111
|
-
// isFullscreen: boolean;
|
|
6112
6358
|
nonce?: string;
|
|
6113
|
-
|
|
6114
|
-
// userResizeHandler?: (data: { viewportWidth: number; viewportHeight: number; fontSize: number }) => void;
|
|
6115
|
-
// VODPlayer?: typeof VODPlayer;
|
|
6116
|
-
// overlappingActionBarHeight?: number;
|
|
6359
|
+
navbarAppearance: NavbarAppearance;
|
|
6117
6360
|
slideRender: SlideRender<T>;
|
|
6118
6361
|
onSlideMounted: OnSlideMounted;
|
|
6119
6362
|
onBeforeShowSlide: OnBeforeShowSlide;
|
|
@@ -6124,6 +6367,7 @@ class Slider {
|
|
|
6124
6367
|
getLayoutDirection: GetLayoutDirection;
|
|
6125
6368
|
|
|
6126
6369
|
onSlideTimerEnd: OnSlideTimerEnd;
|
|
6370
|
+
onSlideChangeActiveIndex: OnSlideChangeActiveIndex;
|
|
6127
6371
|
onSlideStart: OnSlideStart;
|
|
6128
6372
|
onSlideStop: OnSlideStop;
|
|
6129
6373
|
onSlideDataWaiting: OnSlideDataWaiting;
|
|
@@ -6150,6 +6394,7 @@ class CardApi {
|
|
|
6150
6394
|
activeSlide = null;
|
|
6151
6395
|
slides = [];
|
|
6152
6396
|
slidesMode = 0 /* SLIDES_MODE.SINGLE */;
|
|
6397
|
+
cardLoadingStateController = null;
|
|
6153
6398
|
sizeMetrics = {
|
|
6154
6399
|
fontSize: "0px",
|
|
6155
6400
|
isFullscreen: false,
|
|
@@ -6325,7 +6570,10 @@ class CardApi {
|
|
|
6325
6570
|
slider = null;
|
|
6326
6571
|
async showSlides(slides, cardAppearance, index = 0) {
|
|
6327
6572
|
this.slidesMode = 1 /* SLIDES_MODE.MULTIPLE */;
|
|
6328
|
-
this.
|
|
6573
|
+
if (this.cardLoadingStateController === null) {
|
|
6574
|
+
this.cardLoadingStateController = new CardLoadingStateController(this.sdkApi.onCardLoadingStateChange.bind(this.sdkApi));
|
|
6575
|
+
}
|
|
6576
|
+
this.cardLoadingStateController.onSetLoadStartState();
|
|
6329
6577
|
slides.forEach((content, index) => {
|
|
6330
6578
|
if (this.slides[index] == null) {
|
|
6331
6579
|
const item = { content, resourcesReadyPromise: null };
|
|
@@ -6378,6 +6626,15 @@ class CardApi {
|
|
|
6378
6626
|
this.activeSlide = this.slides[index].slide;
|
|
6379
6627
|
return this.slides[index].slide.showSlide().then(_ => ({ moveToIndex: index }));
|
|
6380
6628
|
}
|
|
6629
|
+
else {
|
|
6630
|
+
// quot - // TODO для виджета квест нужно при каждом показе слайда инициализировать виджет???
|
|
6631
|
+
// // пока вызов убран из за того что init жестко завязан на single slide mode
|
|
6632
|
+
// из-за того что перед показом нет приватного вызова SlideApi::_init пока что нужно руками вызывать
|
|
6633
|
+
// slide.activeLayer.timeline.triggerSlideLoadState();
|
|
6634
|
+
// для того чтобы запустить TIMELINE_ACTION.BEFORE_START что нужно для таймлайна слайдера
|
|
6635
|
+
// todo убрать в случае если будем вызывать new SlideApi перед каждым показом слайда
|
|
6636
|
+
this.slides[index].slide.activeLayer.timeline.triggerSlideLoadState();
|
|
6637
|
+
}
|
|
6381
6638
|
this.activeSlide = this.slides[index].slide;
|
|
6382
6639
|
// TODO handle moveToIndex
|
|
6383
6640
|
// return resolve or reject with reason
|
|
@@ -6391,13 +6648,13 @@ class CardApi {
|
|
|
6391
6648
|
// внутри слайдера - обрабатываем moveToIndex
|
|
6392
6649
|
};
|
|
6393
6650
|
const onBeforeLoadSlide = index => {
|
|
6394
|
-
this.
|
|
6651
|
+
this.cardLoadingStateController.onSetLoadStartState();
|
|
6395
6652
|
};
|
|
6396
6653
|
const onSlideLoadingError = (index, reason) => {
|
|
6397
|
-
this.
|
|
6654
|
+
this.cardLoadingStateController.onSetLoadErrorState(reason);
|
|
6398
6655
|
};
|
|
6399
6656
|
const onShowSlide = (slide, index) => {
|
|
6400
|
-
this.
|
|
6657
|
+
this.cardLoadingStateController.onSetLoadEndState();
|
|
6401
6658
|
this.sdkApi.emitEvent("showSlide", { cardId: this.slides[index]?.slide?.slide.cardId ?? 0, index });
|
|
6402
6659
|
// if (index === 0) {
|
|
6403
6660
|
// this.activeSlide = slideApi;
|
|
@@ -6489,6 +6746,7 @@ class CardApi {
|
|
|
6489
6746
|
canMediaMount: resourcesReadyPromise,
|
|
6490
6747
|
})),
|
|
6491
6748
|
nonce: this.config.nonce,
|
|
6749
|
+
navbarAppearance: cardAppearance.navbar ?? {},
|
|
6492
6750
|
slideRender,
|
|
6493
6751
|
onSlideMounted,
|
|
6494
6752
|
onBeforeShowSlide,
|
|
@@ -6498,14 +6756,16 @@ class CardApi {
|
|
|
6498
6756
|
onSlideLeft,
|
|
6499
6757
|
getLayoutDirection: () => this.layoutDirection,
|
|
6500
6758
|
onSlideTimerEnd: () => this.activeSlide.slideTimerEnd(),
|
|
6759
|
+
onSlideChangeActiveIndex: index => (this.activeSlide = this.slides[index].slide),
|
|
6501
6760
|
onSlideStart: () => {
|
|
6502
|
-
|
|
6761
|
+
// return Promise.resolve({currentTime: 0});
|
|
6762
|
+
this.cardLoadingStateController.onSetLoadEndState();
|
|
6503
6763
|
return this.activeSlide.slideStart({ muted: true });
|
|
6504
6764
|
},
|
|
6505
6765
|
onSlideStop: () => this.activeSlide.slideStop({ prepareForRestart: 1 /* ON_SLIDE_STOP_PREPARE_FOR_RESTART.PREPARE */ }),
|
|
6506
|
-
onSlideDataWaiting: () => this.
|
|
6507
|
-
onSlideDataResume: () => this.
|
|
6508
|
-
onSlideDataError: () => this.
|
|
6766
|
+
onSlideDataWaiting: () => this.cardLoadingStateController.onSetLoadStartState(),
|
|
6767
|
+
onSlideDataResume: () => this.cardLoadingStateController.onSetLoadEndState(),
|
|
6768
|
+
onSlideDataError: () => this.cardLoadingStateController.onSetLoadEndState(),
|
|
6509
6769
|
});
|
|
6510
6770
|
await this.slider.showByIndex(index);
|
|
6511
6771
|
// return await onShowActiveCard;
|
|
@@ -6579,6 +6839,15 @@ class CardApi {
|
|
|
6579
6839
|
if (this.slidesMode === 1 /* SLIDES_MODE.MULTIPLE */ && result.canClickNext) {
|
|
6580
6840
|
result.canClickNext = false; // handle nav click via CardsSlider, not via SDK
|
|
6581
6841
|
const currentIndex = this.activeSlide.index;
|
|
6842
|
+
/**
|
|
6843
|
+
* business logic - avoid action on side slides click
|
|
6844
|
+
*/
|
|
6845
|
+
if (currentIndex === 0 && navigationDirection === "backward") {
|
|
6846
|
+
return result;
|
|
6847
|
+
}
|
|
6848
|
+
if (currentIndex === this.slides.length - 1 && navigationDirection === "forward") {
|
|
6849
|
+
return result;
|
|
6850
|
+
}
|
|
6582
6851
|
let index = navigationDirection === "forward" ? currentIndex + 1 : currentIndex - 1;
|
|
6583
6852
|
if (index >= this.slides.length) {
|
|
6584
6853
|
index = 0;
|
|
@@ -6586,11 +6855,7 @@ class CardApi {
|
|
|
6586
6855
|
else if (index < 0) {
|
|
6587
6856
|
index = this.slides.length - 1;
|
|
6588
6857
|
}
|
|
6589
|
-
this.slider.showByIndex(index)
|
|
6590
|
-
if (currentIndex === index)
|
|
6591
|
-
return;
|
|
6592
|
-
this.activeSlide = this.slides[index].slide;
|
|
6593
|
-
});
|
|
6858
|
+
this.slider.showByIndex(index);
|
|
6594
6859
|
}
|
|
6595
6860
|
return result;
|
|
6596
6861
|
}
|
|
@@ -18742,6 +19007,832 @@ class SwipeGestureDetector {
|
|
|
18742
19007
|
static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `boolean`, `(e: MouseEvent | TouchEvent) => boolean`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent, gesture: SwipeGesture) => void`]; }
|
|
18743
19008
|
}
|
|
18744
19009
|
|
|
19010
|
+
class RenderableComponent {
|
|
19011
|
+
_root = null;
|
|
19012
|
+
props;
|
|
19013
|
+
constructor(props) {
|
|
19014
|
+
this.props = (props ?? {});
|
|
19015
|
+
}
|
|
19016
|
+
render() {
|
|
19017
|
+
const newRoot = this.renderTemplate();
|
|
19018
|
+
const style = this.styleContent();
|
|
19019
|
+
if (style) {
|
|
19020
|
+
newRoot?.prepend(this.createStyleElement(style));
|
|
19021
|
+
}
|
|
19022
|
+
if (this._root) {
|
|
19023
|
+
this._root.replaceWith(newRoot ?? "");
|
|
19024
|
+
}
|
|
19025
|
+
this._root = newRoot;
|
|
19026
|
+
return this._root;
|
|
19027
|
+
}
|
|
19028
|
+
updateProps(props) {
|
|
19029
|
+
this.props = { ...this.props, ...props };
|
|
19030
|
+
this.render();
|
|
19031
|
+
}
|
|
19032
|
+
destroy() {
|
|
19033
|
+
this._root?.remove();
|
|
19034
|
+
this._root = null;
|
|
19035
|
+
}
|
|
19036
|
+
createStyleElement(css) {
|
|
19037
|
+
const styleEl = document.createElement("style");
|
|
19038
|
+
styleEl.textContent = css;
|
|
19039
|
+
return styleEl;
|
|
19040
|
+
}
|
|
19041
|
+
styleContent() {
|
|
19042
|
+
return "";
|
|
19043
|
+
}
|
|
19044
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`Props`]; }
|
|
19045
|
+
}
|
|
19046
|
+
|
|
19047
|
+
function h(tag, ...rest) {
|
|
19048
|
+
let props = {};
|
|
19049
|
+
let children = [];
|
|
19050
|
+
if (rest[0] && typeof rest[0] === "object" && !(rest[0] instanceof Node)) {
|
|
19051
|
+
props = rest.shift();
|
|
19052
|
+
}
|
|
19053
|
+
children = rest.flat();
|
|
19054
|
+
const el = document.createElement(tag);
|
|
19055
|
+
for (const [key, value] of Object.entries(props)) {
|
|
19056
|
+
if (value == null)
|
|
19057
|
+
continue;
|
|
19058
|
+
if (key === "class" || key === "className") {
|
|
19059
|
+
el.className = value;
|
|
19060
|
+
}
|
|
19061
|
+
else if (key === "textContent") {
|
|
19062
|
+
el.textContent = value;
|
|
19063
|
+
}
|
|
19064
|
+
else if (key === "html" || key === "innerHTML") {
|
|
19065
|
+
el.innerHTML = value;
|
|
19066
|
+
}
|
|
19067
|
+
else if (key === "ref" && typeof value === "function") {
|
|
19068
|
+
value(el);
|
|
19069
|
+
}
|
|
19070
|
+
else if (key.startsWith("data-")) {
|
|
19071
|
+
el.setAttribute(key, value);
|
|
19072
|
+
}
|
|
19073
|
+
else if (key.startsWith("on") && typeof value === "function") {
|
|
19074
|
+
const event = key.slice(2).toLowerCase();
|
|
19075
|
+
el.addEventListener(event, value);
|
|
19076
|
+
}
|
|
19077
|
+
else if (key in el) {
|
|
19078
|
+
// @ts-ignore — any valid DOM props
|
|
19079
|
+
el[key] = value;
|
|
19080
|
+
}
|
|
19081
|
+
else {
|
|
19082
|
+
el.setAttribute(key, value);
|
|
19083
|
+
}
|
|
19084
|
+
}
|
|
19085
|
+
for (const child of children) {
|
|
19086
|
+
if (child == null)
|
|
19087
|
+
continue;
|
|
19088
|
+
if (typeof child === "string") {
|
|
19089
|
+
el.appendChild(document.createTextNode(child));
|
|
19090
|
+
}
|
|
19091
|
+
else {
|
|
19092
|
+
el.appendChild(child);
|
|
19093
|
+
}
|
|
19094
|
+
}
|
|
19095
|
+
return el;
|
|
19096
|
+
}
|
|
19097
|
+
|
|
19098
|
+
class BottomSheet extends RenderableComponent {
|
|
19099
|
+
isClosing = false;
|
|
19100
|
+
_isOpened = false;
|
|
19101
|
+
constructor(props) {
|
|
19102
|
+
super(props ?? {});
|
|
19103
|
+
}
|
|
19104
|
+
get isOpened() {
|
|
19105
|
+
return this._isOpened;
|
|
19106
|
+
}
|
|
19107
|
+
renderTemplate() {
|
|
19108
|
+
return h("div", { class: `ias-bottom-sheet ${this._isOpened ? "ias-bottom-sheet--open" : ""}` }, h("div", {
|
|
19109
|
+
class: "ias-bottom-sheet__backdrop",
|
|
19110
|
+
onClick: this.handleBackdropClick,
|
|
19111
|
+
}), h("div", { class: "ias-bottom-sheet__container" }, h("div", { class: "ias-bottom-sheet__content" },
|
|
19112
|
+
/* h("div", { class: "ias-bottom-sheet__header" }), */
|
|
19113
|
+
h("div", { class: "ias-bottom-sheet__body" }, ...(this.props?.children?.map(c => c.render()) ?? [])))));
|
|
19114
|
+
}
|
|
19115
|
+
setHeight(height) {
|
|
19116
|
+
if (!this._root)
|
|
19117
|
+
return;
|
|
19118
|
+
const container = this._root.querySelector(".ias-bottom-sheet__container");
|
|
19119
|
+
if (!container)
|
|
19120
|
+
return;
|
|
19121
|
+
container.style.height = height;
|
|
19122
|
+
}
|
|
19123
|
+
open() {
|
|
19124
|
+
if (this.isOpened)
|
|
19125
|
+
return;
|
|
19126
|
+
this._isOpened = true;
|
|
19127
|
+
requestAnimationFrame(() => {
|
|
19128
|
+
requestAnimationFrame(() => {
|
|
19129
|
+
this._root?.classList.add("ias-bottom-sheet--open");
|
|
19130
|
+
});
|
|
19131
|
+
});
|
|
19132
|
+
}
|
|
19133
|
+
async close() {
|
|
19134
|
+
if (!this._root || this.isClosing)
|
|
19135
|
+
return;
|
|
19136
|
+
const root = this._root;
|
|
19137
|
+
root.classList.remove("ias-bottom-sheet--open");
|
|
19138
|
+
this.isClosing = true;
|
|
19139
|
+
await new Promise(resolve => {
|
|
19140
|
+
root.addEventListener("transitionend", () => resolve(), { once: true });
|
|
19141
|
+
});
|
|
19142
|
+
this.isClosing = false;
|
|
19143
|
+
this.props?.onClose?.();
|
|
19144
|
+
}
|
|
19145
|
+
handleBackdropClick = (e) => {
|
|
19146
|
+
e.preventDefault();
|
|
19147
|
+
e.stopPropagation();
|
|
19148
|
+
this.close();
|
|
19149
|
+
};
|
|
19150
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`BottomSheetProps`]; }
|
|
19151
|
+
}
|
|
19152
|
+
|
|
19153
|
+
class ProductDetailsDescription extends RenderableComponent {
|
|
19154
|
+
constructor(props) {
|
|
19155
|
+
super(props);
|
|
19156
|
+
}
|
|
19157
|
+
renderTemplate() {
|
|
19158
|
+
const { name, description } = this.props;
|
|
19159
|
+
return h("div", { class: "ias-product-details__description" }, name ? h("h6", { class: "ias-product-details__name", textContent: name }) : null, description ? h("p", { class: "ias-product-details__text", textContent: description }) : null);
|
|
19160
|
+
}
|
|
19161
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsDescriptionProps`]; }
|
|
19162
|
+
}
|
|
19163
|
+
|
|
19164
|
+
class ProductDetailsGallery extends RenderableComponent {
|
|
19165
|
+
constructor(props) {
|
|
19166
|
+
super(props);
|
|
19167
|
+
}
|
|
19168
|
+
renderTemplate() {
|
|
19169
|
+
const { imageUrls = [] } = this.props;
|
|
19170
|
+
return h("div", { class: "ias-product-details__gallery" }, imageUrls.map(url => h("figure", { class: "ias-product-details__image" }, h("img", { src: url /* , loading: "lazy" */ }))));
|
|
19171
|
+
}
|
|
19172
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsGalleryProps`]; }
|
|
19173
|
+
}
|
|
19174
|
+
|
|
19175
|
+
const ADD_TO_CART_TIMEOUT = 60000;
|
|
19176
|
+
|
|
19177
|
+
class ProductDetailsPurchaseAction extends RenderableComponent {
|
|
19178
|
+
button;
|
|
19179
|
+
constructor(props) {
|
|
19180
|
+
super(props);
|
|
19181
|
+
}
|
|
19182
|
+
renderTemplate() {
|
|
19183
|
+
this.button = h("button", {
|
|
19184
|
+
class: "ias-product-details__action-button",
|
|
19185
|
+
textContent: this.props.translations.addToCart,
|
|
19186
|
+
onClick: this.handleClickAddToCart,
|
|
19187
|
+
});
|
|
19188
|
+
return this.button;
|
|
19189
|
+
}
|
|
19190
|
+
handleClickAddToCart = async () => {
|
|
19191
|
+
try {
|
|
19192
|
+
this.showLoader();
|
|
19193
|
+
await this.addToCart();
|
|
19194
|
+
}
|
|
19195
|
+
catch (error) {
|
|
19196
|
+
this.handleAddToCartError(error);
|
|
19197
|
+
}
|
|
19198
|
+
finally {
|
|
19199
|
+
this.hideLoader();
|
|
19200
|
+
}
|
|
19201
|
+
};
|
|
19202
|
+
showLoader() {
|
|
19203
|
+
this.button.classList.add("ias-product-details__action-button--loading");
|
|
19204
|
+
}
|
|
19205
|
+
hideLoader() {
|
|
19206
|
+
this.button.classList.remove("ias-product-details__action-button--loading");
|
|
19207
|
+
}
|
|
19208
|
+
handleAddToCartError(error) {
|
|
19209
|
+
this.props.onAddToCartError({ error });
|
|
19210
|
+
}
|
|
19211
|
+
async addToCart() {
|
|
19212
|
+
await Promise.race([this.props.onAddToCart(), new Promise((resolve, reject) => setTimeout(reject, ADD_TO_CART_TIMEOUT))]);
|
|
19213
|
+
}
|
|
19214
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchaseActionProps`]; }
|
|
19215
|
+
}
|
|
19216
|
+
|
|
19217
|
+
class ProductDetailsPurchasePrice extends RenderableComponent {
|
|
19218
|
+
constructor(props) {
|
|
19219
|
+
super(props);
|
|
19220
|
+
}
|
|
19221
|
+
renderTemplate() {
|
|
19222
|
+
const { price, oldPrice, currency } = this.props.product;
|
|
19223
|
+
const rootEl = h("div", { class: "ias-product-details__price" });
|
|
19224
|
+
if (price != null && currency) {
|
|
19225
|
+
const currentPriceEl = h("div", {
|
|
19226
|
+
class: "ias-product-details__current-price",
|
|
19227
|
+
html: formatter.asCurrency(price, currency),
|
|
19228
|
+
});
|
|
19229
|
+
rootEl.appendChild(currentPriceEl);
|
|
19230
|
+
}
|
|
19231
|
+
if (oldPrice != null && currency) {
|
|
19232
|
+
const oldPriceEl = h("div", {
|
|
19233
|
+
class: "ias-product-details__old-price",
|
|
19234
|
+
html: formatter.asCurrency(oldPrice, currency),
|
|
19235
|
+
});
|
|
19236
|
+
rootEl.appendChild(oldPriceEl);
|
|
19237
|
+
}
|
|
19238
|
+
return rootEl;
|
|
19239
|
+
}
|
|
19240
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchasePriceProps`]; }
|
|
19241
|
+
}
|
|
19242
|
+
|
|
19243
|
+
class ProductDetailsCounter extends RenderableComponent {
|
|
19244
|
+
_value = 1;
|
|
19245
|
+
countElement = null;
|
|
19246
|
+
get value() {
|
|
19247
|
+
return this._value;
|
|
19248
|
+
}
|
|
19249
|
+
updateProps() {
|
|
19250
|
+
this._value = 1;
|
|
19251
|
+
this.render();
|
|
19252
|
+
}
|
|
19253
|
+
renderTemplate() {
|
|
19254
|
+
return h("div", { class: "ias-product-details__counter" }, h("button", {
|
|
19255
|
+
class: "ias-product-details__counter-button",
|
|
19256
|
+
textContent: "−",
|
|
19257
|
+
onClick: this.handleClickOnMinusButton,
|
|
19258
|
+
}), h("span", {
|
|
19259
|
+
class: "ias-product-details__counter-count",
|
|
19260
|
+
textContent: this._value.toString(),
|
|
19261
|
+
ref: (el) => (this.countElement = el),
|
|
19262
|
+
}), h("button", {
|
|
19263
|
+
class: "ias-product-details__counter-button",
|
|
19264
|
+
textContent: "+",
|
|
19265
|
+
onClick: this.handleClickOnPlusButton,
|
|
19266
|
+
}));
|
|
19267
|
+
}
|
|
19268
|
+
handleClickOnMinusButton = () => {
|
|
19269
|
+
this._value = Math.max(this._value - 1, 1);
|
|
19270
|
+
this.updateCountValue();
|
|
19271
|
+
};
|
|
19272
|
+
handleClickOnPlusButton = () => {
|
|
19273
|
+
this._value++;
|
|
19274
|
+
this.updateCountValue();
|
|
19275
|
+
};
|
|
19276
|
+
updateCountValue() {
|
|
19277
|
+
if (this.countElement) {
|
|
19278
|
+
this.countElement.textContent = this._value.toString();
|
|
19279
|
+
}
|
|
19280
|
+
}
|
|
19281
|
+
}
|
|
19282
|
+
|
|
19283
|
+
class ProductDetailsPurchase extends RenderableComponent {
|
|
19284
|
+
price;
|
|
19285
|
+
action;
|
|
19286
|
+
counter = new ProductDetailsCounter();
|
|
19287
|
+
constructor(props) {
|
|
19288
|
+
super(props);
|
|
19289
|
+
}
|
|
19290
|
+
renderTemplate() {
|
|
19291
|
+
this.price = new ProductDetailsPurchasePrice(this.props);
|
|
19292
|
+
this.action = new ProductDetailsPurchaseAction({
|
|
19293
|
+
onAddToCart: this.handleOnAddToCart,
|
|
19294
|
+
onAddToCartError: this.props.onAddToCartError,
|
|
19295
|
+
translations: this.props.translations,
|
|
19296
|
+
});
|
|
19297
|
+
return h("div", { class: "ias-product-details__purchase" }, h("div", { class: "ias-product-details__price-box" }, this.price.render(), this.counter.render()), this.action.render());
|
|
19298
|
+
}
|
|
19299
|
+
updateProps(props) {
|
|
19300
|
+
this.props = { ...this.props, ...props };
|
|
19301
|
+
this.price.updateProps(this.props);
|
|
19302
|
+
this.counter.updateProps();
|
|
19303
|
+
}
|
|
19304
|
+
handleOnAddToCart = async () => {
|
|
19305
|
+
return this.props.onAddToCart({
|
|
19306
|
+
quantity: this.counter.value,
|
|
19307
|
+
product: this.props.product,
|
|
19308
|
+
});
|
|
19309
|
+
};
|
|
19310
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchaseProps`]; }
|
|
19311
|
+
}
|
|
19312
|
+
|
|
19313
|
+
class ProductOptionButton extends RenderableComponent {
|
|
19314
|
+
constructor(props) {
|
|
19315
|
+
super(props);
|
|
19316
|
+
}
|
|
19317
|
+
renderTemplate() {
|
|
19318
|
+
const params = {
|
|
19319
|
+
class: `ias-product-details__option-button ${this.props.selected ? "ias-product-details__option-button--active" : ""} ${this.props.disabled ? "ias-product-details__option-button--disabled" : ""}`,
|
|
19320
|
+
textContent: this.props.label,
|
|
19321
|
+
onclick: () => {
|
|
19322
|
+
this.props.onClick();
|
|
19323
|
+
},
|
|
19324
|
+
};
|
|
19325
|
+
return h("button", params);
|
|
19326
|
+
}
|
|
19327
|
+
setSelected(selected) {
|
|
19328
|
+
if (!this._root)
|
|
19329
|
+
return;
|
|
19330
|
+
if (selected)
|
|
19331
|
+
this._root.classList.add("ias-product-details__option-button--active");
|
|
19332
|
+
else
|
|
19333
|
+
this._root.classList.remove("ias-product-details__option-button--active");
|
|
19334
|
+
}
|
|
19335
|
+
setDisabled(disabled) {
|
|
19336
|
+
if (!this._root)
|
|
19337
|
+
return;
|
|
19338
|
+
if (disabled)
|
|
19339
|
+
this._root.classList.add("ias-product-details__option-button--disabled");
|
|
19340
|
+
else
|
|
19341
|
+
this._root.classList.remove("ias-product-details__option-button--disabled");
|
|
19342
|
+
}
|
|
19343
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionButtonProps`]; }
|
|
19344
|
+
}
|
|
19345
|
+
|
|
19346
|
+
class ProductOptionsManager {
|
|
19347
|
+
optionNames;
|
|
19348
|
+
productVariants;
|
|
19349
|
+
subscribers = [];
|
|
19350
|
+
selectedOptions = {};
|
|
19351
|
+
allOptionsByName = {};
|
|
19352
|
+
availableOptionsByName = {};
|
|
19353
|
+
constructor(optionNames, productVariants) {
|
|
19354
|
+
this.optionNames = optionNames;
|
|
19355
|
+
this.productVariants = productVariants;
|
|
19356
|
+
this.allOptionsByName = this.extractAllOptions();
|
|
19357
|
+
}
|
|
19358
|
+
get selected() {
|
|
19359
|
+
return { ...this.selectedOptions };
|
|
19360
|
+
}
|
|
19361
|
+
get availableOptions() {
|
|
19362
|
+
return this.availableOptionsByName;
|
|
19363
|
+
}
|
|
19364
|
+
selectOption(option) {
|
|
19365
|
+
const compatibleVariants = this.findCompatibleVariants(option);
|
|
19366
|
+
this.ensureVariantsExist(option, compatibleVariants);
|
|
19367
|
+
const matchingVariant = this.findMatchingVariant(compatibleVariants);
|
|
19368
|
+
this.selectVariant(matchingVariant);
|
|
19369
|
+
}
|
|
19370
|
+
selectVariant(variant) {
|
|
19371
|
+
this.optionNames.forEach(name => {
|
|
19372
|
+
const currentSelected = this.selectedOptions[name];
|
|
19373
|
+
const newOption = variant.options[name];
|
|
19374
|
+
if (currentSelected && newOption && currentSelected.value === newOption.value) {
|
|
19375
|
+
this.selectedOptions[name] = currentSelected;
|
|
19376
|
+
}
|
|
19377
|
+
else {
|
|
19378
|
+
this.selectedOptions[name] = newOption;
|
|
19379
|
+
}
|
|
19380
|
+
});
|
|
19381
|
+
this.availableOptionsByName = this.extractAvailableOptions();
|
|
19382
|
+
this.notifySubscribers(variant);
|
|
19383
|
+
}
|
|
19384
|
+
onChange(callback) {
|
|
19385
|
+
this.subscribers.push(callback);
|
|
19386
|
+
}
|
|
19387
|
+
isOptionSelected(option) {
|
|
19388
|
+
return this.selected[option.name]?.value === option.value;
|
|
19389
|
+
}
|
|
19390
|
+
isOptionDisabled(option) {
|
|
19391
|
+
const options = this.availableOptions[option.name];
|
|
19392
|
+
return !options?.some(o => o.value === option.value);
|
|
19393
|
+
}
|
|
19394
|
+
getOptionsFor(name) {
|
|
19395
|
+
return this.allOptionsByName[name] ?? [];
|
|
19396
|
+
}
|
|
19397
|
+
findCompatibleVariants(option) {
|
|
19398
|
+
return this.productVariants.filter(variant => variant.options[option.name]?.value === option.value);
|
|
19399
|
+
}
|
|
19400
|
+
ensureVariantsExist(option, variants) {
|
|
19401
|
+
if (variants.length === 0) {
|
|
19402
|
+
throw new Error(`[IAS]: No compatible variant for option <${option.name}:${option.value}>`);
|
|
19403
|
+
}
|
|
19404
|
+
}
|
|
19405
|
+
findMatchingVariant(variants) {
|
|
19406
|
+
return (variants.find(variant => this.optionNames.every(name => !this.selectedOptions[name] || variant.options[name]?.value === this.selectedOptions[name]?.value)) ?? variants[0]);
|
|
19407
|
+
}
|
|
19408
|
+
extractAvailableOptions() {
|
|
19409
|
+
const result = {};
|
|
19410
|
+
for (const name of this.optionNames) {
|
|
19411
|
+
const filteredVariants = this.filterVariantsExcludingOption(name);
|
|
19412
|
+
const available = filteredVariants.filter(v => v.available && v.options[name]).map(v => v.options[name]);
|
|
19413
|
+
result[name] = this.getUniqueByKey(available, o => o.value);
|
|
19414
|
+
}
|
|
19415
|
+
return result;
|
|
19416
|
+
}
|
|
19417
|
+
filterVariantsExcludingOption(excludedName) {
|
|
19418
|
+
const filters = { ...this.selectedOptions };
|
|
19419
|
+
delete filters[excludedName];
|
|
19420
|
+
return this.productVariants.filter(variant => Object.entries(filters).every(([name, selected]) => variant.options[name]?.value === selected?.value));
|
|
19421
|
+
}
|
|
19422
|
+
extractAllOptions() {
|
|
19423
|
+
const all = {};
|
|
19424
|
+
for (const name of this.optionNames) {
|
|
19425
|
+
const options = this.productVariants.map(v => v.options[name]).filter(Boolean);
|
|
19426
|
+
all[name] = this.getUniqueByKey(options, o => o.value);
|
|
19427
|
+
}
|
|
19428
|
+
return all;
|
|
19429
|
+
}
|
|
19430
|
+
getUniqueByKey(items, getKey) {
|
|
19431
|
+
return items.filter((item, index, self) => index === self.findIndex(i => getKey(i) === getKey(item)));
|
|
19432
|
+
}
|
|
19433
|
+
notifySubscribers(variant) {
|
|
19434
|
+
this.subscribers.forEach(cb => cb(variant));
|
|
19435
|
+
}
|
|
19436
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionName[]`, `ProductVariant[]`]; }
|
|
19437
|
+
}
|
|
19438
|
+
|
|
19439
|
+
class ProductOptions extends RenderableComponent {
|
|
19440
|
+
optionsManager;
|
|
19441
|
+
optionsContainer;
|
|
19442
|
+
optionButtonsMap = new Map();
|
|
19443
|
+
constructor(props) {
|
|
19444
|
+
super(props);
|
|
19445
|
+
this.optionsManager = new ProductOptionsManager(props.optionNames, props.products);
|
|
19446
|
+
this.init(props.products);
|
|
19447
|
+
}
|
|
19448
|
+
renderTemplate() {
|
|
19449
|
+
this.optionsContainer = h("div", { class: "ias-product-details__options" }, this.renderOptionSelectors());
|
|
19450
|
+
return this.optionsContainer;
|
|
19451
|
+
}
|
|
19452
|
+
init(products) {
|
|
19453
|
+
this.optionsManager.selectVariant(products[0]);
|
|
19454
|
+
this.optionsManager.onChange(variant => {
|
|
19455
|
+
this.updateButtonsState();
|
|
19456
|
+
this.props.onChange(variant);
|
|
19457
|
+
});
|
|
19458
|
+
}
|
|
19459
|
+
renderOptionSelectors() {
|
|
19460
|
+
return this.props.optionNames.map(optionName => this.optionsManager.getOptionsFor(optionName).length > 0
|
|
19461
|
+
? h("div", { class: "ias-product-details__selector" }, h("div", { class: "ias-product-details__selector-name", textContent: this.getOptionLabelByName(optionName) }), h("div", { class: "ias-product-details__option-selector" }, this.renderOptionsBySelector(optionName)))
|
|
19462
|
+
: null);
|
|
19463
|
+
}
|
|
19464
|
+
getOptionLabelByName(optionName) {
|
|
19465
|
+
switch (optionName) {
|
|
19466
|
+
case "color":
|
|
19467
|
+
return this.props.translations.color;
|
|
19468
|
+
case "size":
|
|
19469
|
+
return this.props.translations.size;
|
|
19470
|
+
}
|
|
19471
|
+
}
|
|
19472
|
+
renderOptionsBySelector(name) {
|
|
19473
|
+
const options = this.optionsManager.getOptionsFor(name);
|
|
19474
|
+
const buttons = [];
|
|
19475
|
+
const buttonElements = options.map(option => {
|
|
19476
|
+
const disabled = this.optionsManager.isOptionDisabled(option);
|
|
19477
|
+
const selected = this.optionsManager.isOptionSelected(option);
|
|
19478
|
+
const productOptionButton = new ProductOptionButton({
|
|
19479
|
+
selected,
|
|
19480
|
+
label: option.value,
|
|
19481
|
+
disabled,
|
|
19482
|
+
onClick: () => {
|
|
19483
|
+
this.optionsManager.selectOption(option);
|
|
19484
|
+
},
|
|
19485
|
+
});
|
|
19486
|
+
buttons.push(productOptionButton);
|
|
19487
|
+
return productOptionButton.render();
|
|
19488
|
+
});
|
|
19489
|
+
this.optionButtonsMap.set(name, buttons);
|
|
19490
|
+
return buttonElements;
|
|
19491
|
+
}
|
|
19492
|
+
updateButtonsState() {
|
|
19493
|
+
for (const [optionName, buttons] of this.optionButtonsMap.entries()) {
|
|
19494
|
+
const options = this.optionsManager.getOptionsFor(optionName);
|
|
19495
|
+
buttons.forEach((button, index) => {
|
|
19496
|
+
const option = options[index];
|
|
19497
|
+
const isSelected = this.optionsManager.isOptionSelected(option);
|
|
19498
|
+
const isDisabled = this.optionsManager.isOptionDisabled(option);
|
|
19499
|
+
button.setSelected(isSelected);
|
|
19500
|
+
button.setDisabled(isDisabled);
|
|
19501
|
+
});
|
|
19502
|
+
}
|
|
19503
|
+
}
|
|
19504
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionsProps`]; }
|
|
19505
|
+
}
|
|
19506
|
+
|
|
19507
|
+
class ProductDetailsCover extends RenderableComponent {
|
|
19508
|
+
renderTemplate() {
|
|
19509
|
+
return h(`div`, { class: "ias-product-details__cover" }, h("img", { src: this.props.src }));
|
|
19510
|
+
}
|
|
19511
|
+
styleContent() {
|
|
19512
|
+
return `
|
|
19513
|
+
.ias-product-details__cover {
|
|
19514
|
+
position: absolute;
|
|
19515
|
+
z-index: -1;
|
|
19516
|
+
inset: 0;
|
|
19517
|
+
}
|
|
19518
|
+
|
|
19519
|
+
.ias-product-details__cover img {
|
|
19520
|
+
width: 100%;
|
|
19521
|
+
height: 100%;
|
|
19522
|
+
object-fit: cover;
|
|
19523
|
+
}
|
|
19524
|
+
`;
|
|
19525
|
+
}
|
|
19526
|
+
}
|
|
19527
|
+
|
|
19528
|
+
class ProductDetails extends RenderableComponent {
|
|
19529
|
+
constructor(props) {
|
|
19530
|
+
super(props);
|
|
19531
|
+
}
|
|
19532
|
+
renderTemplate() {
|
|
19533
|
+
const { props } = this;
|
|
19534
|
+
const purchase = new ProductDetailsPurchase(props);
|
|
19535
|
+
const cover = new ProductDetailsCover({
|
|
19536
|
+
src: this.props.product.coverUrl ?? "",
|
|
19537
|
+
});
|
|
19538
|
+
const gallery = new ProductDetailsGallery({
|
|
19539
|
+
imageUrls: this.props.product.imageUrls ?? [],
|
|
19540
|
+
});
|
|
19541
|
+
const description = new ProductDetailsDescription(props.product);
|
|
19542
|
+
const productOptions = this.createProductOptions({ purchase, gallery, description, cover });
|
|
19543
|
+
const relatedProductsLength = this.props.relatedProducts.length ?? 0;
|
|
19544
|
+
return h("div", { class: "ias-product-details" },
|
|
19545
|
+
/* this.props.product.coverUrl ? cover.render() : null, */
|
|
19546
|
+
h("div", { class: "ias-product-details__scrollable" }, gallery.render(), h("div", { class: "ias-product-details__content" }, description.render(), relatedProductsLength > 0 ? productOptions.render() : null)), this.createFooter(purchase));
|
|
19547
|
+
}
|
|
19548
|
+
createProductOptions({ purchase, gallery, description, cover, }) {
|
|
19549
|
+
return new ProductOptions({
|
|
19550
|
+
optionNames: ["color", "size"],
|
|
19551
|
+
products: [this.props.product, ...this.props.relatedProducts],
|
|
19552
|
+
onChange: (product) => {
|
|
19553
|
+
if (this.props.isCartSupported)
|
|
19554
|
+
purchase.updateProps({ product: product });
|
|
19555
|
+
gallery.updateProps(product);
|
|
19556
|
+
description.updateProps(product);
|
|
19557
|
+
cover.updateProps({
|
|
19558
|
+
src: product.coverUrl,
|
|
19559
|
+
});
|
|
19560
|
+
},
|
|
19561
|
+
translations: this.props.translations,
|
|
19562
|
+
});
|
|
19563
|
+
}
|
|
19564
|
+
createFooter(purchase) {
|
|
19565
|
+
if (this.props.isCartSupported) {
|
|
19566
|
+
return h("div", { class: "ias-product-details__footer" }, purchase.render());
|
|
19567
|
+
}
|
|
19568
|
+
else if (this.props.product.url) {
|
|
19569
|
+
return h("div", { class: "ias-product-details__footer" }, this.createOpenUrlButton());
|
|
19570
|
+
}
|
|
19571
|
+
return null;
|
|
19572
|
+
}
|
|
19573
|
+
createOpenUrlButton() {
|
|
19574
|
+
return h("button", {
|
|
19575
|
+
class: "ias-product-details__action-button ias-product-details__open-url-button",
|
|
19576
|
+
textContent: this.props.translations.openUrl,
|
|
19577
|
+
onclick: () => {
|
|
19578
|
+
this.props.onOpenUrl();
|
|
19579
|
+
},
|
|
19580
|
+
});
|
|
19581
|
+
}
|
|
19582
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsProps`]; }
|
|
19583
|
+
}
|
|
19584
|
+
|
|
19585
|
+
class ProductOfferMapper {
|
|
19586
|
+
static fromOfferDtoToProductOffer(offerDto) {
|
|
19587
|
+
return {
|
|
19588
|
+
id: offerDto.id.toString(),
|
|
19589
|
+
offerId: offerDto.offerId,
|
|
19590
|
+
available: offerDto.availability !== 0,
|
|
19591
|
+
availability: offerDto.availability,
|
|
19592
|
+
options: {
|
|
19593
|
+
color: offerDto.color ? { name: "color", value: offerDto.color } : { name: "color", value: "Undefined" },
|
|
19594
|
+
size: offerDto.size ? { name: "size", value: offerDto.size } : { name: "size", value: "Undefined" },
|
|
19595
|
+
},
|
|
19596
|
+
name: offerDto.name,
|
|
19597
|
+
price: offerDto.price,
|
|
19598
|
+
oldPrice: offerDto.oldPrice,
|
|
19599
|
+
currency: offerDto.currency,
|
|
19600
|
+
description: offerDto.description,
|
|
19601
|
+
imageUrls: offerDto.images?.map(image => image.url) ?? [],
|
|
19602
|
+
adult: offerDto.adult,
|
|
19603
|
+
coverUrl: offerDto.coverUrl,
|
|
19604
|
+
groupId: offerDto.groupId,
|
|
19605
|
+
url: offerDto.url,
|
|
19606
|
+
};
|
|
19607
|
+
}
|
|
19608
|
+
static fromOfferDtoToProductCartOffer(offerDto, quantity) {
|
|
19609
|
+
return {
|
|
19610
|
+
offerId: offerDto.offerId,
|
|
19611
|
+
imageUrls: offerDto.images?.map(image => image.url) ?? [],
|
|
19612
|
+
availability: offerDto.availability,
|
|
19613
|
+
quantity,
|
|
19614
|
+
groupId: offerDto.groupId,
|
|
19615
|
+
name: offerDto.name,
|
|
19616
|
+
description: offerDto.description,
|
|
19617
|
+
url: offerDto.url,
|
|
19618
|
+
coverUrl: offerDto.coverUrl,
|
|
19619
|
+
currency: offerDto.currency,
|
|
19620
|
+
price: offerDto.price,
|
|
19621
|
+
oldPrice: offerDto.oldPrice,
|
|
19622
|
+
adult: offerDto.adult,
|
|
19623
|
+
size: offerDto.size,
|
|
19624
|
+
color: offerDto.color,
|
|
19625
|
+
};
|
|
19626
|
+
}
|
|
19627
|
+
}
|
|
19628
|
+
|
|
19629
|
+
const successSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none"><path stroke="#212121" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M40 14 18 36 8 26"></path></svg>`;
|
|
19630
|
+
class ProductCheckout extends RenderableComponent {
|
|
19631
|
+
constructor(props) {
|
|
19632
|
+
super(props);
|
|
19633
|
+
}
|
|
19634
|
+
renderTemplate() {
|
|
19635
|
+
return h("div", { class: "ias-product-checkout" }, h("div", { class: "ias-product-checkout__box" }, h("div", {
|
|
19636
|
+
class: "ias-product-checkout__icon",
|
|
19637
|
+
html: successSvg,
|
|
19638
|
+
}), h("span", {
|
|
19639
|
+
class: "ias-product-checkout__text",
|
|
19640
|
+
textContent: this.props.translations.successAddToCart,
|
|
19641
|
+
}), h("span", {
|
|
19642
|
+
class: "ias-product-checkout__sub-text",
|
|
19643
|
+
textContent: this.props.translations.successSubAddToCart,
|
|
19644
|
+
})), h("div", {
|
|
19645
|
+
class: "ias-product-checkout__actions",
|
|
19646
|
+
}, h("button", {
|
|
19647
|
+
class: "ias-product-checkout__button ias-product-checkout__button--close",
|
|
19648
|
+
textContent: this.props.translations.continueBtn,
|
|
19649
|
+
onclick: () => {
|
|
19650
|
+
this.props.onClose();
|
|
19651
|
+
},
|
|
19652
|
+
}), h("button", {
|
|
19653
|
+
class: "ias-product-checkout__button ias-product-checkout__button--checkout",
|
|
19654
|
+
textContent: this.props.translations.goToCartBtn,
|
|
19655
|
+
onclick: () => {
|
|
19656
|
+
this.props.onCheckout();
|
|
19657
|
+
},
|
|
19658
|
+
})));
|
|
19659
|
+
}
|
|
19660
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductCheckoutProps`]; }
|
|
19661
|
+
}
|
|
19662
|
+
|
|
19663
|
+
const cartSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 20 20" fill="none">
|
|
19664
|
+
<path stroke="rgba(255, 255, 255, 1)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="M4 1.333 2 4v9.333a1.333 1.333 0 0 0 1.333 1.334h9.334A1.334 1.334 0 0 0 14 13.333V4l-2-2.667H4ZM2 4h12"></path>
|
|
19665
|
+
<path stroke="rgba(255, 255, 255, 1)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="M10.667 6.667a2.667 2.667 0 1 1-5.333 0"></path>
|
|
19666
|
+
</svg>`;
|
|
19667
|
+
class ProductCartButton extends RenderableComponent {
|
|
19668
|
+
constructor(props) {
|
|
19669
|
+
super(props);
|
|
19670
|
+
}
|
|
19671
|
+
renderTemplate() {
|
|
19672
|
+
return h("div", { class: "ias-product-cart-button", onclick: () => this.props.onClick(), innerHTML: cartSvg });
|
|
19673
|
+
}
|
|
19674
|
+
styleContent() {
|
|
19675
|
+
return `
|
|
19676
|
+
.ias-product-cart-button {
|
|
19677
|
+
position: absolute;
|
|
19678
|
+
left: 0;
|
|
19679
|
+
top: 20%;
|
|
19680
|
+
padding: .25em;
|
|
19681
|
+
padding-left: .5em;
|
|
19682
|
+
background: black;
|
|
19683
|
+
border-top-right-radius: 0.69em;
|
|
19684
|
+
border-bottom-right-radius: 0.69em;
|
|
19685
|
+
display: flex;
|
|
19686
|
+
justify-content: center;
|
|
19687
|
+
align-items: center;
|
|
19688
|
+
cursor: pointer;
|
|
19689
|
+
transition: all 200ms ease-in;
|
|
19690
|
+
transform: translate3d(-.25em, 0, 0);
|
|
19691
|
+
}
|
|
19692
|
+
|
|
19693
|
+
.ias-product-cart-button:hover {
|
|
19694
|
+
transform: translate3d(0, 0, 0);
|
|
19695
|
+
}
|
|
19696
|
+
`;
|
|
19697
|
+
}
|
|
19698
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductCartButtonProps`]; }
|
|
19699
|
+
}
|
|
19700
|
+
|
|
19701
|
+
class ProductComponentsFactory {
|
|
19702
|
+
widgetDeps;
|
|
19703
|
+
props;
|
|
19704
|
+
constructor(widgetDeps, props) {
|
|
19705
|
+
this.widgetDeps = widgetDeps;
|
|
19706
|
+
this.props = props;
|
|
19707
|
+
}
|
|
19708
|
+
createBottomSheet() {
|
|
19709
|
+
const bs = new BottomSheet({
|
|
19710
|
+
onClose: () => {
|
|
19711
|
+
bs.destroy();
|
|
19712
|
+
},
|
|
19713
|
+
children: [],
|
|
19714
|
+
});
|
|
19715
|
+
return bs;
|
|
19716
|
+
}
|
|
19717
|
+
createProductDetails(params) {
|
|
19718
|
+
return new ProductDetails({
|
|
19719
|
+
product: ProductOfferMapper.fromOfferDtoToProductOffer(params.offer),
|
|
19720
|
+
relatedProducts: params.offer.subOffersApi
|
|
19721
|
+
? params.offer.subOffersApi.map(subOffer => ProductOfferMapper.fromOfferDtoToProductOffer(subOffer))
|
|
19722
|
+
: [],
|
|
19723
|
+
onAddToCart: params.onAddToCart,
|
|
19724
|
+
onAddToCartError: ({ error }) => {
|
|
19725
|
+
this.widgetDeps.slideApiDeps.showToast(error.message);
|
|
19726
|
+
},
|
|
19727
|
+
translations: this.props.translations,
|
|
19728
|
+
isCartSupported: params.isCartSupported,
|
|
19729
|
+
onOpenUrl: () => {
|
|
19730
|
+
if (params.offer.url)
|
|
19731
|
+
this.widgetDeps.slideApiDeps.openUrl({ type: "link", link: { type: "url", target: params.offer.url } });
|
|
19732
|
+
},
|
|
19733
|
+
});
|
|
19734
|
+
}
|
|
19735
|
+
createProductCheckout(bottomSheet, offers) {
|
|
19736
|
+
const offersByIds = {};
|
|
19737
|
+
for (const offer of offers)
|
|
19738
|
+
offersByIds[offer.offerId] = offer;
|
|
19739
|
+
return new ProductCheckout({
|
|
19740
|
+
onClose: () => bottomSheet.close(),
|
|
19741
|
+
onCheckout: () => {
|
|
19742
|
+
this.widgetDeps.slideApiDeps.productCartClicked();
|
|
19743
|
+
},
|
|
19744
|
+
translations: this.props.translations,
|
|
19745
|
+
});
|
|
19746
|
+
}
|
|
19747
|
+
createProductCartButton() {
|
|
19748
|
+
return new ProductCartButton({
|
|
19749
|
+
onClick: async () => {
|
|
19750
|
+
try {
|
|
19751
|
+
const state = await this.widgetDeps.slideApiDeps.productCartGetState();
|
|
19752
|
+
console.log({ cart: state });
|
|
19753
|
+
this.widgetDeps.slideApiDeps.showToast(JSON.stringify(state.offers.map(({ offerId, name, quantity }) => ({
|
|
19754
|
+
offerId,
|
|
19755
|
+
name,
|
|
19756
|
+
quantity,
|
|
19757
|
+
}))));
|
|
19758
|
+
}
|
|
19759
|
+
catch (error) {
|
|
19760
|
+
this.widgetDeps.slideApiDeps.showToast(error.message);
|
|
19761
|
+
}
|
|
19762
|
+
},
|
|
19763
|
+
});
|
|
19764
|
+
}
|
|
19765
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`WidgetDeps`, `{
|
|
19766
|
+
translations: TranslationsMap;
|
|
19767
|
+
}`]; }
|
|
19768
|
+
}
|
|
19769
|
+
|
|
19770
|
+
class ProductDetailsBottomSheet extends RenderableComponent {
|
|
19771
|
+
widgetDeps;
|
|
19772
|
+
factory;
|
|
19773
|
+
bottomSheet;
|
|
19774
|
+
constructor(widgetDeps, props) {
|
|
19775
|
+
super(props);
|
|
19776
|
+
this.widgetDeps = widgetDeps;
|
|
19777
|
+
this.factory = new ProductComponentsFactory(this.widgetDeps, this.props);
|
|
19778
|
+
this.bottomSheet = this.factory.createBottomSheet();
|
|
19779
|
+
}
|
|
19780
|
+
renderTemplate() {
|
|
19781
|
+
return this.bottomSheet.render();
|
|
19782
|
+
}
|
|
19783
|
+
open(params) {
|
|
19784
|
+
this.showProductDetails(params);
|
|
19785
|
+
this.bottomSheet.open();
|
|
19786
|
+
}
|
|
19787
|
+
showProductDetails = ({ offer, isCartSupported }) => {
|
|
19788
|
+
const factory = new ProductComponentsFactory(this.widgetDeps, this.props);
|
|
19789
|
+
const offerDtos = [offer, ...(offer.subOffersApi ?? [])];
|
|
19790
|
+
this.renderProductDetails({ factory, offer, offerDtos, isCartSupported });
|
|
19791
|
+
};
|
|
19792
|
+
renderProductDetails({ factory, offer, offerDtos, isCartSupported, }) {
|
|
19793
|
+
const productDetails = factory.createProductDetails({
|
|
19794
|
+
offer,
|
|
19795
|
+
onAddToCart: async (payload) => {
|
|
19796
|
+
await this.productCartUpdate({
|
|
19797
|
+
offerDtos,
|
|
19798
|
+
product: payload.product,
|
|
19799
|
+
quantity: payload.quantity,
|
|
19800
|
+
});
|
|
19801
|
+
this.showProductCheckout({ offerDtos });
|
|
19802
|
+
},
|
|
19803
|
+
isCartSupported,
|
|
19804
|
+
});
|
|
19805
|
+
this.updateBottomSheetContent(productDetails);
|
|
19806
|
+
}
|
|
19807
|
+
showProductCheckout({ offerDtos }) {
|
|
19808
|
+
const productCheckout = this.factory.createProductCheckout(this.bottomSheet, offerDtos);
|
|
19809
|
+
this.updateBottomSheetContent(productCheckout);
|
|
19810
|
+
this.bottomSheet.setHeight("auto");
|
|
19811
|
+
}
|
|
19812
|
+
updateBottomSheetContent(content) {
|
|
19813
|
+
const cartButton = this.factory.createProductCartButton();
|
|
19814
|
+
const children = process.env.NODE_ENV === "staging" ? [cartButton, content] : [content];
|
|
19815
|
+
this.bottomSheet.updateProps({
|
|
19816
|
+
children,
|
|
19817
|
+
});
|
|
19818
|
+
}
|
|
19819
|
+
async productCartUpdate({ offerDtos, product, quantity }) {
|
|
19820
|
+
const offerDto = offerDtos.find(offerDto => product.offerId === offerDto.offerId);
|
|
19821
|
+
if (!offerDto)
|
|
19822
|
+
throw new Error(`[IAS]: Not found offer for ID ${product.offerId}`);
|
|
19823
|
+
const cartOffer = ProductOfferMapper.fromOfferDtoToProductCartOffer(offerDto, quantity);
|
|
19824
|
+
const delay = async () => new Promise(resolve => setTimeout(resolve, 300));
|
|
19825
|
+
const [productCart] = await Promise.all([
|
|
19826
|
+
await await this.widgetDeps.slideApiDeps.productCartUpdate({
|
|
19827
|
+
offer: cartOffer,
|
|
19828
|
+
}),
|
|
19829
|
+
delay(),
|
|
19830
|
+
]);
|
|
19831
|
+
return productCart.offers;
|
|
19832
|
+
}
|
|
19833
|
+
static get [Symbol.for("___CTOR_ARGS___")]() { return [`WidgetDeps`, `ProductDetailsBottomSheetProps`]; }
|
|
19834
|
+
}
|
|
19835
|
+
|
|
18745
19836
|
/**
|
|
18746
19837
|
* adult: null
|
|
18747
19838
|
* availability: 1
|
|
@@ -18896,7 +19987,7 @@ class WidgetProducts extends WidgetBase {
|
|
|
18896
19987
|
if (!this.linkTarget.length) {
|
|
18897
19988
|
return { message: this.msgServiceError ?? "", models: [] };
|
|
18898
19989
|
}
|
|
18899
|
-
let qs = `id=${this.linkTarget.join(",")}`;
|
|
19990
|
+
let qs = `id=${this.linkTarget.join(",")}&expand=images,subOffersApi`;
|
|
18900
19991
|
const sdkClientVariables = this.widgetDeps.getSdkClientVariables();
|
|
18901
19992
|
if (sdkClientVariables != null && sdkClientVariables.pos != null) {
|
|
18902
19993
|
qs += `&pos=${String(sdkClientVariables.pos)}`;
|
|
@@ -19119,9 +20210,7 @@ class WidgetProducts extends WidgetBase {
|
|
|
19119
20210
|
e.stopPropagation();
|
|
19120
20211
|
e.preventDefault();
|
|
19121
20212
|
this._statEventWidgetCardClick(offer);
|
|
19122
|
-
|
|
19123
|
-
this.widgetDeps.slideApiDeps.openUrl({ type: "link", link: { type: "url", target: offer.url } });
|
|
19124
|
-
}
|
|
20213
|
+
this.showProductDetails({ offer, card });
|
|
19125
20214
|
};
|
|
19126
20215
|
card.appendChild(figure);
|
|
19127
20216
|
// card.appendChild(subTitle);
|
|
@@ -19129,6 +20218,27 @@ class WidgetProducts extends WidgetBase {
|
|
|
19129
20218
|
card.appendChild(title);
|
|
19130
20219
|
return card;
|
|
19131
20220
|
}
|
|
20221
|
+
showProductDetails = ({ card, offer }) => {
|
|
20222
|
+
if (!this.productsView)
|
|
20223
|
+
return;
|
|
20224
|
+
const bs = new ProductDetailsBottomSheet(this.widgetDeps, {
|
|
20225
|
+
translations: {
|
|
20226
|
+
color: getTagData(this.element, "msgColor") ?? "",
|
|
20227
|
+
size: getTagData(this.element, "msgSize") ?? "",
|
|
20228
|
+
addToCart: getTagData(this.element, "msgAddToCart") ?? "",
|
|
20229
|
+
successAddToCart: getTagData(this.element, "msgSuccess") ?? "",
|
|
20230
|
+
successSubAddToCart: getTagData(this.element, "msgSuccessSub") ?? "",
|
|
20231
|
+
errorAddToCart: getTagData(this.element, "msgError") ?? "",
|
|
20232
|
+
goToCartBtn: getTagData(this.element, "msgGoToCart") ?? "",
|
|
20233
|
+
continueBtn: getTagData(this.element, "msgContinue") ?? "",
|
|
20234
|
+
openUrl: getTagData(this.element, "msgOpenUrl") ?? "",
|
|
20235
|
+
},
|
|
20236
|
+
});
|
|
20237
|
+
const isCartEnabled = getTagData(this.element, "isCartEnabled") === "true";
|
|
20238
|
+
const isCartSupported = this.widgetDeps.slideApiDeps.isSdkSupportProductCart && isCartEnabled;
|
|
20239
|
+
this.productsView.appendChild(bs.render());
|
|
20240
|
+
bs.open({ offer, isCartSupported });
|
|
20241
|
+
};
|
|
19132
20242
|
createScrollView(offers) {
|
|
19133
20243
|
const scrollViewGroup = document.createElement("div");
|
|
19134
20244
|
scrollViewGroup.classList.add("ias-products-scroll-view-group");
|