UNPKG

mk9-prebid

Version:

Header Bidding Management Library

266 lines (227 loc) 7.29 kB
import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; const BIDDER_CODE = 'onomagic'; const URL = 'https://bidder.onomagic.com/hb'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], isBidRequestValid, buildRequests, interpretResponse, getUserSyncs }; function buildRequests(bidReqs, bidderRequest) { try { let referrer = ''; if (bidderRequest && bidderRequest.refererInfo) { referrer = bidderRequest.refererInfo.referer; } const onomagicImps = []; const publisherId = utils.getBidIdParameter('publisherId', bidReqs[0].params); utils._each(bidReqs, function (bid) { let bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes; bidSizes = ((utils.isArray(bidSizes) && utils.isArray(bidSizes[0])) ? bidSizes : [bidSizes]); bidSizes = bidSizes.filter(size => utils.isArray(size)); const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})); const element = document.getElementById(bid.adUnitCode); const minSize = _getMinSize(processedSizes); const viewabilityAmount = _isViewabilityMeasurable(element) ? _getViewability(element, utils.getWindowTop(), minSize) : 'na'; const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount); const imp = { id: bid.bidId, banner: { format: processedSizes, ext: { viewability: viewabilityAmountRounded } }, tagid: String(bid.adUnitCode) }; const bidFloor = _getBidFloor(bid); if (bidFloor) { imp.bidfloor = bidFloor; } onomagicImps.push(imp); }); const onomagicBidReq = { id: utils.getUniqueIdentifierStr(), imp: onomagicImps, site: { domain: utils.parseUrl(referrer).host, page: referrer, publisher: { id: publisherId } }, device: { devicetype: _getDeviceType(), w: screen.width, h: screen.height }, tmax: config.getConfig('bidderTimeout') }; return { method: 'POST', url: URL, data: JSON.stringify(onomagicBidReq), options: {contentType: 'text/plain', withCredentials: false} }; } catch (e) { utils.logError(e, {bidReqs, bidderRequest}); } } function isBidRequestValid(bid) { if (bid.bidder !== BIDDER_CODE || typeof bid.params === 'undefined') { return false; } if (typeof bid.params.publisherId === 'undefined') { return false; } return true; } function interpretResponse(serverResponse) { if (!serverResponse.body || typeof serverResponse.body != 'object') { utils.logWarn('Onomagic server returned empty/non-json response: ' + JSON.stringify(serverResponse.body)); return []; } const { body: {id, seatbid} } = serverResponse; try { const onomagicBidResponses = []; if (id && seatbid && seatbid.length > 0 && seatbid[0].bid && seatbid[0].bid.length > 0) { seatbid[0].bid.map(onomagicBid => { onomagicBidResponses.push({ requestId: onomagicBid.impid, cpm: parseFloat(onomagicBid.price), width: parseInt(onomagicBid.w), height: parseInt(onomagicBid.h), creativeId: onomagicBid.crid || onomagicBid.id, currency: 'USD', netRevenue: true, mediaType: BANNER, ad: _getAdMarkup(onomagicBid), ttl: 60, meta: { advertiserDomains: onomagicBid && onomagicBid.adomain ? onomagicBid.adomain : [] } }); }); } return onomagicBidResponses; } catch (e) { utils.logError(e, {id, seatbid}); } } // Don't do user sync for now function getUserSyncs(syncOptions, responses, gdprConsent) { return []; } function _isMobile() { return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); } function _isConnectedTV() { return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); } function _getDeviceType() { return _isMobile() ? 1 : _isConnectedTV() ? 3 : 2; } function _getAdMarkup(bid) { let adm = bid.adm; if ('nurl' in bid) { adm += utils.createTrackPixelHtml(bid.nurl); } return adm; } function _isViewabilityMeasurable(element) { return !_isIframe() && element !== null; } function _getViewability(element, topWin, { w, h } = {}) { return utils.getWindowTop().document.visibilityState === 'visible' ? _getPercentInView(element, topWin, { w, h }) : 0; } function _isIframe() { try { return utils.getWindowSelf() !== utils.getWindowTop(); } catch (e) { return true; } } function _getMinSize(sizes) { return sizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min); } function _getBoundingBox(element, { w, h } = {}) { let { width, height, left, top, right, bottom } = element.getBoundingClientRect(); if ((width === 0 || height === 0) && w && h) { width = w; height = h; right = left + w; bottom = top + h; } return { width, height, left, top, right, bottom }; } function _getIntersectionOfRects(rects) { const bbox = { left: rects[0].left, right: rects[0].right, top: rects[0].top, bottom: rects[0].bottom }; for (let i = 1; i < rects.length; ++i) { bbox.left = Math.max(bbox.left, rects[i].left); bbox.right = Math.min(bbox.right, rects[i].right); if (bbox.left >= bbox.right) { return null; } bbox.top = Math.max(bbox.top, rects[i].top); bbox.bottom = Math.min(bbox.bottom, rects[i].bottom); if (bbox.top >= bbox.bottom) { return null; } } bbox.width = bbox.right - bbox.left; bbox.height = bbox.bottom - bbox.top; return bbox; } function _getPercentInView(element, topWin, { w, h } = {}) { const elementBoundingBox = _getBoundingBox(element, { w, h }); // Obtain the intersection of the element and the viewport const elementInViewBoundingBox = _getIntersectionOfRects([ { left: 0, top: 0, right: topWin.innerWidth, bottom: topWin.innerHeight }, elementBoundingBox ]); let elementInViewArea, elementTotalArea; if (elementInViewBoundingBox !== null) { // Some or all of the element is in view elementInViewArea = elementInViewBoundingBox.width * elementInViewBoundingBox.height; elementTotalArea = elementBoundingBox.width * elementBoundingBox.height; return ((elementInViewArea / elementTotalArea) * 100); } // No overlap between element and the viewport; therefore, the element // lies completely out of view return 0; } function _getBidFloor(bid) { if (!utils.isFn(bid.getFloor)) { return bid.params.bidFloor ? bid.params.bidFloor : null; } let floor = bid.getFloor({ currency: 'USD', mediaType: '*', size: '*' }); if (utils.isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { return floor.floor; } return null; } registerBidder(spec);