forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'prebid:master' into master
- Loading branch information
Showing
91 changed files
with
5,702 additions
and
2,159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,105 +1,13 @@ | ||
<script> | ||
// this script can be returned by an ad server delivering a cross domain iframe, into which the | ||
// creative will be rendered, e.g. GAM delivering a SafeFrame | ||
|
||
const windowLocation = window.location; | ||
const urlParser = document.createElement('a'); | ||
urlParser.href = '%%PATTERN:url%%'; | ||
const publisherDomain = urlParser.protocol + '//' + urlParser.hostname; | ||
const adId = '%%PATTERN:hb_adid%%'; | ||
|
||
function receiveMessage(ev) { | ||
const origin = ev.origin || ev.originalEvent.origin; | ||
if (origin === publisherDomain) { | ||
renderAd(ev); | ||
} | ||
} | ||
|
||
function renderAd(ev) { | ||
const key = ev.message ? 'message' : 'data'; | ||
let adObject = {}; | ||
try { | ||
adObject = JSON.parse(ev[key]); | ||
} catch (e) { | ||
return; | ||
} | ||
|
||
if (adObject.message && adObject.message === 'Prebid Response' && | ||
adObject.adId === adId) { | ||
try { | ||
const body = window.document.body; | ||
const ad = adObject.ad; | ||
const url = adObject.adUrl; | ||
const width = adObject.width; | ||
const height = adObject.height; | ||
|
||
if (adObject.mediaType === 'video') { | ||
signalRenderResult(false, { | ||
reason: 'preventWritingOnMainDocument', | ||
message: `Cannot render video ad ${adId}` | ||
}); | ||
console.log('Error trying to write ad.'); | ||
} else if (ad) { | ||
const frame = document.createElement('iframe'); | ||
frame.setAttribute('FRAMEBORDER', 0); | ||
frame.setAttribute('SCROLLING', 'no'); | ||
frame.setAttribute('MARGINHEIGHT', 0); | ||
frame.setAttribute('MARGINWIDTH', 0); | ||
frame.setAttribute('TOPMARGIN', 0); | ||
frame.setAttribute('LEFTMARGIN', 0); | ||
frame.setAttribute('ALLOWTRANSPARENCY', 'true'); | ||
frame.setAttribute('width', width); | ||
frame.setAttribute('height', height); | ||
body.appendChild(frame); | ||
frame.contentDocument.open(); | ||
frame.contentDocument.write(ad); | ||
frame.contentDocument.close(); | ||
signalRenderResult(true); | ||
} else if (url) { | ||
body.insertAdjacentHTML('beforeend', '<IFRAME SRC="' + url + '" FRAMEBORDER="0" SCROLLING="no" MARGINHEIGHT="0" MARGINWIDTH="0" TOPMARGIN="0" LEFTMARGIN="0" ALLOWTRANSPARENCY="true" WIDTH="' + width + '" HEIGHT="' + height + '"></IFRAME>'); | ||
signalRenderResult(true); | ||
} else { | ||
signalRenderResult(false, { | ||
reason: 'noAd', | ||
message: `No ad for ${adId}` | ||
}); | ||
console.log(`Error trying to write ad. No ad markup or adUrl for ${adId}`); | ||
} | ||
} catch (e) { | ||
signalRenderResult(false, {reason: 'exception', message: e.message}); | ||
console.log(`Error in rendering ad`, e); | ||
} | ||
} | ||
|
||
function signalRenderResult(success, {reason, message} = {}) { | ||
const payload = { | ||
message: 'Prebid Event', | ||
adId, | ||
event: success ? 'adRenderSucceeded' : 'adRenderFailed', | ||
} | ||
if (!success) { | ||
payload.info = {reason, message}; | ||
} | ||
window.parent.postMessage(JSON.stringify(payload), publisherDomain); | ||
} | ||
// this code is autogenerated, also available in 'build/creative/creative.js' | ||
<script>!function(){"use strict";var e=JSON.parse('{"FP":{"h0":"adRenderFailed","gV":"adRenderSucceeded"},"q_":{"Ex":"noAd","XW":"exception"}}');const t=e.FP.gV,n=e.FP.h0,r=e.q_.Ex,s=e.q_.XW,a={frameBorder:0,scrolling:"no",marginHeight:0,marginWidth:0,topMargin:0,leftMargin:0,allowTransparency:"true"};function i(e,t){const n=e.createElement("iframe");return t=Object.assign({},t,a),Object.entries(t).forEach((([e,t])=>n.setAttribute(e,t))),e.body.appendChild(n),n}window.renderAd=function(e=window){return function({adId:a,pubUrl:o,clickUrl:c}){const d=function(){const t=e.document.createElement("a");return t.href=o,t.protocol+"//"+t.host}();function g(t,n,r){e.parent.postMessage(JSON.stringify(Object.assign({message:t,adId:a},n)),d,r)}function u(e){g("Prebid Event",{event:null==e?t:n,info:e})}function h(t){let n={};try{n=JSON.parse(t[t.message?"message":"data"])}catch(e){return}if("Prebid Response"===n.message&&n.adId===a)try{let t=e.document;n.ad&&(t=i(t,{width:n.width,height:n.height}).contentDocument,t.open()),function({ad:e,adUrl:t,width:n,height:s},a,o=document){e||t?(t&&!e?i(o,{width:n,height:s,src:t}):(o.write(e),o.close()),a()):a({reason:r,message:"Missing ad markup or URL"})}(n,u,t)}catch(e){u({reason:s,message:e.message})}}const l=new MessageChannel;l.port1.onmessage=h,g("Prebid Request",{options:{clickUrl:c}},[l.port2]),e.addEventListener("message",h,!1)}}()}();</script> | ||
|
||
} | ||
|
||
|
||
function requestAdFromPrebid() { | ||
const message = JSON.stringify({ | ||
message: 'Prebid Request', | ||
adId | ||
}); | ||
const channel = new MessageChannel(); | ||
channel.port1.onmessage = renderAd; | ||
window.parent.postMessage(message, publisherDomain, [channel.port2]); | ||
} | ||
|
||
function listenAdFromPrebid() { | ||
window.addEventListener('message', receiveMessage, false); | ||
} | ||
|
||
listenAdFromPrebid(); | ||
requestAdFromPrebid(); | ||
<script> | ||
renderAd({ | ||
adId: '%%PATTERN:hb_adid%%', | ||
pubUrl: '%%PATTERN:url%%', | ||
clickUrl: '%%CLICK_URL_UNESC%%' | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import events from '../../src/constants.json'; | ||
|
||
export const PREBID_NATIVE = 'Prebid Native'; | ||
export const PREBID_REQUEST = 'Prebid Request'; | ||
export const PREBID_RESPONSE = 'Prebid Response'; | ||
export const PREBID_EVENT = 'Prebid Event'; | ||
export const AD_RENDER_SUCCEEDED = events.EVENTS.AD_RENDER_SUCCEEDED; | ||
export const AD_RENDER_FAILED = events.EVENTS.AD_RENDER_FAILED; | ||
export const NO_AD = events.AD_RENDER_FAILED_REASON.NO_AD; | ||
export const EXCEPTION = events.AD_RENDER_FAILED_REASON.EXCEPTION; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {mkFrame, writeAd} from './writer.js'; | ||
import { | ||
AD_RENDER_FAILED, | ||
AD_RENDER_SUCCEEDED, | ||
PREBID_EVENT, | ||
PREBID_RESPONSE, | ||
PREBID_REQUEST, | ||
EXCEPTION | ||
} from './constants.js'; | ||
|
||
export function renderer(win = window) { | ||
return function ({adId, pubUrl, clickUrl}) { | ||
const pubDomain = (function() { | ||
const a = win.document.createElement('a'); | ||
a.href = pubUrl; | ||
return a.protocol + '//' + a.host; | ||
})(); | ||
function sendMessage(type, payload, transfer) { | ||
win.parent.postMessage(JSON.stringify(Object.assign({message: type, adId}, payload)), pubDomain, transfer); | ||
} | ||
function cb(err) { | ||
sendMessage(PREBID_EVENT, { | ||
event: err == null ? AD_RENDER_SUCCEEDED : AD_RENDER_FAILED, | ||
info: err | ||
}); | ||
} | ||
function onMessage(ev) { | ||
let data = {}; | ||
try { | ||
data = JSON.parse(ev[ev.message ? 'message' : 'data']); | ||
} catch (e) { | ||
return; | ||
} | ||
if (data.message === PREBID_RESPONSE && data.adId === adId) { | ||
try { | ||
let doc = win.document | ||
if (data.ad) { | ||
doc = mkFrame(doc, {width: data.width, height: data.height}).contentDocument; | ||
doc.open(); | ||
} | ||
writeAd(data, cb, doc); | ||
} catch (e) { | ||
// eslint-disable-next-line standard/no-callback-literal | ||
cb({ reason: EXCEPTION, message: e.message }) | ||
} | ||
} | ||
} | ||
|
||
const channel = new MessageChannel(); | ||
channel.port1.onmessage = onMessage; | ||
sendMessage(PREBID_REQUEST, { | ||
options: {clickUrl} | ||
}, [channel.port2]); | ||
win.addEventListener('message', onMessage, false); | ||
} | ||
} | ||
window.renderAd = renderer(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import {emitAdRenderFail, emitAdRenderSucceeded, handleRender} from '../../src/adRendering.js'; | ||
import {writeAd} from './writer.js'; | ||
import {auctionManager} from '../../src/auctionManager.js'; | ||
import CONSTANTS from '../../src/constants.json'; | ||
import {inIframe, insertElement} from '../../src/utils.js'; | ||
import {getGlobal} from '../../src/prebidGlobal.js'; | ||
import {EXCEPTION} from './constants.js'; | ||
|
||
export function renderAdDirect(doc, adId, options) { | ||
let bid; | ||
function cb(err) { | ||
if (err != null) { | ||
emitAdRenderFail(Object.assign({id: adId, bid}, err)); | ||
} else { | ||
emitAdRenderSucceeded({doc, bid, adId}) | ||
} | ||
} | ||
function renderFn(adData) { | ||
writeAd(adData, cb, doc); | ||
if (doc.defaultView && doc.defaultView.frameElement) { | ||
doc.defaultView.frameElement.width = adData.width; | ||
doc.defaultView.frameElement.height = adData.height; | ||
} | ||
// TODO: this is almost certainly the wrong way to do this | ||
const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`); | ||
insertElement(creativeComment, doc, 'html'); | ||
} | ||
try { | ||
if (!adId || !doc) { | ||
// eslint-disable-next-line standard/no-callback-literal | ||
cb({ | ||
reason: CONSTANTS.AD_RENDER_FAILED_REASON.MISSING_DOC_OR_ADID, | ||
message: `missing ${adId ? 'doc' : 'adId'}` | ||
}); | ||
} else { | ||
bid = auctionManager.findBidByAdId(adId); | ||
|
||
if (FEATURES.VIDEO) { | ||
// TODO: could the video module implement this as a custom renderer, rather than a special case in here? | ||
const adUnit = bid && auctionManager.index.getAdUnit(bid); | ||
const videoModule = getGlobal().videoModule; | ||
if (adUnit?.video && videoModule) { | ||
videoModule.renderBid(adUnit.video.divId, bid); | ||
return; | ||
} | ||
} | ||
|
||
if ((doc === document && !inIframe())) { | ||
// eslint-disable-next-line standard/no-callback-literal | ||
cb({ | ||
reason: CONSTANTS.AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT, | ||
message: `renderAd was prevented from writing to the main document.` | ||
}) | ||
} else { | ||
handleRender(renderFn, {adId, options: {clickUrl: options?.clickThrough}, bidResponse: bid}); | ||
} | ||
} | ||
} catch (e) { | ||
// eslint-disable-next-line standard/no-callback-literal | ||
cb({reason: EXCEPTION, message: e.message}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {NO_AD} from './constants.js'; | ||
|
||
const IFRAME_ATTRS = { | ||
frameBorder: 0, | ||
scrolling: 'no', | ||
marginHeight: 0, | ||
marginWidth: 0, | ||
topMargin: 0, | ||
leftMargin: 0, | ||
allowTransparency: 'true', | ||
}; | ||
|
||
export function mkFrame(doc, attrs) { | ||
const frame = doc.createElement('iframe'); | ||
attrs = Object.assign({}, attrs, IFRAME_ATTRS); | ||
Object.entries(attrs).forEach(([k, v]) => frame.setAttribute(k, v)); | ||
doc.body.appendChild(frame); | ||
return frame; | ||
} | ||
|
||
export function writeAd({ad, adUrl, width, height}, cb, doc = document) { | ||
if (!ad && !adUrl) { | ||
// eslint-disable-next-line standard/no-callback-literal | ||
cb({reason: NO_AD, message: 'Missing ad markup or URL'}); | ||
} else { | ||
if (adUrl && !ad) { | ||
mkFrame(doc, {width, height, src: adUrl}) | ||
} else { | ||
doc.write(ad); | ||
doc.close(); | ||
} | ||
cb(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.