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