prebid-universal-creative 1.15.0 → 1.17.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/.circleci/config.yml +44 -30
- package/.github/workflows/codeql.yml +98 -0
- package/.github/workflows/issue_tracker.yml +32 -16
- package/README.md +4 -2
- package/dist/amp.js +3 -3
- package/dist/banner.js +3 -3
- package/dist/caf7688498213fb0c19f.max.js +1046 -0
- package/dist/creative.js +3 -3
- package/dist/load-cookie-with-consent.html +1 -1
- package/dist/load-cookie.html +1 -1
- package/dist/mobile.js +3 -3
- package/dist/native-render.js +3 -3
- package/dist/native-trk.js +3 -3
- package/dist/native.js +3 -3
- package/dist/uid.js +2 -2
- package/dist/video.js +3 -3
- package/gulpfile.js +15 -31
- package/integ-test/fixtures/test.js +79 -0
- package/integ-test/pages/amp.html +80 -0
- package/integ-test/pages/banner.html +96 -0
- package/integ-test/pages/native_legacy.html +107 -0
- package/integ-test/spec/amp_spec.js +111 -0
- package/integ-test/spec/banner_spec.js +85 -0
- package/integ-test/spec/native_legacy_spec.js +213 -0
- package/karma.conf.maker.js +4 -6
- package/package.json +10 -16
- package/playwright.config.js +108 -0
- package/src/adHtmlRender.js +11 -0
- package/src/cookieSync.js +3 -0
- package/src/cookieSyncWithConsent.js +3 -0
- package/src/domHelper.js +25 -15
- package/src/dynamicRenderer.js +56 -0
- package/src/messaging.js +23 -2
- package/src/mobileAndAmpRender.js +17 -20
- package/src/nativeAssetManager.js +134 -80
- package/src/nativeORTBTrackerManager.js +3 -3
- package/src/nativeRenderManager.js +44 -72
- package/src/nativeTrackerManager.js +2 -2
- package/src/renderingManager.js +17 -18
- package/src/utils.js +0 -9
- package/test/helpers/mocks.js +1 -0
- package/test/spec/dynamicRenderer_spec.js +167 -0
- package/test/spec/messaging_spec.js +98 -3
- package/test/spec/mobileAndAmpRender_spec.js +53 -63
- package/test/spec/nativeAssetManager_spec.js +290 -93
- package/test/spec/nativeORTBTrackerManager_spec.js +3 -19
- package/test/spec/nativeRenderManager_spec.js +77 -56
- package/test/spec/renderingManager_spec.js +20 -6
- package/webpack.conf.js +0 -1
- package/.nvmrc +0 -1
- package/dist/creative.max.js +0 -3101
- package/src/postscribeRender.js +0 -8
- package/test/e2e/specs/hello_world_banner_non_sf.spec.js +0 -14
- package/test/e2e/specs/outstream_non_sf.spec.js +0 -14
- package/test/e2e/specs/outstream_sf.spec.js +0 -14
- package/wdio.conf.js +0 -50
@@ -1,7 +1,7 @@
|
|
1
1
|
import { getCreativeCommentMarkup, triggerPixel, createTrackPixelHtml, loadScript, getCreativeComment, writeAdUrl, transformAuctionTargetingData, sendRequest, getUUID } from './utils';
|
2
2
|
import { isSafeFrame, isMobileApp } from './environment';
|
3
3
|
import { insertElement } from './domHelper';
|
4
|
-
import { writeAdHtml } from './
|
4
|
+
import { writeAdHtml } from './adHtmlRender';
|
5
5
|
|
6
6
|
const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
|
7
7
|
const DEFAULT_CACHE_PATH = '/pbc/v1/cache';
|
@@ -62,26 +62,24 @@ function updateIframe(size) {
|
|
62
62
|
* @param {Number} height height of creative
|
63
63
|
*/
|
64
64
|
function resizeIframe(width, height) {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
if (iframeWidth !== width || iframeHeight !== height) {
|
65
|
+
const iframeWidth = window.innerWidth;
|
66
|
+
const iframeHeight = window.innerHeight;
|
67
|
+
if (iframeWidth !== width || iframeHeight !== height) {
|
68
|
+
if (isSafeFrame(window)) {
|
69
|
+
function resize(status) {
|
70
|
+
let newWidth = width - iframeWidth;
|
71
|
+
let newHeight = height - iframeHeight;
|
72
|
+
window.$sf.ext.expand({r: newWidth, b: newHeight, push: true});
|
73
|
+
}
|
76
74
|
window.$sf.ext.register(width, height, resize);
|
77
|
-
// we need to resize the DFP container as well
|
78
|
-
window.parent.postMessage({
|
79
|
-
sentinel: 'amp',
|
80
|
-
type: 'embed-size',
|
81
|
-
width: width,
|
82
|
-
height: height
|
83
|
-
}, '*');
|
84
75
|
}
|
76
|
+
// AMP resize request in case the parent is AMP
|
77
|
+
window.parent.postMessage({
|
78
|
+
sentinel: 'amp',
|
79
|
+
type: 'embed-size',
|
80
|
+
width: width,
|
81
|
+
height: height
|
82
|
+
}, '*');
|
85
83
|
}
|
86
84
|
}
|
87
85
|
|
@@ -151,7 +149,6 @@ function responseCallback(isMobileApp, hbPb) {
|
|
151
149
|
if (isMobileApp) {
|
152
150
|
let adhtml = loadScript(window, bidObject.nurl);
|
153
151
|
ad += constructMarkup(adhtml.outerHTML, width, height);
|
154
|
-
|
155
152
|
writeAdHtml(ad);
|
156
153
|
} else {
|
157
154
|
let nurl = bidObject.nurl;
|
@@ -7,6 +7,7 @@ import { addNativeClickTrackers, fireNativeImpressionTrackers } from './nativeOR
|
|
7
7
|
import { sendRequest, loadScript } from './utils';
|
8
8
|
import {prebidMessenger} from './messaging.js';
|
9
9
|
import { isSafeFrame } from './environment.js';
|
10
|
+
import {hasDynamicRenderer, runDynamicRenderer} from './dynamicRenderer.js';
|
10
11
|
/*
|
11
12
|
* Native asset->key mapping from Prebid.js/src/constants.json
|
12
13
|
* https://github.com/prebid/Prebid.js/blob/8635c91942de9df4ec236672c39b19448545a812/src/constants.json#L67
|
@@ -59,9 +60,22 @@ const assetTypeMapping = {
|
|
59
60
|
const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
|
60
61
|
const DEFAULT_CACHE_PATH = '/pbc/v1/cache';
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
const CLICK_URL_UNESC = `%%CLICK_URL_UNESC%%`;
|
64
|
+
|
65
|
+
let clickUrlUnesc = '';
|
66
|
+
|
67
|
+
export function newNativeAssetManager(win, nativeTag, mkMessenger = prebidMessenger) {
|
68
|
+
|
69
|
+
// clickUrlUnesc contains the url to track clicks in GAM. we check if it
|
70
|
+
// has been transformed, by GAM, in an URL.
|
71
|
+
// if CLICK_URL_UNESC is the string "%%CLICK_URL_UNESC%%", we're not in GAM.
|
72
|
+
if (nativeTag.clickUrlUnesc && nativeTag.clickUrlUnesc !== CLICK_URL_UNESC) {
|
73
|
+
clickUrlUnesc = nativeTag.clickUrlUnesc;
|
74
|
+
}
|
75
|
+
const {pubUrl} = nativeTag;
|
76
|
+
|
77
|
+
const sendMessage = mkMessenger(pubUrl, win);
|
78
|
+
let callback, errCallback;
|
65
79
|
let errorCountEscapeHatch = 0;
|
66
80
|
let cancelMessageListener;
|
67
81
|
|
@@ -183,7 +197,8 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
183
197
|
* and requestAllAssets flag is set in the tag, postmessage roundtrip
|
184
198
|
* to retrieve native assets that have a value on the corresponding bid
|
185
199
|
*/
|
186
|
-
function loadAssets(adId, cb) {
|
200
|
+
function loadAssets(adId, cb, onError) {
|
201
|
+
errCallback = onError;
|
187
202
|
const placeholders = scanDOMForPlaceHolders(adId);
|
188
203
|
|
189
204
|
if (hasPbNativeData() && win.pbNativeData.hasOwnProperty('assetsToReplace')) {
|
@@ -199,6 +214,8 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
199
214
|
} else if (placeholders.length > 0) {
|
200
215
|
callback = cb;
|
201
216
|
cancelMessageListener = requestAssets(adId, placeholders);
|
217
|
+
} else {
|
218
|
+
onError && onError(new Error('No assets to load: no placeholders found in template'));
|
202
219
|
}
|
203
220
|
}
|
204
221
|
|
@@ -239,7 +256,7 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
239
256
|
assets,
|
240
257
|
};
|
241
258
|
|
242
|
-
return sendMessage(message, replaceAssets);
|
259
|
+
return sendMessage(message, replaceAssets(adId));
|
243
260
|
}
|
244
261
|
|
245
262
|
/*
|
@@ -252,7 +269,7 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
252
269
|
action: 'allAssetRequest',
|
253
270
|
adId,
|
254
271
|
};
|
255
|
-
return sendMessage(message, replaceAssets);
|
272
|
+
return sendMessage(message, replaceAssets(adId));
|
256
273
|
}
|
257
274
|
|
258
275
|
/*
|
@@ -269,117 +286,154 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
269
286
|
sendMessage(message);
|
270
287
|
}
|
271
288
|
|
272
|
-
/*
|
273
|
-
* Postmessage listener for when Prebid responds with requested native assets.
|
274
|
-
*/
|
275
|
-
function replaceAssets(event) {
|
276
|
-
var data = {};
|
277
289
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
if (errorCountEscapeHatch++ > 10) {
|
282
|
-
/*
|
283
|
-
* if for some reason Prebid never responds with the native assets,
|
284
|
-
* get rid of this listener because other messages won't stop coming
|
285
|
-
*/
|
286
|
-
stopListening();
|
287
|
-
}
|
288
|
-
return;
|
289
|
-
}
|
290
|
+
function replaceAssets(adId) {
|
291
|
+
return function(event) {
|
292
|
+
try {
|
290
293
|
|
291
|
-
|
292
|
-
const body = win.document.body.innerHTML;
|
293
|
-
const head = win.document.head.innerHTML;
|
294
|
+
var data = {};
|
294
295
|
|
295
|
-
|
296
|
+
try {
|
297
|
+
data = JSON.parse(event.data);
|
298
|
+
} catch (e) {
|
299
|
+
if (errorCountEscapeHatch++ > 10) {
|
300
|
+
// TODO: this should be a timeout, not an arbitrary cap on the number of messages received
|
301
|
+
/*
|
302
|
+
* if for some reason Prebid never responds with the native assets,
|
303
|
+
* get rid of this listener because other messages won't stop coming
|
304
|
+
*/
|
305
|
+
stopListening();
|
306
|
+
throw e;
|
307
|
+
}
|
308
|
+
return;
|
309
|
+
}
|
296
310
|
|
297
|
-
|
311
|
+
if (data.message === 'assetResponse' && data.adId === adId) {
|
312
|
+
if(hasDynamicRenderer(data)) {
|
313
|
+
runDynamicRenderer(adId, data, sendMessage, win);
|
314
|
+
return;
|
315
|
+
}
|
298
316
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
callback = () => {
|
304
|
-
fireNativeImpressionTrackers(data.adId, sendMessage);
|
305
|
-
addNativeClickTrackers(data.adId, data.ortb, sendMessage);
|
306
|
-
}
|
307
|
-
}
|
317
|
+
// add GAM %%CLICK_URL_UNESC%% to the data object to be eventually used in renderers
|
318
|
+
data.clickUrlUnesc = clickUrlUnesc;
|
319
|
+
const body = win.document.body.innerHTML;
|
320
|
+
const head = win.document.head.innerHTML;
|
308
321
|
|
309
|
-
|
310
|
-
|
311
|
-
|
322
|
+
callback = ((cb) => {
|
323
|
+
return () => {
|
324
|
+
fireNativeImpressionTrackers(data.adId, sendMessage);
|
325
|
+
addNativeClickTrackers(data.adId, sendMessage);
|
326
|
+
cb && cb();
|
327
|
+
}
|
328
|
+
})(callback);
|
312
329
|
|
313
|
-
|
314
|
-
} else if (document.getElementById('pb-native-renderer')) {
|
315
|
-
document.getElementById('pb-native-renderer').addEventListener('load', function() {
|
316
|
-
const newHtml = (win.renderAd && win.renderAd(renderPayload)) || '';
|
330
|
+
if (head) win.document.head.innerHTML = replace(head, data);
|
317
331
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
332
|
+
|
333
|
+
data.assets = data.assets || [];
|
334
|
+
let renderPayload = data.assets;
|
335
|
+
if (data.ortb) {
|
336
|
+
renderPayload.ortb = data.ortb;
|
337
|
+
}
|
338
|
+
|
339
|
+
// if there's a rendererUrl, we need to check whether it's already been loaded.
|
340
|
+
// There are 3 scenarios:
|
341
|
+
// 1) it's already been loaded (window.renderAd is present)
|
342
|
+
// 2) it is currently being loaded (through a script tag with id "pb-native-renderer")
|
343
|
+
// 3) it hasn't been loaded yet
|
344
|
+
// 1 and 2 seem intended to work with logic in nativeRenderManager.js, which (sometimes) loads rendererUrl through a <script id="pb-native-renderer">, but they could conceivably be used in an undocumented way to embed renderer logic directly in the creative.
|
345
|
+
if ((data.hasOwnProperty('rendererUrl') && data.rendererUrl) || (hasPbNativeData() && win.pbNativeData.hasOwnProperty('rendererUrl'))) {
|
346
|
+
if (win.renderAd) {
|
347
|
+
const newHtml = (win.renderAd && win.renderAd(renderPayload)) || '';
|
348
|
+
|
349
|
+
renderAd(newHtml, data);
|
350
|
+
} else if (document.getElementById('pb-native-renderer')) {
|
351
|
+
document.getElementById('pb-native-renderer').addEventListener('load', function () {
|
352
|
+
const newHtml = (win.renderAd && win.renderAd(renderPayload)) || '';
|
353
|
+
|
354
|
+
renderAd(newHtml, data);
|
355
|
+
});
|
356
|
+
} else {
|
357
|
+
loadScript(win, ((hasPbNativeData() && win.pbNativeData.hasOwnProperty('rendererUrl') && win.pbNativeData.rendererUrl) || data.rendererUrl), function () {
|
358
|
+
const newHtml = (win.renderAd && win.renderAd(renderPayload)) || '';
|
359
|
+
|
360
|
+
renderAd(newHtml, data);
|
361
|
+
});
|
362
|
+
}
|
363
|
+
} else if ((data.hasOwnProperty('adTemplate') && data.adTemplate) || (hasPbNativeData() && win.pbNativeData.hasOwnProperty('adTemplate'))) {
|
364
|
+
const template = (hasPbNativeData() && win.pbNativeData.hasOwnProperty('adTemplate') && win.pbNativeData.adTemplate) || data.adTemplate;
|
365
|
+
const newHtml = replace(template, data);
|
323
366
|
|
324
367
|
renderAd(newHtml, data);
|
325
|
-
}
|
368
|
+
} else {
|
369
|
+
const newHtml = replace(body, data);
|
370
|
+
|
371
|
+
win.document.body.innerHTML = newHtml;
|
372
|
+
callback && callback(); // all the other scenarios hit the callback via renderAd()
|
373
|
+
stopListening();
|
374
|
+
}
|
326
375
|
}
|
327
|
-
}
|
328
|
-
|
329
|
-
const newHtml = replace(template, data);
|
330
|
-
|
331
|
-
renderAd(newHtml, data);
|
332
|
-
} else {
|
333
|
-
const newHtml = replace(body, data);
|
334
|
-
|
335
|
-
win.document.body.innerHTML = newHtml;
|
336
|
-
callback && callback();
|
337
|
-
stopListening();
|
376
|
+
} catch (e) {
|
377
|
+
errCallback && errCallback(e);
|
338
378
|
}
|
339
379
|
}
|
340
380
|
}
|
341
381
|
|
342
382
|
/** This function returns the element that contains the current iframe. */
|
343
383
|
function getCurrentFrameContainer(win) {
|
344
|
-
|
345
|
-
|
384
|
+
try {
|
385
|
+
let currentWindow = win;
|
386
|
+
let currentParentWindow;
|
346
387
|
|
347
|
-
|
388
|
+
while (currentWindow !== win.top) {
|
348
389
|
currentParentWindow = currentWindow.parent;
|
349
390
|
if (!currentParentWindow.frames || !currentParentWindow.frames.length) return null;
|
350
391
|
for (let idx = 0; idx < currentParentWindow.frames.length; idx++)
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
}
|
392
|
+
if (currentParentWindow.frames[idx] === currentWindow) {
|
393
|
+
if (!currentParentWindow.document) return null;
|
394
|
+
for (let frameElement of currentParentWindow.document.getElementsByTagName('iframe')) {
|
395
|
+
if (!frameElement.contentWindow) return null;
|
396
|
+
if (frameElement.contentWindow === currentWindow) {
|
397
|
+
return frameElement.parentElement;
|
398
|
+
}
|
359
399
|
}
|
400
|
+
}
|
401
|
+
}
|
402
|
+
} catch (e) {
|
403
|
+
// parent is cross-frame
|
360
404
|
}
|
361
|
-
}
|
405
|
+
}
|
362
406
|
|
363
407
|
function renderAd(html, bid) {
|
364
408
|
// if the current iframe is not a safeframe, try to set the
|
365
409
|
// current iframe width to the width of the container. This
|
366
410
|
// is to handle the case where the native ad is rendered inside
|
367
411
|
// a GAM display ad.
|
412
|
+
|
413
|
+
// NOTE: this may be unnecessary, see https://github.com/prebid/prebid-universal-creative/issues/253.
|
368
414
|
if (!isSafeFrame(window)) {
|
369
415
|
let iframeContainer = getCurrentFrameContainer(win);
|
370
416
|
if (iframeContainer && iframeContainer.children && iframeContainer.children[0]) {
|
371
|
-
const iframe = iframeContainer.children[0];
|
417
|
+
const iframe = iframeContainer.children[0];
|
372
418
|
if (iframe.width === '1' && iframe.height === '1') {
|
373
419
|
let width = iframeContainer.getBoundingClientRect().width;
|
374
420
|
win.document.body.style.width = `${width}px`;
|
375
421
|
}
|
376
422
|
}
|
377
423
|
}
|
424
|
+
|
425
|
+
//substitute CLICK_URL_UNESC with actual value
|
426
|
+
html = html.replaceAll(CLICK_URL_UNESC, bid.clickUrlUnesc || "");
|
427
|
+
|
378
428
|
win.document.body.innerHTML += html;
|
379
429
|
callback && callback();
|
380
|
-
win.removeEventListener('message', replaceAssets);
|
381
430
|
stopListening();
|
382
|
-
|
431
|
+
const resize = () => requestHeightResize(
|
432
|
+
bid.adId,
|
433
|
+
(document.body.clientHeight || document.body.offsetHeight),
|
434
|
+
document.body.clientWidth > 1 ? document.body.clientWidth : undefined
|
435
|
+
);
|
436
|
+
document.readyState === 'complete' ? resize() : window.onload = resize;
|
383
437
|
|
384
438
|
if (typeof window.postRenderAd === 'function') {
|
385
439
|
window.postRenderAd(bid);
|
@@ -405,22 +459,22 @@ export function newNativeAssetManager(win, pubUrl) {
|
|
405
459
|
}
|
406
460
|
|
407
461
|
ortb.assets.forEach(asset => {
|
408
|
-
html = html.
|
462
|
+
html = html.replaceAll(`##hb_native_asset_id_${asset.id}##`, getAssetValue(asset));
|
409
463
|
if (asset.link && asset.link.url) {
|
410
|
-
html = html.
|
464
|
+
html = html.replaceAll(`##hb_native_asset_link_id_${asset.id}##`, asset.link.url);
|
411
465
|
}
|
412
466
|
});
|
413
467
|
|
414
468
|
html = html.replaceAll(/##hb_native_asset_id_\d+##/gm, '');
|
415
469
|
|
416
470
|
if (ortb.privacy) {
|
417
|
-
html = html.
|
471
|
+
html = html.replaceAll("##hb_native_privacy##", ortb.privacy);
|
418
472
|
}
|
419
473
|
|
420
474
|
if (ortb.link) {
|
421
475
|
html = html.replaceAll("##hb_native_linkurl##", ortb.link.url);
|
422
476
|
}
|
423
|
-
|
477
|
+
|
424
478
|
return html;
|
425
479
|
}
|
426
480
|
|
@@ -12,16 +12,16 @@ export function fireNativeImpressionTrackers(adId, sendMessage) {
|
|
12
12
|
sendMessage(message);
|
13
13
|
}
|
14
14
|
|
15
|
-
export function addNativeClickTrackers(adId,
|
15
|
+
export function addNativeClickTrackers(adId, sendMessage) {
|
16
16
|
const message = {
|
17
17
|
message: 'Prebid Native',
|
18
18
|
action: 'click',
|
19
|
-
adId
|
19
|
+
adId
|
20
20
|
};
|
21
21
|
const adElements = document.getElementsByClassName(AD_ANCHOR_CLASS_NAME) || [];
|
22
22
|
// get all assets that have 'link' property, map asset.id -> asset.link
|
23
23
|
for (let i = 0; i < adElements.length; i++) {
|
24
|
-
adElements[i].addEventListener('
|
24
|
+
adElements[i].addEventListener('pointerdown', (event) => {
|
25
25
|
let targetElement = event.target;
|
26
26
|
// check if clicked element is associated with any native asset (look for 'hb_native_asset_id' attribute)
|
27
27
|
let assetId = targetElement && targetElement.getAttribute(ASSET_ID_ELEMENT_ATTRIBUTE);
|
@@ -1,76 +1,48 @@
|
|
1
1
|
/*
|
2
2
|
* Script to handle firing impression and click trackers from native teamplates
|
3
3
|
*/
|
4
|
-
import {
|
5
|
-
import {prebidMessenger} from './messaging.js';
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
// START OF MAIN CODE
|
51
|
-
let renderNativeAd = function(doc, nativeTag) {
|
52
|
-
window.pbNativeData = nativeTag;
|
53
|
-
sendMessage = prebidMessenger(nativeTag.pubUrl, win);
|
54
|
-
const nativeAssetManager = newNativeAssetManager(window, nativeTag.pubUrl);
|
55
|
-
|
56
|
-
if (nativeTag.hasOwnProperty('adId')) {
|
57
|
-
|
58
|
-
if (nativeTag.hasOwnProperty('rendererUrl') && !nativeTag.rendererUrl.match(/##.*##/i)) {
|
59
|
-
const scr = doc.createElement('SCRIPT');
|
60
|
-
scr.src = nativeTag.rendererUrl,
|
61
|
-
scr.id = 'pb-native-renderer';
|
62
|
-
doc.body.appendChild(scr);
|
63
|
-
}
|
64
|
-
nativeAssetManager.loadAssets(nativeTag.adId, () => {
|
65
|
-
fireNativeImpTracker(nativeTag.adId);
|
66
|
-
fireNativeCallback();
|
67
|
-
});
|
68
|
-
} else {
|
69
|
-
console.warn("Prebid Native Tag object was missing 'adId'.");
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
return {
|
74
|
-
renderNativeAd
|
75
|
-
}
|
4
|
+
import {newNativeAssetManager} from './nativeAssetManager';
|
5
|
+
import {prebidMessenger, renderEventMessage} from './messaging.js';
|
6
|
+
|
7
|
+
export function newNativeRenderManager(win, mkMessenger = prebidMessenger, assetMgr = newNativeAssetManager) {
|
8
|
+
let sendMessage;
|
9
|
+
|
10
|
+
|
11
|
+
let renderNativeAd = function (doc, nativeTag) {
|
12
|
+
window.pbNativeData = nativeTag;
|
13
|
+
sendMessage = mkMessenger(nativeTag.pubUrl, win);
|
14
|
+
|
15
|
+
function signalResult(adId, errorInfo) {
|
16
|
+
sendMessage(renderEventMessage(adId, errorInfo));
|
17
|
+
}
|
18
|
+
|
19
|
+
try {
|
20
|
+
const nativeAssetManager = assetMgr(window, nativeTag);
|
21
|
+
|
22
|
+
if (nativeTag.adId != null) {
|
23
|
+
|
24
|
+
if (nativeTag.hasOwnProperty('rendererUrl') && !nativeTag.rendererUrl.match(/##.*##/i)) {
|
25
|
+
const scr = doc.createElement('SCRIPT');
|
26
|
+
scr.src = nativeTag.rendererUrl,
|
27
|
+
scr.id = 'pb-native-renderer';
|
28
|
+
doc.body.appendChild(scr);
|
29
|
+
}
|
30
|
+
nativeAssetManager.loadAssets(nativeTag.adId, () => {
|
31
|
+
signalResult(nativeTag.adId);
|
32
|
+
}, (e) => {
|
33
|
+
signalResult(nativeTag.adId, {reason: 'exception', message: e.message});
|
34
|
+
});
|
35
|
+
} else {
|
36
|
+
signalResult(null, {reason: 'missingDocOrAdid'});
|
37
|
+
console.warn('Prebid Native Tag object was missing \'adId\'.');
|
38
|
+
}
|
39
|
+
} catch (e) {
|
40
|
+
signalResult(nativeTag && nativeTag.adId, {reason: 'exception', message: e.message});
|
41
|
+
console.error('Error rendering ad', e);
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
return {
|
46
|
+
renderNativeAd
|
47
|
+
};
|
76
48
|
}
|
@@ -47,7 +47,7 @@ export function newNativeTrackerManager(win) {
|
|
47
47
|
|
48
48
|
for (let i = 0; i < adElements.length; i++) {
|
49
49
|
let adId = readAdIdFromSingleElement(adElements[i]);
|
50
|
-
adElements[i].addEventListener('
|
50
|
+
adElements[i].addEventListener('pointerdown', function(event) {
|
51
51
|
listener(event, adId);
|
52
52
|
}, true);
|
53
53
|
}
|
@@ -83,7 +83,7 @@ export function newNativeTrackerManager(win) {
|
|
83
83
|
attachClickListeners(false, boundedLoadMobileClickTrackers);
|
84
84
|
|
85
85
|
(impTrackers || []).forEach(triggerPixel);
|
86
|
-
|
86
|
+
|
87
87
|
// fire impression IMG trackers
|
88
88
|
eventtrackers
|
89
89
|
.filter(tracker => tracker.event === 1 && tracker.method === 1)
|
package/src/renderingManager.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import { parseUrl, transformAuctionTargetingData } from './utils';
|
2
2
|
import { canLocatePrebid } from './environment';
|
3
3
|
import { insertElement, getEmptyIframe } from './domHelper';
|
4
|
-
import {prebidMessenger} from './messaging.js';
|
4
|
+
import {prebidMessenger, renderEventMessage} from './messaging.js';
|
5
|
+
import {hasDynamicRenderer, runDynamicRenderer} from './dynamicRenderer.js';
|
5
6
|
|
6
7
|
export function renderBannerOrDisplayAd(doc, dataObject) {
|
7
8
|
const targetingData = transformAuctionTargetingData(dataObject);
|
@@ -19,18 +20,23 @@ export function renderBannerOrDisplayAd(doc, dataObject) {
|
|
19
20
|
* @param {string} adId Id of creative to render
|
20
21
|
*/
|
21
22
|
export function renderLegacy(doc, adId) {
|
23
|
+
let found = false;
|
22
24
|
let w = window;
|
23
25
|
for (let i = 0; i < 10; i++) {
|
24
26
|
w = w.parent;
|
25
27
|
if (w.$$PREBID_GLOBAL$$) {
|
26
28
|
try {
|
27
29
|
w.$$PREBID_GLOBAL$$.renderAd(doc, adId);
|
30
|
+
found = true;
|
28
31
|
break;
|
29
32
|
} catch (e) {
|
30
33
|
continue;
|
31
34
|
}
|
32
35
|
}
|
33
36
|
}
|
37
|
+
if (!found) {
|
38
|
+
console.error("Unable to locate $$PREBID_GLOBAL$$.renderAd function!");
|
39
|
+
}
|
34
40
|
}
|
35
41
|
|
36
42
|
/**
|
@@ -44,6 +50,7 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
44
50
|
let adServerDomain = pubAdServerDomain || win.location.hostname;
|
45
51
|
let fullAdServerDomain = windowLocation.protocol + '//' + adServerDomain;
|
46
52
|
const sendMessage = prebidMessenger(pubUrl, win);
|
53
|
+
const signalRenderResult = (errorInfo) => sendMessage(renderEventMessage(adId, errorInfo));
|
47
54
|
|
48
55
|
function renderAd(ev) {
|
49
56
|
let key = ev.message ? "message" : "data";
|
@@ -59,6 +66,10 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
59
66
|
adObject.message === "Prebid Response" &&
|
60
67
|
adObject.adId === adId
|
61
68
|
) {
|
69
|
+
if (hasDynamicRenderer(adObject)) {
|
70
|
+
runDynamicRenderer(adId, adObject, sendMessage, win);
|
71
|
+
return;
|
72
|
+
}
|
62
73
|
try {
|
63
74
|
let body = win.document.body;
|
64
75
|
let ad = adObject.ad;
|
@@ -67,7 +78,7 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
67
78
|
let height = adObject.height;
|
68
79
|
|
69
80
|
if (adObject.mediaType === "video") {
|
70
|
-
signalRenderResult(
|
81
|
+
signalRenderResult({
|
71
82
|
reason: "preventWritingOnMainDocument",
|
72
83
|
message: `Cannot render video ad ${adId}`,
|
73
84
|
});
|
@@ -78,7 +89,7 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
78
89
|
iframe.contentDocument.open();
|
79
90
|
iframe.contentDocument.write(ad);
|
80
91
|
iframe.contentDocument.close();
|
81
|
-
signalRenderResult(
|
92
|
+
signalRenderResult();
|
82
93
|
} else if (url) {
|
83
94
|
const iframe = getEmptyIframe(height, width);
|
84
95
|
iframe.style.display = "inline";
|
@@ -86,9 +97,9 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
86
97
|
iframe.src = url;
|
87
98
|
|
88
99
|
insertElement(iframe, document, "body");
|
89
|
-
signalRenderResult(
|
100
|
+
signalRenderResult();
|
90
101
|
} else {
|
91
|
-
signalRenderResult(
|
102
|
+
signalRenderResult({
|
92
103
|
reason: "noAd",
|
93
104
|
message: `No ad for ${adId}`,
|
94
105
|
});
|
@@ -97,22 +108,10 @@ export function renderCrossDomain(win, adId, pubAdServerDomain = '', pubUrl) {
|
|
97
108
|
);
|
98
109
|
}
|
99
110
|
} catch (e) {
|
100
|
-
signalRenderResult(
|
111
|
+
signalRenderResult({ reason: "exception", message: e.message });
|
101
112
|
console.log(`Error in rendering ad`, e);
|
102
113
|
}
|
103
114
|
}
|
104
|
-
|
105
|
-
function signalRenderResult(success, { reason, message } = {}) {
|
106
|
-
const payload = {
|
107
|
-
message: "Prebid Event",
|
108
|
-
adId,
|
109
|
-
event: success ? "adRenderSucceeded" : "adRenderFailed",
|
110
|
-
};
|
111
|
-
if (!success) {
|
112
|
-
payload.info = { reason, message };
|
113
|
-
}
|
114
|
-
sendMessage(payload);
|
115
|
-
}
|
116
115
|
}
|
117
116
|
|
118
117
|
function requestAdFromPrebid() {
|
package/src/utils.js
CHANGED
@@ -30,15 +30,6 @@ export function writeAdUrl(adUrl, width, height) {
|
|
30
30
|
document.body.appendChild(iframe);
|
31
31
|
}
|
32
32
|
|
33
|
-
export function writeAdHtml(markup) {
|
34
|
-
// remove <?xml> and <!doctype> tags
|
35
|
-
// https://github.com/prebid/prebid-universal-creative/issues/134
|
36
|
-
markup = markup.replace(/\<(\?xml|(\!DOCTYPE[^\>\[]+(\[[^\]]+)?))+[^>]+\>/g, '');
|
37
|
-
postscribe(document.body, markup, {
|
38
|
-
error: console.error
|
39
|
-
});
|
40
|
-
}
|
41
|
-
|
42
33
|
export function sendRequest(url, callback) {
|
43
34
|
function reqListener() {
|
44
35
|
callback(oReq.responseText);
|