Google Analytics Enhanced
/**
Table of Contents: Analytics
============================
1.0 - Functions
2.0 - Processing
**/
/* globals consoleMessage, ga, ready, forEachElement, checkForParent */
/*--------------------------------------------------------------
1.0 - Functions
--------------------------------------------------------------*/
/**
* Send analytics data for tracking.
*
* @param {url.string} the url to send to analytics
* @param {category.string} the category variable to send
* @param {action.string} the action variable to send
* @param {label.string} the label variable to send
*
*/
function sendAnalytics(category, action, label, url, value) {
'use strict';
// Category default.
if ( category === null || category === undefined ) {
category = 'link';
}
// Action default.
if ( action === null || action === undefined ) {
action = 'click';
}
// Label default.
if ( label === null || label === undefined ) {
if ( url.indexOf('#') === 0 ) {
label = 'Anchor Link';
} else {
label = 'Content Link';
}
}
// URL default.
if ( url === null || url === undefined ) {
url = 'non link';
}
// Set other GA functions [cough] YOAST! [cough].
if ( typeof __gaTracker == 'function' ) {
__gaTracker( function() {
window.ga = __gaTracker;
});
}
// Send to analytics.
if ( typeof ga == 'function' ) {
if ( value === undefined || value === null ) {
// Report the data sent to analytics.
if ( typeof consoleMessage == 'function' ) {
consoleMessage('info', 'ga send: [event], ['+ category +'], ['+ action +'], ['+ label +' ('+ url +')]');
}
// Send to analytics.
ga('send', 'event', category, action, label + ': ' + url);
} else {
// Report the data sent to analytics.
if ( typeof consoleMessage == 'function' ) {
consoleMessage('info', 'ga send: [event], ['+ category +'], ['+ action +'], ['+ label +' ('+ url +')], ['+ value +']');
}
// Send to analytics.
ga('send', 'event', category, action, label + ': ' + url, value);
}
} else {
return false;
}
}
/**
* Send analytics when the user reaches the bottom of
* the page - only once.
*
* @param {markerID.string} the ID of the elment at the bottom to test (footer, site credit, ets)
*/
function getToTheBottom(markerId) {
'use strict';
// Set default bottom test to false.
var scrolledToBottom = false;
function hitBottom() {
var body = document.body,
scroll = body.scrollTop,
// Get the id of the markerId.
bottomMarker = document.getElementById(markerId),
// Get the bounding rectangle and it's top position.
rect = bottomMarker.getBoundingClientRect(),
top = rect.top + scroll,
// Get the coordinates of the bottom minus 50px.
nearBottom = top - 50 - window.innerHeight;
// If we srolled near the bottom.
if ( scroll > nearBottom && !scrolledToBottom ) {
// Send to analytics.
if ( typeof sendAnalytics == 'function') {
sendAnalytics('scroll', 'bottom', 'Scrolled to Bottom');
}
/**
* Set the bottom test to true so we don't keep
* sending the analytic variable. Only prosess once.
*/
scrolledToBottom = true;
}
}
window.onscroll = function(){
hitBottom();
};
window.onresize = function() {
hitBottom();
};
}
/**
* Attach listener to all <a> elements to gather data analytics and send.
* Set as function to call after user interaction items.
*
* @param {conainer.string} Element to target for {selector} children
*/
function linkListenAnalytics(container) {
'use strict';
// For every link.
forEachElement(container,'a', function(el){
// Add a listenter for the click.
el.addEventListener('click', function(event){
// Don't use the link just yet.
event.preventDefault();
// Get the data attributes.
var aCategory = el.getAttribute('data-analytics-category'),
aAction = el.getAttribute('data-analytics-action'),
aLabel = el.getAttribute('data-analytics-label'),
aURL = el.getAttribute('href'),
aTarget = el.getAttribute('target');
// Check for the click type.
if ( event.metaKey || event.ctrlKey || event.which == 2 ) {
aTarget = '_blank';
}
// Set the label to the content html if empty.
if ( aLabel === null ) {
aLabel = el.innerHTML;
}
// Set the Category.
if ( !aCategory ) {
// Default is link item.
aCategory = 'link';
// Check if we have a list item.
var isListItem = checkForParent(el, 'LI');
if ( isListItem ) {
// Check if the link is part of a menu or sub-menu.
var isMenuItem = el.parentNode.classList.contains('menu-item'),
isSubMenuItem = el.parentNode.parentNode.classList.contains('sub-menu');
// Check if the list item is part of a nav, sub menu, or default to list item.
aCategory = 'list item';
if ( isMenuItem ) {
aCategory = 'menu';
}
if ( isSubMenuItem ) {
aCategory = 'sub menu';
}
}
}
// If the link is not a nav button.
if ( !el.classList.contains('nav-button') && !el.classList.contains('button-popular-links') ) {
sendAnalytics(aCategory, aAction, aLabel, aURL);
}
// Check if we have a click time set.
if ( typeof( clickTime ) !== 'undefined') {
clearTimeout(clickTime);
}
// After a timeout, go to the intended link.
var clickTime = setTimeout( function() {
// If you disabale this - the mobile menu will not work.
// No target link.
if ( aTarget === undefined || aTarget === null || aTarget != '_blank' ) {
// Comment out for testing.
document.location.href = aURL;
}
// Target link.
else {
// Comment out for testing.
window.open( aURL, aTarget );
}
}, 200);
});
});
}
/**
* Capture the input for search and pass to analytics.
*
* @return {void}
*/
function searchAnalytics() {
'use strict';
// Get the class.
var searchForm = '.search-form';
forEachElement(null, searchForm, function(el) {
// Listen for the search form to be submitted.
el.addEventListener('submit', function(event){
// Don't process the form yet.
event.preventDefault();
// Get the search input and it's value.
var searchValue = el.querySelector('.search-field').value;
// If sendAnalytics exist - send the value to analytics.
if ( typeof sendAnalytics == 'function' ) {
sendAnalytics('search', 'submit', 'Search Term', searchValue);
}
// Check if we have a click time set.
if ( typeof( searchTime ) !== 'undefined') {
clearTimeout(searchTime);
}
// After a timeout, go to the intended link.
var searchTime = setTimeout( function() {
// .2s delay to allow the form to be tracked.
el.submit();
}, 200);
});
});
}
/*--------------------------------------------------------------
2.0 - Processing
--------------------------------------------------------------*/
// When the document is loaded and ready.
ready(function(){
'use strict';
var wrapper = document.getElementById('site-outer-wrapper');
// Set listener for <a> tag links.
linkListenAnalytics(wrapper);
// Search analytics.
searchAnalytics();
// Reached the bottom of the page.
getToTheBottom('analytics-bottom-tracker');
});