@betarena/ad-engine 0.4.0 → 1.0.0
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 +4 -9
- package/src/App.svelte +2 -12
- package/src/lib/Advert-Engine-Widget.svelte +357 -643
- package/src/lib/Advert-General-Child.svelte +39 -22
- package/src/lib/Advert-InterScroller-Child.svelte +4 -3
- package/src/lib/Advert-Slide-Child.svelte +96 -63
- package/src/lib/misc/admin/Dev-Info-Box.svelte +11 -1
- package/src/lib/store/session.ts +5 -7
- package/src/lib/types/session.d.ts +0 -10
- package/src/style/app.css +0 -3024
- package/src/style/app.css.map +0 -1
- package/src/style/app.purged.min.scss +0 -137
- package/src/style/app.scss +0 -19
- package/src/style/scss/_document.scss +0 -41
- package/src/style/scss/_root.scss +0 -439
- package/src/style/scss/animation.scss +0 -36
- package/src/style/scss/button.scss +0 -266
- package/src/style/scss/common.scss +0 -40
- package/src/style/scss/font.scss +0 -296
- package/src/style/scss/layout.scss +0 -175
- package/src/style/scss/main.scss +0 -46
- package/src/style/scss/misc.scss +0 -189
- package/src/style/scss/spacing.scss +0 -41
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
-->
|
|
23
23
|
|
|
24
24
|
<script lang="ts">
|
|
25
|
-
|
|
26
25
|
// #region ➤ 📦 Package Imports
|
|
27
26
|
|
|
28
27
|
// ╭────────────────────────────────────────────────────────────────────────╮
|
|
@@ -38,27 +37,27 @@
|
|
|
38
37
|
// │ 5. type(s) imports(s) │
|
|
39
38
|
// ╰────────────────────────────────────────────────────────────────────────╯
|
|
40
39
|
|
|
41
|
-
import { onDestroy, onMount, SvelteComponent } from
|
|
40
|
+
import { onDestroy, onMount, SvelteComponent } from "svelte";
|
|
42
41
|
// import '@fontsource/roboto';
|
|
43
42
|
|
|
44
|
-
import { ServiceAdEngine } from
|
|
45
|
-
import { removeNull } from
|
|
46
|
-
import { betarenaAdEngineStore } from
|
|
47
|
-
import { betarenaEndpoint } from
|
|
48
|
-
import { storeSession } from
|
|
49
|
-
import { logger } from
|
|
50
|
-
import { detectDeviceWithUA } from
|
|
51
|
-
import { getUserLocation } from
|
|
52
|
-
|
|
53
|
-
import WidgetAdGeneral from
|
|
54
|
-
import AdvertInterScrollerChild from
|
|
55
|
-
import AdvertLeftSide from
|
|
56
|
-
import WidgetAdvertSlide from
|
|
57
|
-
import DevInfoBox from
|
|
58
|
-
|
|
59
|
-
import type { IAdsServiceData } from
|
|
60
|
-
import type { AdsCreativeMain } from
|
|
61
|
-
import type { GeoJsResponse } from
|
|
43
|
+
import { ServiceAdEngine } from "@betarena/scores-lib/dist/classes/_service.adengine.js";
|
|
44
|
+
import { removeNull } from "@betarena/scores-lib/dist/util/common.js";
|
|
45
|
+
import { betarenaAdEngineStore } from "./_store.js";
|
|
46
|
+
import { betarenaEndpoint } from "./constants/instance.js";
|
|
47
|
+
import { storeSession } from "./store/session.js";
|
|
48
|
+
import { logger } from "./utils/debug.js";
|
|
49
|
+
import { detectDeviceWithUA } from "./utils/device.js";
|
|
50
|
+
import { getUserLocation } from "./utils/geo.js";
|
|
51
|
+
|
|
52
|
+
import WidgetAdGeneral from "./Advert-General-Child.svelte";
|
|
53
|
+
import AdvertInterScrollerChild from "./Advert-InterScroller-Child.svelte";
|
|
54
|
+
import AdvertLeftSide from "./Advert-LeftSide-Child.svelte";
|
|
55
|
+
import WidgetAdvertSlide from "./Advert-Slide-Child.svelte";
|
|
56
|
+
import DevInfoBox from "./misc/admin/Dev-Info-Box.svelte";
|
|
57
|
+
|
|
58
|
+
import type { IAdsServiceData } from "@betarena/scores-lib/types/ad-engine/index.js";
|
|
59
|
+
import type { AdsCreativeMain } from "@betarena/scores-lib/types/v8/_HASURA-0.js";
|
|
60
|
+
import type { GeoJsResponse } from "./types/geojs.js";
|
|
62
61
|
|
|
63
62
|
// #endregion ➤ 📦 Package Imports
|
|
64
63
|
|
|
@@ -76,8 +75,7 @@
|
|
|
76
75
|
// │ 4. $: [..] │
|
|
77
76
|
// ╰────────────────────────────────────────────────────────────────────────╯
|
|
78
77
|
|
|
79
|
-
export let
|
|
80
|
-
/**
|
|
78
|
+
export let /**
|
|
81
79
|
* @description
|
|
82
80
|
* 📝 Width device change onset number
|
|
83
81
|
*/
|
|
@@ -97,29 +95,18 @@
|
|
|
97
95
|
* 📝 Logged-in users should bypass the initial global slider delay.
|
|
98
96
|
*/
|
|
99
97
|
isLoggedIn = false,
|
|
100
|
-
/**
|
|
101
|
-
* @description
|
|
102
|
-
* 📝 Dark theme value
|
|
103
|
-
*/
|
|
104
|
-
isDarkTheme: boolean = false,
|
|
105
98
|
/**
|
|
106
99
|
* @description
|
|
107
100
|
* 📝 Translation target
|
|
108
101
|
*/
|
|
109
|
-
strTranslationTarget =
|
|
110
|
-
/**
|
|
111
|
-
* @description
|
|
112
|
-
* 📝 Condition for testing
|
|
113
|
-
*/
|
|
114
|
-
isStandalone = true,
|
|
102
|
+
strTranslationTarget = "en",
|
|
115
103
|
/**
|
|
116
104
|
* @description
|
|
117
105
|
* 📝 Signal from the host that the current page is an article page.
|
|
118
106
|
* Zone 1 body-mounted ads (slider/popup) must only inject when this is `true`.
|
|
119
107
|
* Defaults to `false` so the widget fails closed on non-article pages.
|
|
120
108
|
*/
|
|
121
|
-
isArticlePage: boolean = false
|
|
122
|
-
;
|
|
109
|
+
isArticlePage: boolean = false;
|
|
123
110
|
|
|
124
111
|
// Retained as a supported public prop for API compatibility.
|
|
125
112
|
// Device detection is UA-based; this value is not consumed internally.
|
|
@@ -129,20 +116,13 @@
|
|
|
129
116
|
* @description
|
|
130
117
|
* 📝 Component Local Interface
|
|
131
118
|
*/
|
|
132
|
-
type IDeviceType =
|
|
133
|
-
| 'desktop'
|
|
134
|
-
| 'tablet'
|
|
135
|
-
| 'mobile'
|
|
136
|
-
;
|
|
137
|
-
|
|
138
|
-
$: $storeSession.isDarkTheme = isDarkTheme;
|
|
119
|
+
type IDeviceType = "desktop" | "tablet" | "mobile";
|
|
139
120
|
|
|
140
|
-
let
|
|
141
|
-
/**
|
|
121
|
+
let /**
|
|
142
122
|
* @description
|
|
143
123
|
* 📝 device type detected
|
|
144
124
|
*/
|
|
145
|
-
deviceType: IDeviceType =
|
|
125
|
+
deviceType: IDeviceType = "desktop",
|
|
146
126
|
/**
|
|
147
127
|
* @description
|
|
148
128
|
* 📝 geo-location response
|
|
@@ -152,24 +132,24 @@
|
|
|
152
132
|
* @description
|
|
153
133
|
* 📝 `Map` where, `key=ZoneId` and `value=HTMLElement`
|
|
154
134
|
*/
|
|
155
|
-
mapBetarenaAdvertStandardElement = new Map
|
|
135
|
+
mapBetarenaAdvertStandardElement = new Map<number, Element>(),
|
|
156
136
|
/**
|
|
157
137
|
* @description
|
|
158
138
|
* 📝 `Map` where, `key=CreativeId` and `value=AdvertObject` (temporary)
|
|
159
139
|
*/
|
|
160
|
-
mapCreative = new Map
|
|
140
|
+
mapCreative = new Map<number, AdsCreativeMain>(),
|
|
161
141
|
/**
|
|
162
142
|
* @description
|
|
163
143
|
* 📝 Shared promise for one-time prerequisite initialization (device type + geolocation).
|
|
164
144
|
* Set on first call to `ensureReady()`; subsequent callers await the same promise.
|
|
165
145
|
*/
|
|
166
|
-
readinessPromise: Promise
|
|
146
|
+
readinessPromise: Promise<void> | null = null,
|
|
167
147
|
/**
|
|
168
148
|
* @description
|
|
169
149
|
* 📝 ID of the deferred `initialize()` timeout, used to cancel it if the component
|
|
170
150
|
* is destroyed before the delay elapses.
|
|
171
151
|
*/
|
|
172
|
-
initTimeoutId: ReturnType
|
|
152
|
+
initTimeoutId: ReturnType<typeof setTimeout> | null = null,
|
|
173
153
|
/**
|
|
174
154
|
* @description
|
|
175
155
|
* 📝 Set to `true` once `onDestroy` fires, so any in-flight async work can bail out.
|
|
@@ -186,17 +166,12 @@
|
|
|
186
166
|
* 📝 Previous value of `window.betarenaAdEngine` saved before this instance assigns it,
|
|
187
167
|
* so it can be restored on destroy instead of unconditionally deleting.
|
|
188
168
|
*/
|
|
189
|
-
prevWindowApi: unknown = undefined
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
/**
|
|
169
|
+
prevWindowApi: unknown = undefined;
|
|
170
|
+
const /**
|
|
194
171
|
* @description
|
|
195
172
|
* 📝 `List` of dynamically created advert components (to be destroyed on cleanup)
|
|
196
173
|
*/
|
|
197
|
-
listAdWidgetElements: SvelteComponent[] = []
|
|
198
|
-
;
|
|
199
|
-
|
|
174
|
+
listAdWidgetElements: SvelteComponent[] = [];
|
|
200
175
|
// #endregion ➤ 📌 VARIABLES
|
|
201
176
|
|
|
202
177
|
// #region ➤ 🛠️ METHODS
|
|
@@ -220,40 +195,30 @@
|
|
|
220
195
|
* 📝 `Map` generation for `HTMLElements`.
|
|
221
196
|
* @returns { void }
|
|
222
197
|
*/
|
|
223
|
-
function generateElementMap
|
|
224
|
-
(
|
|
225
|
-
rootElement?: ParentNode
|
|
226
|
-
): void
|
|
227
|
-
{
|
|
198
|
+
function generateElementMap(rootElement?: ParentNode): void {
|
|
228
199
|
mapBetarenaAdvertStandardElement.clear();
|
|
229
200
|
|
|
230
|
-
const
|
|
231
|
-
/**
|
|
201
|
+
const /**
|
|
232
202
|
* @description
|
|
233
203
|
* 📝 `List` of `HTMLElements` identified on `page` expecting a target `zone` advertisement injection.
|
|
234
204
|
*/
|
|
235
|
-
listElementTarget = (rootElement ?? document).querySelectorAll(
|
|
236
|
-
|
|
237
|
-
|
|
205
|
+
listElementTarget = (rootElement ?? document).querySelectorAll(
|
|
206
|
+
"[data-betarena-zone-id]",
|
|
207
|
+
);
|
|
238
208
|
// ╭─────
|
|
239
209
|
// │ NOTE:
|
|
240
210
|
// │ |: querySelectorAll only returns descendants — if rootElement itself carries
|
|
241
211
|
// │ |: the zone attribute it would be missed. Include it explicitly.
|
|
242
212
|
// ╰─────
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
{
|
|
253
|
-
const
|
|
254
|
-
token = rawToken.trim(),
|
|
255
|
-
id = Number.parseInt(token, 10)
|
|
256
|
-
;
|
|
213
|
+
if (
|
|
214
|
+
rootElement instanceof Element &&
|
|
215
|
+
rootElement.hasAttribute("data-betarena-zone-id")
|
|
216
|
+
) {
|
|
217
|
+
const value = rootElement.getAttribute("data-betarena-zone-id");
|
|
218
|
+
if (value) {
|
|
219
|
+
for (const rawToken of value.split(",")) {
|
|
220
|
+
const token = rawToken.trim(),
|
|
221
|
+
id = Number.parseInt(token, 10);
|
|
257
222
|
if (!token || !Number.isFinite(id)) continue;
|
|
258
223
|
mapBetarenaAdvertStandardElement.set(id, rootElement);
|
|
259
224
|
}
|
|
@@ -261,59 +226,41 @@
|
|
|
261
226
|
}
|
|
262
227
|
|
|
263
228
|
// [🐞]
|
|
264
|
-
logger
|
|
265
|
-
|
|
266
|
-
[
|
|
267
|
-
|
|
268
|
-
`🔹 [var] ➤ listElementTarget.length ${listElementTarget.length}`
|
|
269
|
-
]
|
|
270
|
-
);
|
|
229
|
+
logger([
|
|
230
|
+
"🚏 checkpoint ➤ generateElementMap(..) // START",
|
|
231
|
+
`🔹 [var] ➤ listElementTarget.length ${listElementTarget.length}`,
|
|
232
|
+
]);
|
|
271
233
|
|
|
272
234
|
// ╭─────
|
|
273
235
|
// │ NOTE: |:| loop over elements detected as betarena elegible advert injection (global/outer)
|
|
274
236
|
// ╰─────
|
|
275
|
-
for (const elem of listElementTarget)
|
|
276
|
-
|
|
277
|
-
let
|
|
278
|
-
/**
|
|
237
|
+
for (const elem of listElementTarget) {
|
|
238
|
+
let /**
|
|
279
239
|
* @description
|
|
280
240
|
* 📝 Value of Betarena Zone Id
|
|
281
241
|
*/
|
|
282
|
-
value = elem.attributes.getNamedItem(
|
|
283
|
-
;
|
|
284
|
-
|
|
242
|
+
value = elem.attributes.getNamedItem("data-betarena-zone-id")?.value;
|
|
285
243
|
if (!value) continue;
|
|
286
244
|
|
|
287
245
|
// [🐞]
|
|
288
|
-
logger
|
|
289
|
-
(
|
|
290
|
-
[
|
|
291
|
-
`🔹 [var] ➤ value ${value}`
|
|
292
|
-
]
|
|
293
|
-
);
|
|
246
|
+
logger([`🔹 [var] ➤ value ${value}`]);
|
|
294
247
|
|
|
295
|
-
for (const rawToken of value.split(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
token = rawToken.trim(),
|
|
299
|
-
id = Number.parseInt(token, 10)
|
|
300
|
-
;
|
|
248
|
+
for (const rawToken of value.split(",")) {
|
|
249
|
+
const token = rawToken.trim(),
|
|
250
|
+
id = Number.parseInt(token, 10);
|
|
301
251
|
if (!token || !Number.isFinite(id)) continue;
|
|
302
252
|
mapBetarenaAdvertStandardElement.set(id, elem);
|
|
303
253
|
}
|
|
304
254
|
}
|
|
305
255
|
|
|
306
256
|
// [🐞]
|
|
307
|
-
logger
|
|
308
|
-
|
|
309
|
-
[
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
'🚏 checkpoint ➤ generateElementMap(..) // END'
|
|
313
|
-
]
|
|
314
|
-
);
|
|
257
|
+
logger([
|
|
258
|
+
`🔹 [var] ➤ mapBetarenaAdvertStandardElement.keys ${[...mapBetarenaAdvertStandardElement.keys()]}`,
|
|
259
|
+
`🔹 [var] ➤ mapBetarenaAdvertStandardElement.size ${mapBetarenaAdvertStandardElement.size}`,
|
|
260
|
+
"🚏 checkpoint ➤ generateElementMap(..) // END",
|
|
261
|
+
]);
|
|
315
262
|
|
|
316
|
-
return
|
|
263
|
+
return;
|
|
317
264
|
}
|
|
318
265
|
|
|
319
266
|
/**
|
|
@@ -327,97 +274,70 @@
|
|
|
327
274
|
* 💠 **[required]** `list` of zone ids
|
|
328
275
|
* @returns { Promise < void > }
|
|
329
276
|
*/
|
|
330
|
-
async function injectBetarenaAds
|
|
331
|
-
|
|
332
|
-
opts: IAdsServiceData['request']['body'],
|
|
277
|
+
async function injectBetarenaAds(
|
|
278
|
+
opts: IAdsServiceData["request"]["body"],
|
|
333
279
|
includesGlobalZone: boolean,
|
|
334
|
-
refreshToken: number
|
|
335
|
-
): Promise
|
|
336
|
-
{
|
|
280
|
+
refreshToken: number,
|
|
281
|
+
): Promise<void> {
|
|
337
282
|
if (!document) return;
|
|
338
283
|
|
|
339
|
-
const
|
|
340
|
-
/**
|
|
284
|
+
const /**
|
|
341
285
|
* @description
|
|
342
286
|
* 📝 Response from `fetch`
|
|
343
287
|
*/
|
|
344
|
-
dataRes0
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
).getAdEngineData
|
|
349
|
-
(
|
|
350
|
-
{
|
|
351
|
-
query: {},
|
|
352
|
-
body: opts
|
|
353
|
-
}
|
|
354
|
-
),
|
|
288
|
+
dataRes0 = await new ServiceAdEngine(betarenaEndpoint).getAdEngineData({
|
|
289
|
+
query: {},
|
|
290
|
+
body: opts,
|
|
291
|
+
}),
|
|
355
292
|
/**
|
|
356
293
|
* @description
|
|
357
294
|
* 📝 Response from `fetch`
|
|
358
295
|
*/
|
|
359
|
-
dataRes1
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
language: strTranslationTarget
|
|
368
|
-
},
|
|
369
|
-
body: {}
|
|
370
|
-
}
|
|
371
|
-
)
|
|
372
|
-
;
|
|
373
|
-
|
|
296
|
+
dataRes1 = await new ServiceAdEngine(
|
|
297
|
+
betarenaEndpoint,
|
|
298
|
+
).getAdEgnineTranslationData({
|
|
299
|
+
query: {
|
|
300
|
+
language: strTranslationTarget,
|
|
301
|
+
},
|
|
302
|
+
body: {},
|
|
303
|
+
});
|
|
374
304
|
// [🐞]
|
|
375
|
-
logger
|
|
376
|
-
|
|
377
|
-
[
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
`🔹 [var] ➤ dataRes1 ${JSON.stringify(dataRes1)}`
|
|
381
|
-
]
|
|
382
|
-
);
|
|
305
|
+
logger([
|
|
306
|
+
"🚏 checkpoint ➤ injectBetarenaAds(..) // START",
|
|
307
|
+
`🔹 [var] ➤ dataRes0 ${JSON.stringify(dataRes0)}`,
|
|
308
|
+
`🔹 [var] ➤ dataRes1 ${JSON.stringify(dataRes1)}`,
|
|
309
|
+
]);
|
|
383
310
|
|
|
384
311
|
if (isDestroyed || refreshToken !== refreshSerial) return;
|
|
385
312
|
|
|
386
|
-
storeSession.updateData
|
|
387
|
-
(
|
|
388
|
-
[
|
|
389
|
-
[
|
|
390
|
-
'setTranslation',
|
|
391
|
-
dataRes1.success.data
|
|
392
|
-
]
|
|
393
|
-
]
|
|
394
|
-
);
|
|
313
|
+
storeSession.updateData([["setTranslation", dataRes1.success.data]]);
|
|
395
314
|
|
|
396
315
|
mapCreative = new Map(dataRes0.success.data.ads ?? []);
|
|
397
316
|
|
|
398
|
-
const
|
|
399
|
-
/**
|
|
317
|
+
const /**
|
|
400
318
|
* @description
|
|
401
319
|
* 📝 `Map` where, `key=ZoneId` and `value=listCampaignId`
|
|
402
320
|
*/
|
|
403
|
-
mapZoneIdToCampaignId = new Map
|
|
321
|
+
mapZoneIdToCampaignId = new Map(
|
|
322
|
+
dataRes0.success.data.mapZoneIdToCampaignId,
|
|
323
|
+
),
|
|
404
324
|
/**
|
|
405
325
|
* @description
|
|
406
326
|
* 📝 `Map` where, `key=CampaignId` and `value=listCreativeId`
|
|
407
327
|
*/
|
|
408
|
-
mapCampaignIdToCreativeId = new Map
|
|
328
|
+
mapCampaignIdToCreativeId = new Map(
|
|
329
|
+
dataRes0.success.data.mapCampaignIdToCreativeId,
|
|
330
|
+
),
|
|
409
331
|
/**
|
|
410
332
|
* @description
|
|
411
333
|
* 📝 `Map` where, `key=ZoneId` and `value=listAuthorId`
|
|
412
334
|
*/
|
|
413
|
-
mapZoneToAuthorIds = new Map
|
|
335
|
+
mapZoneToAuthorIds = new Map(dataRes0.success.data.mapZoneIdToAuthorIds),
|
|
414
336
|
/**
|
|
415
337
|
* @description
|
|
416
338
|
* 📝 `Map` where, `key=ZoneId` and `value=listTagId`
|
|
417
339
|
*/
|
|
418
|
-
mapZoneToTagIds = new Map
|
|
419
|
-
;
|
|
420
|
-
|
|
340
|
+
mapZoneToTagIds = new Map(dataRes0.success.data.mapZoneIdToTagIds);
|
|
421
341
|
// ╭──────────────────────────────────────────────────────────────────────────────────╮
|
|
422
342
|
// │ 💠 │ STEP :: ADVERT INJECTION │
|
|
423
343
|
// ╰──────────────────────────────────────────────────────────────────────────────────╯
|
|
@@ -429,161 +349,118 @@
|
|
|
429
349
|
// ┣─────
|
|
430
350
|
// ┃ ZONE-ID :: 1,2,3,4
|
|
431
351
|
// ╰─────
|
|
432
|
-
for (const [zoneId, element] of mapBetarenaAdvertStandardElement)
|
|
433
|
-
|
|
434
|
-
const
|
|
435
|
-
el = element as HTMLElement,
|
|
352
|
+
for (const [zoneId, element] of mapBetarenaAdvertStandardElement) {
|
|
353
|
+
const el = element as HTMLElement,
|
|
436
354
|
parent = el.parentElement as HTMLElement | null,
|
|
437
|
-
mountedAttr =
|
|
438
|
-
[
|
|
355
|
+
mountedAttr = [
|
|
439
356
|
el.dataset.betarenaAdMounted,
|
|
440
|
-
parent?.dataset?.betarenaAdMounted
|
|
441
|
-
]
|
|
442
|
-
|
|
443
|
-
|
|
357
|
+
parent?.dataset?.betarenaAdMounted,
|
|
358
|
+
]
|
|
359
|
+
.filter(Boolean)
|
|
360
|
+
.join(","),
|
|
361
|
+
mountedZones = mountedAttr
|
|
362
|
+
.split(",")
|
|
363
|
+
.map((z) => z.trim())
|
|
364
|
+
.filter(Boolean);
|
|
444
365
|
if (mountedZones.includes(String(zoneId))) continue;
|
|
445
366
|
|
|
446
|
-
const
|
|
447
|
-
/**
|
|
367
|
+
const /**
|
|
448
368
|
* @description
|
|
449
369
|
* 📝 **campaign ids** of respective **zone id**
|
|
450
370
|
*/
|
|
451
|
-
campaignIds
|
|
452
|
-
= (mapZoneIdToCampaignId.get(zoneId) ?? []),
|
|
371
|
+
campaignIds = mapZoneIdToCampaignId.get(zoneId) ?? [],
|
|
453
372
|
/**
|
|
454
373
|
* @description
|
|
455
374
|
* 📝 `List` of creative data point(s)
|
|
456
375
|
*/
|
|
457
|
-
creativeAdData
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
return false;
|
|
473
|
-
}
|
|
474
|
-
)
|
|
376
|
+
creativeAdData = removeNull(
|
|
377
|
+
campaignIds
|
|
378
|
+
// ╭─────
|
|
379
|
+
// │ NOTE:
|
|
380
|
+
// │ |: Filter out `campaign ids` that have no `creative ids`
|
|
381
|
+
// ╰─────
|
|
382
|
+
.filter((x) => {
|
|
383
|
+
if (mapCampaignIdToCreativeId.has(x)) return true;
|
|
384
|
+
return false;
|
|
385
|
+
})
|
|
386
|
+
// ╭─────
|
|
387
|
+
// │ NOTE:
|
|
388
|
+
// │ |: Map over `campaign ids` and return `creative data`
|
|
389
|
+
// ╰─────
|
|
390
|
+
.map((x) => {
|
|
475
391
|
// ╭─────
|
|
476
392
|
// │ NOTE:
|
|
477
|
-
// │ |:
|
|
393
|
+
// │ |: Loop over creative data and inject adverts
|
|
478
394
|
// ╰─────
|
|
479
|
-
.
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
// │ |: Loop over creative data and inject adverts
|
|
486
|
-
// ╰─────
|
|
487
|
-
for (const creativeId of mapCampaignIdToCreativeId.get(x)!)
|
|
488
|
-
{
|
|
489
|
-
if (mapCreative.has(creativeId))
|
|
490
|
-
return mapCreative.get(creativeId);
|
|
491
|
-
;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
)
|
|
495
|
-
) as AdsCreativeMain[]
|
|
496
|
-
;
|
|
497
|
-
|
|
395
|
+
for (const creativeId of mapCampaignIdToCreativeId.get(x)!) {
|
|
396
|
+
if (mapCreative.has(creativeId))
|
|
397
|
+
return mapCreative.get(creativeId);
|
|
398
|
+
}
|
|
399
|
+
}),
|
|
400
|
+
) as AdsCreativeMain[];
|
|
498
401
|
// [🐞]
|
|
499
|
-
logger
|
|
500
|
-
(
|
|
501
|
-
[
|
|
502
|
-
`🔹 [var] ➤ creativeAdData.length ${creativeAdData.length}`
|
|
503
|
-
]
|
|
504
|
-
);
|
|
402
|
+
logger([`🔹 [var] ➤ creativeAdData.length ${creativeAdData.length}`]);
|
|
505
403
|
|
|
506
404
|
// ╭─────
|
|
507
405
|
// │ NOTE:
|
|
508
406
|
// │ |: Loop over creative data and inject adverts, based on respective `zoneId`.
|
|
509
407
|
// ╰─────
|
|
510
|
-
if (zoneId == 1)
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
adData
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
);
|
|
523
|
-
;
|
|
524
|
-
if (creativeAdData.length > 0)
|
|
525
|
-
{
|
|
408
|
+
if (zoneId == 1) {
|
|
409
|
+
for (const adData of creativeAdData ?? [])
|
|
410
|
+
new WidgetAdGeneral({
|
|
411
|
+
target: element,
|
|
412
|
+
props: {
|
|
413
|
+
adData,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
if (creativeAdData.length > 0) {
|
|
526
417
|
mountedZones.push(String(zoneId));
|
|
527
|
-
el.dataset.betarenaAdMounted = mountedZones.join(
|
|
418
|
+
el.dataset.betarenaAdMounted = mountedZones.join(",");
|
|
528
419
|
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
instanceNode: element,
|
|
540
|
-
objectAdvertData: adData
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
);
|
|
544
|
-
;
|
|
545
|
-
if (creativeAdData.length > 0)
|
|
546
|
-
{
|
|
420
|
+
} else if (zoneId == 2 || zoneId == 3) {
|
|
421
|
+
for (const adData of creativeAdData ?? [])
|
|
422
|
+
new AdvertInterScrollerChild({
|
|
423
|
+
target: element,
|
|
424
|
+
props: {
|
|
425
|
+
instanceNode: element,
|
|
426
|
+
objectAdvertData: adData,
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
if (creativeAdData.length > 0) {
|
|
547
430
|
mountedZones.push(String(zoneId));
|
|
548
|
-
el.dataset.betarenaAdMounted = mountedZones.join(
|
|
431
|
+
el.dataset.betarenaAdMounted = mountedZones.join(",");
|
|
549
432
|
}
|
|
550
|
-
}
|
|
551
|
-
else if (zoneId == 4)
|
|
552
|
-
{
|
|
433
|
+
} else if (zoneId == 4) {
|
|
553
434
|
if (!element.parentElement) continue;
|
|
554
435
|
|
|
555
|
-
for (const adData of
|
|
556
|
-
new AdvertLeftSide
|
|
557
|
-
|
|
558
|
-
{
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
);
|
|
566
|
-
;
|
|
567
|
-
if (creativeAdData.length > 0)
|
|
568
|
-
{
|
|
436
|
+
for (const adData of creativeAdData ?? [])
|
|
437
|
+
new AdvertLeftSide({
|
|
438
|
+
target: element.parentElement,
|
|
439
|
+
props: {
|
|
440
|
+
objectAdvertData: adData,
|
|
441
|
+
},
|
|
442
|
+
});
|
|
443
|
+
if (creativeAdData.length > 0) {
|
|
569
444
|
mountedZones.push(String(zoneId));
|
|
570
|
-
el.dataset.betarenaAdMounted = mountedZones.join(
|
|
445
|
+
el.dataset.betarenaAdMounted = mountedZones.join(",");
|
|
571
446
|
// ╭─────
|
|
572
447
|
// │ NOTE:
|
|
573
448
|
// │ |: Also mark the actual injection target (parentElement) so that
|
|
574
449
|
// │ |: if the zone element is replaced while the parent persists,
|
|
575
450
|
// │ |: subsequent refreshAds() calls won't re-inject into the same parent.
|
|
576
451
|
// ╰─────
|
|
577
|
-
if (element.parentElement)
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
parentMountedZones = parentMountedRaw
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
452
|
+
if (element.parentElement) {
|
|
453
|
+
const parentMountedRaw =
|
|
454
|
+
(element.parentElement as HTMLElement).dataset
|
|
455
|
+
.betarenaAdMounted ?? "",
|
|
456
|
+
parentMountedZones = parentMountedRaw
|
|
457
|
+
.split(",")
|
|
458
|
+
.map((z) => z.trim())
|
|
459
|
+
.filter(Boolean);
|
|
460
|
+
if (!parentMountedZones.includes(String(zoneId))) {
|
|
585
461
|
parentMountedZones.push(String(zoneId));
|
|
586
|
-
(element.parentElement as HTMLElement).dataset.betarenaAdMounted =
|
|
462
|
+
(element.parentElement as HTMLElement).dataset.betarenaAdMounted =
|
|
463
|
+
parentMountedZones.join(",");
|
|
587
464
|
}
|
|
588
465
|
}
|
|
589
466
|
}
|
|
@@ -599,88 +476,66 @@
|
|
|
599
476
|
// │ |: (not from DOM-filtered targetZoneIds) so global placements inject correctly
|
|
600
477
|
// │ |: even when no zone-1 element exists in the DOM.
|
|
601
478
|
// ╰─────
|
|
602
|
-
if (
|
|
603
|
-
|
|
479
|
+
if (
|
|
480
|
+
includesGlobalZone &&
|
|
481
|
+
isArticlePage &&
|
|
482
|
+
(authorId || authorArticleTagIds.length > 0)
|
|
483
|
+
) {
|
|
604
484
|
// ╭─────
|
|
605
485
|
// │ NOTE:
|
|
606
486
|
// │ |: loop over creative data AND inject adverts, based on 'authorId'
|
|
607
487
|
// ╰─────
|
|
608
|
-
for (const [zoneId, authorIds] of mapZoneToAuthorIds)
|
|
609
|
-
|
|
610
|
-
|
|
488
|
+
for (const [zoneId, authorIds] of mapZoneToAuthorIds) {
|
|
489
|
+
if (
|
|
490
|
+
!authorId ||
|
|
491
|
+
(authorIds.length > 0 && !authorIds.includes(authorId))
|
|
492
|
+
)
|
|
611
493
|
continue;
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const
|
|
615
|
-
/**
|
|
494
|
+
const /**
|
|
616
495
|
* @description
|
|
617
496
|
* 📝 **campaign ids** of respective **zone id**
|
|
618
497
|
*/
|
|
619
|
-
campaignIds
|
|
620
|
-
= (mapZoneIdToCampaignId.get(zoneId) ?? []),
|
|
498
|
+
campaignIds = mapZoneIdToCampaignId.get(zoneId) ?? [],
|
|
621
499
|
/**
|
|
622
500
|
* @description
|
|
623
501
|
* 📝 `List` of creative data point(s)
|
|
624
502
|
*/
|
|
625
|
-
creativeAdData
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
* @description
|
|
637
|
-
* 📝 **creative ids**
|
|
638
|
-
*/
|
|
639
|
-
creativeIds = mapCampaignIdToCreativeId.get(x)!
|
|
640
|
-
;
|
|
641
|
-
|
|
642
|
-
for (const creativeId of creativeIds)
|
|
643
|
-
{
|
|
644
|
-
if (mapCreative.has(creativeId))
|
|
645
|
-
return mapCreative.get(creativeId);
|
|
646
|
-
;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
503
|
+
creativeAdData = removeNull(
|
|
504
|
+
campaignIds.map((x) => {
|
|
505
|
+
if (mapCampaignIdToCreativeId.has(x)) {
|
|
506
|
+
const /**
|
|
507
|
+
* @description
|
|
508
|
+
* 📝 **creative ids**
|
|
509
|
+
*/
|
|
510
|
+
creativeIds = mapCampaignIdToCreativeId.get(x)!;
|
|
511
|
+
for (const creativeId of creativeIds) {
|
|
512
|
+
if (mapCreative.has(creativeId))
|
|
513
|
+
return mapCreative.get(creativeId);
|
|
649
514
|
}
|
|
650
|
-
|
|
651
|
-
)
|
|
652
|
-
|
|
653
|
-
|
|
515
|
+
}
|
|
516
|
+
}),
|
|
517
|
+
) as AdsCreativeMain[];
|
|
654
518
|
// [🐞]
|
|
655
|
-
logger
|
|
656
|
-
|
|
657
|
-
[
|
|
658
|
-
|
|
659
|
-
`🔹 [var] ➤ creativeAdData ${creativeAdData.length}`
|
|
660
|
-
]
|
|
661
|
-
);
|
|
519
|
+
logger([
|
|
520
|
+
"🚏 checkpoint ➤ injectBetarenaAds(..) // CHECKPOINT-1",
|
|
521
|
+
`🔹 [var] ➤ creativeAdData ${creativeAdData.length}`,
|
|
522
|
+
]);
|
|
662
523
|
|
|
663
524
|
// ╭─────
|
|
664
525
|
// │ NOTE:
|
|
665
526
|
// │ |: Loop over creative data and inject adverts
|
|
666
527
|
// ╰─────
|
|
667
|
-
for (const adData of creativeAdData)
|
|
668
|
-
{
|
|
528
|
+
for (const adData of creativeAdData) {
|
|
669
529
|
if (zoneId != 1) continue;
|
|
670
530
|
|
|
671
|
-
listAdWidgetElements.push
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
adData,
|
|
680
|
-
isLoggedIn
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
)
|
|
531
|
+
listAdWidgetElements.push(
|
|
532
|
+
new WidgetAdvertSlide({
|
|
533
|
+
target: document.body,
|
|
534
|
+
props: {
|
|
535
|
+
adData,
|
|
536
|
+
isLoggedIn,
|
|
537
|
+
},
|
|
538
|
+
}),
|
|
684
539
|
);
|
|
685
540
|
}
|
|
686
541
|
}
|
|
@@ -689,82 +544,59 @@
|
|
|
689
544
|
// │ NOTE:
|
|
690
545
|
// │ |: loop over creative data AND inject adverts, based on 'tagIds'
|
|
691
546
|
// ╰─────
|
|
692
|
-
for (const [zoneId, tagIds] of mapZoneToTagIds)
|
|
693
|
-
|
|
694
|
-
|
|
547
|
+
for (const [zoneId, tagIds] of mapZoneToTagIds) {
|
|
548
|
+
if (
|
|
549
|
+
tagIds.length > 0 &&
|
|
550
|
+
authorArticleTagIds.filter((x) => {
|
|
551
|
+
return tagIds.includes(x);
|
|
552
|
+
}).length == 0
|
|
553
|
+
)
|
|
695
554
|
continue;
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const
|
|
699
|
-
/**
|
|
555
|
+
const /**
|
|
700
556
|
* @description
|
|
701
557
|
* 📝 **campaign ids** of respective **zone id**
|
|
702
558
|
*/
|
|
703
|
-
campaignIds
|
|
704
|
-
= (mapZoneIdToCampaignId.get(zoneId) ?? []),
|
|
559
|
+
campaignIds = mapZoneIdToCampaignId.get(zoneId) ?? [],
|
|
705
560
|
/**
|
|
706
561
|
* @description
|
|
707
562
|
* 📝 `List` of creative data point(s)
|
|
708
563
|
*/
|
|
709
|
-
creativeAdData
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
* @description
|
|
721
|
-
* 📝 **creative ids**
|
|
722
|
-
*/
|
|
723
|
-
creativeIds = mapCampaignIdToCreativeId.get(x)!
|
|
724
|
-
;
|
|
725
|
-
|
|
726
|
-
for (const creativeId of creativeIds)
|
|
727
|
-
{
|
|
728
|
-
if (mapCreative.has(creativeId))
|
|
729
|
-
return mapCreative.get(creativeId);
|
|
730
|
-
;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
564
|
+
creativeAdData = removeNull(
|
|
565
|
+
campaignIds.map((x) => {
|
|
566
|
+
if (mapCampaignIdToCreativeId.has(x)) {
|
|
567
|
+
const /**
|
|
568
|
+
* @description
|
|
569
|
+
* 📝 **creative ids**
|
|
570
|
+
*/
|
|
571
|
+
creativeIds = mapCampaignIdToCreativeId.get(x)!;
|
|
572
|
+
for (const creativeId of creativeIds) {
|
|
573
|
+
if (mapCreative.has(creativeId))
|
|
574
|
+
return mapCreative.get(creativeId);
|
|
733
575
|
}
|
|
734
|
-
|
|
735
|
-
)
|
|
736
|
-
|
|
737
|
-
|
|
576
|
+
}
|
|
577
|
+
}),
|
|
578
|
+
) as AdsCreativeMain[];
|
|
738
579
|
// [🐞]
|
|
739
|
-
logger
|
|
740
|
-
|
|
741
|
-
[
|
|
742
|
-
|
|
743
|
-
`🔹 [var] ➤ creativeAdData ${creativeAdData.length}`
|
|
744
|
-
]
|
|
745
|
-
);
|
|
580
|
+
logger([
|
|
581
|
+
"🚏 checkpoint ➤ injectBetarenaAds(..) // CHECKPOINT-2",
|
|
582
|
+
`🔹 [var] ➤ creativeAdData ${creativeAdData.length}`,
|
|
583
|
+
]);
|
|
746
584
|
|
|
747
585
|
// ╭─────
|
|
748
586
|
// │ NOTE:
|
|
749
587
|
// │ |: Loop over creative data and inject adverts
|
|
750
588
|
// ╰─────
|
|
751
|
-
for (const adData of creativeAdData)
|
|
752
|
-
{
|
|
589
|
+
for (const adData of creativeAdData) {
|
|
753
590
|
if (zoneId != 1) continue;
|
|
754
591
|
|
|
755
|
-
listAdWidgetElements.push
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
adData,
|
|
764
|
-
isLoggedIn
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
)
|
|
592
|
+
listAdWidgetElements.push(
|
|
593
|
+
new WidgetAdvertSlide({
|
|
594
|
+
target: document.body,
|
|
595
|
+
props: {
|
|
596
|
+
adData,
|
|
597
|
+
isLoggedIn,
|
|
598
|
+
},
|
|
599
|
+
}),
|
|
768
600
|
);
|
|
769
601
|
}
|
|
770
602
|
}
|
|
@@ -778,16 +610,12 @@
|
|
|
778
610
|
// │ |: Inject STANDARD SLIDER adverts in 'document.body'
|
|
779
611
|
// │ |: Guard with `includesGlobalZone` to avoid body injections on scoped refreshes.
|
|
780
612
|
// ╰─────
|
|
781
|
-
else if (includesGlobalZone && isArticlePage)
|
|
782
|
-
{
|
|
613
|
+
else if (includesGlobalZone && isArticlePage) {
|
|
783
614
|
// [🐞]
|
|
784
|
-
logger
|
|
785
|
-
|
|
786
|
-
[
|
|
787
|
-
|
|
788
|
-
`🔹 [var] ➤ mapCreative.length ${mapCreative.size}`
|
|
789
|
-
]
|
|
790
|
-
);
|
|
615
|
+
logger([
|
|
616
|
+
"🚏 checkpoint ➤ injectBetarenaAds(..) // CHECKPOINT-3",
|
|
617
|
+
`🔹 [var] ➤ mapCreative.length ${mapCreative.size}`,
|
|
618
|
+
]);
|
|
791
619
|
|
|
792
620
|
// ╭─────
|
|
793
621
|
// │ NOTE:
|
|
@@ -795,35 +623,24 @@
|
|
|
795
623
|
// │ |: Build a Set of creative IDs that belong to zone 1 so we only
|
|
796
624
|
// │ |: inject zone-1-specific creatives rather than all slider-type creatives.
|
|
797
625
|
// ╰─────
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
.flatMap(campaignId => mapCampaignIdToCreativeId.get(campaignId) ?? [])
|
|
806
|
-
)
|
|
807
|
-
;
|
|
808
|
-
|
|
809
|
-
for (const [creativeId, adData] of mapCreative)
|
|
810
|
-
{
|
|
626
|
+
const zone1CampaignIds = mapZoneIdToCampaignId.get(1) ?? [],
|
|
627
|
+
zone1CreativeIds = new Set(
|
|
628
|
+
zone1CampaignIds.flatMap(
|
|
629
|
+
(campaignId) => mapCampaignIdToCreativeId.get(campaignId) ?? [],
|
|
630
|
+
),
|
|
631
|
+
);
|
|
632
|
+
for (const [creativeId, adData] of mapCreative) {
|
|
811
633
|
if (adData.type != 1) continue;
|
|
812
634
|
if (!zone1CreativeIds.has(creativeId)) continue;
|
|
813
635
|
|
|
814
|
-
listAdWidgetElements.push
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
adData,
|
|
823
|
-
isLoggedIn
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
)
|
|
636
|
+
listAdWidgetElements.push(
|
|
637
|
+
new WidgetAdvertSlide({
|
|
638
|
+
target: document.body,
|
|
639
|
+
props: {
|
|
640
|
+
adData,
|
|
641
|
+
isLoggedIn,
|
|
642
|
+
},
|
|
643
|
+
}),
|
|
827
644
|
);
|
|
828
645
|
}
|
|
829
646
|
}
|
|
@@ -842,28 +659,18 @@
|
|
|
842
659
|
* await the same in-flight promise.
|
|
843
660
|
* @returns { Promise < void > }
|
|
844
661
|
*/
|
|
845
|
-
async function ensureReady
|
|
846
|
-
(
|
|
847
|
-
): Promise < void >
|
|
848
|
-
{
|
|
662
|
+
async function ensureReady(): Promise<void> {
|
|
849
663
|
if (readinessPromise) return readinessPromise;
|
|
850
664
|
|
|
851
|
-
readinessPromise =
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
geoLocation = await getUserLocation();
|
|
859
|
-
}
|
|
860
|
-
catch (e)
|
|
861
|
-
{
|
|
862
|
-
readinessPromise = null;
|
|
863
|
-
throw e;
|
|
864
|
-
}
|
|
665
|
+
readinessPromise = (async () => {
|
|
666
|
+
try {
|
|
667
|
+
deviceType = detectDeviceWithUA() as IDeviceType;
|
|
668
|
+
geoLocation = await getUserLocation();
|
|
669
|
+
} catch (e) {
|
|
670
|
+
readinessPromise = null;
|
|
671
|
+
throw e;
|
|
865
672
|
}
|
|
866
|
-
)();
|
|
673
|
+
})();
|
|
867
674
|
|
|
868
675
|
return readinessPromise;
|
|
869
676
|
}
|
|
@@ -882,39 +689,26 @@
|
|
|
882
689
|
* 💠 Optional scope: restrict to specific zone IDs and / or a DOM subtree.
|
|
883
690
|
* @returns { Promise < void > }
|
|
884
691
|
*/
|
|
885
|
-
async function refreshAds
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
zoneIds?: number[];
|
|
890
|
-
rootElement?: HTMLElement;
|
|
891
|
-
}
|
|
892
|
-
): Promise < void >
|
|
893
|
-
{
|
|
692
|
+
async function refreshAds(opts?: {
|
|
693
|
+
zoneIds?: number[];
|
|
694
|
+
rootElement?: HTMLElement;
|
|
695
|
+
}): Promise<void> {
|
|
894
696
|
if (isDestroyed) return;
|
|
895
697
|
|
|
896
|
-
const
|
|
897
|
-
mySerial = ++refreshSerial
|
|
898
|
-
;
|
|
899
|
-
|
|
698
|
+
const mySerial = ++refreshSerial;
|
|
900
699
|
await ensureReady();
|
|
901
700
|
|
|
902
701
|
if (isDestroyed || mySerial !== refreshSerial) return;
|
|
903
702
|
|
|
904
703
|
generateElementMap(opts?.rootElement);
|
|
905
704
|
|
|
906
|
-
let
|
|
907
|
-
/**
|
|
705
|
+
let /**
|
|
908
706
|
* @description
|
|
909
707
|
* 📝 Zone IDs discovered in the current DOM scan (or filtered subset).
|
|
910
708
|
*/
|
|
911
|
-
targetZoneIds = [...mapBetarenaAdvertStandardElement.keys()]
|
|
912
|
-
;
|
|
913
|
-
|
|
709
|
+
targetZoneIds = [...mapBetarenaAdvertStandardElement.keys()];
|
|
914
710
|
if (opts?.zoneIds && opts.zoneIds.length > 0)
|
|
915
|
-
targetZoneIds = targetZoneIds.filter(id => opts.zoneIds!.includes(id));
|
|
916
|
-
;
|
|
917
|
-
|
|
711
|
+
targetZoneIds = targetZoneIds.filter((id) => opts.zoneIds!.includes(id));
|
|
918
712
|
// ╭─────
|
|
919
713
|
// │ NOTE:
|
|
920
714
|
// │ |: Zone 1 (global slider/popup) has no DOM element and will never appear
|
|
@@ -924,16 +718,10 @@
|
|
|
924
718
|
// │ |: article pages; creative-level targeting handles device/country/author filtering.
|
|
925
719
|
// │ |: Respect scoped refreshes: only add zone 1 if the caller's scope includes it.
|
|
926
720
|
// ╰─────
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
;
|
|
932
|
-
|
|
933
|
-
if (shouldRequestZone1 && !targetZoneIds.includes(1))
|
|
934
|
-
targetZoneIds.push(1);
|
|
935
|
-
;
|
|
936
|
-
|
|
721
|
+
const shouldRequestZone1 =
|
|
722
|
+
isArticlePage &&
|
|
723
|
+
(!opts?.zoneIds || opts.zoneIds.length === 0 || opts.zoneIds.includes(1));
|
|
724
|
+
if (shouldRequestZone1 && !targetZoneIds.includes(1)) targetZoneIds.push(1);
|
|
937
725
|
// ╭─────
|
|
938
726
|
// │ NOTE:
|
|
939
727
|
// │ |: Only tear down previously injected global/body components when the
|
|
@@ -942,22 +730,22 @@
|
|
|
942
730
|
// │ |: Scoped refreshes that exclude zone 1 leave existing body-mounted
|
|
943
731
|
// │ |: widgets untouched to avoid permanently removing them.
|
|
944
732
|
// ╰─────
|
|
945
|
-
if (
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
733
|
+
if (
|
|
734
|
+
!opts?.zoneIds ||
|
|
735
|
+
opts.zoneIds.length === 0 ||
|
|
736
|
+
opts.zoneIds.includes(1)
|
|
737
|
+
) {
|
|
738
|
+
for (const item of listAdWidgetElements) item.$destroy();
|
|
950
739
|
listAdWidgetElements.length = 0;
|
|
951
740
|
}
|
|
952
741
|
|
|
953
|
-
await injectBetarenaAds
|
|
954
|
-
(
|
|
742
|
+
await injectBetarenaAds(
|
|
955
743
|
{
|
|
956
744
|
deviceType,
|
|
957
|
-
isoCountryCode: geoLocation?.country_code ??
|
|
745
|
+
isoCountryCode: geoLocation?.country_code ?? "EN",
|
|
958
746
|
authorId: authorId ?? undefined,
|
|
959
747
|
tagIds: authorArticleTagIds,
|
|
960
|
-
zoneIds: targetZoneIds
|
|
748
|
+
zoneIds: targetZoneIds,
|
|
961
749
|
},
|
|
962
750
|
// ╭─────
|
|
963
751
|
// │ NOTE:
|
|
@@ -966,7 +754,7 @@
|
|
|
966
754
|
// │ |: won't include 1, but a full/zone-1 refresh should still inject global placements.
|
|
967
755
|
// ╰─────
|
|
968
756
|
!opts?.zoneIds || opts.zoneIds.length === 0 || opts.zoneIds.includes(1),
|
|
969
|
-
mySerial
|
|
757
|
+
mySerial,
|
|
970
758
|
);
|
|
971
759
|
|
|
972
760
|
return;
|
|
@@ -981,17 +769,9 @@
|
|
|
981
769
|
* 📝 Logic bundle for advert initialization
|
|
982
770
|
* @returns { Promise < void > }
|
|
983
771
|
*/
|
|
984
|
-
async function initialize
|
|
985
|
-
(
|
|
986
|
-
): Promise < void >
|
|
987
|
-
{
|
|
772
|
+
async function initialize(): Promise<void> {
|
|
988
773
|
// [🐞]
|
|
989
|
-
logger
|
|
990
|
-
(
|
|
991
|
-
[
|
|
992
|
-
'🚏 checkpoint ➤ initialize(..) // START'
|
|
993
|
-
]
|
|
994
|
-
);
|
|
774
|
+
logger(["🚏 checkpoint ➤ initialize(..) // START"]);
|
|
995
775
|
|
|
996
776
|
await refreshAds();
|
|
997
777
|
|
|
@@ -1009,117 +789,71 @@
|
|
|
1009
789
|
// │ as soon as 'this' .svelte file is ran. │
|
|
1010
790
|
// ╰────────────────────────────────────────────────────────────────────────╯
|
|
1011
791
|
|
|
1012
|
-
onMount
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
{
|
|
1038
|
-
logger
|
|
1039
|
-
(
|
|
1040
|
-
[
|
|
1041
|
-
'🚨 checkpoint ➤ initialize(..) // UNHANDLED ERROR',
|
|
1042
|
-
`🔹 [var] ➤ error ${error}`
|
|
1043
|
-
]
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
);
|
|
1047
|
-
},
|
|
1048
|
-
1000
|
|
1049
|
-
);
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
1052
|
-
);
|
|
1053
|
-
|
|
1054
|
-
onDestroy
|
|
1055
|
-
(
|
|
1056
|
-
() =>
|
|
1057
|
-
{
|
|
1058
|
-
// [🐞]
|
|
1059
|
-
logger
|
|
1060
|
-
(
|
|
1061
|
-
[
|
|
1062
|
-
'Betarena Ad-Engine ⏰ onMount ⏰ cleanup',
|
|
1063
|
-
`🔹 [var] ➤ listAdWidgetElements.length ${listAdWidgetElements.length}`
|
|
1064
|
-
],
|
|
1065
|
-
);
|
|
1066
|
-
|
|
1067
|
-
isDestroyed = true;
|
|
1068
|
-
|
|
1069
|
-
if (initTimeoutId !== null)
|
|
1070
|
-
clearTimeout(initTimeoutId);
|
|
1071
|
-
;
|
|
792
|
+
onMount(async () => {
|
|
793
|
+
betarenaAdEngineStore.useLocalStorage();
|
|
794
|
+
// ╭─────
|
|
795
|
+
// │ NOTE:
|
|
796
|
+
// │ |: Expose public API immediately so host apps can call refreshAds()
|
|
797
|
+
// │ |: without waiting for the delayed initialize().
|
|
798
|
+
// │ |: refreshAds() self-initializes prerequisites via ensureReady() if needed.
|
|
799
|
+
// │ |: Save any existing value so it can be restored when this instance is destroyed.
|
|
800
|
+
// ╰─────
|
|
801
|
+
prevWindowApi = (window as any).betarenaAdEngine;
|
|
802
|
+
(window as any).betarenaAdEngine = { refreshAds };
|
|
803
|
+
// ╭─────
|
|
804
|
+
// │ NOTE:
|
|
805
|
+
// │ |: Delay initialization to ensure all elements are loaded on page
|
|
806
|
+
// ╰─────
|
|
807
|
+
initTimeoutId = setTimeout(() => {
|
|
808
|
+
initialize().catch((error) => {
|
|
809
|
+
logger([
|
|
810
|
+
"🚨 checkpoint ➤ initialize(..) // UNHANDLED ERROR",
|
|
811
|
+
`🔹 [var] ➤ error ${error}`,
|
|
812
|
+
]);
|
|
813
|
+
});
|
|
814
|
+
}, 1000);
|
|
815
|
+
return;
|
|
816
|
+
});
|
|
1072
817
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
{
|
|
1080
|
-
if (prevWindowApi !== undefined)
|
|
1081
|
-
(window as any).betarenaAdEngine = prevWindowApi;
|
|
1082
|
-
else
|
|
1083
|
-
delete (window as any).betarenaAdEngine;
|
|
1084
|
-
}
|
|
818
|
+
onDestroy(() => {
|
|
819
|
+
// [🐞]
|
|
820
|
+
logger([
|
|
821
|
+
"Betarena Ad-Engine ⏰ onMount ⏰ cleanup",
|
|
822
|
+
`🔹 [var] ➤ listAdWidgetElements.length ${listAdWidgetElements.length}`,
|
|
823
|
+
]);
|
|
1085
824
|
|
|
1086
|
-
|
|
1087
|
-
// │ NOTE:
|
|
1088
|
-
// │ |: Destroy all dynamically created advert components
|
|
1089
|
-
// ╰─────
|
|
1090
|
-
for (const item of listAdWidgetElements)
|
|
1091
|
-
item.$destroy();
|
|
1092
|
-
;
|
|
825
|
+
isDestroyed = true;
|
|
1093
826
|
|
|
1094
|
-
|
|
827
|
+
if (initTimeoutId !== null) clearTimeout(initTimeoutId);
|
|
828
|
+
// ╭─────
|
|
829
|
+
// │ NOTE:
|
|
830
|
+
// │ |: Only remove/restore the global if this instance still owns it.
|
|
831
|
+
// │ |: A later-mounted instance or host code may have overwritten it.
|
|
832
|
+
// ╰─────
|
|
833
|
+
if ((window as any).betarenaAdEngine?.refreshAds === refreshAds) {
|
|
834
|
+
if (prevWindowApi !== undefined)
|
|
835
|
+
(window as any).betarenaAdEngine = prevWindowApi;
|
|
836
|
+
else delete (window as any).betarenaAdEngine;
|
|
1095
837
|
}
|
|
1096
|
-
);
|
|
1097
838
|
|
|
1098
|
-
|
|
839
|
+
// ╭─────
|
|
840
|
+
// │ NOTE:
|
|
841
|
+
// │ |: Destroy all dynamically created advert components
|
|
842
|
+
// ╰─────
|
|
843
|
+
for (const item of listAdWidgetElements) item.$destroy();
|
|
844
|
+
return;
|
|
845
|
+
});
|
|
1099
846
|
|
|
847
|
+
// #endregion ➤ 🔄 LIFECYCLE [SVELTE]
|
|
1100
848
|
</script>
|
|
1101
849
|
|
|
1102
850
|
<svelte:window
|
|
1103
|
-
on:resize=
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
detectDeviceWithUA();
|
|
1108
|
-
return;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
851
|
+
on:resize={() => {
|
|
852
|
+
detectDeviceWithUA();
|
|
853
|
+
return;
|
|
854
|
+
}}
|
|
1111
855
|
/>
|
|
1112
856
|
|
|
1113
|
-
<svelte:head>
|
|
1114
|
-
|
|
1115
|
-
{#if isStandalone}
|
|
1116
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
1117
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
|
|
1118
|
-
<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">
|
|
1119
|
-
{/if}
|
|
1120
|
-
|
|
1121
|
-
</svelte:head>
|
|
1122
|
-
|
|
1123
857
|
<!--
|
|
1124
858
|
╭──────────────────────────────────────────────────────────────────────────────────╮
|
|
1125
859
|
│ 💠 Svelte Component HTML │
|
|
@@ -1170,7 +904,7 @@
|
|
|
1170
904
|
>
|
|
1171
905
|
</div> -->
|
|
1172
906
|
|
|
1173
|
-
<hr
|
|
907
|
+
<hr />
|
|
1174
908
|
|
|
1175
909
|
<!-- <div
|
|
1176
910
|
data-betarena-zone-id=2,3
|
|
@@ -1182,10 +916,7 @@
|
|
|
1182
916
|
{/each}
|
|
1183
917
|
</div> -->
|
|
1184
918
|
|
|
1185
|
-
<div
|
|
1186
|
-
data-betarena-zone-id=4
|
|
1187
|
-
>
|
|
1188
|
-
</div>
|
|
919
|
+
<div data-betarena-zone-id="4"></div>
|
|
1189
920
|
{/if}
|
|
1190
921
|
|
|
1191
922
|
<!--
|
|
@@ -1198,20 +929,3 @@
|
|
|
1198
929
|
╰──────────────────────────────────────────────────────────────────────────────────╯
|
|
1199
930
|
-->
|
|
1200
931
|
|
|
1201
|
-
<style lang="scss">
|
|
1202
|
-
|
|
1203
|
-
:global
|
|
1204
|
-
{
|
|
1205
|
-
// ╭─────
|
|
1206
|
-
// │ NOTE:
|
|
1207
|
-
// │ |: Use purged styles for production build
|
|
1208
|
-
// ╰─────
|
|
1209
|
-
@import '../style/app.purged.min.scss';
|
|
1210
|
-
// ╭─────
|
|
1211
|
-
// │ NOTE:
|
|
1212
|
-
// │ |: Import main styles (uncomment for development)
|
|
1213
|
-
// ╰─────
|
|
1214
|
-
// @import '../style/app.scss';
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
</style>
|