stormcloud-video-player 0.2.9 → 0.2.11
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/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +469 -118
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +469 -118
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +206 -66
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +206 -66
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +206 -66
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +116 -31
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +469 -118
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -101,9 +101,22 @@ function createImaController(video, options) {
|
|
|
101
101
|
'script[data-ima="true"]'
|
|
102
102
|
);
|
|
103
103
|
if (existing) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
if (window.google?.ima) {
|
|
105
|
+
return Promise.resolve();
|
|
106
|
+
}
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
const timeout = setTimeout(() => {
|
|
109
|
+
reject(new Error("IMA SDK load timeout"));
|
|
110
|
+
}, 1e4);
|
|
111
|
+
existing.addEventListener("load", () => {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
resolve();
|
|
114
|
+
});
|
|
115
|
+
existing.addEventListener("error", () => {
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
reject(new Error("IMA SDK load failed"));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
107
120
|
}
|
|
108
121
|
return new Promise((resolve, reject) => {
|
|
109
122
|
const script = document.createElement("script");
|
|
@@ -132,6 +145,17 @@ function createImaController(video, options) {
|
|
|
132
145
|
adsRequest.adTagUrl = vastTagUrl;
|
|
133
146
|
adsLoader.requestAds(adsRequest);
|
|
134
147
|
}
|
|
148
|
+
function destroyAdsManager() {
|
|
149
|
+
if (adsManager) {
|
|
150
|
+
try {
|
|
151
|
+
console.log("[IMA] Destroying existing ads manager");
|
|
152
|
+
adsManager.destroy();
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.warn("[IMA] Error destroying ads manager:", error);
|
|
155
|
+
}
|
|
156
|
+
adsManager = void 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
135
159
|
return {
|
|
136
160
|
initialize() {
|
|
137
161
|
ensureImaLoaded().then(() => {
|
|
@@ -164,9 +188,22 @@ function createImaController(video, options) {
|
|
|
164
188
|
},
|
|
165
189
|
async requestAds(vastTagUrl) {
|
|
166
190
|
console.log("[IMA] Requesting ads:", vastTagUrl);
|
|
191
|
+
if (adPlaying) {
|
|
192
|
+
console.warn(
|
|
193
|
+
"[IMA] Cannot request new ads while an ad is playing. Call stop() first."
|
|
194
|
+
);
|
|
195
|
+
return Promise.reject(
|
|
196
|
+
new Error("Ad already playing - cannot request new ads")
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
destroyAdsManager();
|
|
200
|
+
adsLoadedReject = void 0;
|
|
201
|
+
adsLoadedResolve = void 0;
|
|
202
|
+
let currentReject;
|
|
167
203
|
adsLoadedPromise = new Promise((resolve, reject) => {
|
|
168
204
|
adsLoadedResolve = resolve;
|
|
169
205
|
adsLoadedReject = reject;
|
|
206
|
+
currentReject = reject;
|
|
170
207
|
setTimeout(() => {
|
|
171
208
|
if (adsLoadedReject) {
|
|
172
209
|
adsLoadedReject(new Error("Ad request timeout"));
|
|
@@ -188,7 +225,7 @@ function createImaController(video, options) {
|
|
|
188
225
|
container.style.top = "0";
|
|
189
226
|
container.style.right = "0";
|
|
190
227
|
container.style.bottom = "0";
|
|
191
|
-
container.style.display = "
|
|
228
|
+
container.style.display = "none";
|
|
192
229
|
container.style.alignItems = "center";
|
|
193
230
|
container.style.justifyContent = "center";
|
|
194
231
|
container.style.pointerEvents = "none";
|
|
@@ -228,14 +265,14 @@ function createImaController(video, options) {
|
|
|
228
265
|
AdErrorEvent.AD_ERROR,
|
|
229
266
|
(errorEvent) => {
|
|
230
267
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
231
|
-
|
|
232
|
-
adsManager?.destroy?.();
|
|
233
|
-
} catch {
|
|
234
|
-
}
|
|
268
|
+
destroyAdsManager();
|
|
235
269
|
adPlaying = false;
|
|
236
270
|
video.muted = originalMutedState;
|
|
237
|
-
if (adContainerEl)
|
|
271
|
+
if (adContainerEl) {
|
|
238
272
|
adContainerEl.style.pointerEvents = "none";
|
|
273
|
+
adContainerEl.style.display = "none";
|
|
274
|
+
console.log("[IMA] Ad container hidden after error");
|
|
275
|
+
}
|
|
239
276
|
if (adsLoadedReject) {
|
|
240
277
|
adsLoadedReject(new Error("Ad playback error"));
|
|
241
278
|
adsLoadedReject = void 0;
|
|
@@ -258,8 +295,11 @@ function createImaController(video, options) {
|
|
|
258
295
|
);
|
|
259
296
|
emit("ad_error");
|
|
260
297
|
if (!options?.continueLiveStreamDuringAds) {
|
|
261
|
-
video.
|
|
262
|
-
|
|
298
|
+
if (video.paused) {
|
|
299
|
+
console.log("[IMA] Resuming paused video after ad error");
|
|
300
|
+
video.play()?.catch(() => {
|
|
301
|
+
});
|
|
302
|
+
}
|
|
263
303
|
}
|
|
264
304
|
}
|
|
265
305
|
}
|
|
@@ -268,10 +308,6 @@ function createImaController(video, options) {
|
|
|
268
308
|
AdEvent.CONTENT_PAUSE_REQUESTED,
|
|
269
309
|
() => {
|
|
270
310
|
console.log("[IMA] Content pause requested");
|
|
271
|
-
if (!adPlaying) {
|
|
272
|
-
originalMutedState = video.muted;
|
|
273
|
-
}
|
|
274
|
-
video.muted = true;
|
|
275
311
|
if (!options?.continueLiveStreamDuringAds) {
|
|
276
312
|
video.pause();
|
|
277
313
|
console.log("[IMA] Video paused (VOD mode)");
|
|
@@ -280,20 +316,34 @@ function createImaController(video, options) {
|
|
|
280
316
|
"[IMA] Video continues playing but muted (Live mode)"
|
|
281
317
|
);
|
|
282
318
|
}
|
|
319
|
+
video.muted = true;
|
|
283
320
|
adPlaying = true;
|
|
284
|
-
if (adContainerEl)
|
|
285
|
-
adContainerEl.style.pointerEvents = "auto";
|
|
286
321
|
emit("content_pause");
|
|
287
322
|
}
|
|
288
323
|
);
|
|
324
|
+
adsManager.addEventListener(AdEvent.STARTED, () => {
|
|
325
|
+
console.log("[IMA] Ad started playing");
|
|
326
|
+
if (adContainerEl) {
|
|
327
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
328
|
+
adContainerEl.style.display = "flex";
|
|
329
|
+
console.log(
|
|
330
|
+
"[IMA] Ad container visibility set to flex with pointer events enabled"
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
289
334
|
adsManager.addEventListener(
|
|
290
335
|
AdEvent.CONTENT_RESUME_REQUESTED,
|
|
291
336
|
() => {
|
|
292
337
|
console.log("[IMA] Content resume requested");
|
|
293
338
|
adPlaying = false;
|
|
294
339
|
video.muted = originalMutedState;
|
|
295
|
-
if (adContainerEl)
|
|
340
|
+
if (adContainerEl) {
|
|
296
341
|
adContainerEl.style.pointerEvents = "none";
|
|
342
|
+
adContainerEl.style.display = "none";
|
|
343
|
+
console.log(
|
|
344
|
+
"[IMA] Ad container hidden - pointer events disabled"
|
|
345
|
+
);
|
|
346
|
+
}
|
|
297
347
|
if (!options?.continueLiveStreamDuringAds) {
|
|
298
348
|
video.play()?.catch(() => {
|
|
299
349
|
});
|
|
@@ -310,7 +360,13 @@ function createImaController(video, options) {
|
|
|
310
360
|
console.log("[IMA] All ads completed");
|
|
311
361
|
adPlaying = false;
|
|
312
362
|
video.muted = originalMutedState;
|
|
313
|
-
if (adContainerEl)
|
|
363
|
+
if (adContainerEl) {
|
|
364
|
+
adContainerEl.style.pointerEvents = "none";
|
|
365
|
+
adContainerEl.style.display = "none";
|
|
366
|
+
console.log(
|
|
367
|
+
"[IMA] Ad container hidden after all ads completed"
|
|
368
|
+
);
|
|
369
|
+
}
|
|
314
370
|
if (!options?.continueLiveStreamDuringAds) {
|
|
315
371
|
video.play().catch(() => {
|
|
316
372
|
});
|
|
@@ -334,10 +390,17 @@ function createImaController(video, options) {
|
|
|
334
390
|
console.error("[IMA] Error setting up ads manager:", e);
|
|
335
391
|
adPlaying = false;
|
|
336
392
|
video.muted = originalMutedState;
|
|
337
|
-
if (adContainerEl)
|
|
393
|
+
if (adContainerEl) {
|
|
394
|
+
adContainerEl.style.pointerEvents = "none";
|
|
395
|
+
adContainerEl.style.display = "none";
|
|
396
|
+
console.log("[IMA] Ad container hidden after setup error");
|
|
397
|
+
}
|
|
338
398
|
if (!options?.continueLiveStreamDuringAds) {
|
|
339
|
-
video.
|
|
340
|
-
|
|
399
|
+
if (video.paused) {
|
|
400
|
+
console.log("[IMA] Resuming paused video after setup error");
|
|
401
|
+
video.play().catch(() => {
|
|
402
|
+
});
|
|
403
|
+
}
|
|
341
404
|
}
|
|
342
405
|
if (adsLoadedReject) {
|
|
343
406
|
adsLoadedReject(new Error("Failed to setup ads manager"));
|
|
@@ -353,6 +416,20 @@ function createImaController(video, options) {
|
|
|
353
416
|
google.ima.AdErrorEvent.Type.AD_ERROR,
|
|
354
417
|
(adErrorEvent) => {
|
|
355
418
|
console.error("[IMA] Ads loader error:", adErrorEvent.getError());
|
|
419
|
+
adPlaying = false;
|
|
420
|
+
video.muted = originalMutedState;
|
|
421
|
+
if (adContainerEl) {
|
|
422
|
+
adContainerEl.style.pointerEvents = "none";
|
|
423
|
+
adContainerEl.style.display = "none";
|
|
424
|
+
console.log("[IMA] Ad container hidden after loader error");
|
|
425
|
+
}
|
|
426
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
427
|
+
if (video.paused) {
|
|
428
|
+
console.log("[IMA] Resuming paused video after loader error");
|
|
429
|
+
video.play().catch(() => {
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
356
433
|
if (adsLoadedReject) {
|
|
357
434
|
adsLoadedReject(new Error("Ads loader error"));
|
|
358
435
|
adsLoadedReject = void 0;
|
|
@@ -368,11 +445,9 @@ function createImaController(video, options) {
|
|
|
368
445
|
return adsLoadedPromise;
|
|
369
446
|
} catch (error) {
|
|
370
447
|
console.error("[IMA] Failed to request ads:", error);
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
adsLoadedResolve = void 0;
|
|
375
|
-
}
|
|
448
|
+
currentReject?.(error);
|
|
449
|
+
adsLoadedReject = void 0;
|
|
450
|
+
adsLoadedResolve = void 0;
|
|
376
451
|
return Promise.reject(error);
|
|
377
452
|
}
|
|
378
453
|
},
|
|
@@ -409,10 +484,16 @@ function createImaController(video, options) {
|
|
|
409
484
|
async stop() {
|
|
410
485
|
adPlaying = false;
|
|
411
486
|
video.muted = originalMutedState;
|
|
487
|
+
if (adContainerEl) {
|
|
488
|
+
adContainerEl.style.pointerEvents = "none";
|
|
489
|
+
adContainerEl.style.display = "none";
|
|
490
|
+
console.log("[IMA] Ad container hidden after stop");
|
|
491
|
+
}
|
|
412
492
|
try {
|
|
413
493
|
adsManager?.stop?.();
|
|
414
494
|
} catch {
|
|
415
495
|
}
|
|
496
|
+
destroyAdsManager();
|
|
416
497
|
if (!options?.continueLiveStreamDuringAds) {
|
|
417
498
|
video.play().catch(() => {
|
|
418
499
|
});
|
|
@@ -422,12 +503,13 @@ function createImaController(video, options) {
|
|
|
422
503
|
}
|
|
423
504
|
},
|
|
424
505
|
destroy() {
|
|
425
|
-
|
|
426
|
-
adsManager?.destroy?.();
|
|
427
|
-
} catch {
|
|
428
|
-
}
|
|
506
|
+
destroyAdsManager();
|
|
429
507
|
adPlaying = false;
|
|
430
508
|
video.muted = originalMutedState;
|
|
509
|
+
if (adContainerEl) {
|
|
510
|
+
adContainerEl.style.pointerEvents = "none";
|
|
511
|
+
adContainerEl.style.display = "none";
|
|
512
|
+
}
|
|
431
513
|
try {
|
|
432
514
|
adsLoader?.destroy?.();
|
|
433
515
|
} catch {
|
|
@@ -435,6 +517,9 @@ function createImaController(video, options) {
|
|
|
435
517
|
if (adContainerEl?.parentElement) {
|
|
436
518
|
adContainerEl.parentElement.removeChild(adContainerEl);
|
|
437
519
|
}
|
|
520
|
+
adContainerEl = void 0;
|
|
521
|
+
adDisplayContainer = void 0;
|
|
522
|
+
adsLoader = void 0;
|
|
438
523
|
},
|
|
439
524
|
isAdPlaying() {
|
|
440
525
|
return adPlaying;
|
|
@@ -912,32 +997,33 @@ var StormcloudVideoPlayer = class {
|
|
|
912
997
|
this.video.muted = !!this.config.muted;
|
|
913
998
|
this.ima.initialize();
|
|
914
999
|
this.ima.on("all_ads_completed", () => {
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
918
|
-
const next = this.adPodQueue.shift();
|
|
919
|
-
this.currentAdIndex++;
|
|
920
|
-
this.playSingleAd(next).catch(() => {
|
|
921
|
-
});
|
|
922
|
-
} else {
|
|
923
|
-
this.currentAdIndex = 0;
|
|
924
|
-
this.totalAdsInBreak = 0;
|
|
925
|
-
this.showAds = false;
|
|
1000
|
+
if (this.config.debugAdTiming) {
|
|
1001
|
+
console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
|
|
926
1002
|
}
|
|
927
1003
|
});
|
|
928
1004
|
this.ima.on("ad_error", () => {
|
|
929
1005
|
if (this.config.debugAdTiming) {
|
|
930
1006
|
console.log("[StormcloudVideoPlayer] IMA ad_error event received");
|
|
931
1007
|
}
|
|
932
|
-
if (
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1008
|
+
if (this.showAds) {
|
|
1009
|
+
if (this.inAdBreak) {
|
|
1010
|
+
const remaining = this.getRemainingAdMs();
|
|
1011
|
+
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
1012
|
+
const next = this.adPodQueue.shift();
|
|
1013
|
+
this.currentAdIndex++;
|
|
1014
|
+
this.playSingleAd(next).catch(() => {
|
|
1015
|
+
});
|
|
1016
|
+
} else {
|
|
1017
|
+
this.handleAdFailure();
|
|
1018
|
+
}
|
|
1019
|
+
} else {
|
|
1020
|
+
if (this.config.debugAdTiming) {
|
|
1021
|
+
console.log(
|
|
1022
|
+
"[StormcloudVideoPlayer] Ad error before ad break established - cleaning up"
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
this.handleAdFailure();
|
|
1026
|
+
}
|
|
941
1027
|
}
|
|
942
1028
|
});
|
|
943
1029
|
this.ima.on("content_pause", () => {
|
|
@@ -953,6 +1039,26 @@ var StormcloudVideoPlayer = class {
|
|
|
953
1039
|
);
|
|
954
1040
|
}
|
|
955
1041
|
this.clearAdFailsafeTimer();
|
|
1042
|
+
if (!this.inAdBreak) return;
|
|
1043
|
+
const remaining = this.getRemainingAdMs();
|
|
1044
|
+
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
1045
|
+
const next = this.adPodQueue.shift();
|
|
1046
|
+
this.currentAdIndex++;
|
|
1047
|
+
if (this.config.debugAdTiming) {
|
|
1048
|
+
console.log(
|
|
1049
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
this.playSingleAd(next).catch(() => {
|
|
1053
|
+
});
|
|
1054
|
+
} else {
|
|
1055
|
+
if (this.config.debugAdTiming) {
|
|
1056
|
+
console.log("[StormcloudVideoPlayer] Ad pod completed");
|
|
1057
|
+
}
|
|
1058
|
+
this.currentAdIndex = 0;
|
|
1059
|
+
this.totalAdsInBreak = 0;
|
|
1060
|
+
this.showAds = false;
|
|
1061
|
+
}
|
|
956
1062
|
});
|
|
957
1063
|
this.video.addEventListener("timeupdate", () => {
|
|
958
1064
|
this.onTimeUpdate(this.video.currentTime);
|
|
@@ -1498,9 +1604,20 @@ var StormcloudVideoPlayer = class {
|
|
|
1498
1604
|
return;
|
|
1499
1605
|
}
|
|
1500
1606
|
if (vastTagUrl) {
|
|
1607
|
+
this.inAdBreak = true;
|
|
1501
1608
|
this.showAds = true;
|
|
1502
1609
|
this.currentAdIndex++;
|
|
1503
|
-
|
|
1610
|
+
try {
|
|
1611
|
+
await this.playSingleAd(vastTagUrl);
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
if (this.config.debugAdTiming) {
|
|
1614
|
+
console.error(
|
|
1615
|
+
"[StormcloudVideoPlayer] Ad playback failed in handleAdStart:",
|
|
1616
|
+
error
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
this.handleAdFailure();
|
|
1620
|
+
}
|
|
1504
1621
|
}
|
|
1505
1622
|
if (this.expectedAdBreakDurationMs == null && scheduled?.durationMs != null) {
|
|
1506
1623
|
this.expectedAdBreakDurationMs = scheduled.durationMs;
|
|
@@ -1602,21 +1719,21 @@ var StormcloudVideoPlayer = class {
|
|
|
1602
1719
|
if (this.config.debugAdTiming) {
|
|
1603
1720
|
console.log("[StormcloudVideoPlayer] Attempting to play ad:", vastTagUrl);
|
|
1604
1721
|
}
|
|
1605
|
-
this.ima.
|
|
1606
|
-
if (!this.shouldContinueLiveStreamDuringAds()) {
|
|
1607
|
-
if (this.config.debugAdTiming) {
|
|
1608
|
-
console.log("[StormcloudVideoPlayer] Pausing video immediately for ad (VOD mode)");
|
|
1609
|
-
}
|
|
1610
|
-
this.video.pause();
|
|
1611
|
-
} else {
|
|
1722
|
+
if (this.ima.isAdPlaying()) {
|
|
1612
1723
|
if (this.config.debugAdTiming) {
|
|
1613
|
-
console.
|
|
1724
|
+
console.warn(
|
|
1725
|
+
"[StormcloudVideoPlayer] Ad already playing - skipping new ad request"
|
|
1726
|
+
);
|
|
1614
1727
|
}
|
|
1615
|
-
|
|
1728
|
+
return;
|
|
1616
1729
|
}
|
|
1730
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
1617
1731
|
this.startAdFailsafeTimer();
|
|
1618
1732
|
try {
|
|
1619
1733
|
await this.ima.requestAds(vastTagUrl);
|
|
1734
|
+
if (this.config.debugAdTiming) {
|
|
1735
|
+
console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
|
|
1736
|
+
}
|
|
1620
1737
|
await this.ima.play();
|
|
1621
1738
|
if (this.config.debugAdTiming) {
|
|
1622
1739
|
console.log("[StormcloudVideoPlayer] Ad playback started successfully");
|
|
@@ -1631,7 +1748,13 @@ var StormcloudVideoPlayer = class {
|
|
|
1631
1748
|
handleAdFailure() {
|
|
1632
1749
|
if (this.config.debugAdTiming) {
|
|
1633
1750
|
console.log(
|
|
1634
|
-
"[StormcloudVideoPlayer] Handling ad failure - resuming content"
|
|
1751
|
+
"[StormcloudVideoPlayer] Handling ad failure - resuming content",
|
|
1752
|
+
{
|
|
1753
|
+
inAdBreak: this.inAdBreak,
|
|
1754
|
+
showAds: this.showAds,
|
|
1755
|
+
videoPaused: this.video.paused,
|
|
1756
|
+
adPlaying: this.ima.isAdPlaying()
|
|
1757
|
+
}
|
|
1635
1758
|
);
|
|
1636
1759
|
}
|
|
1637
1760
|
this.inAdBreak = false;
|
|
@@ -1644,14 +1767,29 @@ var StormcloudVideoPlayer = class {
|
|
|
1644
1767
|
this.showAds = false;
|
|
1645
1768
|
this.currentAdIndex = 0;
|
|
1646
1769
|
this.totalAdsInBreak = 0;
|
|
1770
|
+
const originalMutedState = this.ima.getOriginalMutedState();
|
|
1771
|
+
this.video.muted = originalMutedState;
|
|
1772
|
+
if (this.config.debugAdTiming) {
|
|
1773
|
+
console.log(
|
|
1774
|
+
`[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1647
1777
|
if (this.video.paused) {
|
|
1648
|
-
this.
|
|
1778
|
+
if (this.config.debugAdTiming) {
|
|
1779
|
+
console.log("[StormcloudVideoPlayer] Resuming paused video");
|
|
1780
|
+
}
|
|
1781
|
+
this.video.play()?.catch((error) => {
|
|
1649
1782
|
if (this.config.debugAdTiming) {
|
|
1650
1783
|
console.error(
|
|
1651
|
-
"[StormcloudVideoPlayer] Failed to resume video after ad failure"
|
|
1784
|
+
"[StormcloudVideoPlayer] Failed to resume video after ad failure:",
|
|
1785
|
+
error
|
|
1652
1786
|
);
|
|
1653
1787
|
}
|
|
1654
1788
|
});
|
|
1789
|
+
} else {
|
|
1790
|
+
if (this.config.debugAdTiming) {
|
|
1791
|
+
console.log("[StormcloudVideoPlayer] Video is already playing, no resume needed");
|
|
1792
|
+
}
|
|
1655
1793
|
}
|
|
1656
1794
|
}
|
|
1657
1795
|
startAdFailsafeTimer() {
|
|
@@ -1663,10 +1801,12 @@ var StormcloudVideoPlayer = class {
|
|
|
1663
1801
|
);
|
|
1664
1802
|
}
|
|
1665
1803
|
this.adFailsafeTimerId = window.setTimeout(() => {
|
|
1666
|
-
|
|
1804
|
+
const shouldTrigger = this.video.paused || this.showAds && !this.ima.isAdPlaying();
|
|
1805
|
+
if (shouldTrigger) {
|
|
1667
1806
|
if (this.config.debugAdTiming) {
|
|
1668
1807
|
console.warn(
|
|
1669
|
-
"[StormcloudVideoPlayer] Failsafe timer triggered - forcing video resume"
|
|
1808
|
+
"[StormcloudVideoPlayer] Failsafe timer triggered - forcing video resume",
|
|
1809
|
+
{ paused: this.video.paused, showAds: this.showAds, adPlaying: this.ima.isAdPlaying() }
|
|
1670
1810
|
);
|
|
1671
1811
|
}
|
|
1672
1812
|
this.handleAdFailure();
|
|
@@ -2587,39 +2727,144 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2587
2727
|
left: "50%",
|
|
2588
2728
|
transform: "translateX(-50%)",
|
|
2589
2729
|
marginBottom: "4px",
|
|
2590
|
-
background: "linear-gradient(135deg, rgba(0, 0, 0, 0.
|
|
2730
|
+
background: "linear-gradient(135deg, rgba(0, 0, 0, 0.88) 0%, rgba(20, 20, 20, 0.92) 100%)",
|
|
2591
2731
|
backdropFilter: "blur(15px)",
|
|
2592
|
-
padding: "
|
|
2593
|
-
borderRadius: "
|
|
2594
|
-
border: "1px solid rgba(255, 255, 255, 0.
|
|
2732
|
+
padding: "10px 14px",
|
|
2733
|
+
borderRadius: "14px",
|
|
2734
|
+
border: "1px solid rgba(255, 255, 255, 0.15)",
|
|
2595
2735
|
display: "flex",
|
|
2596
2736
|
flexDirection: "column",
|
|
2597
2737
|
alignItems: "center",
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2738
|
+
justifyContent: "center",
|
|
2739
|
+
height: "128px",
|
|
2740
|
+
boxShadow: "0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)",
|
|
2741
|
+
zIndex: 10,
|
|
2742
|
+
transition: "transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out"
|
|
2601
2743
|
},
|
|
2602
|
-
onMouseEnter: () =>
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
"
|
|
2744
|
+
onMouseEnter: (e) => {
|
|
2745
|
+
setShowVolumeSlider(true);
|
|
2746
|
+
e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
|
|
2747
|
+
e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.6), 0 6px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 0 24px rgba(59, 130, 246, 0.3)";
|
|
2748
|
+
e.currentTarget.style.borderColor = "rgba(59, 130, 246, 0.4)";
|
|
2749
|
+
},
|
|
2750
|
+
onMouseLeave: (e) => {
|
|
2751
|
+
setShowVolumeSlider(false);
|
|
2752
|
+
e.currentTarget.style.transform = "translateX(-50%)";
|
|
2753
|
+
e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)";
|
|
2754
|
+
e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.15)";
|
|
2755
|
+
},
|
|
2756
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2757
|
+
"div",
|
|
2606
2758
|
{
|
|
2607
|
-
type: "range",
|
|
2608
|
-
min: "0",
|
|
2609
|
-
max: "1",
|
|
2610
|
-
step: "0.01",
|
|
2611
|
-
value: isMuted ? 0 : volume,
|
|
2612
|
-
onChange: (e) => handleVolumeChange(parseFloat(e.target.value)),
|
|
2613
2759
|
style: {
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
}
|
|
2760
|
+
position: "relative",
|
|
2761
|
+
width: "8px",
|
|
2762
|
+
height: "104px",
|
|
2763
|
+
cursor: "pointer",
|
|
2764
|
+
transition: "transform 0.2s ease-in-out"
|
|
2765
|
+
},
|
|
2766
|
+
onMouseEnter: (e) => {
|
|
2767
|
+
e.currentTarget.style.transform = "scaleX(1.2)";
|
|
2768
|
+
},
|
|
2769
|
+
onMouseLeave: (e) => {
|
|
2770
|
+
e.currentTarget.style.transform = "scaleX(1)";
|
|
2771
|
+
},
|
|
2772
|
+
onMouseDown: (e) => {
|
|
2773
|
+
e.preventDefault();
|
|
2774
|
+
const sliderElement = e.currentTarget;
|
|
2775
|
+
const handleMouseMove = (moveEvent) => {
|
|
2776
|
+
if (!sliderElement) return;
|
|
2777
|
+
const rect2 = sliderElement.getBoundingClientRect();
|
|
2778
|
+
const y2 = moveEvent.clientY - rect2.top;
|
|
2779
|
+
const percentage2 = 1 - Math.max(0, Math.min(1, y2 / rect2.height));
|
|
2780
|
+
handleVolumeChange(percentage2);
|
|
2781
|
+
};
|
|
2782
|
+
const handleMouseUp = () => {
|
|
2783
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
2784
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
2785
|
+
};
|
|
2786
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
2787
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
2788
|
+
const rect = sliderElement.getBoundingClientRect();
|
|
2789
|
+
const y = e.clientY - rect.top;
|
|
2790
|
+
const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
|
|
2791
|
+
handleVolumeChange(percentage);
|
|
2792
|
+
},
|
|
2793
|
+
onClick: (e) => {
|
|
2794
|
+
e.stopPropagation();
|
|
2795
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
2796
|
+
const y = e.clientY - rect.top;
|
|
2797
|
+
const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
|
|
2798
|
+
handleVolumeChange(percentage);
|
|
2799
|
+
},
|
|
2800
|
+
children: [
|
|
2801
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2802
|
+
"div",
|
|
2803
|
+
{
|
|
2804
|
+
style: {
|
|
2805
|
+
position: "absolute",
|
|
2806
|
+
bottom: "0",
|
|
2807
|
+
left: "0",
|
|
2808
|
+
width: "100%",
|
|
2809
|
+
height: "100%",
|
|
2810
|
+
background: "linear-gradient(180deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.15) 100%)",
|
|
2811
|
+
borderRadius: "4px",
|
|
2812
|
+
boxShadow: "inset 0 1px 3px rgba(0, 0, 0, 0.2)"
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
),
|
|
2816
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2817
|
+
"div",
|
|
2818
|
+
{
|
|
2819
|
+
style: {
|
|
2820
|
+
position: "absolute",
|
|
2821
|
+
bottom: "0",
|
|
2822
|
+
left: "0",
|
|
2823
|
+
width: "100%",
|
|
2824
|
+
height: `${(isMuted ? 0 : volume) * 100}%`,
|
|
2825
|
+
background: "linear-gradient(180deg, rgba(96, 165, 250, 1) 0%, rgba(59, 130, 246, 0.95) 50%, rgba(37, 99, 235, 0.9) 100%)",
|
|
2826
|
+
borderRadius: "4px",
|
|
2827
|
+
transition: "height 0.15s ease-out, box-shadow 0.2s ease-in-out",
|
|
2828
|
+
boxShadow: "0 0 8px rgba(59, 130, 246, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
),
|
|
2832
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2833
|
+
"div",
|
|
2834
|
+
{
|
|
2835
|
+
style: {
|
|
2836
|
+
position: "absolute",
|
|
2837
|
+
bottom: `calc(${(isMuted ? 0 : volume) * 100}% - 7px)`,
|
|
2838
|
+
left: "50%",
|
|
2839
|
+
transform: "translateX(-50%)",
|
|
2840
|
+
width: "14px",
|
|
2841
|
+
height: "14px",
|
|
2842
|
+
background: "linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%)",
|
|
2843
|
+
borderRadius: "50%",
|
|
2844
|
+
boxShadow: "0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(59, 130, 246, 0.3), 0 0 12px rgba(59, 130, 246, 0.4)",
|
|
2845
|
+
transition: "bottom 0.15s ease-out, transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, width 0.2s ease-in-out, height 0.2s ease-in-out",
|
|
2846
|
+
cursor: "grab"
|
|
2847
|
+
},
|
|
2848
|
+
onMouseEnter: (e) => {
|
|
2849
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
|
|
2850
|
+
e.currentTarget.style.boxShadow = "0 3px 10px rgba(0, 0, 0, 0.4), 0 0 0 3px rgba(59, 130, 246, 0.5), 0 0 20px rgba(59, 130, 246, 0.6)";
|
|
2851
|
+
e.currentTarget.style.cursor = "grab";
|
|
2852
|
+
},
|
|
2853
|
+
onMouseLeave: (e) => {
|
|
2854
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1)";
|
|
2855
|
+
e.currentTarget.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(59, 130, 246, 0.3), 0 0 12px rgba(59, 130, 246, 0.4)";
|
|
2856
|
+
},
|
|
2857
|
+
onMouseDown: (e) => {
|
|
2858
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.4)";
|
|
2859
|
+
e.currentTarget.style.cursor = "grabbing";
|
|
2860
|
+
},
|
|
2861
|
+
onMouseUp: (e) => {
|
|
2862
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
|
|
2863
|
+
e.currentTarget.style.cursor = "grab";
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
)
|
|
2867
|
+
]
|
|
2623
2868
|
}
|
|
2624
2869
|
)
|
|
2625
2870
|
}
|
|
@@ -2936,40 +3181,146 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2936
3181
|
left: "50%",
|
|
2937
3182
|
transform: "translateX(-50%)",
|
|
2938
3183
|
marginBottom: "4px",
|
|
2939
|
-
background: "linear-gradient(135deg, rgba(0, 0, 0, 0.
|
|
3184
|
+
background: "linear-gradient(135deg, rgba(0, 0, 0, 0.96) 0%, rgba(20, 20, 20, 0.92) 100%)",
|
|
2940
3185
|
backdropFilter: "blur(20px)",
|
|
2941
|
-
padding: "
|
|
2942
|
-
borderRadius: "
|
|
2943
|
-
border: "2px solid rgba(255, 255, 255, 0.
|
|
3186
|
+
padding: "10px 14px",
|
|
3187
|
+
borderRadius: "14px",
|
|
3188
|
+
border: "2px solid rgba(255, 255, 255, 0.7)",
|
|
2944
3189
|
display: "flex",
|
|
2945
3190
|
flexDirection: "column",
|
|
2946
3191
|
alignItems: "center",
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
3192
|
+
justifyContent: "center",
|
|
3193
|
+
height: "128px",
|
|
3194
|
+
boxShadow: "0 12px 40px rgba(0, 0, 0, 0.85), 0 4px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35)",
|
|
3195
|
+
zIndex: 10,
|
|
3196
|
+
transition: "transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out"
|
|
2950
3197
|
},
|
|
2951
|
-
onMouseEnter: () =>
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
"
|
|
3198
|
+
onMouseEnter: (e) => {
|
|
3199
|
+
setShowVolumeSlider(true);
|
|
3200
|
+
e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
|
|
3201
|
+
e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.9), 0 6px 16px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 24px rgba(96, 165, 250, 0.4)";
|
|
3202
|
+
e.currentTarget.style.borderColor = "rgba(96, 165, 250, 0.8)";
|
|
3203
|
+
},
|
|
3204
|
+
onMouseLeave: (e) => {
|
|
3205
|
+
setShowVolumeSlider(false);
|
|
3206
|
+
e.currentTarget.style.transform = "translateX(-50%)";
|
|
3207
|
+
e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.85), 0 4px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35)";
|
|
3208
|
+
e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.7)";
|
|
3209
|
+
},
|
|
3210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
3211
|
+
"div",
|
|
2955
3212
|
{
|
|
2956
|
-
type: "range",
|
|
2957
|
-
min: "0",
|
|
2958
|
-
max: "1",
|
|
2959
|
-
step: "0.01",
|
|
2960
|
-
value: isMuted ? 0 : volume,
|
|
2961
|
-
onChange: (e) => handleVolumeChange(parseFloat(e.target.value)),
|
|
2962
3213
|
style: {
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
height: "90px",
|
|
2967
|
-
background: "linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.4) 100%)",
|
|
2968
|
-
borderRadius: "3px",
|
|
2969
|
-
outline: "none",
|
|
3214
|
+
position: "relative",
|
|
3215
|
+
width: "8px",
|
|
3216
|
+
height: "104px",
|
|
2970
3217
|
cursor: "pointer",
|
|
2971
|
-
|
|
2972
|
-
}
|
|
3218
|
+
transition: "transform 0.2s ease-in-out"
|
|
3219
|
+
},
|
|
3220
|
+
onMouseEnter: (e) => {
|
|
3221
|
+
e.currentTarget.style.transform = "scaleX(1.2)";
|
|
3222
|
+
},
|
|
3223
|
+
onMouseLeave: (e) => {
|
|
3224
|
+
e.currentTarget.style.transform = "scaleX(1)";
|
|
3225
|
+
},
|
|
3226
|
+
onMouseDown: (e) => {
|
|
3227
|
+
e.preventDefault();
|
|
3228
|
+
const sliderElement = e.currentTarget;
|
|
3229
|
+
const handleMouseMove = (moveEvent) => {
|
|
3230
|
+
if (!sliderElement) return;
|
|
3231
|
+
const rect2 = sliderElement.getBoundingClientRect();
|
|
3232
|
+
const y2 = moveEvent.clientY - rect2.top;
|
|
3233
|
+
const percentage2 = 1 - Math.max(0, Math.min(1, y2 / rect2.height));
|
|
3234
|
+
handleVolumeChange(percentage2);
|
|
3235
|
+
};
|
|
3236
|
+
const handleMouseUp = () => {
|
|
3237
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
3238
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
3239
|
+
};
|
|
3240
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
3241
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
3242
|
+
const rect = sliderElement.getBoundingClientRect();
|
|
3243
|
+
const y = e.clientY - rect.top;
|
|
3244
|
+
const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
|
|
3245
|
+
handleVolumeChange(percentage);
|
|
3246
|
+
},
|
|
3247
|
+
onClick: (e) => {
|
|
3248
|
+
e.stopPropagation();
|
|
3249
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
3250
|
+
const y = e.clientY - rect.top;
|
|
3251
|
+
const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
|
|
3252
|
+
handleVolumeChange(percentage);
|
|
3253
|
+
},
|
|
3254
|
+
children: [
|
|
3255
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
3256
|
+
"div",
|
|
3257
|
+
{
|
|
3258
|
+
style: {
|
|
3259
|
+
position: "absolute",
|
|
3260
|
+
bottom: "0",
|
|
3261
|
+
left: "0",
|
|
3262
|
+
width: "100%",
|
|
3263
|
+
height: "100%",
|
|
3264
|
+
background: "linear-gradient(180deg, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0.5) 100%)",
|
|
3265
|
+
borderRadius: "4px",
|
|
3266
|
+
border: "1px solid rgba(255, 255, 255, 0.4)",
|
|
3267
|
+
boxShadow: "inset 0 1px 3px rgba(0, 0, 0, 0.3)"
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
),
|
|
3271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
3272
|
+
"div",
|
|
3273
|
+
{
|
|
3274
|
+
style: {
|
|
3275
|
+
position: "absolute",
|
|
3276
|
+
bottom: "0",
|
|
3277
|
+
left: "0",
|
|
3278
|
+
width: "100%",
|
|
3279
|
+
height: `${(isMuted ? 0 : volume) * 100}%`,
|
|
3280
|
+
background: "linear-gradient(180deg, rgba(125, 211, 252, 1) 0%, rgba(96, 165, 250, 0.98) 50%, rgba(59, 130, 246, 0.95) 100%)",
|
|
3281
|
+
borderRadius: "4px",
|
|
3282
|
+
transition: "height 0.15s ease-out, box-shadow 0.2s ease-in-out",
|
|
3283
|
+
boxShadow: "0 0 12px rgba(96, 165, 250, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.4)"
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
),
|
|
3287
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
3288
|
+
"div",
|
|
3289
|
+
{
|
|
3290
|
+
style: {
|
|
3291
|
+
position: "absolute",
|
|
3292
|
+
bottom: `calc(${(isMuted ? 0 : volume) * 100}% - 8px)`,
|
|
3293
|
+
left: "50%",
|
|
3294
|
+
transform: "translateX(-50%)",
|
|
3295
|
+
width: "16px",
|
|
3296
|
+
height: "16px",
|
|
3297
|
+
background: "linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%)",
|
|
3298
|
+
borderRadius: "50%",
|
|
3299
|
+
border: "2px solid rgba(96, 165, 250, 0.9)",
|
|
3300
|
+
boxShadow: "0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(96, 165, 250, 0.4), 0 0 16px rgba(96, 165, 250, 0.5)",
|
|
3301
|
+
transition: "bottom 0.15s ease-out, transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, width 0.2s ease-in-out, height 0.2s ease-in-out",
|
|
3302
|
+
cursor: "grab"
|
|
3303
|
+
},
|
|
3304
|
+
onMouseEnter: (e) => {
|
|
3305
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
|
|
3306
|
+
e.currentTarget.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(96, 165, 250, 0.6), 0 0 24px rgba(96, 165, 250, 0.7)";
|
|
3307
|
+
e.currentTarget.style.cursor = "grab";
|
|
3308
|
+
},
|
|
3309
|
+
onMouseLeave: (e) => {
|
|
3310
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1)";
|
|
3311
|
+
e.currentTarget.style.boxShadow = "0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(96, 165, 250, 0.4), 0 0 16px rgba(96, 165, 250, 0.5)";
|
|
3312
|
+
},
|
|
3313
|
+
onMouseDown: (e) => {
|
|
3314
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.45)";
|
|
3315
|
+
e.currentTarget.style.cursor = "grabbing";
|
|
3316
|
+
},
|
|
3317
|
+
onMouseUp: (e) => {
|
|
3318
|
+
e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
|
|
3319
|
+
e.currentTarget.style.cursor = "grab";
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
)
|
|
3323
|
+
]
|
|
2973
3324
|
}
|
|
2974
3325
|
)
|
|
2975
3326
|
}
|