@betarena/ad-engine 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +15 -15
- package/package.json +1 -1
- package/src/lib/Advert-Engine-Widget.svelte +300 -41
- package/src/lib/Advert-General-Child.svelte +1 -0
- package/src/lib/Advert-InterScroller-Child.svelte +2 -0
- package/src/lib/Advert-LeftSide-Child.svelte +2 -0
- package/src/lib/Advert-Slide-Child.svelte +16 -12
package/package.json
CHANGED
|
@@ -109,6 +109,10 @@
|
|
|
109
109
|
isStandalone = true
|
|
110
110
|
;
|
|
111
111
|
|
|
112
|
+
// Retained as a supported public prop for API compatibility.
|
|
113
|
+
// Device detection is UA-based; this value is not consumed internally.
|
|
114
|
+
$: void deviceWidthList;
|
|
115
|
+
|
|
112
116
|
/**
|
|
113
117
|
* @description
|
|
114
118
|
* 📝 Component Local Interface
|
|
@@ -141,7 +145,36 @@
|
|
|
141
145
|
* @description
|
|
142
146
|
* 📝 `Map` where, `key=CreativeId` and `value=AdvertObject` (temporary)
|
|
143
147
|
*/
|
|
144
|
-
mapCreative = new Map < number, AdsCreativeMain > ()
|
|
148
|
+
mapCreative = new Map < number, AdsCreativeMain > (),
|
|
149
|
+
/**
|
|
150
|
+
* @description
|
|
151
|
+
* 📝 Shared promise for one-time prerequisite initialization (device type + geolocation).
|
|
152
|
+
* Set on first call to `ensureReady()`; subsequent callers await the same promise.
|
|
153
|
+
*/
|
|
154
|
+
readinessPromise: Promise < void > | null = null,
|
|
155
|
+
/**
|
|
156
|
+
* @description
|
|
157
|
+
* 📝 ID of the deferred `initialize()` timeout, used to cancel it if the component
|
|
158
|
+
* is destroyed before the delay elapses.
|
|
159
|
+
*/
|
|
160
|
+
initTimeoutId: ReturnType < typeof setTimeout > | null = null,
|
|
161
|
+
/**
|
|
162
|
+
* @description
|
|
163
|
+
* 📝 Set to `true` once `onDestroy` fires, so any in-flight async work can bail out.
|
|
164
|
+
*/
|
|
165
|
+
isDestroyed = false,
|
|
166
|
+
/**
|
|
167
|
+
* @description
|
|
168
|
+
* 📝 Incremented on each `refreshAds()` call. Passed into `injectBetarenaAds()`
|
|
169
|
+
* so that a superseded refresh can bail out after its network awaits complete.
|
|
170
|
+
*/
|
|
171
|
+
refreshSerial = 0,
|
|
172
|
+
/**
|
|
173
|
+
* @description
|
|
174
|
+
* 📝 Previous value of `window.betarenaAdEngine` saved before this instance assigns it,
|
|
175
|
+
* so it can be restored on destroy instead of unconditionally deleting.
|
|
176
|
+
*/
|
|
177
|
+
prevWindowApi: unknown = undefined
|
|
145
178
|
;
|
|
146
179
|
|
|
147
180
|
const
|
|
@@ -168,7 +201,7 @@
|
|
|
168
201
|
|
|
169
202
|
/**
|
|
170
203
|
* @author
|
|
171
|
-
* @
|
|
204
|
+
* @jonsnowpt
|
|
172
205
|
* @summary
|
|
173
206
|
* 🟥 MAIN
|
|
174
207
|
* @description
|
|
@@ -177,16 +210,44 @@
|
|
|
177
210
|
*/
|
|
178
211
|
function generateElementMap
|
|
179
212
|
(
|
|
213
|
+
rootElement?: ParentNode
|
|
180
214
|
): void
|
|
181
215
|
{
|
|
216
|
+
mapBetarenaAdvertStandardElement.clear();
|
|
217
|
+
|
|
182
218
|
const
|
|
183
219
|
/**
|
|
184
220
|
* @description
|
|
185
221
|
* 📝 `List` of `HTMLElements` identified on `page` expecting a target `zone` advertisement injection.
|
|
186
222
|
*/
|
|
187
|
-
listElementTarget = document.querySelectorAll('[data-betarena-zone-id]')
|
|
223
|
+
listElementTarget = (rootElement ?? document).querySelectorAll('[data-betarena-zone-id]')
|
|
188
224
|
;
|
|
189
225
|
|
|
226
|
+
// ╭─────
|
|
227
|
+
// │ NOTE:
|
|
228
|
+
// │ |: querySelectorAll only returns descendants — if rootElement itself carries
|
|
229
|
+
// │ |: the zone attribute it would be missed. Include it explicitly.
|
|
230
|
+
// ╰─────
|
|
231
|
+
if (rootElement instanceof Element && rootElement.hasAttribute('data-betarena-zone-id'))
|
|
232
|
+
{
|
|
233
|
+
const
|
|
234
|
+
value = rootElement.getAttribute('data-betarena-zone-id')
|
|
235
|
+
;
|
|
236
|
+
|
|
237
|
+
if (value)
|
|
238
|
+
{
|
|
239
|
+
for (const rawToken of value.split(','))
|
|
240
|
+
{
|
|
241
|
+
const
|
|
242
|
+
token = rawToken.trim(),
|
|
243
|
+
id = Number.parseInt(token, 10)
|
|
244
|
+
;
|
|
245
|
+
if (!token || !Number.isFinite(id)) continue;
|
|
246
|
+
mapBetarenaAdvertStandardElement.set(id, rootElement);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
190
251
|
// [🐞]
|
|
191
252
|
logger
|
|
192
253
|
(
|
|
@@ -219,23 +280,14 @@
|
|
|
219
280
|
]
|
|
220
281
|
);
|
|
221
282
|
|
|
222
|
-
|
|
283
|
+
for (const rawToken of value.split(','))
|
|
223
284
|
{
|
|
224
285
|
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
* 📝 Split value by `,`
|
|
228
|
-
*/
|
|
229
|
-
values = value.split(',')
|
|
286
|
+
token = rawToken.trim(),
|
|
287
|
+
id = Number.parseInt(token, 10)
|
|
230
288
|
;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
mapBetarenaAdvertStandardElement.set(parseInt(val), elem);
|
|
234
|
-
;
|
|
235
|
-
}
|
|
236
|
-
else
|
|
237
|
-
{
|
|
238
|
-
mapBetarenaAdvertStandardElement.set(parseInt(value), elem);
|
|
289
|
+
if (!token || !Number.isFinite(id)) continue;
|
|
290
|
+
mapBetarenaAdvertStandardElement.set(id, elem);
|
|
239
291
|
}
|
|
240
292
|
}
|
|
241
293
|
|
|
@@ -254,7 +306,7 @@
|
|
|
254
306
|
|
|
255
307
|
/**
|
|
256
308
|
* @author
|
|
257
|
-
* @
|
|
309
|
+
* @jonsnowpt
|
|
258
310
|
* @summary
|
|
259
311
|
* 🟦 HELPER
|
|
260
312
|
* @description
|
|
@@ -265,7 +317,9 @@
|
|
|
265
317
|
*/
|
|
266
318
|
async function injectBetarenaAds
|
|
267
319
|
(
|
|
268
|
-
opts: IAdsServiceData['request']['body']
|
|
320
|
+
opts: IAdsServiceData['request']['body'],
|
|
321
|
+
includesGlobalZone: boolean,
|
|
322
|
+
refreshToken: number
|
|
269
323
|
): Promise < void >
|
|
270
324
|
{
|
|
271
325
|
if (!document) return;
|
|
@@ -315,6 +369,8 @@
|
|
|
315
369
|
]
|
|
316
370
|
);
|
|
317
371
|
|
|
372
|
+
if (isDestroyed || refreshToken !== refreshSerial) return;
|
|
373
|
+
|
|
318
374
|
storeSession.updateData
|
|
319
375
|
(
|
|
320
376
|
[
|
|
@@ -363,7 +419,17 @@
|
|
|
363
419
|
// ╰─────
|
|
364
420
|
for (const [zoneId, element] of mapBetarenaAdvertStandardElement)
|
|
365
421
|
{
|
|
366
|
-
|
|
422
|
+
const
|
|
423
|
+
el = element as HTMLElement,
|
|
424
|
+
parent = el.parentElement as HTMLElement | null,
|
|
425
|
+
mountedAttr =
|
|
426
|
+
[
|
|
427
|
+
el.dataset.betarenaAdMounted,
|
|
428
|
+
parent?.dataset?.betarenaAdMounted
|
|
429
|
+
].filter(Boolean).join(','),
|
|
430
|
+
mountedZones = mountedAttr.split(',').map(z => z.trim()).filter(Boolean)
|
|
431
|
+
;
|
|
432
|
+
if (mountedZones.includes(String(zoneId))) continue;
|
|
367
433
|
|
|
368
434
|
const
|
|
369
435
|
/**
|
|
@@ -443,6 +509,11 @@
|
|
|
443
509
|
}
|
|
444
510
|
);
|
|
445
511
|
;
|
|
512
|
+
if (creativeAdData.length > 0)
|
|
513
|
+
{
|
|
514
|
+
mountedZones.push(String(zoneId));
|
|
515
|
+
el.dataset.betarenaAdMounted = mountedZones.join(',');
|
|
516
|
+
}
|
|
446
517
|
}
|
|
447
518
|
else if (zoneId == 2 || zoneId == 3)
|
|
448
519
|
{
|
|
@@ -459,9 +530,16 @@
|
|
|
459
530
|
}
|
|
460
531
|
);
|
|
461
532
|
;
|
|
533
|
+
if (creativeAdData.length > 0)
|
|
534
|
+
{
|
|
535
|
+
mountedZones.push(String(zoneId));
|
|
536
|
+
el.dataset.betarenaAdMounted = mountedZones.join(',');
|
|
537
|
+
}
|
|
462
538
|
}
|
|
463
539
|
else if (zoneId == 4)
|
|
464
540
|
{
|
|
541
|
+
if (!element.parentElement) continue;
|
|
542
|
+
|
|
465
543
|
for (const adData of (creativeAdData ?? []))
|
|
466
544
|
new AdvertLeftSide
|
|
467
545
|
(
|
|
@@ -474,6 +552,29 @@
|
|
|
474
552
|
}
|
|
475
553
|
);
|
|
476
554
|
;
|
|
555
|
+
if (creativeAdData.length > 0)
|
|
556
|
+
{
|
|
557
|
+
mountedZones.push(String(zoneId));
|
|
558
|
+
el.dataset.betarenaAdMounted = mountedZones.join(',');
|
|
559
|
+
// ╭─────
|
|
560
|
+
// │ NOTE:
|
|
561
|
+
// │ |: Also mark the actual injection target (parentElement) so that
|
|
562
|
+
// │ |: if the zone element is replaced while the parent persists,
|
|
563
|
+
// │ |: subsequent refreshAds() calls won't re-inject into the same parent.
|
|
564
|
+
// ╰─────
|
|
565
|
+
if (element.parentElement)
|
|
566
|
+
{
|
|
567
|
+
const
|
|
568
|
+
parentMountedRaw = (element.parentElement as HTMLElement).dataset.betarenaAdMounted ?? '',
|
|
569
|
+
parentMountedZones = parentMountedRaw.split(',').map(z => z.trim()).filter(Boolean)
|
|
570
|
+
;
|
|
571
|
+
if (!parentMountedZones.includes(String(zoneId)))
|
|
572
|
+
{
|
|
573
|
+
parentMountedZones.push(String(zoneId));
|
|
574
|
+
(element.parentElement as HTMLElement).dataset.betarenaAdMounted = parentMountedZones.join(',');
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
477
578
|
}
|
|
478
579
|
}
|
|
479
580
|
|
|
@@ -482,8 +583,11 @@
|
|
|
482
583
|
// │ |: for case of injection of 'GLOBAL' placements for adverts,
|
|
483
584
|
// │ |: ⦿ (a.k.a SLIDER / POPUP ads)
|
|
484
585
|
// │ |: ⦿ (a.k.a document.body injections)
|
|
586
|
+
// │ |: `includesGlobalZone` is computed from the caller's original scope in refreshAds()
|
|
587
|
+
// │ |: (not from DOM-filtered targetZoneIds) so global placements inject correctly
|
|
588
|
+
// │ |: even when no zone-1 element exists in the DOM.
|
|
485
589
|
// ╰─────
|
|
486
|
-
if (authorId || authorArticleTagIds.length > 0)
|
|
590
|
+
if (includesGlobalZone && (authorId || authorArticleTagIds.length > 0))
|
|
487
591
|
{
|
|
488
592
|
// ╭─────
|
|
489
593
|
// │ NOTE:
|
|
@@ -658,8 +762,9 @@
|
|
|
658
762
|
// │ |: BUT, data for ADS was still successfully fetched
|
|
659
763
|
// │ |: ⦿ (a.k.a Advert Condition was RETRIEVED/HIT).
|
|
660
764
|
// │ |: Inject STANDARD SLIDER adverts in 'document.body'
|
|
765
|
+
// │ |: Guard with `includesGlobalZone` to avoid body injections on scoped refreshes.
|
|
661
766
|
// ╰─────
|
|
662
|
-
else
|
|
767
|
+
else if (includesGlobalZone)
|
|
663
768
|
{
|
|
664
769
|
// [🐞]
|
|
665
770
|
logger
|
|
@@ -699,7 +804,129 @@
|
|
|
699
804
|
|
|
700
805
|
/**
|
|
701
806
|
* @author
|
|
702
|
-
* @
|
|
807
|
+
* @jonsnowpt
|
|
808
|
+
* @summary
|
|
809
|
+
* 🟦 HELPER
|
|
810
|
+
* @description
|
|
811
|
+
* 📝 Ensures prerequisites (`deviceType`, `geoLocation`) are resolved exactly once.
|
|
812
|
+
* Callers that race — whether `initialize()` or an external `refreshAds()` — all
|
|
813
|
+
* await the same in-flight promise.
|
|
814
|
+
* @returns { Promise < void > }
|
|
815
|
+
*/
|
|
816
|
+
async function ensureReady
|
|
817
|
+
(
|
|
818
|
+
): Promise < void >
|
|
819
|
+
{
|
|
820
|
+
if (readinessPromise) return readinessPromise;
|
|
821
|
+
|
|
822
|
+
readinessPromise =
|
|
823
|
+
(
|
|
824
|
+
async () =>
|
|
825
|
+
{
|
|
826
|
+
try
|
|
827
|
+
{
|
|
828
|
+
deviceType = detectDeviceWithUA() as IDeviceType;
|
|
829
|
+
geoLocation = await getUserLocation();
|
|
830
|
+
}
|
|
831
|
+
catch (e)
|
|
832
|
+
{
|
|
833
|
+
readinessPromise = null;
|
|
834
|
+
throw e;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
)();
|
|
838
|
+
|
|
839
|
+
return readinessPromise;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* @author
|
|
844
|
+
* @jonsnowpt
|
|
845
|
+
* @summary
|
|
846
|
+
* 🟥 MAIN
|
|
847
|
+
* @description
|
|
848
|
+
* 📝 Re-scans the DOM for ad zone elements and injects ads for any that have not
|
|
849
|
+
* yet been mounted. Safe to call multiple times — already-injected nodes store a
|
|
850
|
+
* comma-separated list of mounted zone IDs in `data-betarena-ad-mounted`
|
|
851
|
+
* (e.g. `"1,2"`), and zones whose ID is present in that list are skipped.
|
|
852
|
+
* @param {{ zoneIds?: number[]; rootElement?: HTMLElement }} [opts]
|
|
853
|
+
* 💠 Optional scope: restrict to specific zone IDs and / or a DOM subtree.
|
|
854
|
+
* @returns { Promise < void > }
|
|
855
|
+
*/
|
|
856
|
+
async function refreshAds
|
|
857
|
+
(
|
|
858
|
+
opts?:
|
|
859
|
+
{
|
|
860
|
+
zoneIds?: number[];
|
|
861
|
+
rootElement?: HTMLElement;
|
|
862
|
+
}
|
|
863
|
+
): Promise < void >
|
|
864
|
+
{
|
|
865
|
+
if (isDestroyed) return;
|
|
866
|
+
|
|
867
|
+
const
|
|
868
|
+
mySerial = ++refreshSerial
|
|
869
|
+
;
|
|
870
|
+
|
|
871
|
+
await ensureReady();
|
|
872
|
+
|
|
873
|
+
if (isDestroyed || mySerial !== refreshSerial) return;
|
|
874
|
+
|
|
875
|
+
generateElementMap(opts?.rootElement);
|
|
876
|
+
|
|
877
|
+
let
|
|
878
|
+
/**
|
|
879
|
+
* @description
|
|
880
|
+
* 📝 Zone IDs discovered in the current DOM scan (or filtered subset).
|
|
881
|
+
*/
|
|
882
|
+
targetZoneIds = [...mapBetarenaAdvertStandardElement.keys()]
|
|
883
|
+
;
|
|
884
|
+
|
|
885
|
+
if (opts?.zoneIds && opts.zoneIds.length > 0)
|
|
886
|
+
targetZoneIds = targetZoneIds.filter(id => opts.zoneIds!.includes(id));
|
|
887
|
+
;
|
|
888
|
+
|
|
889
|
+
// ╭─────
|
|
890
|
+
// │ NOTE:
|
|
891
|
+
// │ |: Only tear down previously injected global/body components when the
|
|
892
|
+
// │ |: refresh scope includes zone 1 (the global placement zone) or when
|
|
893
|
+
// │ |: no zone filter was applied (full refresh).
|
|
894
|
+
// │ |: Scoped refreshes that exclude zone 1 leave existing body-mounted
|
|
895
|
+
// │ |: widgets untouched to avoid permanently removing them.
|
|
896
|
+
// ╰─────
|
|
897
|
+
if (!opts?.zoneIds || opts.zoneIds.length === 0 || opts.zoneIds.includes(1))
|
|
898
|
+
{
|
|
899
|
+
for (const item of listAdWidgetElements)
|
|
900
|
+
item.$destroy();
|
|
901
|
+
;
|
|
902
|
+
listAdWidgetElements.length = 0;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
await injectBetarenaAds
|
|
906
|
+
(
|
|
907
|
+
{
|
|
908
|
+
deviceType,
|
|
909
|
+
isoCountryCode: geoLocation?.country_code ?? 'EN',
|
|
910
|
+
authorId: authorId ?? undefined,
|
|
911
|
+
tagIds: authorArticleTagIds,
|
|
912
|
+
zoneIds: targetZoneIds
|
|
913
|
+
},
|
|
914
|
+
// ╭─────
|
|
915
|
+
// │ NOTE:
|
|
916
|
+
// │ |: Derived from the caller's originally requested scope, NOT targetZoneIds
|
|
917
|
+
// │ |: (which is DOM-filtered). If the DOM has no zone-1 element, targetZoneIds
|
|
918
|
+
// │ |: won't include 1, but a full/zone-1 refresh should still inject global placements.
|
|
919
|
+
// ╰─────
|
|
920
|
+
!opts?.zoneIds || opts.zoneIds.length === 0 || opts.zoneIds.includes(1),
|
|
921
|
+
mySerial
|
|
922
|
+
);
|
|
923
|
+
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* @author
|
|
929
|
+
* @jonsnowpt
|
|
703
930
|
* @summary
|
|
704
931
|
* 🟥 MAIN
|
|
705
932
|
* @description
|
|
@@ -710,10 +937,6 @@
|
|
|
710
937
|
(
|
|
711
938
|
): Promise < void >
|
|
712
939
|
{
|
|
713
|
-
deviceType = detectDeviceWithUA() as IDeviceType;
|
|
714
|
-
geoLocation = await getUserLocation();
|
|
715
|
-
generateElementMap();
|
|
716
|
-
|
|
717
940
|
// [🐞]
|
|
718
941
|
logger
|
|
719
942
|
(
|
|
@@ -722,18 +945,7 @@
|
|
|
722
945
|
]
|
|
723
946
|
);
|
|
724
947
|
|
|
725
|
-
|
|
726
|
-
(
|
|
727
|
-
{
|
|
728
|
-
deviceType,
|
|
729
|
-
// deviceType: 'desktop',
|
|
730
|
-
isoCountryCode: geoLocation.country_code ?? 'EN',
|
|
731
|
-
// isoCountryCode: 'BR',
|
|
732
|
-
authorId,
|
|
733
|
-
tagIds: authorArticleTagIds,
|
|
734
|
-
zoneIds: [...mapBetarenaAdvertStandardElement.keys()]
|
|
735
|
-
}
|
|
736
|
-
);
|
|
948
|
+
await refreshAds();
|
|
737
949
|
|
|
738
950
|
return;
|
|
739
951
|
}
|
|
@@ -756,9 +968,37 @@
|
|
|
756
968
|
betarenaAdEngineStore.useLocalStorage();
|
|
757
969
|
// ╭─────
|
|
758
970
|
// │ NOTE:
|
|
971
|
+
// │ |: Expose public API immediately so host apps can call refreshAds()
|
|
972
|
+
// │ |: without waiting for the delayed initialize().
|
|
973
|
+
// │ |: refreshAds() self-initializes prerequisites via ensureReady() if needed.
|
|
974
|
+
// │ |: Save any existing value so it can be restored when this instance is destroyed.
|
|
975
|
+
// ╰─────
|
|
976
|
+
prevWindowApi = (window as any).betarenaAdEngine;
|
|
977
|
+
(window as any).betarenaAdEngine = { refreshAds };
|
|
978
|
+
// ╭─────
|
|
979
|
+
// │ NOTE:
|
|
759
980
|
// │ |: Delay initialization to ensure all elements are loaded on page
|
|
760
981
|
// ╰─────
|
|
761
|
-
|
|
982
|
+
initTimeoutId = setTimeout
|
|
983
|
+
(
|
|
984
|
+
() =>
|
|
985
|
+
{
|
|
986
|
+
initialize().catch
|
|
987
|
+
(
|
|
988
|
+
(error) =>
|
|
989
|
+
{
|
|
990
|
+
logger
|
|
991
|
+
(
|
|
992
|
+
[
|
|
993
|
+
'🚨 checkpoint ➤ initialize(..) // UNHANDLED ERROR',
|
|
994
|
+
`🔹 [var] ➤ error ${error}`
|
|
995
|
+
]
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
);
|
|
999
|
+
},
|
|
1000
|
+
1000
|
|
1001
|
+
);
|
|
762
1002
|
return;
|
|
763
1003
|
}
|
|
764
1004
|
);
|
|
@@ -776,6 +1016,25 @@
|
|
|
776
1016
|
],
|
|
777
1017
|
);
|
|
778
1018
|
|
|
1019
|
+
isDestroyed = true;
|
|
1020
|
+
|
|
1021
|
+
if (initTimeoutId !== null)
|
|
1022
|
+
clearTimeout(initTimeoutId);
|
|
1023
|
+
;
|
|
1024
|
+
|
|
1025
|
+
// ╭─────
|
|
1026
|
+
// │ NOTE:
|
|
1027
|
+
// │ |: Only remove/restore the global if this instance still owns it.
|
|
1028
|
+
// │ |: A later-mounted instance or host code may have overwritten it.
|
|
1029
|
+
// ╰─────
|
|
1030
|
+
if ((window as any).betarenaAdEngine?.refreshAds === refreshAds)
|
|
1031
|
+
{
|
|
1032
|
+
if (prevWindowApi !== undefined)
|
|
1033
|
+
(window as any).betarenaAdEngine = prevWindowApi;
|
|
1034
|
+
else
|
|
1035
|
+
delete (window as any).betarenaAdEngine;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
779
1038
|
// ╭─────
|
|
780
1039
|
// │ NOTE:
|
|
781
1040
|
// │ |: Destroy all dynamically created advert components
|
|
@@ -807,7 +1066,7 @@
|
|
|
807
1066
|
|
|
808
1067
|
{#if isStandalone}
|
|
809
1068
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
810
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
1069
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
|
|
811
1070
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
|
812
1071
|
{/if}
|
|
813
1072
|
|
|
@@ -114,11 +114,13 @@
|
|
|
114
114
|
|
|
115
115
|
<a
|
|
116
116
|
target='_blank'
|
|
117
|
+
rel='noopener noreferrer'
|
|
117
118
|
href={objectAdvertData.data?.cta_link}
|
|
118
119
|
on:click=
|
|
119
120
|
{
|
|
120
121
|
() =>
|
|
121
122
|
{
|
|
123
|
+
if (objectAdvertData.id === undefined) return;
|
|
122
124
|
new ServiceAdEngine
|
|
123
125
|
(
|
|
124
126
|
betarenaEndpoint
|
|
@@ -247,16 +247,11 @@
|
|
|
247
247
|
╰─────
|
|
248
248
|
-->
|
|
249
249
|
{#if isAdvertCloseBtnShown}
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
loading='lazy'
|
|
256
|
-
class=
|
|
257
|
-
"
|
|
258
|
-
cursor-pointer
|
|
259
|
-
"
|
|
250
|
+
<button
|
|
251
|
+
type="button"
|
|
252
|
+
aria-label="Close advert"
|
|
253
|
+
class="cursor-pointer"
|
|
254
|
+
style="background:none;border:none;padding:0;"
|
|
260
255
|
on:click=
|
|
261
256
|
{
|
|
262
257
|
() =>
|
|
@@ -274,7 +269,14 @@
|
|
|
274
269
|
return;
|
|
275
270
|
}
|
|
276
271
|
}
|
|
277
|
-
|
|
272
|
+
>
|
|
273
|
+
<img
|
|
274
|
+
class='close-btn'
|
|
275
|
+
src={iconClose}
|
|
276
|
+
alt=''
|
|
277
|
+
loading='lazy'
|
|
278
|
+
/>
|
|
279
|
+
</button>
|
|
278
280
|
{/if}
|
|
279
281
|
|
|
280
282
|
<!--
|
|
@@ -295,6 +297,7 @@
|
|
|
295
297
|
{
|
|
296
298
|
() =>
|
|
297
299
|
{
|
|
300
|
+
if (adData.id === undefined) return;
|
|
298
301
|
new ServiceAdEngine
|
|
299
302
|
(
|
|
300
303
|
betarenaEndpoint
|
|
@@ -428,6 +431,7 @@
|
|
|
428
431
|
{
|
|
429
432
|
() =>
|
|
430
433
|
{
|
|
434
|
+
if (adData.id === undefined) return;
|
|
431
435
|
new ServiceAdEngine
|
|
432
436
|
(
|
|
433
437
|
betarenaEndpoint
|
|
@@ -520,7 +524,7 @@
|
|
|
520
524
|
|
|
521
525
|
img
|
|
522
526
|
{
|
|
523
|
-
|
|
527
|
+
&.close-btn
|
|
524
528
|
{
|
|
525
529
|
/* 📌 position */
|
|
526
530
|
position: absolute;
|