diff --git a/modules/.submodules.json b/modules/.submodules.json index bd00333a1d9..105528b18bb 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -52,6 +52,7 @@ ], "rtdModule": [ "1plusXRtdProvider", + "aaxBlockmeterRtdProvider", "airgridRtdProvider", "akamaiDapRtdProvider", "blueconicRtdProvider", @@ -77,4 +78,4 @@ "topicsFpdModule" ] } -} \ No newline at end of file +} diff --git a/modules/aaxBlockmeterRtdProvider.js b/modules/aaxBlockmeterRtdProvider.js new file mode 100644 index 00000000000..a3b7b4812a7 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.js @@ -0,0 +1,59 @@ +import {isEmptyStr, isStr, logError, isFn, logWarn} from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import { loadExternalScript } from '../src/adloader.js'; + +export const _config = { + MODULE: 'aaxBlockmeter', + ADSERVER_TARGETING_KEY: 'atk', + BLOCKMETER_URL: 'c.aaxads.com/aax.js', + VERSION: '1.2' +}; + +window.aax = window.aax || {}; + +function loadBlockmeter(_rtdConfig) { + if (!(_rtdConfig.params && _rtdConfig.params.pub) || !isStr(_rtdConfig.params && _rtdConfig.params.pub) || isEmptyStr(_rtdConfig.params && _rtdConfig.params.pub)) { + logError(`${_config.MODULE}: params.pub should be a string`); + return false; + } + + const params = []; + params.push(`pub=${_rtdConfig.params.pub}`); + params.push(`dn=${window.location.hostname}`); + + let url = _rtdConfig.params.url; + if (!url || isEmptyStr(url)) { + logWarn(`${_config.MODULE}: params.url is missing, using default url.`); + url = `${_config.BLOCKMETER_URL}?ver=${_config.VERSION}`; + } + + const scriptUrl = `https://${url}&${params.join('&')}`; + loadExternalScript(scriptUrl, _config.MODULE); + return true; +} + +function markAdBlockInventory(codes, _rtdConfig, _userConsent) { + return codes.reduce((targets, code) => { + targets[code] = targets[code] || {}; + const getAaxTargets = () => isFn(window.aax.getTargetingData) + ? window.aax.getTargetingData(code, _rtdConfig, _userConsent) + : {}; + targets[code] = { + [_config.ADSERVER_TARGETING_KEY]: code, + ...getAaxTargets() + }; + return targets; + }, {}); +} + +export const aaxBlockmeterRtdModule = { + name: _config.MODULE, + init: loadBlockmeter, + getTargetingData: markAdBlockInventory, +}; + +function registerSubModule() { + submodule('realTimeData', aaxBlockmeterRtdModule); +} + +registerSubModule(); diff --git a/modules/aaxBlockmeterRtdProvider.md b/modules/aaxBlockmeterRtdProvider.md new file mode 100644 index 00000000000..0a317f85b85 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.md @@ -0,0 +1,48 @@ +## Overview + +Module Name: AAX Blockmeter Realtime Data Module +Module Type: Rtd Provider +Maintainer: product@aax.media + +## Description + +The module enables publishers to measure traffic coming from visitors using adblockers. + +AAX can also help publishers monetize this traffic by allowing them to serve [acceptable ads](https://acceptableads.com/about/) to these adblock visitors and recover their lost revenue. [Reach out to us](https://www.aax.media/try-blockmeter/) to know more. + +## Integration + +Build the AAX Blockmeter Realtime Data Module into the Prebid.js package with: + +``` +gulp build --modules=aaxBlockmeterRtdProvider,rtdModule +``` + +## Configuration + +This module is configured as part of the `realTimeData.dataProviders` object. + +| Name | Scope | Description | Example | Type | +|:----------:|:--------:|:-----------------------------|:---------------:|:------:| +| `name` | required | Real time data module name | `'aaxBlockmeter'` | `string` | +| `params` | required | | | `Object` | +| `params.pub` | required | AAX to share pub ID, [Reach out to us](https://www.aax.media/try-blockmeter/) to know more! | `'AAX00000'` | `string` | +| `params.url` | optional | AAX Blockmeter Script Url. Defaults to `'c.aaxads.com/aax.js?ver=1.2'` | `'c.aaxads.com/aax.js?ver=1.2'` | `string` | + +### Example + +```javascript +pbjs.setConfig({ + "realTimeData": { + "dataProviders": [ + { + "name": "aaxBlockmeter", + "params": { + "pub": "AAX00000", + "url": "c.aaxads.com/aax.js?ver=1.2", + } + } + ] + } +}) +``` diff --git a/src/adloader.js b/src/adloader.js index 6b7427d3e52..64408683e9f 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -19,7 +19,8 @@ const _approvedLoadExternalJSList = [ 'inskin', 'hadron', 'medianet', - 'improvedigital' + 'improvedigital', + 'aaxBlockmeter' ] /** diff --git a/test/spec/modules/aaxBlockmeter_spec.js b/test/spec/modules/aaxBlockmeter_spec.js new file mode 100644 index 00000000000..f9704361976 --- /dev/null +++ b/test/spec/modules/aaxBlockmeter_spec.js @@ -0,0 +1,58 @@ +import {aaxBlockmeterRtdModule} from '../../../modules/aaxBlockmeterRtdProvider.js'; +import * as sinon from 'sinon'; +import {assert} from 'chai'; + +let sandbox; +let getTargetingDataSpy; + +const config = { + dataProviders: [{ + 'name': 'aaxBlockmeter', + 'params': { + 'pub': 'publisher_id', + } + }] +}; + +describe('aaxBlockmeter realtime module', function () { + beforeEach(function () { + sandbox = sinon.sandbox.create(); + window.aax = window.aax || {}; + window.aax.getTargetingData = getTargetingDataSpy = sandbox.spy(); + }); + + afterEach(function () { + sandbox.restore(); + window.aax = {}; + }); + + it('init should return false when config is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({}), false); + }); + + it('init should return false when config.params id is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {}}), false); + }); + + it('init should return true when config.params.pub is not string', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {pub: 12345}}), false); + }); + + it('init should return true when config.params.pub id is passed and is string typed', function () { + assert.equal(aaxBlockmeterRtdModule.init(config.dataProviders[0]), true); + }); + + describe('getTargetingData should work correctly', function () { + it('should return ad unit codes when ad units are present', function () { + const codes = ['code1', 'code2']; + assert.deepEqual(aaxBlockmeterRtdModule.getTargetingData(codes), { + code1: {'atk': 'code1'}, + code2: {'atk': 'code2'}, + }); + }); + + it('should call aax.getTargetingData if loaded', function () { + aaxBlockmeterRtdModule.getTargetingData([], config.dataProviders[0], null); + }); + }); +});