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