@adhese/sdk 0.3.0 → 0.5.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/cjs/index.js +627 -530
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.js +629 -532
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +71 -150
- package/package.json +4 -3
package/dist/cjs/index.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
-
var __publicField = (obj, key, value) => {
|
|
5
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
-
return value;
|
|
7
|
-
};
|
|
8
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
3
|
const sdkDevtools = require("@adhese/sdk-devtools");
|
|
4
|
+
const runtimeCore = require("@vue/runtime-core");
|
|
10
5
|
const lodashEs = require("lodash-es");
|
|
11
6
|
const zod = require("zod");
|
|
12
7
|
async function waitForDomLoad() {
|
|
@@ -68,91 +63,132 @@ function createEvent() {
|
|
|
68
63
|
removeListener
|
|
69
64
|
};
|
|
70
65
|
}
|
|
66
|
+
function renderIframe(ad, element) {
|
|
67
|
+
const iframe = document.createElement("iframe");
|
|
68
|
+
iframe.srcdoc = `
|
|
69
|
+
<!DOCTYPE html>
|
|
70
|
+
<html>
|
|
71
|
+
<head>
|
|
72
|
+
<style>
|
|
73
|
+
body {
|
|
74
|
+
margin: 0;
|
|
75
|
+
padding: 0;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
79
|
+
</head>
|
|
80
|
+
<body>
|
|
81
|
+
${String(ad.tag)}
|
|
82
|
+
</body>
|
|
83
|
+
`.replaceAll(/\s+/g, " ").trim();
|
|
84
|
+
iframe.style.border = "none";
|
|
85
|
+
iframe.style.width = ad.width ?? "auto";
|
|
86
|
+
iframe.style.height = ad.height ?? "auto";
|
|
87
|
+
element.replaceChildren(iframe);
|
|
88
|
+
}
|
|
89
|
+
function renderInline(ad, element) {
|
|
90
|
+
element.style.width = ad.width ?? "auto";
|
|
91
|
+
element.style.height = ad.height ?? "auto";
|
|
92
|
+
element.innerHTML = String(ad.tag);
|
|
93
|
+
}
|
|
94
|
+
function generateName(location, format, slot) {
|
|
95
|
+
return `${location}${slot ? `${slot}` : ""}-${format}`;
|
|
96
|
+
}
|
|
71
97
|
async function findDomSlots(context) {
|
|
72
98
|
await waitForDomLoad();
|
|
73
|
-
return
|
|
99
|
+
return Array.from(document.querySelectorAll(".adunit")).filter((element) => {
|
|
100
|
+
var _a;
|
|
101
|
+
if (!element.dataset.format)
|
|
102
|
+
return false;
|
|
103
|
+
const name = generateName(
|
|
104
|
+
context.location,
|
|
105
|
+
element.dataset.format,
|
|
106
|
+
element.dataset.slot
|
|
107
|
+
);
|
|
108
|
+
return !((_a = context.getAll) == null ? void 0 : _a.call(context).some((activeSlot) => activeSlot.name.value === name));
|
|
109
|
+
}).map((element) => createSlot({
|
|
74
110
|
format: element.dataset.format,
|
|
75
111
|
containingElement: element,
|
|
76
112
|
slot: element.dataset.slot,
|
|
77
113
|
context
|
|
78
|
-
}))
|
|
114
|
+
})).filter((slot) => {
|
|
79
115
|
var _a;
|
|
80
|
-
return !((_a = context.getAll) == null ? void 0 : _a.call(context).some((activeSlot) => activeSlot.
|
|
116
|
+
return !((_a = context.getAll) == null ? void 0 : _a.call(context).some((activeSlot) => activeSlot.name.value === slot.name.value));
|
|
81
117
|
});
|
|
82
118
|
}
|
|
83
|
-
|
|
119
|
+
function createSlotManager({
|
|
84
120
|
initialSlots = [],
|
|
85
121
|
context
|
|
86
122
|
}) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return Array.from(slots).map(([, slot]) => slot);
|
|
94
|
-
}
|
|
95
|
-
async function add(options) {
|
|
96
|
-
var _a, _b;
|
|
97
|
-
const slot = await createSlot({
|
|
98
|
-
...options,
|
|
99
|
-
onDispose,
|
|
100
|
-
onNameChange,
|
|
101
|
-
context
|
|
123
|
+
const scope = runtimeCore.effectScope();
|
|
124
|
+
return scope.run(() => {
|
|
125
|
+
const slots = runtimeCore.shallowReactive(/* @__PURE__ */ new Map());
|
|
126
|
+
runtimeCore.watchEffect(() => {
|
|
127
|
+
var _a;
|
|
128
|
+
(_a = context.events) == null ? void 0 : _a.changeSlots.dispatch(Array.from(slots.values()));
|
|
102
129
|
});
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
function getAll() {
|
|
131
|
+
return Array.from(slots).map(([, slot]) => slot);
|
|
132
|
+
}
|
|
133
|
+
function add(options) {
|
|
134
|
+
var _a;
|
|
135
|
+
const slot = createSlot({
|
|
136
|
+
...options,
|
|
137
|
+
onDispose,
|
|
138
|
+
context
|
|
139
|
+
});
|
|
140
|
+
function onDispose() {
|
|
141
|
+
var _a2;
|
|
142
|
+
slots.delete(slot.name.value);
|
|
143
|
+
logger.debug("Slot removed", {
|
|
144
|
+
slot,
|
|
145
|
+
slots: Array.from(slots)
|
|
146
|
+
});
|
|
147
|
+
(_a2 = context.events) == null ? void 0 : _a2.removeSlot.dispatch(slot);
|
|
148
|
+
}
|
|
149
|
+
slots.set(slot.name.value, slot);
|
|
150
|
+
runtimeCore.watch(slot.name, (newName, previousName) => {
|
|
151
|
+
slots.set(newName, slot);
|
|
152
|
+
slots.delete(previousName);
|
|
153
|
+
});
|
|
154
|
+
logger.debug("Slot added", {
|
|
107
155
|
slot,
|
|
108
|
-
slots: Array.from(slots)
|
|
156
|
+
slots: Array.from(slots.values())
|
|
109
157
|
});
|
|
110
|
-
(
|
|
111
|
-
|
|
158
|
+
(_a = context.events) == null ? void 0 : _a.addSlot.dispatch(slot);
|
|
159
|
+
return slot;
|
|
112
160
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
161
|
+
async function findDomSlots$1() {
|
|
162
|
+
const domSlots = await findDomSlots(
|
|
163
|
+
context
|
|
164
|
+
);
|
|
165
|
+
for (const slot of domSlots)
|
|
166
|
+
slots.set(slot.name.value, slot);
|
|
167
|
+
return domSlots;
|
|
119
168
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
slots: Array.from(slots.values())
|
|
123
|
-
});
|
|
124
|
-
(_a = context.events) == null ? void 0 : _a.addSlot.dispatch(slot);
|
|
125
|
-
(_b = context.events) == null ? void 0 : _b.changeSlots.dispatch(Array.from(slots.values()));
|
|
126
|
-
return slot;
|
|
127
|
-
}
|
|
128
|
-
async function findDomSlots$1() {
|
|
129
|
-
var _a;
|
|
130
|
-
const domSlots = await findDomSlots(
|
|
131
|
-
context
|
|
132
|
-
);
|
|
133
|
-
for (const slot of domSlots) {
|
|
134
|
-
slots.set(slot.getName(), slot);
|
|
135
|
-
(_a = context.events) == null ? void 0 : _a.changeSlots.dispatch(Array.from(slots.values()));
|
|
169
|
+
function get(name) {
|
|
170
|
+
return slots.get(name);
|
|
136
171
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
172
|
+
function dispose() {
|
|
173
|
+
for (const slot of slots.values())
|
|
174
|
+
slot.dispose();
|
|
175
|
+
slots.clear();
|
|
176
|
+
scope.stop();
|
|
177
|
+
}
|
|
178
|
+
for (const options of initialSlots) {
|
|
179
|
+
add({
|
|
180
|
+
...options,
|
|
181
|
+
lazyLoading: false
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
getAll,
|
|
186
|
+
add,
|
|
187
|
+
findDomSlots: findDomSlots$1,
|
|
188
|
+
get,
|
|
189
|
+
dispose
|
|
190
|
+
};
|
|
191
|
+
});
|
|
156
192
|
}
|
|
157
193
|
function onTcfConsentChange(callback) {
|
|
158
194
|
var _a;
|
|
@@ -272,7 +308,7 @@ const logger = createLogger({
|
|
|
272
308
|
scope: "Adhese SDK"
|
|
273
309
|
});
|
|
274
310
|
function createParameters(options, queryDetector) {
|
|
275
|
-
const parameters = new
|
|
311
|
+
const parameters = /* @__PURE__ */ new Map();
|
|
276
312
|
if (options.logReferrer)
|
|
277
313
|
parameters.set("re", btoa(document.referrer));
|
|
278
314
|
if (options.logUrl)
|
|
@@ -299,230 +335,231 @@ function setupLogging(mergedOptions) {
|
|
|
299
335
|
function isPreviewMode() {
|
|
300
336
|
return window.location.search.includes("adhesePreviewCreativeId");
|
|
301
337
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
338
|
+
function createHook({
|
|
339
|
+
onRun,
|
|
340
|
+
onAdd
|
|
341
|
+
}) {
|
|
342
|
+
const callbacks = /* @__PURE__ */ new Set();
|
|
343
|
+
function run() {
|
|
344
|
+
for (const callback of callbacks)
|
|
345
|
+
callback();
|
|
346
|
+
onRun == null ? void 0 : onRun();
|
|
306
347
|
}
|
|
307
|
-
|
|
308
|
-
|
|
348
|
+
function add(callback) {
|
|
349
|
+
callbacks.add(callback);
|
|
350
|
+
onAdd == null ? void 0 : onAdd();
|
|
309
351
|
}
|
|
310
|
-
|
|
311
|
-
|
|
352
|
+
return [run, add];
|
|
353
|
+
}
|
|
354
|
+
let resolveOnInitPromise = () => {
|
|
355
|
+
};
|
|
356
|
+
let isInit = false;
|
|
357
|
+
new Promise((resolve) => {
|
|
358
|
+
resolveOnInitPromise = resolve;
|
|
359
|
+
});
|
|
360
|
+
const [runOnInit, onInit] = createHook({
|
|
361
|
+
onRun() {
|
|
362
|
+
isInit = true;
|
|
363
|
+
resolveOnInitPromise();
|
|
364
|
+
logger.debug("Initialization completed");
|
|
365
|
+
},
|
|
366
|
+
onAdd() {
|
|
367
|
+
if (isInit)
|
|
368
|
+
runOnInit();
|
|
312
369
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
370
|
+
});
|
|
371
|
+
function createAdhese(options) {
|
|
372
|
+
const scope = runtimeCore.effectScope();
|
|
373
|
+
return scope.run(() => {
|
|
374
|
+
const mergedOptions = {
|
|
375
|
+
host: `https://ads-${options.account}.adhese.com`,
|
|
376
|
+
poolHost: `https://pool-${options.account}.adhese.com`,
|
|
377
|
+
location: "homepage",
|
|
378
|
+
requestType: "POST",
|
|
379
|
+
debug: false,
|
|
380
|
+
initialSlots: [],
|
|
381
|
+
findDomSlotsOnLoad: false,
|
|
382
|
+
consent: false,
|
|
383
|
+
logReferrer: true,
|
|
384
|
+
logUrl: true,
|
|
385
|
+
eagerRendering: false,
|
|
386
|
+
viewabilityTracking: true,
|
|
387
|
+
...options
|
|
388
|
+
};
|
|
389
|
+
setupLogging(mergedOptions);
|
|
390
|
+
const context = runtimeCore.reactive({
|
|
391
|
+
location: mergedOptions.location,
|
|
392
|
+
consent: mergedOptions.consent,
|
|
393
|
+
debug: mergedOptions.debug,
|
|
394
|
+
getAll,
|
|
395
|
+
get,
|
|
396
|
+
options: mergedOptions,
|
|
397
|
+
logger
|
|
317
398
|
});
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
399
|
+
context.events = createEventManager();
|
|
400
|
+
function getLocation() {
|
|
401
|
+
return context.location;
|
|
402
|
+
}
|
|
403
|
+
function setLocation(newLocation) {
|
|
404
|
+
var _a;
|
|
405
|
+
context.location = newLocation;
|
|
406
|
+
(_a = context.events) == null ? void 0 : _a.locationChange.dispatch(newLocation);
|
|
407
|
+
}
|
|
408
|
+
const queryDetector = createQueryDetector({
|
|
409
|
+
onChange: onQueryChange,
|
|
410
|
+
queries: mergedOptions.queries
|
|
324
411
|
});
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
412
|
+
context.parameters = createParameters(mergedOptions, queryDetector);
|
|
413
|
+
runtimeCore.watch(
|
|
414
|
+
context.parameters,
|
|
415
|
+
onParametersChange,
|
|
416
|
+
{
|
|
417
|
+
deep: true,
|
|
418
|
+
immediate: true
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
function onParametersChange() {
|
|
422
|
+
var _a;
|
|
423
|
+
if (context.parameters)
|
|
424
|
+
(_a = context.events) == null ? void 0 : _a.parametersChange.dispatch(context.parameters);
|
|
425
|
+
}
|
|
426
|
+
async function onQueryChange() {
|
|
427
|
+
var _a, _b;
|
|
428
|
+
const query = queryDetector.getQuery();
|
|
429
|
+
(_a = context.parameters) == null ? void 0 : _a.set("dt", query);
|
|
430
|
+
(_b = context.parameters) == null ? void 0 : _b.set("br", query);
|
|
431
|
+
await fetchAndRenderAllSlots();
|
|
432
|
+
}
|
|
433
|
+
function getConsent() {
|
|
434
|
+
return context.consent;
|
|
435
|
+
}
|
|
436
|
+
function setConsent(newConsent) {
|
|
437
|
+
var _a, _b;
|
|
438
|
+
(_a = context.parameters) == null ? void 0 : _a.set("tl", newConsent ? "all" : "none");
|
|
439
|
+
context.consent = newConsent;
|
|
440
|
+
(_b = context.events) == null ? void 0 : _b.consentChange.dispatch(newConsent);
|
|
441
|
+
}
|
|
442
|
+
const slotManager = createSlotManager({
|
|
443
|
+
initialSlots: mergedOptions.initialSlots,
|
|
444
|
+
context
|
|
330
445
|
});
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
viewabilityTracking: true,
|
|
356
|
-
...options
|
|
357
|
-
};
|
|
358
|
-
setupLogging(mergedOptions);
|
|
359
|
-
const context = new Proxy({
|
|
360
|
-
location: mergedOptions.location,
|
|
361
|
-
consent: mergedOptions.consent,
|
|
362
|
-
debug: mergedOptions.debug,
|
|
363
|
-
getAll,
|
|
364
|
-
get,
|
|
365
|
-
options: mergedOptions,
|
|
366
|
-
logger
|
|
367
|
-
}, {});
|
|
368
|
-
context.events = createEventManager();
|
|
369
|
-
function getLocation() {
|
|
370
|
-
return context.location;
|
|
371
|
-
}
|
|
372
|
-
function setLocation(newLocation) {
|
|
373
|
-
var _a2;
|
|
374
|
-
context.location = newLocation;
|
|
375
|
-
(_a2 = context.events) == null ? void 0 : _a2.locationChange.dispatch(newLocation);
|
|
376
|
-
}
|
|
377
|
-
const queryDetector = createQueryDetector({
|
|
378
|
-
onChange: onQueryChange,
|
|
379
|
-
queries: mergedOptions.queries
|
|
380
|
-
});
|
|
381
|
-
context.parameters = createParameters(mergedOptions, queryDetector);
|
|
382
|
-
context.parameters.addEventListener(onParametersChange);
|
|
383
|
-
let unmountDevtools;
|
|
384
|
-
if (mergedOptions.debug || window.location.search.includes("adhese_debug=true") || isPreviewMode()) {
|
|
385
|
-
unmountDevtools = await sdkDevtools.createDevtools(context);
|
|
386
|
-
(_a = context.events) == null ? void 0 : _a.debugChange.dispatch(true);
|
|
387
|
-
}
|
|
388
|
-
function onParametersChange() {
|
|
389
|
-
var _a2;
|
|
390
|
-
if (context.parameters)
|
|
391
|
-
(_a2 = context.events) == null ? void 0 : _a2.parametersChange.dispatch(context.parameters);
|
|
392
|
-
}
|
|
393
|
-
async function onQueryChange() {
|
|
394
|
-
var _a2, _b;
|
|
395
|
-
const query = queryDetector.getQuery();
|
|
396
|
-
(_a2 = context.parameters) == null ? void 0 : _a2.set("dt", query);
|
|
397
|
-
(_b = context.parameters) == null ? void 0 : _b.set("br", query);
|
|
398
|
-
await fetchAndRenderAllSlots();
|
|
399
|
-
}
|
|
400
|
-
function getConsent() {
|
|
401
|
-
return context.consent;
|
|
402
|
-
}
|
|
403
|
-
function setConsent(newConsent) {
|
|
404
|
-
var _a2, _b;
|
|
405
|
-
(_a2 = context.parameters) == null ? void 0 : _a2.set("tl", newConsent ? "all" : "none");
|
|
406
|
-
context.consent = newConsent;
|
|
407
|
-
(_b = context.events) == null ? void 0 : _b.consentChange.dispatch(newConsent);
|
|
408
|
-
}
|
|
409
|
-
const slotManager = await createSlotManager({
|
|
410
|
-
initialSlots: mergedOptions.initialSlots,
|
|
411
|
-
context
|
|
412
|
-
});
|
|
413
|
-
function getAll() {
|
|
414
|
-
return slotManager.getAll();
|
|
415
|
-
}
|
|
416
|
-
function get(name) {
|
|
417
|
-
return slotManager.get(name);
|
|
418
|
-
}
|
|
419
|
-
async function addSlot(slotOptions) {
|
|
420
|
-
const slot = await slotManager.add(slotOptions);
|
|
421
|
-
if (!slot.lazyLoading) {
|
|
422
|
-
const ad = await requestAd({
|
|
423
|
-
slot,
|
|
424
|
-
host: mergedOptions.host,
|
|
425
|
-
parameters: context.parameters,
|
|
426
|
-
account: mergedOptions.account,
|
|
446
|
+
function getAll() {
|
|
447
|
+
return slotManager.getAll() ?? [];
|
|
448
|
+
}
|
|
449
|
+
function get(name) {
|
|
450
|
+
return slotManager.get(name);
|
|
451
|
+
}
|
|
452
|
+
async function addSlot(slotOptions) {
|
|
453
|
+
if (!slotManager)
|
|
454
|
+
throw new Error("Slot manager not initialized");
|
|
455
|
+
const slot = slotManager.add(slotOptions);
|
|
456
|
+
if (!slot.lazyLoading) {
|
|
457
|
+
slot.ad.value = await requestAd({
|
|
458
|
+
slot,
|
|
459
|
+
context
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return slot;
|
|
463
|
+
}
|
|
464
|
+
async function findDomSlots2() {
|
|
465
|
+
const domSlots = (await slotManager.findDomSlots() ?? []).filter((slot) => !slot.lazyLoading);
|
|
466
|
+
if (domSlots.length <= 0)
|
|
467
|
+
return [];
|
|
468
|
+
const ads = await requestAds({
|
|
469
|
+
slots: domSlots,
|
|
427
470
|
context
|
|
428
471
|
});
|
|
429
|
-
|
|
472
|
+
for (const ad of ads) {
|
|
473
|
+
const slot = slotManager.get(ad.slotName);
|
|
474
|
+
if (slot)
|
|
475
|
+
slot.ad.value = ad;
|
|
476
|
+
}
|
|
477
|
+
return domSlots;
|
|
430
478
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
479
|
+
let unmountDevtools;
|
|
480
|
+
async function toggleDebug() {
|
|
481
|
+
var _a, _b;
|
|
482
|
+
context.debug = !context.debug;
|
|
483
|
+
if (context.debug && !unmountDevtools) {
|
|
484
|
+
unmountDevtools = await sdkDevtools.createDevtools(context);
|
|
485
|
+
logger.setMinLogLevelThreshold("debug");
|
|
486
|
+
logger.debug("Debug mode enabled");
|
|
487
|
+
(_a = context.events) == null ? void 0 : _a.debugChange.dispatch(true);
|
|
488
|
+
} else {
|
|
489
|
+
logger.debug("Debug mode disabled");
|
|
490
|
+
unmountDevtools == null ? void 0 : unmountDevtools();
|
|
491
|
+
unmountDevtools = void 0;
|
|
492
|
+
logger.setMinLogLevelThreshold("info");
|
|
493
|
+
(_b = context.events) == null ? void 0 : _b.debugChange.dispatch(false);
|
|
494
|
+
}
|
|
495
|
+
return context.debug;
|
|
496
|
+
}
|
|
497
|
+
async function fetchAndRenderAllSlots() {
|
|
498
|
+
const slots = (slotManager.getAll() ?? []).filter((slot) => !slot.lazyLoading);
|
|
499
|
+
if (slots.length === 0)
|
|
500
|
+
return;
|
|
501
|
+
const ads = await requestAds({
|
|
502
|
+
slots,
|
|
503
|
+
context
|
|
504
|
+
});
|
|
505
|
+
for (const ad of ads) {
|
|
506
|
+
const slot = slotManager.get(ad.slotName);
|
|
507
|
+
if (slot)
|
|
508
|
+
slot.ad.value = ad;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const disposeOnTcfConsentChange = onTcfConsentChange(async (data) => {
|
|
512
|
+
var _a, _b;
|
|
513
|
+
if (!data.tcString)
|
|
514
|
+
return;
|
|
515
|
+
logger.debug("TCF v2 consent data received", {
|
|
516
|
+
data
|
|
517
|
+
});
|
|
518
|
+
(_a = context.parameters) == null ? void 0 : _a.set("xt", data.tcString);
|
|
519
|
+
(_b = context.parameters) == null ? void 0 : _b.delete("tl");
|
|
520
|
+
await fetchAndRenderAllSlots();
|
|
442
521
|
});
|
|
443
|
-
|
|
444
|
-
var
|
|
445
|
-
return (_a2 = slotManager.get(ad.slotName)) == null ? void 0 : _a2.setAd(ad);
|
|
446
|
-
}));
|
|
447
|
-
return domSlots;
|
|
448
|
-
}
|
|
449
|
-
async function toggleDebug() {
|
|
450
|
-
var _a2, _b;
|
|
451
|
-
context.debug = !context.debug;
|
|
452
|
-
if (context.debug && !unmountDevtools) {
|
|
453
|
-
unmountDevtools = await sdkDevtools.createDevtools(context);
|
|
454
|
-
logger.setMinLogLevelThreshold("debug");
|
|
455
|
-
logger.debug("Debug mode enabled");
|
|
456
|
-
(_a2 = context.events) == null ? void 0 : _a2.debugChange.dispatch(true);
|
|
457
|
-
} else {
|
|
458
|
-
logger.debug("Debug mode disabled");
|
|
522
|
+
function dispose() {
|
|
523
|
+
var _a, _b;
|
|
459
524
|
unmountDevtools == null ? void 0 : unmountDevtools();
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
525
|
+
queryDetector.dispose();
|
|
526
|
+
slotManager.dispose();
|
|
527
|
+
queryDetector.dispose();
|
|
528
|
+
disposeOnTcfConsentChange();
|
|
529
|
+
(_a = context.parameters) == null ? void 0 : _a.clear();
|
|
530
|
+
logger.resetLogs();
|
|
531
|
+
(_b = context.events) == null ? void 0 : _b.dispose();
|
|
532
|
+
logger.info("Adhese instance disposed");
|
|
533
|
+
scope.stop();
|
|
463
534
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
535
|
+
onInit(async () => {
|
|
536
|
+
var _a;
|
|
537
|
+
if ((slotManager.getAll().length ?? 0) > 0)
|
|
538
|
+
await fetchAndRenderAllSlots().catch(logger.error);
|
|
539
|
+
if (mergedOptions.findDomSlotsOnLoad)
|
|
540
|
+
await findDomSlots2();
|
|
541
|
+
if (mergedOptions.debug || window.location.search.includes("adhese_debug=true") || isPreviewMode()) {
|
|
542
|
+
unmountDevtools = await sdkDevtools.createDevtools(context);
|
|
543
|
+
(_a = context.events) == null ? void 0 : _a.debugChange.dispatch(true);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
runOnInit();
|
|
547
|
+
return {
|
|
548
|
+
...mergedOptions,
|
|
549
|
+
...slotManager,
|
|
475
550
|
parameters: context.parameters,
|
|
551
|
+
events: context.events,
|
|
552
|
+
getLocation,
|
|
553
|
+
setLocation,
|
|
554
|
+
getConsent,
|
|
555
|
+
setConsent,
|
|
556
|
+
addSlot,
|
|
557
|
+
findDomSlots: findDomSlots2,
|
|
558
|
+
dispose,
|
|
559
|
+
toggleDebug,
|
|
476
560
|
context
|
|
477
|
-
}
|
|
478
|
-
await Promise.allSettled(ads.map((ad) => {
|
|
479
|
-
var _a2;
|
|
480
|
-
return (_a2 = slotManager.get(ad.slotName)) == null ? void 0 : _a2.setAd(ad);
|
|
481
|
-
}));
|
|
482
|
-
}
|
|
483
|
-
const disposeOnTcfConsentChange = onTcfConsentChange(async (data) => {
|
|
484
|
-
var _a2, _b;
|
|
485
|
-
if (!data.tcString)
|
|
486
|
-
return;
|
|
487
|
-
logger.debug("TCF v2 consent data received", {
|
|
488
|
-
data
|
|
489
|
-
});
|
|
490
|
-
(_a2 = context.parameters) == null ? void 0 : _a2.set("xt", data.tcString);
|
|
491
|
-
(_b = context.parameters) == null ? void 0 : _b.delete("tl");
|
|
492
|
-
await fetchAndRenderAllSlots();
|
|
561
|
+
};
|
|
493
562
|
});
|
|
494
|
-
if (slotManager.getAll().length > 0)
|
|
495
|
-
await fetchAndRenderAllSlots().catch(logger.error);
|
|
496
|
-
function dispose() {
|
|
497
|
-
var _a2, _b, _c;
|
|
498
|
-
queryDetector.dispose();
|
|
499
|
-
slotManager.dispose();
|
|
500
|
-
queryDetector.dispose();
|
|
501
|
-
disposeOnTcfConsentChange();
|
|
502
|
-
(_a2 = context.parameters) == null ? void 0 : _a2.dispose();
|
|
503
|
-
(_b = context.parameters) == null ? void 0 : _b.clear();
|
|
504
|
-
logger.resetLogs();
|
|
505
|
-
(_c = context.events) == null ? void 0 : _c.dispose();
|
|
506
|
-
unmountDevtools == null ? void 0 : unmountDevtools();
|
|
507
|
-
logger.info("Adhese instance disposed");
|
|
508
|
-
}
|
|
509
|
-
if (mergedOptions.findDomSlotsOnLoad)
|
|
510
|
-
await slotManager.findDomSlots();
|
|
511
|
-
return {
|
|
512
|
-
...mergedOptions,
|
|
513
|
-
...slotManager,
|
|
514
|
-
parameters: context.parameters,
|
|
515
|
-
events: context.events,
|
|
516
|
-
getLocation,
|
|
517
|
-
setLocation,
|
|
518
|
-
getConsent,
|
|
519
|
-
setConsent,
|
|
520
|
-
addSlot,
|
|
521
|
-
findDomSlots: findDomSlots2,
|
|
522
|
-
dispose,
|
|
523
|
-
toggleDebug,
|
|
524
|
-
context
|
|
525
|
-
};
|
|
526
563
|
}
|
|
527
564
|
function addTrackingPixel(url) {
|
|
528
565
|
const img = document.createElement("img");
|
|
@@ -535,118 +572,7 @@ function addTrackingPixel(url) {
|
|
|
535
572
|
img.style.top = "0";
|
|
536
573
|
return document.body.appendChild(img);
|
|
537
574
|
}
|
|
538
|
-
function
|
|
539
|
-
const iframe = document.createElement("iframe");
|
|
540
|
-
iframe.srcdoc = `
|
|
541
|
-
<!DOCTYPE html>
|
|
542
|
-
<html>
|
|
543
|
-
<head>
|
|
544
|
-
<style>
|
|
545
|
-
body {
|
|
546
|
-
margin: 0;
|
|
547
|
-
padding: 0;
|
|
548
|
-
overflow: hidden;
|
|
549
|
-
}
|
|
550
|
-
</style>
|
|
551
|
-
</head>
|
|
552
|
-
<body>
|
|
553
|
-
${ad.tag}
|
|
554
|
-
</body>
|
|
555
|
-
`.replaceAll(/\s+/g, " ").trim();
|
|
556
|
-
iframe.style.border = "none";
|
|
557
|
-
iframe.style.width = ad.width ? `${ad.width}px` : "100%";
|
|
558
|
-
iframe.style.height = ad.height ? `${ad.height}px` : "100%";
|
|
559
|
-
element.replaceChildren(iframe);
|
|
560
|
-
}
|
|
561
|
-
function renderInline(ad, element) {
|
|
562
|
-
element.style.width = ad.width ? `${ad.width}px` : "100%";
|
|
563
|
-
element.style.height = ad.height ? `${ad.height}px` : "100%";
|
|
564
|
-
element.innerHTML = ad.tag;
|
|
565
|
-
}
|
|
566
|
-
const renderFunctions = {
|
|
567
|
-
iframe: renderIframe,
|
|
568
|
-
inline: renderInline
|
|
569
|
-
};
|
|
570
|
-
async function createSlot(options) {
|
|
571
|
-
var _a;
|
|
572
|
-
const {
|
|
573
|
-
containingElement,
|
|
574
|
-
slot,
|
|
575
|
-
context,
|
|
576
|
-
renderMode = "iframe"
|
|
577
|
-
} = options;
|
|
578
|
-
await waitForDomLoad();
|
|
579
|
-
const parameters = new Map(Object.entries(options.parameters ?? {}));
|
|
580
|
-
let format;
|
|
581
|
-
let queryDetector = null;
|
|
582
|
-
if (typeof options.format === "string") {
|
|
583
|
-
format = options.format;
|
|
584
|
-
} else {
|
|
585
|
-
queryDetector = createQueryDetector({
|
|
586
|
-
onChange: setFormat,
|
|
587
|
-
queries: Object.fromEntries(options.format.map((item) => [item.format, item.query]))
|
|
588
|
-
});
|
|
589
|
-
format = queryDetector.getQuery();
|
|
590
|
-
}
|
|
591
|
-
async function setFormat(newFormat) {
|
|
592
|
-
var _a2;
|
|
593
|
-
const oldName = getName();
|
|
594
|
-
format = newFormat;
|
|
595
|
-
(_a2 = options.onNameChange) == null ? void 0 : _a2.call(options, getName(), oldName);
|
|
596
|
-
const newAd = await requestAd({
|
|
597
|
-
slot: {
|
|
598
|
-
getName,
|
|
599
|
-
parameters
|
|
600
|
-
},
|
|
601
|
-
account: context.options.account,
|
|
602
|
-
host: context.options.host,
|
|
603
|
-
parameters: context.parameters,
|
|
604
|
-
context
|
|
605
|
-
});
|
|
606
|
-
cleanElement();
|
|
607
|
-
await setAd(newAd);
|
|
608
|
-
}
|
|
609
|
-
function getFormat() {
|
|
610
|
-
return format;
|
|
611
|
-
}
|
|
612
|
-
let element = typeof containingElement === "string" || !containingElement ? document.querySelector(`.adunit[data-format="${format}"]#${containingElement}${slot ? `[data-slot="${slot}"]` : ""}`) : containingElement;
|
|
613
|
-
function getElement() {
|
|
614
|
-
if (renderMode === "iframe")
|
|
615
|
-
return (element == null ? void 0 : element.querySelector("iframe")) ?? null;
|
|
616
|
-
return (element == null ? void 0 : element.innerHTML) ? element.firstElementChild : null;
|
|
617
|
-
}
|
|
618
|
-
let impressionTrackingPixelElement = null;
|
|
619
|
-
let viewabilityTrackingPixelElement = null;
|
|
620
|
-
let isInViewport = false;
|
|
621
|
-
let ad = null;
|
|
622
|
-
function getAd() {
|
|
623
|
-
return ad;
|
|
624
|
-
}
|
|
625
|
-
async function setAd(newAd) {
|
|
626
|
-
var _a2, _b;
|
|
627
|
-
ad = newAd;
|
|
628
|
-
if (isInViewport || context.options.eagerRendering)
|
|
629
|
-
await render(ad);
|
|
630
|
-
if (element) {
|
|
631
|
-
element.style.width = `${ad.width}px`;
|
|
632
|
-
element.style.height = `${ad.height}px`;
|
|
633
|
-
}
|
|
634
|
-
await ((_b = context.events) == null ? void 0 : _b.changeSlots.dispatchAsync(Array.from(((_a2 = context.getAll) == null ? void 0 : _a2.call(context)) ?? [])));
|
|
635
|
-
}
|
|
636
|
-
const renderIntersectionObserver = new IntersectionObserver((entries) => {
|
|
637
|
-
isInViewport = entries.some((entry) => entry.isIntersecting);
|
|
638
|
-
if (isInViewport) {
|
|
639
|
-
(async () => {
|
|
640
|
-
if (!ad && options.lazyLoading)
|
|
641
|
-
await render();
|
|
642
|
-
else if (ad)
|
|
643
|
-
await render(ad);
|
|
644
|
-
})().catch(logger.error);
|
|
645
|
-
}
|
|
646
|
-
}, {
|
|
647
|
-
rootMargin: ((_a = options.lazyLoadingOptions) == null ? void 0 : _a.rootMargin) ?? "200px",
|
|
648
|
-
threshold: 0
|
|
649
|
-
});
|
|
575
|
+
function useViewabilityObserver({ context, ad, name, element }) {
|
|
650
576
|
let timeoutId = null;
|
|
651
577
|
const {
|
|
652
578
|
threshold,
|
|
@@ -658,17 +584,19 @@ async function createSlot(options) {
|
|
|
658
584
|
rootMargin: "0px",
|
|
659
585
|
...context.options.viewabilityTrackingOptions
|
|
660
586
|
};
|
|
587
|
+
const trackingPixel = runtimeCore.ref(null);
|
|
588
|
+
const isTracked = runtimeCore.computed(() => Boolean(trackingPixel.value));
|
|
661
589
|
const viewabilityObserver = new IntersectionObserver(([entry]) => {
|
|
662
|
-
if (context.options.viewabilityTracking && !
|
|
590
|
+
if (context.options.viewabilityTracking && !trackingPixel.value && ad) {
|
|
663
591
|
const ratio = lodashEs.round(entry.intersectionRatio, 1);
|
|
664
592
|
if (ratio >= threshold && !timeoutId) {
|
|
665
593
|
timeoutId = setTimeout(() => {
|
|
666
|
-
var
|
|
594
|
+
var _a, _b, _c;
|
|
667
595
|
timeoutId = null;
|
|
668
|
-
if (ad == null ? void 0 :
|
|
669
|
-
|
|
670
|
-
logger.debug(`Viewability tracking pixel fired for ${
|
|
671
|
-
(
|
|
596
|
+
if ((_a = ad.value) == null ? void 0 : _a.viewableImpressionCounter) {
|
|
597
|
+
trackingPixel.value = addTrackingPixel(ad.value.viewableImpressionCounter);
|
|
598
|
+
logger.debug(`Viewability tracking pixel fired for ${name.value}`);
|
|
599
|
+
(_c = context.events) == null ? void 0 : _c.changeSlots.dispatch(Array.from(((_b = context.getAll) == null ? void 0 : _b.call(context)) ?? []));
|
|
672
600
|
}
|
|
673
601
|
}, duration);
|
|
674
602
|
} else if (ratio < threshold && timeoutId) {
|
|
@@ -680,90 +608,218 @@ async function createSlot(options) {
|
|
|
680
608
|
rootMargin,
|
|
681
609
|
threshold: Array.from({ length: 11 }, (_, i) => i * 0.1)
|
|
682
610
|
});
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
getName,
|
|
693
|
-
parameters
|
|
694
|
-
},
|
|
695
|
-
account: context.options.account,
|
|
696
|
-
host: context.options.host,
|
|
697
|
-
parameters: context.parameters,
|
|
698
|
-
context
|
|
699
|
-
});
|
|
700
|
-
if (!element) {
|
|
701
|
-
const error = `Could not create slot for format ${format}. No element found.`;
|
|
702
|
-
logger.error(error, options);
|
|
703
|
-
throw new Error(error);
|
|
704
|
-
}
|
|
705
|
-
if (context.debug)
|
|
706
|
-
element.style.position = "relative";
|
|
707
|
-
renderFunctions[renderMode](ad, element);
|
|
708
|
-
if ((ad == null ? void 0 : ad.impressionCounter) && !impressionTrackingPixelElement) {
|
|
709
|
-
impressionTrackingPixelElement = addTrackingPixel(ad.impressionCounter);
|
|
710
|
-
logger.debug(`Impression tracking pixel fired for ${getName()}`);
|
|
711
|
-
}
|
|
712
|
-
logger.debug("Slot rendered", {
|
|
713
|
-
renderedElement: element,
|
|
714
|
-
location: context.location,
|
|
715
|
-
format,
|
|
716
|
-
containingElement
|
|
717
|
-
});
|
|
718
|
-
renderIntersectionObserver.disconnect();
|
|
719
|
-
await ((_b = context.events) == null ? void 0 : _b.changeSlots.dispatchAsync(Array.from(((_a2 = context.getAll) == null ? void 0 : _a2.call(context)) ?? [])));
|
|
720
|
-
return element;
|
|
721
|
-
}
|
|
722
|
-
function cleanElement() {
|
|
723
|
-
if (!element)
|
|
724
|
-
return;
|
|
725
|
-
element.innerHTML = "";
|
|
726
|
-
element.style.position = "";
|
|
727
|
-
element.style.width = "";
|
|
728
|
-
element.style.height = "";
|
|
729
|
-
}
|
|
730
|
-
function getName() {
|
|
731
|
-
return `${context.location}${slot ? `${slot}` : ""}-${format}`;
|
|
611
|
+
function observe(newElement, oldElement) {
|
|
612
|
+
if (oldElement)
|
|
613
|
+
viewabilityObserver.unobserve(oldElement);
|
|
614
|
+
if (newElement && context.options.viewabilityTracking)
|
|
615
|
+
viewabilityObserver.observe(newElement);
|
|
616
|
+
return () => {
|
|
617
|
+
if (newElement)
|
|
618
|
+
viewabilityObserver.unobserve(newElement);
|
|
619
|
+
};
|
|
732
620
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
element = null;
|
|
739
|
-
ad = null;
|
|
740
|
-
renderIntersectionObserver.disconnect();
|
|
621
|
+
runtimeCore.watch(element, observe);
|
|
622
|
+
observe(element.value);
|
|
623
|
+
return [isTracked, () => {
|
|
624
|
+
var _a;
|
|
625
|
+
(_a = trackingPixel.value) == null ? void 0 : _a.remove();
|
|
741
626
|
viewabilityObserver.disconnect();
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
627
|
+
}];
|
|
628
|
+
}
|
|
629
|
+
function useRenderIntersectionObserver({ ad, options, element, render }) {
|
|
630
|
+
var _a;
|
|
631
|
+
const isInViewport = runtimeCore.ref(false);
|
|
632
|
+
const renderIntersectionObserver = new IntersectionObserver((entries) => {
|
|
633
|
+
isInViewport.value = entries.some((entry) => entry.isIntersecting);
|
|
634
|
+
if (isInViewport.value) {
|
|
635
|
+
(async () => {
|
|
636
|
+
if (!ad.value && options.lazyLoading)
|
|
637
|
+
await render();
|
|
638
|
+
await render(ad.value ?? void 0);
|
|
639
|
+
})().catch(logger.error);
|
|
640
|
+
}
|
|
641
|
+
}, {
|
|
642
|
+
rootMargin: ((_a = options.lazyLoadingOptions) == null ? void 0 : _a.rootMargin) ?? "200px",
|
|
643
|
+
threshold: 0
|
|
644
|
+
});
|
|
645
|
+
function observe(newElement, oldElement) {
|
|
646
|
+
if (oldElement)
|
|
647
|
+
renderIntersectionObserver.unobserve(oldElement);
|
|
648
|
+
if (newElement)
|
|
649
|
+
renderIntersectionObserver.observe(newElement);
|
|
650
|
+
return () => {
|
|
651
|
+
if (newElement)
|
|
652
|
+
renderIntersectionObserver.unobserve(newElement);
|
|
653
|
+
};
|
|
750
654
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
655
|
+
runtimeCore.watch(element, observe);
|
|
656
|
+
observe(element.value);
|
|
657
|
+
return [isInViewport, () => {
|
|
658
|
+
renderIntersectionObserver.disconnect();
|
|
659
|
+
}];
|
|
660
|
+
}
|
|
661
|
+
const renderFunctions = {
|
|
662
|
+
iframe: renderIframe,
|
|
663
|
+
inline: renderInline
|
|
664
|
+
};
|
|
665
|
+
function createSlot(options) {
|
|
666
|
+
const scope = runtimeCore.effectScope();
|
|
667
|
+
return scope.run(() => {
|
|
668
|
+
const {
|
|
669
|
+
containingElement,
|
|
670
|
+
slot,
|
|
671
|
+
context,
|
|
672
|
+
renderMode = "iframe"
|
|
673
|
+
} = options;
|
|
674
|
+
const parameters = runtimeCore.reactive(new Map(Object.entries(options.parameters ?? {})));
|
|
675
|
+
let queryDetector = null;
|
|
676
|
+
if (typeof options.format !== "string") {
|
|
677
|
+
queryDetector = createQueryDetector({
|
|
678
|
+
onChange: onQueryChange,
|
|
679
|
+
queries: Object.fromEntries(options.format.map((item) => [item.format, item.query]))
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
const format = runtimeCore.ref(queryDetector ? queryDetector.getQuery() : options.format);
|
|
683
|
+
function onQueryChange(newFormat) {
|
|
684
|
+
format.value = newFormat;
|
|
685
|
+
}
|
|
686
|
+
const ad = runtimeCore.ref(null);
|
|
687
|
+
const name = runtimeCore.computed(() => generateName(context.location, format.value, slot));
|
|
688
|
+
runtimeCore.watch(name, async (newName, oldName) => {
|
|
689
|
+
var _a;
|
|
690
|
+
if (newName === oldName)
|
|
691
|
+
return;
|
|
692
|
+
(_a = options.onNameChange) == null ? void 0 : _a.call(options, newName, oldName);
|
|
693
|
+
const newAd = await requestAd({
|
|
694
|
+
slot: {
|
|
695
|
+
name: newName,
|
|
696
|
+
parameters
|
|
697
|
+
},
|
|
698
|
+
context
|
|
699
|
+
});
|
|
700
|
+
cleanElement();
|
|
701
|
+
ad.value = newAd;
|
|
702
|
+
});
|
|
703
|
+
const isDomLoaded = useDomLoaded();
|
|
704
|
+
const element = runtimeCore.computed(
|
|
705
|
+
() => {
|
|
706
|
+
if (!(typeof containingElement === "string" || !containingElement))
|
|
707
|
+
return containingElement;
|
|
708
|
+
if (!isDomLoaded.value)
|
|
709
|
+
return null;
|
|
710
|
+
return document.querySelector(`.adunit[data-format="${format.value}"]#${containingElement}${slot ? `[data-slot="${slot}"]` : ""}`);
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
function getElement() {
|
|
714
|
+
var _a, _b;
|
|
715
|
+
if (renderMode === "iframe")
|
|
716
|
+
return ((_a = element.value) == null ? void 0 : _a.querySelector("iframe")) ?? null;
|
|
717
|
+
return ((_b = element.value) == null ? void 0 : _b.innerHTML) ? element.value.firstElementChild : null;
|
|
718
|
+
}
|
|
719
|
+
const [isInViewport, disposeRenderIntersectionObserver] = useRenderIntersectionObserver({
|
|
720
|
+
ad,
|
|
721
|
+
options,
|
|
722
|
+
element,
|
|
723
|
+
render
|
|
724
|
+
});
|
|
725
|
+
runtimeCore.watch([ad, isInViewport], async ([newAd, newIsInViewport], [oldAd]) => {
|
|
726
|
+
var _a, _b;
|
|
727
|
+
if (!newAd || lodashEs.isEqual(newAd, oldAd))
|
|
728
|
+
return;
|
|
729
|
+
if (newIsInViewport || context.options.eagerRendering)
|
|
730
|
+
await render(newAd);
|
|
731
|
+
if (element.value) {
|
|
732
|
+
element.value.style.width = `${newAd.width}px`;
|
|
733
|
+
element.value.style.height = `${newAd.height}px`;
|
|
734
|
+
}
|
|
735
|
+
(_b = context.events) == null ? void 0 : _b.changeSlots.dispatch(Array.from(((_a = context.getAll) == null ? void 0 : _a.call(context)) ?? []));
|
|
736
|
+
});
|
|
737
|
+
const [
|
|
738
|
+
isViewabilityTracked,
|
|
739
|
+
disposeViewabilityObserver
|
|
740
|
+
] = useViewabilityObserver({
|
|
741
|
+
context,
|
|
742
|
+
ad,
|
|
743
|
+
name,
|
|
744
|
+
element
|
|
745
|
+
});
|
|
746
|
+
const impressionTrackingPixelElement = runtimeCore.ref(null);
|
|
747
|
+
const isImpressionTracked = runtimeCore.computed(() => Boolean(impressionTrackingPixelElement.value));
|
|
748
|
+
async function render(adToRender) {
|
|
749
|
+
var _a, _b, _c, _d;
|
|
750
|
+
await waitForDomLoad();
|
|
751
|
+
ad.value = adToRender ?? ad.value ?? await requestAd({
|
|
752
|
+
slot: {
|
|
753
|
+
name,
|
|
754
|
+
parameters
|
|
755
|
+
},
|
|
756
|
+
context
|
|
757
|
+
});
|
|
758
|
+
ad.value = ((_a = options.onBeforeRender) == null ? void 0 : _a.call(options, ad.value)) ?? ad.value;
|
|
759
|
+
if (!element.value) {
|
|
760
|
+
const error = `Could not create slot for format ${format.value}. No element found.`;
|
|
761
|
+
logger.error(error, options);
|
|
762
|
+
throw new Error(error);
|
|
763
|
+
}
|
|
764
|
+
if (context.debug)
|
|
765
|
+
element.value.style.position = "relative";
|
|
766
|
+
renderFunctions[renderMode](ad.value, element.value);
|
|
767
|
+
if (((_b = ad.value) == null ? void 0 : _b.impressionCounter) && !impressionTrackingPixelElement.value) {
|
|
768
|
+
impressionTrackingPixelElement.value = addTrackingPixel((_c = ad.value) == null ? void 0 : _c.impressionCounter);
|
|
769
|
+
logger.debug(`Impression tracking pixel fired for ${name.value}`);
|
|
770
|
+
}
|
|
771
|
+
logger.debug("Slot rendered", {
|
|
772
|
+
renderedElement: element,
|
|
773
|
+
location: context.location,
|
|
774
|
+
format,
|
|
775
|
+
containingElement
|
|
776
|
+
});
|
|
777
|
+
(_d = options.onRender) == null ? void 0 : _d.call(options, element.value);
|
|
778
|
+
disposeRenderIntersectionObserver();
|
|
779
|
+
return element.value;
|
|
780
|
+
}
|
|
781
|
+
function cleanElement() {
|
|
782
|
+
if (!element.value)
|
|
783
|
+
return;
|
|
784
|
+
element.value.innerHTML = "";
|
|
785
|
+
element.value.style.position = "";
|
|
786
|
+
element.value.style.width = "";
|
|
787
|
+
element.value.style.height = "";
|
|
788
|
+
}
|
|
789
|
+
function dispose() {
|
|
790
|
+
var _a, _b;
|
|
791
|
+
cleanElement();
|
|
792
|
+
(_a = impressionTrackingPixelElement.value) == null ? void 0 : _a.remove();
|
|
793
|
+
ad.value = null;
|
|
794
|
+
disposeRenderIntersectionObserver();
|
|
795
|
+
disposeViewabilityObserver();
|
|
796
|
+
(_b = options.onDispose) == null ? void 0 : _b.call(options);
|
|
797
|
+
queryDetector == null ? void 0 : queryDetector.dispose();
|
|
798
|
+
scope.stop();
|
|
799
|
+
}
|
|
800
|
+
return {
|
|
801
|
+
location: context.location,
|
|
802
|
+
lazyLoading: options.lazyLoading ?? false,
|
|
803
|
+
slot,
|
|
804
|
+
parameters,
|
|
805
|
+
format,
|
|
806
|
+
name,
|
|
807
|
+
ad,
|
|
808
|
+
isViewabilityTracked,
|
|
809
|
+
isImpressionTracked,
|
|
810
|
+
render,
|
|
811
|
+
getElement,
|
|
812
|
+
dispose
|
|
813
|
+
};
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
function useDomLoaded() {
|
|
817
|
+
const isDomLoaded = runtimeCore.ref(false);
|
|
818
|
+
onInit(async () => {
|
|
819
|
+
await waitForDomLoad();
|
|
820
|
+
isDomLoaded.value = true;
|
|
821
|
+
});
|
|
822
|
+
return isDomLoaded;
|
|
767
823
|
}
|
|
768
824
|
const numberLike = zod.union([zod.coerce.string().regex(/^\d+$/), zod.literal("")]).transform((value) => value === "" ? void 0 : Number(value));
|
|
769
825
|
const booleanLike = zod.union([zod.coerce.boolean(), zod.literal("")]);
|
|
@@ -782,13 +838,48 @@ const dateLike = zod.union([zod.coerce.string(), zod.literal("")]).transform((va
|
|
|
782
838
|
return void 0;
|
|
783
839
|
return date;
|
|
784
840
|
});
|
|
785
|
-
const
|
|
841
|
+
const cssValueLike = zod.union([zod.coerce.string(), zod.literal(""), zod.number()]).transform((value) => {
|
|
842
|
+
if (value === "" || value === 0 || value === "0")
|
|
843
|
+
return void 0;
|
|
844
|
+
if (numberLike.parse(value))
|
|
845
|
+
return `${numberLike.parse(value)}px`;
|
|
846
|
+
return String(value);
|
|
847
|
+
});
|
|
848
|
+
const isJson = zod.string().transform((value, { addIssue }) => {
|
|
849
|
+
try {
|
|
850
|
+
return JSON.parse(value.replaceAll("'", '"'));
|
|
851
|
+
} catch (error) {
|
|
852
|
+
addIssue({
|
|
853
|
+
code: zod.ZodIssueCode.custom,
|
|
854
|
+
message: `Invalid JSON: ${error.message}`
|
|
855
|
+
});
|
|
856
|
+
return zod.NEVER;
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
const isHtmlString = zod.string().transform((value, { addIssue }) => {
|
|
860
|
+
var _a;
|
|
861
|
+
const htmlParser = new DOMParser();
|
|
862
|
+
try {
|
|
863
|
+
const html = htmlParser.parseFromString(value, "text/html");
|
|
864
|
+
if (((_a = html.body) == null ? void 0 : _a.children.length) === 0)
|
|
865
|
+
throw new Error("Invalid HTML");
|
|
866
|
+
return value;
|
|
867
|
+
} catch (error) {
|
|
868
|
+
addIssue({
|
|
869
|
+
code: zod.ZodIssueCode.custom,
|
|
870
|
+
message: error.message
|
|
871
|
+
});
|
|
872
|
+
return zod.NEVER;
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
const isJsonOrHtmlString = zod.union([isJson, isHtmlString]);
|
|
876
|
+
const isJsonOrHtmlOptionalString = zod.union([zod.coerce.string(), isJsonOrHtmlString]).transform((value) => {
|
|
877
|
+
if (value === "")
|
|
878
|
+
return void 0;
|
|
879
|
+
return value;
|
|
880
|
+
}).optional();
|
|
881
|
+
const baseSchema = zod.object({
|
|
786
882
|
adDuration: numberLike.optional(),
|
|
787
|
-
adDuration2nd: numberLike.optional(),
|
|
788
|
-
adDuration3rd: numberLike.optional(),
|
|
789
|
-
adDuration4th: numberLike.optional(),
|
|
790
|
-
adDuration5th: numberLike.optional(),
|
|
791
|
-
adDuration6th: numberLike.optional(),
|
|
792
883
|
adFormat: zod.string().optional(),
|
|
793
884
|
adType: zod.string(),
|
|
794
885
|
additionalCreativeTracker: urlLike.optional(),
|
|
@@ -800,34 +891,27 @@ const baseAdResponseScheme = zod.object({
|
|
|
800
891
|
advertiserId: zod.string().optional(),
|
|
801
892
|
altText: zod.string().optional(),
|
|
802
893
|
auctionable: booleanLike.optional(),
|
|
803
|
-
body:
|
|
894
|
+
body: isJsonOrHtmlOptionalString,
|
|
804
895
|
clickTag: urlLike.optional(),
|
|
805
896
|
comment: zod.string().optional(),
|
|
806
897
|
creativeName: zod.string().optional(),
|
|
807
898
|
deliveryGroupId: zod.string().optional(),
|
|
808
899
|
deliveryMultiples: zod.string().optional(),
|
|
809
|
-
dm: zod.string().optional(),
|
|
810
900
|
ext: zod.string().optional(),
|
|
811
901
|
extension: zod.object({
|
|
812
902
|
mediaType: zod.string(),
|
|
813
903
|
prebid: zod.unknown().optional()
|
|
814
904
|
}).optional(),
|
|
815
|
-
|
|
816
|
-
extraField2: zod.string().optional(),
|
|
817
|
-
height: numberLike.optional(),
|
|
818
|
-
height3rd: numberLike.optional(),
|
|
819
|
-
height4th: numberLike.optional(),
|
|
820
|
-
height5th: numberLike.optional(),
|
|
821
|
-
height6th: numberLike.optional(),
|
|
822
|
-
heightLarge: numberLike.optional(),
|
|
905
|
+
height: cssValueLike.optional(),
|
|
823
906
|
id: zod.string().optional(),
|
|
824
907
|
impressionCounter: urlLike.optional(),
|
|
825
908
|
libId: zod.string().optional(),
|
|
826
909
|
orderId: zod.string().optional(),
|
|
827
910
|
orderName: zod.string().optional(),
|
|
828
911
|
orderProperty: zod.string().optional(),
|
|
829
|
-
origin: zod.
|
|
912
|
+
origin: zod.union([zod.literal("JERLICIA"), zod.literal("DALE")]),
|
|
830
913
|
originData: zod.unknown().optional(),
|
|
914
|
+
originInstance: zod.string().optional(),
|
|
831
915
|
poolPath: urlLike.optional(),
|
|
832
916
|
preview: booleanLike.optional(),
|
|
833
917
|
priority: numberLike.optional(),
|
|
@@ -836,12 +920,7 @@ const baseAdResponseScheme = zod.object({
|
|
|
836
920
|
slotID: zod.string(),
|
|
837
921
|
slotName: zod.string(),
|
|
838
922
|
swfSrc: urlLike.optional(),
|
|
839
|
-
|
|
840
|
-
swfSrc3rd: zod.string().optional(),
|
|
841
|
-
swfSrc4th: zod.string().optional(),
|
|
842
|
-
swfSrc5th: zod.string().optional(),
|
|
843
|
-
swfSrc6th: zod.string().optional(),
|
|
844
|
-
tag: zod.string(),
|
|
923
|
+
tag: isJsonOrHtmlOptionalString,
|
|
845
924
|
tagUrl: urlLike.optional(),
|
|
846
925
|
timeStamp: dateLike.optional(),
|
|
847
926
|
trackedImpressionCounter: urlLike.optional(),
|
|
@@ -849,14 +928,21 @@ const baseAdResponseScheme = zod.object({
|
|
|
849
928
|
trackingUrl: urlLike.optional(),
|
|
850
929
|
url: urlLike.optional(),
|
|
851
930
|
viewableImpressionCounter: urlLike.optional(),
|
|
852
|
-
width:
|
|
853
|
-
|
|
854
|
-
width4th: numberLike.optional(),
|
|
855
|
-
width5th: numberLike.optional(),
|
|
856
|
-
width6th: numberLike.optional(),
|
|
857
|
-
widthLarge: numberLike.optional()
|
|
931
|
+
width: cssValueLike.optional(),
|
|
932
|
+
widthLarge: cssValueLike.optional()
|
|
858
933
|
});
|
|
859
|
-
const
|
|
934
|
+
const jerliciaSchema = zod.object({
|
|
935
|
+
origin: zod.literal("JERLICIA"),
|
|
936
|
+
tag: isJsonOrHtmlString
|
|
937
|
+
}).passthrough();
|
|
938
|
+
const daleSchema = zod.object({
|
|
939
|
+
origin: zod.literal("DALE"),
|
|
940
|
+
body: isJsonOrHtmlString
|
|
941
|
+
}).passthrough().transform(({ body, ...data }) => ({
|
|
942
|
+
...data,
|
|
943
|
+
tag: body
|
|
944
|
+
}));
|
|
945
|
+
const adResponseSchema = baseSchema.extend({
|
|
860
946
|
additionalCreatives: zod.lazy(() => zod.union([adResponseSchema.array(), zod.string()]).optional())
|
|
861
947
|
});
|
|
862
948
|
const adSchema = adResponseSchema.transform(({
|
|
@@ -871,6 +957,21 @@ const adSchema = adResponseSchema.transform(({
|
|
|
871
957
|
additionalCreatives: Array.isArray(additionalCreatives) ? additionalCreatives.map((creative) => adSchema.parse(creative)) : additionalCreatives
|
|
872
958
|
};
|
|
873
959
|
});
|
|
960
|
+
function parseResponse(response) {
|
|
961
|
+
const schemaMap = {
|
|
962
|
+
/* eslint-disable ts/naming-convention */
|
|
963
|
+
JERLICIA: jerliciaSchema,
|
|
964
|
+
DALE: daleSchema
|
|
965
|
+
/* eslint-enable ts/naming-convention */
|
|
966
|
+
};
|
|
967
|
+
const preParsed = adResponseSchema.array().parse(response);
|
|
968
|
+
return preParsed.map((item) => {
|
|
969
|
+
const schema = schemaMap[item.origin];
|
|
970
|
+
if (!schema)
|
|
971
|
+
return adSchema.parse(item);
|
|
972
|
+
return schema.parse(item);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
874
975
|
async function requestPreviews(account) {
|
|
875
976
|
const previewObjects = getPreviewObjects();
|
|
876
977
|
const list = (await Promise.allSettled(previewObjects.filter((previewObject) => "adhesePreviewCreativeId" in previewObject).map(async (previewObject) => {
|
|
@@ -916,16 +1017,16 @@ function getPreviewObjects() {
|
|
|
916
1017
|
return previewObjects;
|
|
917
1018
|
}
|
|
918
1019
|
function requestWithPost({
|
|
919
|
-
host,
|
|
1020
|
+
context: { options: { host }, parameters },
|
|
920
1021
|
...options
|
|
921
1022
|
}) {
|
|
922
1023
|
const payload = {
|
|
923
1024
|
...options,
|
|
924
1025
|
slots: options.slots.map((slot) => ({
|
|
925
|
-
slotname: slot.
|
|
1026
|
+
slotname: runtimeCore.toValue(slot.name),
|
|
926
1027
|
parameters: parseParameters(slot.parameters)
|
|
927
1028
|
})),
|
|
928
|
-
parameters:
|
|
1029
|
+
parameters: parameters && parseParameters(parameters)
|
|
929
1030
|
};
|
|
930
1031
|
return fetch(`${new URL(host).href}json`, {
|
|
931
1032
|
method: "POST",
|
|
@@ -936,8 +1037,8 @@ function requestWithPost({
|
|
|
936
1037
|
}
|
|
937
1038
|
});
|
|
938
1039
|
}
|
|
939
|
-
async function requestWithGet(
|
|
940
|
-
return fetch(new URL(`${options.host}/json/sl${
|
|
1040
|
+
async function requestWithGet({ context, slots }) {
|
|
1041
|
+
return fetch(new URL(`${context.options.host}/json/sl${slots.map((slot) => runtimeCore.toValue(slot.name)).join("/sl")}`), {
|
|
941
1042
|
method: "GET",
|
|
942
1043
|
headers: {
|
|
943
1044
|
// eslint-disable-next-line ts/naming-convention
|
|
@@ -953,23 +1054,19 @@ function parseParameters(parameters) {
|
|
|
953
1054
|
return false;
|
|
954
1055
|
}));
|
|
955
1056
|
}
|
|
956
|
-
async function requestAds({
|
|
957
|
-
|
|
958
|
-
context
|
|
959
|
-
...options
|
|
960
|
-
}) {
|
|
961
|
-
var _a, _b, _c, _d;
|
|
1057
|
+
async function requestAds(options) {
|
|
1058
|
+
var _a, _b, _c, _d, _e;
|
|
1059
|
+
const { context } = options;
|
|
962
1060
|
try {
|
|
963
1061
|
(_a = context.events) == null ? void 0 : _a.requestAd.dispatch({
|
|
964
1062
|
...options,
|
|
965
|
-
context
|
|
966
|
-
method
|
|
1063
|
+
context
|
|
967
1064
|
});
|
|
968
|
-
const [response, previews] = await Promise.all([(
|
|
1065
|
+
const [response, previews] = await Promise.all([((_b = context.options.requestType) == null ? void 0 : _b.toUpperCase()) === "POST" ? requestWithPost(options) : requestWithGet(options), requestPreviews(context.options.account)]);
|
|
969
1066
|
logger.debug("Received response", response);
|
|
970
1067
|
if (!response.ok)
|
|
971
1068
|
throw new Error(`Failed to request ad: ${response.status} ${response.statusText}`);
|
|
972
|
-
const result =
|
|
1069
|
+
const result = parseResponse(await response.json());
|
|
973
1070
|
logger.debug("Parsed ad", result);
|
|
974
1071
|
if (previews.length > 0)
|
|
975
1072
|
logger.info(`Found ${previews.length} ${previews.length === 1 ? "preview" : "previews"}. Replacing ads in response with preview items`, previews);
|
|
@@ -981,18 +1078,18 @@ async function requestAds({
|
|
|
981
1078
|
};
|
|
982
1079
|
});
|
|
983
1080
|
if (matchedPreviews.length > 0)
|
|
984
|
-
(
|
|
1081
|
+
(_c = context.events) == null ? void 0 : _c.previewReceived.dispatch(matchedPreviews);
|
|
985
1082
|
const mergedResult = [
|
|
986
1083
|
...result.filter((ad) => !previews.some((preview) => preview.libId === ad.libId)),
|
|
987
1084
|
...matchedPreviews
|
|
988
1085
|
];
|
|
989
1086
|
if (mergedResult.length === 0)
|
|
990
1087
|
throw new Error("No ads found");
|
|
991
|
-
(
|
|
1088
|
+
(_d = context.events) == null ? void 0 : _d.responseReceived.dispatch(mergedResult);
|
|
992
1089
|
return mergedResult;
|
|
993
1090
|
} catch (error) {
|
|
994
1091
|
logger.error(String(error));
|
|
995
|
-
(
|
|
1092
|
+
(_e = context.events) == null ? void 0 : _e.requestError.dispatch(error);
|
|
996
1093
|
throw error;
|
|
997
1094
|
}
|
|
998
1095
|
}
|