Skip to content

Commit

Permalink
Merged PM_Revamp branch
Browse files Browse the repository at this point in the history
  • Loading branch information
pm-harshad-mane committed Aug 10, 2017
2 parents 28b379c + 98e0dc6 commit 2808b0b
Show file tree
Hide file tree
Showing 4 changed files with 470 additions and 75 deletions.
246 changes: 171 additions & 75 deletions src/adapters/pubmatic.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var utils = require('../utils.js');
var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
const constants = require('../constants.json');

/**
* Adapter for requesting bids from Pubmatic.
Expand All @@ -10,128 +11,223 @@ var bidmanager = require('../bidmanager.js');
*/
var PubmaticAdapter = function PubmaticAdapter() {
var bids;
var _pm_pub_id;
var _pm_pub_age;
var _pm_pub_gender;
var _pm_pub_kvs;
var _pm_optimize_adslots = [];
var usersync = false;
var _secure = 0;
let _protocol = (window.location.protocol === 'https:' ? (_secure = 1, 'https') : 'http') + '://';
let iframe;

function _callBids(params) {
bids = params.bids;
_pm_optimize_adslots = [];
for (var i = 0; i < bids.length; i++) {
var bid = bids[i];
// bidmanager.pbCallbackMap['' + bid.params.adSlot] = bid;
_pm_pub_id = _pm_pub_id || bid.params.publisherId;
_pm_pub_age = _pm_pub_age || (bid.params.age || '');
_pm_pub_gender = _pm_pub_gender || (bid.params.gender || '');
_pm_pub_kvs = _pm_pub_kvs || (bid.params.kvs || '');
_pm_optimize_adslots.push(bid.params.adSlot);
var dealChannelValues = {
1: 'PMP',
5: 'PREF',
6: 'PMPG'
};

var customPars = {
'kadgender': 'gender',
'age': 'kadage',
'dctr': 'dctr', // Custom Targeting
'wiid': 'wiid', // Wrapper Impression ID
'profId': 'profId', // Legacy: Profile ID
'verId': 'verId', // Legacy: version ID
'pmzoneid': { // Zone ID
n: 'pmZoneId',
m: function(zoneId) {
if (utils.isStr(zoneId)) {
return zoneId.split(',').slice(0, 50).join();
} else {
return '';
}
}
}
};

function _initConf() {
var conf = {},
currTime = new Date();

conf.SAVersion = '1100';
conf.wp = 'PreBid';
conf.js = 1;
conf.wv = constants.REPO_AND_VERSION;
_secure && (conf.sec = 1);
conf.screenResolution = screen.width + 'x' + screen.height;
conf.ranreq = Math.random();
conf.inIframe = window != top ? '1' : '0';

// istanbul ignore else
if (window.navigator.cookieEnabled === false) {
conf.fpcd = '1';
}

try {
conf.pageURL = window.top.location.href;
conf.refurl = window.top.document.referrer;
} catch (e) {
conf.pageURL = window.location.href;
conf.refurl = window.document.referrer;
}

// Load pubmatic script in an iframe, because they call document.write
_getBids();
conf.kltstamp = currTime.getFullYear() +
'-' + (currTime.getMonth() + 1) +
'-' + currTime.getDate() +
' ' + currTime.getHours() +
':' + currTime.getMinutes() +
':' + currTime.getSeconds();
conf.timezone = currTime.getTimezoneOffset() / 60 * -1;

return conf;
}

function _getBids() {
// create the iframe
iframe = utils.createInvisibleIframe();
function _handleCustomParams(params, conf) {
// istanbul ignore else
if (!conf.kadpageurl) {
conf.kadpageurl = conf.pageURL;
}

var elToAppend = document.getElementsByTagName('head')[0];
var key, value, entry;
for (key in customPars) {
// istanbul ignore else
if (customPars.hasOwnProperty(key)) {
value = params[key];
// istanbul ignore else
if (value) {
entry = customPars[key];

if (typeof entry === 'object') {
value = entry.m(value, conf);
key = entry.n;
} else {
if (utils.isStr(value)) {
key = customPars[key];
} else {
utils.logWarn('PubMatic: Ignoring param key: ' + customPars[key] + ', expects string-value, found ' + typeof value);
}
}

// istanbul ignore else
if (value) {
conf[key] = value;
}
}
}
}
return conf;
}

// insert the iframe into document
elToAppend.insertBefore(iframe, elToAppend.firstChild);
function _cleanSlots(slots) {
var i,
len = slots.length,
tempSlot,
tempSlots = [];

for (i = 0; i < len; i++) {
tempSlot = slots[i];
// istanbul ignore else
if (utils.isStr(tempSlot)) {
tempSlot = tempSlot.replace(/^\s+/g, '').replace(/\s+$/g, '');
// istanbul ignore else
if (tempSlot.length > 0) {
tempSlots.push(tempSlot);
}
}
}

return tempSlots;
}

function _legacyExecution(conf, slots) {
var url = _generateLegacyCall(conf, slots);
iframe = utils.createInvisibleIframe();
var elToAppend = document.getElementsByTagName('head')[0];
elToAppend.insertBefore(iframe, elToAppend.firstChild);
var iframeDoc = utils.getIframeDocument(iframe);
iframeDoc.write(_createRequestContent());
var content = utils.createContentToExecuteExtScriptInFriendlyFrame(url);
content = content.replace(`<!--POST_SCRIPT_TAG_MACRO-->`, `<script>window.parent.$$PREBID_GLOBAL$$.handlePubmaticCallback(window.bidDetailsMap, window.progKeyValueMap);</script>`);
iframeDoc.write(content);
iframeDoc.close();
}

function _createRequestContent() {
var content = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' +
' "http://www.w3.org/TR/html4/loose.dtd"><html><head><base target="_top" /><scr' +
'ipt>inDapIF=true;</scr' + 'ipt></head>';
content += '<body>';
content += '<scr' + 'ipt>';
content += '' +
'window.pm_pub_id = "%%PM_PUB_ID%%";' +
'window.pm_optimize_adslots = [%%PM_OPTIMIZE_ADSLOTS%%];' +
'window.kaddctr = "%%PM_ADDCTR%%";' +
'window.kadgender = "%%PM_GENDER%%";' +
'window.kadage = "%%PM_AGE%%";' +
'window.pm_async_callback_fn = "window.parent.$$PREBID_GLOBAL$$.handlePubmaticCallback";';

content += '</scr' + 'ipt>';

var map = {};
map.PM_PUB_ID = _pm_pub_id;
map.PM_ADDCTR = _pm_pub_kvs;
map.PM_GENDER = _pm_pub_gender;
map.PM_AGE = _pm_pub_age;
map.PM_OPTIMIZE_ADSLOTS = _pm_optimize_adslots.map(function (adSlot) {
return "'" + adSlot + "'";
}).join(',');

content += '<scr' + 'ipt src="https://ads.pubmatic.com/AdServer/js/gshowad.js"></scr' + 'ipt>';
content += '<scr' + 'ipt>';
content += '</scr' + 'ipt>';
content += '</body></html>';
content = utils.replaceTokenInString(content, map, '%%');

return content;
function _generateLegacyCall(conf, slots) {
var request_url = 'gads.pubmatic.com/AdServer/AdCallAggregator';
return _protocol + request_url + '?' + utils.parseQueryStringParameters(conf) + 'adslots=' + encodeURIComponent('[' + slots.join(',') + ']');
}

$$PREBID_GLOBAL$$.handlePubmaticCallback = function () {
let bidDetailsMap = {};
let progKeyValueMap = {};
try {
bidDetailsMap = iframe.contentWindow.bidDetailsMap;
progKeyValueMap = iframe.contentWindow.progKeyValueMap;
} catch (e) {
utils.logError(e, 'Error parsing Pubmatic response');
function _initUserSync(pubId) {
// istanbul ignore else
if (!usersync) {
var iframe = utils.createInvisibleIframe();
iframe.src = _protocol + 'ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=' + pubId;
utils.insertElement(iframe, document);
usersync = true;
}
}

function _callBids(params) {
var conf = _initConf(),
slots = [];

conf.pubId = 0;
bids = params.bids || [];

for (var i = 0; i < bids.length; i++) {
var bid = bids[i];
conf.pubId = conf.pubId || bid.params.publisherId;
conf = _handleCustomParams(bid.params, conf);
slots.push(bid.params.adSlot);
}

slots = _cleanSlots(slots);

// istanbul ignore else
if (conf.pubId && slots.length > 0) {
_legacyExecution(conf, slots);
}

_initUserSync(conf.pubId);
}

$$PREBID_GLOBAL$$.handlePubmaticCallback = function(bidDetailsMap, progKeyValueMap) {
var i;
var adUnit;
var adUnitInfo;
var bid;
var bidResponseMap = bidDetailsMap || {};
var bidInfoMap = progKeyValueMap || {};
var dimensions;
var bidResponseMap = bidDetailsMap;
var bidInfoMap = progKeyValueMap;

if (!bidResponseMap || !bidInfoMap) {
return;
}

for (i = 0; i < bids.length; i++) {
var adResponse;
bid = bids[i].params;

adUnit = bidResponseMap[bid.adSlot] || {};

// adUnitInfo example: bidstatus=0;bid=0.0000;bidid=39620189@320x50;wdeal=

// if using DFP GPT, the params string comes in the format:
// "bidstatus;1;bid;5.0000;bidid;hb_test@468x60;wdeal;"
// the code below detects and handles this.
// istanbul ignore else
if (bidInfoMap[bid.adSlot] && bidInfoMap[bid.adSlot].indexOf('=') === -1) {
bidInfoMap[bid.adSlot] = bidInfoMap[bid.adSlot].replace(/([a-z]+);(.[^;]*)/ig, '$1=$2');
}

adUnitInfo = (bidInfoMap[bid.adSlot] || '').split(';').reduce(function (result, pair) {
adUnitInfo = (bidInfoMap[bid.adSlot] || '').split(';').reduce(function(result, pair) {
var parts = pair.split('=');
result[parts[0]] = parts[1];
return result;
}, {});

if (adUnitInfo.bidstatus === '1') {
dimensions = adUnitInfo.bidid.split('@')[1].split('x');
adResponse = bidfactory.createBid(1);
adResponse.bidderCode = 'pubmatic';
adResponse.adSlot = bid.adSlot;
adResponse.cpm = Number(adUnitInfo.bid);
adResponse.ad = unescape(adUnit.creative_tag);
adResponse.ad += utils.createTrackPixelIframeHtml(decodeURIComponent(adUnit.tracking_url));
adResponse.width = dimensions[0];
adResponse.height = dimensions[1];
adResponse.width = adUnit.width;
adResponse.height = adUnit.height;
adResponse.dealId = adUnitInfo.wdeal;
adResponse.dealChannel = dealChannelValues[adUnit.deal_channel] || null;

bidmanager.addBidResponse(bids[i].placementCode, adResponse);
} else {
Expand Down
13 changes: 13 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,16 @@ export function getBidderRequest(bidder, adUnitCode) {
.filter(bid => bid.bidder === bidder && bid.placementCode === adUnitCode).length > 0;
}) || { start: null, requestId: null };
}

/**
* Returns content for a friendly iframe to execute a URL in script tag
* @param {url} URL to be executed in a script tag in friendly iframe
* <!--PRE_SCRIPT_TAG_MACRO--> and <!--POST_SCRIPT_TAG_MACRO--> are macros left to be replaced if required
*/
export function createContentToExecuteExtScriptInFriendlyFrame(url) {
if (!url) {
return '';
}

return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><base target="_top" /><script>inDapIF=true;</script></head><body><!--PRE_SCRIPT_TAG_MACRO--><script src="${url}"></script><!--POST_SCRIPT_TAG_MACRO--></body></html>`;
}
Loading

0 comments on commit 2808b0b

Please sign in to comment.