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