/**
* Module for handling all types of Analytics
*
* @module Analytics
*/
const Analytics = {
types: ['adobe', 'ga'],
modules: false,
/*
* Binds initialize various types of analytics and add click listeners for click tracking
*
* @param {Array} modules - list of analytics modules to be initiated
* @method init
*/
init( modules ) {
if ( ! modules ) {
return;
}
this.modules = modules;
[].forEach.call( Object.keys( modules ), ( key ) => {
const analyticsModule = modules[key];
analyticsModule.init();
});
// Listen to clicks to elements with data attribute trackable=true
const trackableLinks = document.querySelectorAll( '[data-trackable="true"]' );
for ( let i = 0; i < trackableLinks.length; i += 1 ) {
trackableLinks[i].addEventListener( 'click', ( evt ) => {
// click tracking enabled for adobe and ga by default
let blockedLink = '';
const link = evt.currentTarget.getAttribute( 'href' );
if ( link && '_blank' !== evt.currentTarget.getAttribute( 'target' ) ) {
evt.preventDefault();
blockedLink = link;
}
let trackTypes = evt.currentTarget.dataset.tracktypes ? evt.currentTarget.dataset.tracktypes : '';
trackTypes = '' !== trackTypes ? trackTypes.split( ',' ) : this.types;
// Delay defaults to 0.5 seconds
let delay = 0.5;
if ( evt.currentTarget.dataset.trackdelay ) {
delay = evt.currentTarget.dataset.trackdelay;
}
const eventType = evt.currentTarget.dataset.trackEventType || evt.type;
const elem = evt.currentTarget;
setTimeout( () => {
this.track( trackTypes, this.getTrackingObject( eventType, elem ), blockedLink );
}, parseFloat( delay, 10 ) * 1000 );
});
}
},
getTrackingObject( type, elem ) {
let trackAction = elem.dataset.trackaction;
trackAction = this.getTrackingValue( elem, trackAction );
let trackData = elem.dataset.trackdata;
trackData = trackData ? JSON.parse( this.getTrackingValue( elem, trackData ).replace( /'/g, '"' ) ) : '';
const details = {
eventType: type,
action: trackAction,
data: trackData,
target: elem,
};
return details;
},
getTrackingValue( elem, trackingString ) {
let updatedTrackingString = trackingString;
const match = new RegExp( '(!)*\\${([^}]+)}', 'g' ).exec( trackingString ); // eslint-disable-line no-template-curly-in-string
if ( match && match.length >= 3 ) {
const [replaceString, operator, tokenKey] = match;
let tokenValue = elem.getAttribute( tokenKey );
if ( '!' === operator ) {
if ( 'false' === tokenValue ) {
tokenValue = 'true';
} else {
tokenValue = 'false';
}
}
updatedTrackingString = updatedTrackingString.replace( replaceString, tokenValue );
}
return updatedTrackingString;
},
/*
* Trigger custom tracking calls
*
* examples:
* gn_analytics.Analytics.track( 'adobe', { action: 'next slide', data: { slidenumber: 1} } );
* gn_analytics.Analytics.track( 'ga', { eventType: 'Click', action: 'Next slide' } );
*
* @param {Array|String} types - types of analytics to track
* @param {Object} details - data to be tracked
* @method track
*/
track( types, details, blockedLink = '' ) {
if ( ! types || ! this.modules ) {
return;
}
let trackTypes = types;
if ( 'string' === typeof ( trackTypes ) ) {
trackTypes = [trackTypes];
}
const {
eventType,
target,
action,
data,
} = details;
[].forEach.call( trackTypes, ( type ) => {
switch ( type ) {
case 'adobe':
if ( this.modules.adobe ) {
const linkName = ( eventType ? `${eventType} | ` : '' ) + action;
this.modules.adobe.trackLink( target, 'o', linkName, data );
}
break;
case 'ga':
/* global ga */
if ( 'undefined' !== typeof ( ga ) ) {
ga( 'send', 'event', eventType, action );
}
break;
case 'permutive':
if ( 'undefined' !== typeof ( window.permutive ) && data ) {
window.permutive.track( 'AffiliateLinkClick', data );
}
break;
default:
break;
}
});
// blockedLink will be handled by Adobe's tracking call
// Handle blocked link manually for non-Adobe calls.
if ( blockedLink && trackTypes.length < 2 && 'adobe' !== trackTypes[0]) {
// link was blocked to ensure tracking call gets made
// Navigate to blocked link in 500 ms
setTimeout( () => {
if ( blockedLink.length > 0 ) {
window.location.href = blockedLink;
}
}, 500 );
}
},
};
export default Analytics;