Created
November 13, 2013 14:37
-
-
Save mailopl/7450102 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
var ipc = ipc || {}; | |
// Step 1: Maintain BC with ipc.adtech | |
ipc.adloader = ipc.adtech = function () { | |
/** | |
* DFP acount ID | |
*/ | |
var _dfp_account_id = '', | |
/** | |
* Used to track the current request | |
*/ | |
_user_id = (new Date().getTime()) + "" + Math.floor((Math.random()*1000)), | |
/** | |
* Have we started loading yet? | |
*/ | |
_loading_ads = false, | |
/** | |
* Display mode, can be mobile, desktop or responsive | |
*/ | |
_display_mode = 'desktop', | |
/** | |
* The current environment | |
*/ | |
_environment = 'live', | |
/** | |
* If the display width is less than this, switch to mobile mode when | |
* responsive | |
*/ | |
_mobile_mode_width_threshold = 742, | |
/** | |
* The slot configuration taken from ipc tags | |
*/ | |
_slots_config = {}, | |
/** | |
* Slots ready to render when data is returned | |
*/ | |
_ready_slots = [], | |
/** | |
* Actual DFP slots that have been created using _googletag | |
*/ | |
_defined_slots = {}, | |
_has_third_parties = true, | |
/** | |
* Third parties loaded and waiting on results from | |
*/ | |
_pending_third_parties = { 'running' : 0 }, | |
/** | |
* URL for beaconing third party load times too | |
*/ | |
_beacon_url = '', | |
/** | |
* Store the provider to be used as part of the migration | |
* Default to adtech but can be set to DFP by url param, | |
* includes config or cookie | |
*/ | |
_provider = "adtech", | |
/** | |
* Local googletag object | |
*/ | |
_googletag = {}, | |
/** | |
* Holds timing information for a piece of 3rd party javascript or adcall | |
* @property _timings_log | |
* @type {Array} Stores all the additional parameter that need to be augmented | |
* @access private | |
*/ | |
_timings_log = [], | |
/** | |
* key/value of data that can be used by ads | |
* separate to targeting params as these will | |
* not be pushed into ad slots | |
* @type {object} | |
*/ | |
_ad_params = {}, | |
/** | |
* Targeting parameters to push into ad calls, see pushTargetingParam | |
*/ | |
_targeting_params = {}; | |
/** | |
* keeps track of which functions have been applied, see _apply_function | |
* @type {object} | |
*/ | |
_applied_functions = {}, | |
/** | |
* check to see if we have shown an out of page slot as we can only have one per page | |
* @type {object} | |
*/ | |
_out_of_page_unit_defined = false, | |
/** | |
* Cleans up the private variables | |
* for the next set of url that needs | |
* cleaning up | |
* @method _clean | |
* @access private | |
* @return void | |
*/ | |
_clean = function () { | |
adcall = {}; | |
_index_for_key = -1; | |
_params_to_push_after_key = []; | |
_params_to_push_before_key = []; | |
}, | |
/** | |
* Returns true if in debug mode | |
* | |
* @method _is_debug | |
* @return bool | |
*/ | |
_is_debug = function() { | |
return (typeof(_get_variable('adloader_debug')) !== 'undefined'); | |
}, | |
/** | |
* The over ride functionality is a stop gap measure but the config in ipcTags is confirmed | |
* @deprecated to replaced by the variable store in #51 | |
* @method _set_display_mode | |
* @param display_mode | |
*/ | |
_set_display_mode = function (display_mode) { | |
if (typeof(ipcTags) !== 'undefined' && typeof(ipcTags.dfp_config.display_mode) !== 'undefined') { | |
_display_mode = ipcTags.dfp_config.display_mode; | |
} else { | |
_display_mode = display_mode; | |
} | |
}, | |
/** | |
* @method _is_mobile | |
* @return bool | |
*/ | |
_is_mobile = function () { | |
return navigator.userAgent.match(/(Android .*Mobile|Mobile .*Android|Opera Mini|Opera Mobi|iPhone|iPod|Nintendo Wii|Window Mobile|Windows Phone|BlackBerry|N900|PSP|webOS|alcatel|audiovox|benq|blackberry|cdm-|docomo|ericsson|ezwap|go\.web\/|htc|lg|lg-|lge-|midp-2\.0|mitsu\/|mmp\/2\.0|mobileexplorer|mot-|nec-|nokia|palmsource|panasonic|philips|portalmmm|rim handheld|rim pager|sagem-|samsung-sgh|sec-s|sie-|sharp|symbianos|symbian os|up\.browser|up\.link|up\/4\.|[wW]indows [cC][eE]|iPhone|MIDP)/i) != null; | |
}, | |
/** | |
* Desktop and mobile are treated slightly | |
* differently, smaller display widths get | |
* are treated as mobile as well | |
* @method _get_display_mode | |
* @return _display_mode | |
*/ | |
_get_display_mode = function () { | |
if(_display_mode == 'responsive'){ | |
if(_is_mobile()) { | |
return 'mobile'; | |
} else { | |
return 'desktop'; | |
} | |
} | |
return _display_mode; | |
}, | |
/** | |
* Sets the ad provider. The passed provider can be overridden | |
* by query params or a cookie, both called 'adloader_provider' | |
* | |
* @method _set_provider | |
* @param provider | |
*/ | |
_get_variable = function (name, default_value) { | |
var query_value = _get_query_variable(name); | |
var cookie_value = _read_cookie(name); | |
if (query_value != '') { | |
ipc.utils.ipcCreateCookie(name, query_value, 1); | |
return query_value; | |
} else if(cookie_value != false){ | |
return cookie_value; | |
} else if (typeof(default_value) !== 'undefined') { | |
return default_value; | |
} else { | |
return; | |
} | |
}, | |
/** | |
* @method _get_provider | |
* @return _provider | |
*/ | |
_get_provider = function () { | |
return _provider; | |
}, | |
/** | |
* @method _set_environment | |
*/ | |
_set_environment = function (environment) { | |
_environment = environment; | |
}, | |
/** | |
* @method _get_environment | |
* @return _environment | |
*/ | |
_get_environment = function () { | |
return _environment; | |
}, | |
/** | |
* Pushes timings onto a stack to beacon later | |
* @method _log_timing | |
* @access private | |
* @return void | |
*/ | |
_log_timing = function(o) { | |
if (o.name && o.totalTime) { | |
_timings_log.push(o.name + '=' + o.totalTime); | |
} | |
}, | |
/** | |
* Read ipcTags json data from the site, only push in specified values from | |
* the required tags field | |
* @method _read_site_tags | |
*/ | |
_read_site_tags = function () { | |
// check integrity of ipcTags | |
if(typeof(ipcTags.dfp_config.slots) === 'undefined' || _is_object_empty(ipcTags.dfp_config.slots)){ | |
_log_event('NoSlotsDefined', 'error'); | |
} else { | |
_slots_config = {}; | |
_out_of_page_unit_defined = false; | |
// define the ad slots, filter out any unwanted/duplicate ones | |
for(var slot in ipcTags.dfp_config.slots){ | |
var slot_config = ipcTags.dfp_config.slots[slot]; | |
// Length of one means an array inside an array so break it out to ensure out of page test works correctly | |
if (slot_config.sizes.length === 1) { | |
slot_config.sizes = slot_config.sizes[0]; | |
} | |
// 1x1 ads need to be defined as out of page slots, only one is | |
// allowed per page though | |
if ((slot_config.sizes[0] === 1) && (slot_config.sizes[1] === 1)) { | |
if (_out_of_page_unit_defined) { | |
_log_event('Attempt to define multiple Out Of Page Units', 'error'); | |
continue; | |
} | |
_out_of_page_unit_defined = true; | |
} | |
_slots_config[slot] = slot_config; | |
} | |
} | |
// add any targeting params from ipcTags | |
if (typeof(ipcTags.dfp_config.required_tags) !== 'undefined') { | |
for (var i=0; i < ipcTags.dfp_config.required_tags.length; i++) { | |
if (typeof(ipcTags[ipcTags.dfp_config.required_tags[i]]) !== 'undefined' && ipcTags[ipcTags.dfp_config.required_tags[i]] !== null) { | |
_push_targeting_param({ | |
'name' : ipcTags.dfp_config.required_tags[i], | |
'value' : _format_targeting_param(ipcTags[ipcTags.dfp_config.required_tags[i]]) | |
}); | |
} else { | |
_log_event('Null Tag: ' + ipcTags.dfp_config.required_tags[i], 'error'); | |
} | |
} | |
} | |
// add environment into targeting params | |
_push_targeting_param({ | |
'name' : 'env', | |
'value' : _get_environment() | |
}); | |
// add screen dimensions into targeting params | |
_push_targeting_param({ | |
'name' : 'browwidth', | |
'value' : String(_get_display_width()) | |
}); | |
// add screen dimensions into targeting params | |
_push_targeting_param({ | |
'name' : 'browheight', | |
'value' : String(_get_display_height()) | |
}); | |
_put_ad_param('browwidth', String(_get_display_width())); | |
_put_ad_param('browheight', String(_get_display_height())); | |
ipc.adloader.targeting.addCookieTargeting(); | |
}, | |
/** | |
* Initiate 3rd party code using iFrames and meebo dynamic iframe approach | |
* http://www.aaronpeters.nl/blog/iframe-loading-techniques-performance#dynamic | |
* Set a timer dependant on how long we are willing to wait to get the data back | |
* @todo variable timer probably set in Includes | |
*/ | |
_load_third_parties = function () { | |
var beacon_data = { }; | |
beacon_data.expected = []; | |
var iframeId = "dfp-third-party-loader-adprobe"; | |
// remove existing iframe if present | |
if(document.getElementById(iframeId)){ | |
var iframeCurrent = document.getElementById(iframeId); | |
iframeCurrent.parentNode.removeChild(iframeCurrent); | |
} | |
beacon_data.expected.push('ipcThirdPartyLoaderadprobe'); | |
_pending_third_parties.running++; | |
_pending_third_parties.ipcThirdPartyLoaderadprobe = ''; | |
_pending_third_parties.ipcThirdPartyLoaderadprobe = []; | |
_pending_third_parties.ipcThirdPartyLoaderadprobe['name'] = 'adprobe'; | |
_pending_third_parties.ipcThirdPartyLoaderadprobe['status'] = 'running'; | |
var iframe = document.body.appendChild(document.createElement('iframe')), | |
doc = iframe.contentWindow.document; | |
iframe.id = iframeId; | |
// style the iframe so it does not appear to the user | |
iframe.style.cssText = "position:absolute;width:0px;height:0px;left:-9999px;top:0px;"; | |
// Set start_time here as if the script is too fast then it can return before the setTimout is created | |
// so can't be cleared by _register_third_party causing a secondary call to _load_ads | |
_pending_third_parties.ipcThirdPartyLoaderadprobe.start_time = new Date().getTime(); | |
ipcThirdPartyLoaderadprobe = setTimeout(function() { | |
_timeout_third_party('ipcThirdPartyLoaderadprobe'); | |
}, 10000); | |
doc.open().write('<!doctype html><head><scr' + 'ipt type="text/javascript">' + | |
'window.ipc_adloader_name = \'ipcThirdPartyLoaderadprobe\'; ' + | |
'adprobe = {};\n' + | |
'adprobe.wlOrd = new Date().getTime();\n' + | |
'adprobe.publisher_id = 1568;\n' + | |
'adprobe.website_id = 6654;\n' + | |
'adprobe.content_unit_id = 13103;\n' + | |
'adprobe.content_unit_ids = \'13103,13104\';\n' + | |
'adprobe.placement_unit_ids = [];\n' + | |
'adprobe.placement_unit_ids.push( {\'size\': 225, \'contentid\': 13103});\n' + | |
'adprobe.placement_unit_ids.push( {\'size\': 170, \'contentid\': 13104});\n' + | |
'adprobe.url = \'req.connect.wunderloop.net/AP/\' + adprobe.publisher_id + \'/\' + adprobe.website_id + \'/\' + adprobe.content_unit_id + \'/js?cus=\' + adprobe.content_unit_ids + \'&ord=\' + adprobe.wlOrd;\n' + | |
'var elem = document.createElement(\'script\');\n' + | |
'elem.src = (document.location.protocol == "https:" ? "https://" : "http://") + adprobe.url;\n' + | |
'elem.type = "text/javascript";\n' + | |
'var scpt = document.getElementsByTagName(\'script\')[0]; scpt.parentNode.insertBefore(elem, scpt);\n' + | |
'function sendData() {\n' + | |
' if (typeof(window[\'wl\' + adprobe.content_unit_id + \'camp\']) === "undefined") {\n' + | |
' return;\n' + | |
' }\n' + | |
' \n' + | |
' // function to push params\n' + | |
' function push_placements(content_ids) {\n' + | |
' for (var i=0; i < content_ids.length; i+=1) {\n' + | |
' var content_unit_key = \'wl\' + content_ids[i];\n' + | |
' var content_unit_id_name = \'wl\' + content_ids[i] + \'camp\';\n' + | |
' if(typeof(window[content_unit_id_name]) !== \'undefined\') {\n' + | |
' var value = \'yes\';\n' + | |
' if (window[content_unit_id_name] === \'\') {\n' + | |
' value = \'no\';\n' + | |
' }\n' + | |
' parent.ipc.adloader.putAdParam(content_unit_id_name, window[content_unit_id_name]);\n' + | |
' parent.ipc.adloader.pushTargetingParam({\n' + | |
' \'name\' : content_unit_key,\n' + | |
' \'value\' : value,\n' + | |
' \'scope\' : \'slots\'\n' + | |
' });\n' + | |
' }\n' + | |
' }\n' + | |
' }\n' + | |
' var content_unit_ids = [];\n' + | |
' if(adprobe.placement_unit_ids.length > 0) {\n' + | |
' for (i=0; i < adprobe.placement_unit_ids.length; i++) {\n' + | |
' content_unit_ids.push(adprobe.placement_unit_ids[i].contentid);\n' + | |
' }\n' + | |
' } else {\n' + | |
' content_unit_ids = adprobe.content_unit_ids.split(\',\');\n' + | |
' }\n' + | |
' push_placements(content_unit_ids);\n' + | |
' parent.ipc.adloader.registerThirdPartyLoad(ipc_adloader_name);\n' + | |
' clearInterval(dataSender);\n' + | |
'}\n' + | |
'var dataSender = setInterval(\'sendData()\', 25);\n' + | |
'</scr' + 'ipt></head><body></body></html>'); | |
doc.close(); //iframe onload event happens | |
var iframeId = "dfp-third-party-loader-grapeshot"; | |
// remove existing iframe if present | |
if(document.getElementById(iframeId)){ | |
var iframeCurrent = document.getElementById(iframeId); | |
iframeCurrent.parentNode.removeChild(iframeCurrent); | |
} | |
beacon_data.expected.push('ipcThirdPartyLoadergrapeshot'); | |
_pending_third_parties.running++; | |
_pending_third_parties.ipcThirdPartyLoadergrapeshot = ''; | |
_pending_third_parties.ipcThirdPartyLoadergrapeshot = []; | |
_pending_third_parties.ipcThirdPartyLoadergrapeshot['name'] = 'grapeshot'; | |
_pending_third_parties.ipcThirdPartyLoadergrapeshot['status'] = 'running'; | |
var iframe = document.body.appendChild(document.createElement('iframe')), | |
doc = iframe.contentWindow.document; | |
iframe.id = iframeId; | |
// style the iframe so it does not appear to the user | |
iframe.style.cssText = "position:absolute;width:0px;height:0px;left:-9999px;top:0px;"; | |
// Set start_time here as if the script is too fast then it can return before the setTimout is created | |
// so can't be cleared by _register_third_party causing a secondary call to _load_ads | |
_pending_third_parties.ipcThirdPartyLoadergrapeshot.start_time = new Date().getTime(); | |
ipcThirdPartyLoadergrapeshot = setTimeout(function() { | |
_timeout_third_party('ipcThirdPartyLoadergrapeshot'); | |
}, 10000); | |
doc.open().write('<!doctype html><head><scr' + 'ipt type="text/javascript">' + | |
'window.ipc_adloader_name = \'ipcThirdPartyLoadergrapeshot\'; ' + | |
'var elem = document.createElement(\'script\');\n' + | |
'elem.src = \'http://ipcmedia.grapeshot.co.uk/channels.cgi?url=\' + escape(top.location.href);\n' + | |
'elem.type = "text/javascript";\n' + | |
'var scpt = document.getElementsByTagName(\'script\')[0];\n' + | |
'scpt.parentNode.insertBefore(elem, scpt);\n' + | |
'function sendData() {\n' + | |
' if (typeof(gs_channels) === "undefined") {\n' + | |
' return;\n' + | |
' }\n' + | |
' \n' + | |
' if (!gs_channels) {\n' + | |
' gs_channels = \'default\';\n' + | |
' }\n' + | |
' \n' + | |
' parent.ipc.adloader.pushTargetingParam({\n' + | |
' \'name\' : \'gs_chans\',\n' + | |
' \'value\' : gs_channels\n' + | |
' });\n' + | |
' parent.ipc.adloader.registerThirdPartyLoad(ipc_adloader_name);\n' + | |
' clearInterval(dataSender);\n' + | |
'}\n' + | |
'var dataSender = setInterval(\'sendData()\', 25);\n' + | |
'</scr' + 'ipt></head><body></body></html>'); | |
doc.close(); //iframe onload event happens | |
_beacon_data('requests', beacon_data); | |
_log_event(beacon_data, 'info'); | |
}, | |
/** | |
* Timeout a third party as it took too long to return | |
* Make sure we load the ads if all third parties have | |
* completed/timed out | |
*/ | |
_timeout_third_party = function (third_party) { | |
_log_event('Timing Out '+third_party, 'info'); | |
if (_pending_third_parties[third_party]['status'] == 'running') { | |
_pending_third_parties.running--; | |
_pending_third_parties[third_party]['status'] = 'timeout'; | |
} | |
if (_pending_third_parties.running == 0 && _get_provider() === 'dfp') { | |
_load_ads(); | |
} | |
}, | |
/** | |
* Register third party load, called by a third party when it has received its data | |
* If the third party does not exist it has timed out so beacon as such | |
* Clears the timeout as well | |
*/ | |
_register_third_party_load = function (third_party) { | |
clearTimeout(window[third_party]); | |
var currTime = new Date().getTime() | |
duration = currTime - _pending_third_parties[third_party]['start_time']; | |
if (_pending_third_parties[third_party]['status'] == 'running') { | |
_pending_third_parties[third_party]['status'] = 'complete'; | |
_pending_third_parties.running--; | |
var beacon_data = { }; | |
beacon_data.third_party = third_party; | |
beacon_data.status = 'success'; | |
beacon_data.duration = duration; | |
_beacon_data('responses', beacon_data); | |
_log_event(beacon_data, 'info'); | |
if (_pending_third_parties.running == 0 && _get_provider() === 'dfp') { | |
_load_ads(); | |
} | |
} else { | |
var beacon_data = { }; | |
beacon_data.third_party = third_party; | |
beacon_data.status = 'failure'; | |
beacon_data.duration = duration; | |
_beacon_data('responses', beacon_data); | |
_log_event(beacon_data, 'info'); | |
} | |
}, | |
/** | |
* Load dfp ads, reload the ads if the initial | |
* load has already taken place. | |
* | |
* Normally called when all third parties have | |
* completed or timed out. | |
* | |
* If ads have already been loaded then reload the ads | |
*/ | |
_load_ads = function () { | |
if (!_loading_ads) { | |
_googletag.cmd.push(function() { | |
_set_global_targeting(); | |
_define_slots(); | |
// Single request does not seem to work properly with gpt_mobile | |
if(_get_display_mode() == 'mobile') { | |
_googletag.pubads().enableAsyncRendering(); | |
} else { | |
if ( (typeof(ipcTags.dfp_config.disableSingleRequest) !== 'undefined') && (ipcTags.dfp_config.disableSingleRequest === true) ) { | |
_log_event('singleRequest Mode Not Enabled', 'info'); | |
} else { | |
_log_event('singleRequest Mode Enabled', 'info'); | |
_googletag.pubads().enableSingleRequest(); | |
} | |
} | |
_googletag.pubads().collapseEmptyDivs(); | |
_googletag.enableServices(); | |
}); | |
// This looks unneeded but we have to display the slots in this way | |
// or we get some weird issues | |
for (var i=0; i<_ready_slots.length; i++) { | |
if (!_slot_exists(_ready_slots[i])) { | |
_log_event('Not displaying '+_ready_slots[i], 'info'); | |
continue; | |
} | |
_log_event('Displaying '+_ready_slots[i], 'info'); | |
_googletag.cmd.push(function(_ready_slots_item) { | |
return function(){_googletag.display(_ready_slots_item)}; | |
}(_ready_slots[i])); | |
} | |
_loading_ads = true; | |
} else { | |
_reload_ads(); | |
} | |
}, | |
/** | |
* Initiates a refresh of the ad slots. | |
* | |
* Resets targeting parameters first, | |
* if third parties are present then third parties | |
* will be reloaded and the ads will be refreshed | |
* once they have all loaded or timed out | |
*/ | |
_refresh = function() { | |
// reset targeting and whatnot, only keep items that have been marked | |
// as persistent. Refreshes are essentially a blank slate, targeting | |
// parameters, written data etc. all have a persistent option that will | |
// keep them in place when refreshing. | |
_ad_params = {}; | |
_clear_targeting_params(); | |
_clear_written_data(); | |
_read_site_tags(); | |
if(_has_third_parties){ | |
_load_third_parties(); | |
} else { | |
_reload_ads(); | |
} | |
}, | |
/** | |
* Reset targeting on each slot and then | |
* call dfp refresh on all ad slots | |
*/ | |
_reload_ads = function () { | |
for(var slotName in _defined_slots){ | |
_googletag.cmd.push(function() { | |
_defined_slots[slotName].clearTargeting(); | |
_set_slot_targeting(_defined_slots[slotName], slotName); | |
}); | |
} | |
_googletag.cmd.push(function() { | |
_googletag.pubads().refresh(); | |
}); | |
}, | |
/** | |
* Define slots | |
* Creates and sets targeting on dfp slots, | |
* saves the slots for later as well | |
*/ | |
_define_slots = function () { | |
var unitName = "/" + _dfp_account_id; | |
if ( ( typeof(ipcTags.site) !== "undefined" ) && ( ipcTags.site !== "" ) ) { | |
var site = ipcTags.site; | |
} else { | |
var site = "undefined"; | |
_log_event('Site is not defined', 'error'); | |
} | |
// add '_mobile' to 'ipcTags.site' if we are in mobile mode | |
if(_get_display_mode() == 'mobile') { | |
unitName = unitName + "/" + site + "_mobile"; | |
} else { | |
unitName = unitName + "/" + site; | |
} | |
if ( ( typeof(ipcTags.section) !== "undefined" ) && ( ipcTags.section !== "" ) ) { | |
unitName = unitName + "/" + _slugify(ipcTags.section); | |
} else { | |
_log_event('NoSection', 'error'); | |
} | |
if ( ( typeof(ipcTags.subsection) !== "undefined" ) && ( ipcTags.subsection !== "" ) ) { | |
unitName = unitName + "/" + _slugify(ipcTags.subsection); | |
} | |
for(var slot in _slots_config){ | |
var slot_config = _slots_config[slot]; | |
// 1x1 ads need to be defined as out of page slots, only one is | |
// allowed per page though | |
if ((slot_config.sizes[0] === 1) && (slot_config.sizes[1] === 1)) { | |
_defined_slots[slot] = _googletag.defineOutOfPageSlot(unitName, slot).addService(_googletag.pubads()); | |
} else { | |
_defined_slots[slot] = _googletag.defineSlot(unitName, slot_config.sizes, slot).addService(_googletag.pubads()); | |
} | |
_set_slot_targeting(_defined_slots[slot], slot); | |
} | |
}, | |
/** | |
* Register slot | |
* Registers a dfp slot that will be defined later on, called by the site | |
* that the adloader is embedded into | |
*/ | |
_register_slot = function (slot_id) { | |
if (_loading_ads) { | |
if (_slot_exists(slot_id)) { | |
_log_event('Registering slot to _googletag ' + slot_id, 'info'); | |
_googletag.cmd.push(function() { | |
_googletag.display(slot_id); | |
}); | |
} else { | |
_log_event('Unable to registering slot to _googletag as slot does not exist ' + slot_id, 'warn'); | |
} | |
} else { | |
_log_event('Queueing registering slot ' + slot_id, 'info'); | |
_ready_slots.push(slot_id); | |
} | |
}, | |
/** | |
* Check that a slot has been defined in _slots_config, in the event of | |
* multiple out of page slots additional ones after the first are not defined, | |
* so we need to detect if this has happened before we display a slot | |
*/ | |
_slot_exists = function(slot_id) { | |
if (typeof(_slots_config[slot_id]) === "undefined") { | |
_log_event('Attempt to use non-existant slot: ' + slot_id, 'error'); | |
return false; | |
} | |
return true; | |
}, | |
/** | |
* Sets global targeting for dfp ad slots | |
*/ | |
_set_global_targeting = function (dfp_slot, name) { | |
targeting_params = _targeting_params; | |
if(_has_test_targeting()) { | |
targeting_params = _get_test_targeting(); | |
} | |
for (var name in targeting_params) { | |
if(targeting_params[name]['scope'] == 'global') { | |
_googletag.pubads().setTargeting(name, targeting_params[name]['value']); | |
} | |
} | |
}, | |
/** | |
* Sets slot level targeting for dfp ad slots | |
*/ | |
_set_slot_targeting = function (dfp_slot, name) { | |
dfp_slot.setTargeting( "name", ipcTags.dfp_config.slots[name]['name'] ); | |
if(_has_test_targeting()) { | |
return; | |
} | |
for (var name in _targeting_params) { | |
if(_targeting_params[name]['scope'] == 'slots') { | |
dfp_slot.setTargeting(name, _targeting_params[name]['value']); | |
} | |
} | |
}, | |
/** | |
* Formats targeting params for DFP, converts ints to strings, removes | |
* spaces and special characters. Only used for interal params at the moment | |
* (the ones that are passed in via ipcTags) | |
* | |
* @method _format_targeting_param | |
* @access private | |
* @param {Mixed} The unformatted parameter | |
* @return {Mixed} The formatted parameter | |
*/ | |
_format_targeting_param = function(param) { | |
var formatted_param = false; | |
if(param instanceof Array) { | |
formatted_param = [] | |
for(i = 0; i < param.length; i++) { | |
formatted_param[i] = _slugify(param[i]); | |
} | |
} else { | |
formatted_param = _slugify(param); | |
} | |
return formatted_param; | |
}, | |
/** | |
* Slugifies strings for use as targeting variables | |
* | |
* @method _slugify | |
* @access private | |
* @param {String} The unformatted string | |
* @return {String} The formatted string | |
*/ | |
_slugify = function(str) { | |
str = String(str); | |
str = str.toLowerCase(); | |
str = str.replace(/[^\w\s]/g, ' '); | |
str = str.replace(/\ +/g, '_'); | |
str = str.replace(/\-$/g, ''); | |
str = str.replace(/^\-/g, ''); | |
return str; | |
}, | |
/** | |
* Returns true if some test targeting has been set (see _get_test_targeting) | |
* | |
* @method _has_test_targeting | |
* @return bool | |
*/ | |
_has_test_targeting = function () { | |
if (_get_query_variable('adloader_test_mode') != '' || _read_cookie('adloader_test_targeting') != false) { | |
return true; | |
} | |
return false; | |
}, | |
/** | |
* Custom targeting can be set via cookies allowing for | |
* detailed testing of ad placements | |
* | |
* Format should be like so... | |
* test_var1=test1&test_var2=test2&test_var3=test3 | |
* | |
* In addition to the cookie setting a query parameter | |
* can be set which switches targeting to test mode, | |
* where the only targeting param will be 'testmode' => true | |
* this can be set by adding 'adloader_test_mode=1' to | |
* the query string | |
* | |
* @method _get_custom_targeting | |
* @return mixed either an object containing | |
* targeting params or boolean false if there | |
* are custom params | |
*/ | |
_get_test_targeting = function () { | |
if(!_has_test_targeting) { | |
return false; | |
} | |
test_targeting_params = {}; | |
var custom_targeting = {}; | |
var custom_targeting_string = _read_cookie('adloader_test_targeting'); | |
if (_get_query_variable('adloader_test_mode') != '') { | |
test_targeting_params['testmode'] = { | |
'name' : 'testmode', | |
'value' : 'on', | |
'scope' : 'global' | |
} | |
} else if(custom_targeting_string != false) { | |
var vars = custom_targeting_string.split("&"); | |
for (var i=0;i<vars.length;i++) { | |
var pair = vars[i].split("="); | |
test_targeting_params[pair[0]] = { | |
'name' : pair[0], | |
'value' : decodeURIComponent(pair[1]), | |
'scope' : 'global' | |
} | |
} | |
} | |
return test_targeting_params; | |
}, | |
/** | |
* Parse the string of unit sizes into an array of ints, there must be a better way to do this! | |
* If this comment is in production we either: | |
* a) didn't have time to refactor this | |
* b) decided it was ok so could be left | |
* c) didn't touch it as it's a work of beauty | |
* | |
* Hint, it's not c and I doubt it will be b! | |
*/ | |
_parse_unit_sizes = function (unit_details_sizes) { | |
var unit_sizes = []; | |
unit_sizes_array = unit_details_sizes.split(":"); | |
for (var i=0; i<unit_sizes_array.length; i++) { | |
unit_sizes_size = unit_sizes_array[i].split(","); | |
unit_sizes.push([parseInt(unit_sizes_size[0]), parseInt(unit_sizes_size[1])]); | |
} | |
return unit_sizes; | |
}, | |
/** | |
* Simple helper method that extracts | |
* query parameters from the current request | |
* | |
* @method _get_query_variable | |
* @access private | |
* @return {String} the value | |
*/ | |
_get_query_variable = function(variable) { | |
var query = window.location.search.substring(1); | |
var vars = query.split("&"); | |
for (var i=0;i<vars.length;i++) { | |
var pair = vars[i].split("="); | |
if (pair[0] == variable) { | |
return decodeURIComponent(pair[1]); | |
} | |
} | |
return ''; | |
}, | |
/** | |
* Simple helper method that extracts | |
* hash parameters from the current request | |
* | |
* @method _get_hash_variable | |
* @access private | |
* @return {String} the value | |
*/ | |
_get_hash_variable = function() { | |
var length = window.location.hash.length; | |
return window.location.hash.substring(1, length); | |
}, | |
/** | |
* Simple helper method that checks for the | |
* existence of a value within an array | |
* @method _in_array | |
* @access private | |
* @return void | |
*/ | |
_in_array = function(needle, haystack) { | |
for (key in haystack) { | |
if (haystack[key] === needle) { | |
return true; | |
} | |
} | |
return false; | |
}, | |
/** | |
* Push data param onto stack | |
* @access private | |
* @method _put_ad_param | |
* @return void | |
*/ | |
_put_ad_param = function(key, value){ | |
_ad_params[key] = value; | |
}, | |
/** | |
* Get data param onto stack | |
* @access private | |
* @method _get_ad_param | |
* @return mixed | |
*/ | |
_get_ad_param = function(key){ | |
if(typeof(_ad_params[key]) == 'undefined') { | |
return; | |
} | |
return _ad_params[key]; | |
}, | |
/** | |
* Push a targeting parameter into the ad slots, see pushTargetingParam | |
* @access private | |
* @method _push_targeting_param | |
* @return void | |
* | |
* @todo In the future scope could be expanded to target individual ad | |
* slots, possibly by passing an array of sizes as the scope. | |
*/ | |
_push_targeting_param = function (config) { | |
if(typeof(config['scope']) == 'undefined') { | |
config['scope'] = 'global'; | |
} | |
if(typeof(config['persistent']) == 'undefined') { | |
config['persistent'] = false; | |
} | |
// DFP limits parameter names to 10 characters | |
var name = config['name']; | |
if(name.length > 10) { | |
_log_event('Targeting parameter name over 10 character limit: ' + name, 'warn'); | |
name = name.slice(0, 10); | |
} | |
_targeting_params[name] = config; | |
}, | |
/** | |
* Clears targeting parameters between refreshes, keeps any that have been | |
* set as persistant. | |
* @access private | |
* @method _clear_targeting_params | |
* @return void | |
*/ | |
_clear_targeting_params = function () { | |
_cleared_targeting_params = {}; | |
for (var name in _targeting_params) { | |
if(_targeting_params[name]['persistent']) { | |
_cleared_targeting_params[name] = _targeting_params[name]; | |
} | |
} | |
_targeting_params = _cleared_targeting_params; | |
}, | |
/** | |
* Log error depending on severity | |
* info - information on progress to enable debugging | |
* warn - caught errors e.g. Out Of Page units defined twice | |
* error - an error which meant ads could not be displayed | |
* | |
* Info logs to console in all environments but only in debug mode | |
* warn and error go to console in dev/qa/stage or ipc.utils.trackEvent in live | |
* @deprecated To be replaced with ipc.analytics.log see #64 | |
* @access private | |
* @method _log_event | |
* @return void | |
*/ | |
_log_event = function (message, severity){ | |
if ( _is_debug() || ((_get_environment() !== 'live') && (severity !== "info")) ) { | |
console.log("DFP : " + severity + " : " + JSON.stringify(message)); | |
if (typeof(ipcTags.debug) === 'undefined') { | |
ipcTags.debug = []; | |
} | |
ipcTags.debug.push({ | |
'time': new Date(), | |
'severity': severity, | |
'message': JSON.stringify(message) | |
}); | |
} | |
if ((_get_environment() === 'live') && (typeof(ipc.utils) !== "undefined") && (severity !== "info")) { | |
ipc.utils.trackEvent('DFP : ' + severity, message, window.location.href); | |
} | |
}, | |
/** | |
* Beacon data as json | |
* @todo cross browser | |
*/ | |
_beacon_data = function( endpoint, data, beacon_url ) { | |
if (typeof(beacon_url) !== 'undefined') { | |
_beacon_url = beacon_url; | |
} | |
if(_beacon_url != '') { | |
data.user_id = _user_id; | |
xmlhttp = new XMLHttpRequest(); | |
xmlhttp.open("POST", _beacon_url + '/' + endpoint, true); | |
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); | |
xmlhttp.send("data="+JSON.stringify(data)); | |
} | |
}, | |
/** | |
* Beacon data as json | |
* @todo cross browser | |
*/ | |
_beacon_debug_data = function( beacon_url ) { | |
_beacon_data( 'debug.php', ipcTags.debug, beacon_url); | |
event_log = _googletag.getEventLog(); | |
clean_event_log = []; | |
// This is unreliable as the varibale names can change see #65 | |
for (var i = 0; i < event_log['H'].length; i++) { | |
event = event_log['H'][i]['Sa']; | |
clean_event_log.push(event); | |
} | |
_beacon_data( 'debug.php', clean_event_log, beacon_url); | |
}, | |
/** | |
* Load google console | |
*/ | |
_load_google_console = function( ) { | |
_googletag.console.mc(); | |
}, | |
/** | |
* Simple read cookie method | |
* @access private | |
* @method _read_cookie | |
* @return mixed, false if cookie does not exist | |
*/ | |
_read_cookie = function (name) { | |
var value = (document.cookie.match('(^|; )'+name+'=([^;]*)')||0)[2]; | |
if(typeof value == 'undefined') { | |
return false; | |
} | |
return value; | |
}, | |
_is_object_empty = function(obj) { | |
for(var prop in obj) { | |
if(obj.hasOwnProperty(prop)) | |
return false; | |
} | |
return true; | |
}, | |
/** | |
* Get the users display width | |
* @access private | |
* @method _get_display_width | |
* @return int | |
*/ | |
_get_display_width = function () { | |
var width = 0; | |
if (typeof window.innerWidth != 'undefined') { | |
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight | |
width = window.innerWidth; | |
} else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) { | |
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document) | |
width = document.documentElement.clientWidth; | |
} else { | |
// older versions of IE | |
width = document.getElementsByTagName('body')[0].clientWidth; | |
} | |
return Number(width); | |
}, | |
/** | |
* Get the users display height | |
* @access private | |
* @method _get_display_height | |
* @return int | |
*/ | |
_get_display_height = function () { | |
var height = 0; | |
if (typeof window.innerHeight != 'undefined') { | |
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerHeight and window.innerHeight | |
height = window.innerHeight; | |
} else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientHeight != 'undefined' && document.documentElement.clientHeight != 0) { | |
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document) | |
height = document.documentElement.clientHeight; | |
} else { | |
// older versions of IE | |
height = document.getElementsByTagName('body')[0].clientHeight; | |
} | |
return Number(height); | |
}, | |
/** | |
* See writeData | |
* @access private | |
* @method _write_data | |
* @return void | |
*/ | |
_write_data = function (config) { | |
if(typeof(config['persistent']) === 'undefined') { | |
config['persistent'] = false; | |
} | |
config['id'] += '_adloader'; | |
var dataDiv = document.getElementById(config['id']); | |
var dataDivClass = 'adloader_written_data'; | |
// If persistent do not overwrite | |
if(config['persistent']) { | |
if(dataDiv) { | |
return; | |
} | |
dataDivClass += '_persistent'; | |
} | |
if(!dataDiv) { | |
var dataDiv = document.createElement('div'); | |
dataDiv.setAttribute("id", config['id']); | |
dataDiv.setAttribute("class", dataDivClass); | |
} | |
dataDiv.innerHTML = config['data']; | |
document.body.appendChild(dataDiv); | |
}, | |
/** | |
* Clears any non persistent written data during refreshes | |
* @access private | |
* @method _clear_written_data | |
* @return void | |
*/ | |
_clear_written_data = function() { | |
elems = document.querySelectorAll('div.adloader_written_data'); | |
if(elems.length > 0) { | |
for(var i; i<elems.length; i++) { | |
elems[i].parentNode.removeChild(elems[i]); | |
} | |
} | |
} | |
/** | |
* See applyStyling | |
* @access private | |
* @method _apply_takeover | |
* @return void | |
*/ | |
_apply_styling = function(config) { | |
if(typeof(config['persistent']) === 'undefined') { | |
config['persistent'] = false; | |
} | |
// Find the element by id or tag name | |
var elem = false; | |
if(config['keyType'] == 'id') { | |
elem = document.getElementById(config['key']); | |
} else if(config['keyType'] == 'tag') { | |
elems = document.getElementsByTagName(config['key']); | |
if (elems.length > 0) { | |
elem = elems[0]; | |
} | |
} | |
if(elem) { | |
// If persistent, do not alter class if it has already been altered | |
if(config['persistent']) { | |
var persistent_class = 'adloader_modified'; | |
if(_has_class(elem, persistent_class)) { | |
return; | |
} | |
elem.className += persistent_class; | |
} | |
// apply styling | |
var style_str = ''; | |
if(elem.getAttribute('cssText')) { | |
style_str = elem.getAttribute('cssText'); | |
} else { | |
style_str = elem.getAttribute('style'); | |
} | |
// combine all the styles into a string so it works crossbrowser | |
for(var styleName in config['styles']) { | |
style_str = style_str + styleName + ': ' + config['styles'][styleName] + '; '; | |
} | |
// crossbrowser checking, damn ie | |
if(elem.style.setAttribute) { | |
// ie | |
elem.style.setAttribute("cssText", style_str); | |
} else { | |
// decent browsers | |
elem.setAttribute("style", style_str); | |
} | |
// Add click event if needed | |
if(typeof(config['clickable']) !== 'undefined') { | |
clickable = function(event) { | |
event = _normalise_event(event); | |
// Ensure that the target element has been clicked, | |
// otherwise child elements will fire this event | |
var clicked = false; | |
if(config['keyType'] == 'id' && event.target.id == elem.id) { | |
clicked = true; | |
} else if(config['keyType'] == 'tag' && event.target.tagName == elem.tagName) { | |
clicked = true; | |
} | |
if(clicked) { | |
if(typeof(config['clickable']['function']) !== 'undefined') { | |
var arguments = [event]; | |
if(typeof(config['clickable']['function_args']) !== 'undefined') { | |
arguments = arguments.concat(config['clickable']['function_args']); | |
} | |
config['clickable']['function'].apply(config['clickable']['function'], arguments); | |
} else if(typeof(config['clickable']['url']) !== 'undefined') { | |
if(typeof(config['clickable']['url_target']) !== 'undefined') { | |
window.open(config['clickable']['url'], config['clickable']['url_target']); | |
} else { | |
window.location = config['clickable']['url']; | |
} | |
} | |
} | |
} | |
_add_event(elem, 'click', clickable); | |
elem.style.cursor = 'pointer'; | |
} | |
} | |
}, | |
/** | |
* See applyFunction | |
* @access private | |
* @method _apply_function | |
* @return void | |
*/ | |
_apply_function = function(config) { | |
if(typeof(config['persistent']) === 'undefined') { | |
config['persistent'] = false; | |
} | |
if(config['persistent']) { | |
if(typeof(_applied_functions[config['id']]) !== 'undefined') { | |
return; | |
} | |
_applied_functions[config['id']] = true; | |
} | |
// Execute the function with the supplied arguments | |
if(typeof(config['function_args']) === 'undefined') { | |
config['function_args'] = []; | |
} | |
config['function'].apply(config['function'], config['function_args']); | |
}, | |
/** | |
* Check to see if an element has a class assigned to it | |
* @access private | |
* @method _has_class | |
* @param {dom element} the element to check | |
* @param {string} the class name to check for | |
* @return void | |
*/ | |
_has_class = function(elem, target_class) { | |
if(elem.className.match(/(?:^|\s)+target_class+(?!\S)/)) { | |
return true; | |
} | |
return false; | |
}, | |
_add_event = function(elem, event, fn) { | |
if(elem.attachEvent) { //Internet Explorer | |
elem.attachEvent("on" + event, function() {fn.call(elem);}); | |
} else if(elem.addEventListener) { //Firefox & company | |
elem.addEventListener(event, fn, false); //don't need the 'call' trick because in FF everything already works in the right way | |
} | |
}, | |
/** | |
* Stolen from jquery and adapted, normalises event objects | |
*/ | |
_normalise_event = function(event) { | |
if(typeof(event) == 'undefined') { | |
event = window.event; | |
} | |
// Fix target property, if necessary | |
if ( !event.target ) { | |
// Fixes #1925 where srcElement might not be defined either | |
event.target = event.srcElement || document; | |
} | |
// check if target is a textnode (safari) | |
if ( event.target.nodeType === 3 ) { | |
event.target = event.target.parentNode; | |
} | |
// Add relatedTarget, if necessary | |
if ( !event.relatedTarget && event.fromElement ) { | |
event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; | |
} | |
// Calculate pageX/Y if missing and clientX/Y available | |
if ( event.pageX == null && event.clientX != null ) { | |
var doc = document.documentElement, | |
body = document.body; | |
event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); | |
event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); | |
} | |
// Add which for key events | |
if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { | |
event.which = event.charCode != null ? event.charCode : event.keyCode; | |
} | |
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) | |
if ( !event.metaKey && event.ctrlKey ) { | |
event.metaKey = event.ctrlKey; | |
} | |
// Add which for click: 1 === left; 2 === middle; 3 === right | |
// Note: button is not normalized, so don't use it | |
if ( !event.which && event.button !== undefined ) { | |
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); | |
} | |
return event; | |
} | |
return { | |
/** | |
* Sets up dfp parameters. | |
* All options are required apart from beaconUrl: | |
* | |
* { | |
* 'accountId': '', | |
* 'environment': '' | |
* 'googleTag': googletag, | |
* 'beaconUrl': '' | |
* } | |
*/ | |
init: function(config) { | |
_dfp_account_id = config['accountId']; | |
_set_environment(config['environment']); | |
_googletag = config['googleTag']; | |
if(typeof(config['beaconUrl']) != 'undefined') { | |
_beacon_url = config['beaconUrl']; | |
} | |
_read_site_tags(); | |
_load_third_parties(); | |
if (_pending_third_parties.running == 0) { | |
_load_ads(); | |
} | |
}, | |
/** | |
* Sets the display mode | |
*/ | |
setDisplayMode: function (display_mode) { | |
_set_display_mode(display_mode); | |
}, | |
/** | |
* Gets the display mode | |
*/ | |
getDisplayMode: function () { | |
return _get_display_mode(); | |
}, | |
/** | |
* Sets the provider | |
*/ | |
setProvider: function (provider) { | |
_provider = _get_variable('adloader_provider', provider); | |
}, | |
/** | |
* Get the provider | |
*/ | |
getProvider: function () { | |
return _get_provider(); | |
}, | |
/** | |
* Sets the environment | |
*/ | |
setEnvironment: function (environment) { | |
_set_environment(environment); | |
}, | |
/** | |
* Get the environment | |
*/ | |
getEnvironment: function () { | |
return _get_environment(); | |
}, | |
/** | |
* Refresh the ads | |
*/ | |
refresh: function() { | |
_refresh(); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
getAugmentedUrl: function (url) { | |
_log_event('Deprecated method called: getAugmentedUrl', 'error'); | |
}, | |
/** | |
* Set googletag | |
*/ | |
setGoogletag: function (googletag) { | |
_googletag = googletag; | |
}, | |
/** | |
* Read in site data from ipc tags json object | |
*/ | |
readSiteTags: function () { | |
_read_site_tags(); | |
}, | |
/** | |
* Initiate third party code | |
*/ | |
loadThirdParties: function () { | |
_load_third_parties(); | |
}, | |
/** | |
* Load the ads | |
* Only call the _load_ads function if there are no pending third parties, if there are pending third parties | |
* the _load_ads call will be made when they are all back or they have timed out | |
*/ | |
loadAds: function () { | |
if (_pending_third_parties.running == 0) { | |
_load_ads(); | |
} | |
}, | |
/** | |
* Register third party load | |
*/ | |
registerThirdPartyLoad: function (third_party) { | |
_register_third_party_load(third_party); | |
}, | |
/** | |
* Register slots to load | |
*/ | |
registerSlot: function (slot_id) { | |
_register_slot(slot_id); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
getBeaconUrl: function(host, namespace) { | |
_log_event('Deprecated method called: getBeaconUrl', 'error'); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
pushParams: function (o) { | |
_log_event('Deprecated method called: pushParams', 'error'); | |
}, | |
/** | |
* Put parameters into the targeting stack. | |
* @access public | |
* @method ipc.adloader.putAdParam | |
* @static | |
* @param {string} The key of the parameter to return | |
* @return mixed or null if the key doesn't exist | |
*/ | |
putAdParam: function(key, value) { | |
_put_ad_param(key, value); | |
}, | |
/** | |
* Get parameters from the targeting stack. | |
* @access public | |
* @method ipc.adloader.getAdParam | |
* @static | |
* @param {string} The key of the parameter to return | |
* @return mixed or null if the key doesn't exist | |
*/ | |
getAdParam: function(key) { | |
return _get_ad_param(key); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
pushTransferVariables: function (o) { | |
_log_event('Deprecated method called: pushTransferVariables', 'error'); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
getTransferVariables: function () { | |
_log_event('Deprecated method called: getTransferVariables', 'error'); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
injectTransferVariables: function (safe_vars) { | |
_log_event('Deprecated method called: injectTransferVariables', 'error'); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
pushNvp: function (o) { | |
_log_event('Deprecated method called: pushNvp', 'error'); | |
}, | |
/** | |
* Push a targeting parameter into the ad slots, parameters can be either | |
* global | |
* @access public | |
* @method ipc.adloader.pushTargetingParam | |
* @static | |
* @param {object} config for the data, takes the form: | |
* { | |
* "name" : "" - {string} a unique identifier for the ad parameter. | |
* "value" : "" - {mixed} the value for the parameter. | |
* "persistent" : "" - {boolean} optional, default false, if true this parameter will not be cleared during ad refreshes. | |
* "scope" : "" - {string} optional, default global, the scope for the parameter, can be global or slots, if local then the parameter can have a different value between refreshes. | |
* "targets" : - {object} optional, this field can be used to target this parameter an individual slots or sizes. Overrides the scope parameter. | |
* { | |
* "slots" : - {array} optional, slot names to target with this parameter | |
* "sizes" : - {array} optional, size arrays to target with this parameter | |
* } | |
* } | |
* @return void | |
* | |
* @todo In the future scope could be expanded to target individual ad | |
* slots, possibly by passing an array of sizes as the scope. | |
*/ | |
pushTargetingParam: function (config) { | |
_push_targeting_param(config); | |
}, | |
/** | |
* @todo deprecated method, should be removed | |
*/ | |
displayParamsToAdd: function () { | |
_log_event('Deprecated method called: displayParamsToAdd', 'error'); | |
}, | |
/* | |
* Push timings to the stack. These parameters are | |
* pushed on to the array which are later used to augment the url | |
* @access public | |
* @method ipc.adloader.logTiming | |
* @static | |
* @param {Object} takes two attributes 'name': [required], 'fn': [required] | |
* @return void | |
*/ | |
logTiming: function(o) { | |
_log_timing(o); | |
}, | |
/* | |
* Writes data to the page, to be called from iFrames | |
* @access public | |
* @method ipc.adloader.writeData | |
* @param {object} config for the data, takes the form: | |
* { | |
* 'id' : '' - {String} A unique identifier for the ad | |
* slot making the request | |
* 'data' : '' - {object} html to write into the page | |
* 'persistent' : '' - {boolean} Optional, if true further | |
* calls to write data from the same source will be ignored | |
* } | |
* @return void | |
*/ | |
writeData: function(config) { | |
_write_data(config); | |
}, | |
/** | |
* Applies styling to an element targeted either by its ID or it’s tag | |
* (eg.body). Styles are is a key/value object which can contain standard | |
* js element.style options | |
* (https://developer.mozilla.org/en-US/docs/CSS/CSS_Reference). | |
* @access public | |
* @method ipc.adloader.applyStyling | |
* @param {object} config for the styling, takes the form: | |
* { | |
* 'key' : '' - {string} tag name or element id | |
* 'keyType' : '' - {string} id/tag | |
* 'persistent' : '' - {boolean} optional, true or false, will | |
* not run on refreshes if true | |
* 'clickable' : - {object} Optional, config for making | |
* the target element clickable | |
* { | |
* 'url' : - {string} target url to trigger when | |
* clicked | |
* 'url_target' : - {string} optional, defaults to blank | |
* 'function' : - {function} function to trigger when | |
* clicked | |
* 'function_args' : - {array} optional, function arguments | |
* } | |
* 'styles' : - {object} required, | |
* { | |
* 'backgroundColor' : '' | |
* 'backgroundImage' : '' | |
* etc. | |
* } | |
* } | |
* @return void | |
*/ | |
applyStyling: function(config) { | |
_apply_styling(config); | |
}, | |
/** | |
* Executes a function on the parent page, could be a function that is | |
* on page eg. inskin functions, or it could be an anonymous function. | |
* @access public | |
* @method ipc.adloader.applyFunction | |
* @param {object} config for the function, takes the form: | |
* { | |
* 'id' : '', - {string} just a unique identifier | |
* 'persistent' : '', - {boolean} optional, true or false, will | |
* not run on refreshes if true | |
* 'function' : '', - {object} anonymous function, or reference | |
* 'function_args' : '' - {array} optional, array of arguments for | |
* function | |
* } | |
* @return void | |
*/ | |
applyFunction: function(config) { | |
_apply_function(config); | |
}, | |
/** | |
* Debug the debug data away | |
* @access public | |
* @method ipc.adloader.beaconDebugData | |
* @param {string} endpoint, default to _beacon_url | |
* @return void | |
*/ | |
beaconDebugData: function(beacon_url) { | |
_beacon_debug_data(beacon_url); | |
}, | |
/** | |
* Load google console | |
* @access public | |
* @method ipc.adloader.loadGoogleConsole | |
* @return void | |
*/ | |
loadGoogleConsole: function() { | |
_load_google_console(); | |
}, | |
/** | |
* Log an event | |
* @access public | |
* @method ipc.adtech.loadEvent | |
* @return void | |
*/ | |
logEvent: function(message, severity) { | |
_log_event(message, severity); | |
} | |
}; | |
}(); | |
/** | |
* This class should contain functions that deal with ad targeting | |
*/ | |
ipc.adloader.targeting = function () { | |
/** | |
* Reads a cookie value and pushes it in as a targeting | |
* parameter. | |
* | |
* Type can be one of two values: | |
* | |
* 'value': The cookie's literal value will be pushed, or false if the cookie does not exist | |
* 'boolean': True/false based on the existence of the cookie | |
* | |
* { | |
* 'name': 'ric_sc', | |
* 'cookie_name': '__ric_sc1123', | |
* 'type': 'value' | |
* } | |
* | |
* @access private | |
* @method _add_cookie_targeting_param | |
* @param {object} config for this cookie targeting parameter | |
* @return void | |
*/ | |
_add_cookie_targeting_param = function(config) { | |
var targeting_config = { | |
'name': config['name'], | |
'value': 'false', | |
'persistent': true | |
}; | |
var cookie_value = ipc.adloader.utils.readCookie(config['cookie_name']); | |
if(cookie_value) { | |
if(config['type'] == 'value') { | |
targeting_config.value = ipc.adloader.utils.slugify(cookie_value); | |
} else if(config['type'] == 'boolean') { | |
targeting_config.value = 'true'; | |
} | |
} | |
ipc.adloader.pushTargetingParam(targeting_config); | |
} | |
return { | |
/** | |
* Reads ipcTags to see if any cookies need to be added as targeting parameters | |
* @access public | |
* @method addCookieTargeting | |
* @return void | |
*/ | |
addCookieTargeting: function() { | |
if(typeof(window.ipcTags.dfp_config.read_cookies) == 'undefined') { | |
return; | |
} | |
var read_cookies = window.ipcTags.dfp_config.read_cookies; | |
for (var name in read_cookies) { | |
_add_cookie_targeting_param(read_cookies[name]); | |
} | |
} | |
}; | |
}(); | |
/** | |
* This class should contain helper functions, usually for performing everyday tasks or xbrowser functionality | |
*/ | |
ipc.adloader.utils = function () { | |
return { | |
/** | |
* Simple read cookie method | |
* @access private | |
* @method _read_cookie | |
* @return mixed, false if cookie does not exist | |
*/ | |
readCookie: function (name) { | |
var value = (document.cookie.match('(^|; )'+name+'=([^;]*)')||0)[2]; | |
if(typeof value == 'undefined') { | |
return false; | |
} | |
return value; | |
}, | |
/** | |
* Slugifies strings for use as targeting variables | |
* | |
* @method _slugify | |
* @access private | |
* @param {String} The unformatted string | |
* @return {String} The formatted string | |
*/ | |
slugify: function(str) { | |
str = String(str); | |
str = str.toLowerCase(); | |
str = str.replace(/[^\w\s]/g, ' '); | |
str = str.replace(/\ +/g, '_'); | |
str = str.replace(/\-$/g, ''); | |
str = str.replace(/^\-/g, ''); | |
return str; | |
} | |
}; | |
}(); | |
if( typeof document.querySelector == "undefined") { | |
// IE7 support for querySelectorAll in 274 bytes. Supports multiple / grouped selectors and the attribute selector with a "for" attribute. http://www.codecouch.com/ | |
(function(d,s){d=document,s=d.createStyleSheet();d.querySelectorAll=function(r,c,i,j,a){a=d.all,c=[],r=r.replace(/\[for\b/gi,'[htmlFor').split(',');for(i=r.length;i--;){s.addRule(r[i],'k:v');for(j=a.length;j--;)a[j].currentStyle.k&&c.push(a[j]);s.removeRule(0)}return c}})() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment