AJAX Event Listener
/*
* v0.1.0
* Created by the Google Analytics consultants at http://www.lunametrics.com
* Written by @notdanwilkerson
* Documentation: http://www.lunametrics.com/blog/2015/08/27/ajax-event-listener-google-tag-manager/
* Licensed under the Creative Commons 4.0 Attribution Public License
*/
(function() {
// 'use strict';
/*
var $, n = 0;
init();
function init(n) {
if (typeof jQuery !== 'undefined') { // Ensure jQuery is available before anything
$ = jQuery; // Define our $ shortcut locally
bindToAjax();
} else if (n < 20) { // Check for up to 10 seconds
n++;
setTimeout(init, 500);
}
}
function bindToAjax() {
$(document).bind('ajaxComplete', function(evt, jqXhr, opts) {
var fullUrl = document.createElement('a'); // Create a fake a element for magically simple URL parsing
fullUrl.href = opts.url;
var pathname = fullUrl.pathname[0] === '/' ? fullUrl.pathname : '/' + fullUrl.pathname; // IE9+ strips the leading slash from a.pathname because who wants to get home on time Friday anyways
var queryString = fullUrl.search[0] === '?' ? fullUrl.search.slice(1) : fullUrl.search; // Manually remove the leading question mark, if there is one
var queryParameters = objMap(queryString, '&', '=', true); // Turn our params and headers into objects for easier reference
var headers = objMap(jqXhr.getAllResponseHeaders(), '\n', ':');
var response = jqXhr.responseJSON || jqXhr.responseXML || jqXhr.responseText || '';
console.log('pathname >', pathname, 'response >', response);
if (pathname == '/ajax/order/make/' && response.length) {
dataLayer.push({
'event': 'userEvent true',
'dataEvent': {
'category': 'Coupon',
'event': 'Order sent',
'label': coupon
}
});
console.log('response >', JSON.parse(response).error);
}
/*
dataLayer.push({ // Blindly push to the dataLayer because this fires within GTM
'event': 'ajaxComplete',
'attributes': { // Return empty strings to prevent accidental inheritance of old data
'type': opts.type || '',
'url': fullUrl.href || '',
'queryParameters': queryParameters,
'pathname': pathname || '',
'hostname': fullUrl.hostname || '',
'protocol': fullUrl.protocol || '',
'fragment': fullUrl.hash || '',
'statusCode': jqXhr.status || '',
'statusText': jqXhr.statusText || '',
'headers': headers,
'timestamp': evt.timeStamp || '',
'contentType': opts.contentType || '',
'response': (jqXhr.responseJSON || jqXhr.responseXML || jqXhr.responseText || '') // Defer to jQuery's handling of the response
}
});
});
}
function objMap(data, delim, spl, decode) {
var obj = {};
if (!data || !delim || !spl) return {}; // If one of our parameters is missing, return an empty object
var i, arr = data.split(delim);
if (arr) {
for (i = 0; i < arr.length; i++) {
var item = decode ? decodeURIComponent(arr[i]) : arr[i]; // If the decode flag is present, URL decode the set
var pair = item.split(spl);
var key = trim_(pair[0]);
var value = trim_(pair[1]);
if (key && value) {
obj[key] = value;
}
}
}
return obj;
}
function trim_(str) { // Basic .trim() polyfill
if (str) return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
*/
})();
sl.ajaxEvent = {
n: 0,
init: function(n) {
var $;
if (typeof jQuery !== 'undefined') { // Ensure jQuery is available before anything
$ = jQuery; // Define our $ shortcut locally
this.bindToAjax();
} else if (this.n < 20) { // Check for up to 10 seconds
this.n++;
setTimeout(this.init, 500);
}
},
bindToAjax: function() {
var self = this;
$(document).bind('ajaxComplete', function(evt, jqXhr, opts) {
var fullUrl = document.createElement('a'); // Create a fake a element for magically simple URL parsing
fullUrl.href = opts.url;
var pathname = fullUrl.pathname[0] === '/' ? fullUrl.pathname : '/' + fullUrl.pathname; // IE9+ strips the leading slash from a.pathname because who wants to get home on time Friday anyways
// var queryString = fullUrl.search[0] === '?' ? fullUrl.search.slice(1) : fullUrl.search; // Manually remove the leading question mark, if there is one
// var queryParameters = self.objMap(queryString, '&', '=', true); // Turn our params and headers into objects for easier reference
var headers = self.objMap(jqXhr.getAllResponseHeaders(), '\n', ':');
var response = jqXhr.responseJSON || jqXhr.responseXML || jqXhr.responseText || '';
sl.ajaxEvent.list(pathname, response);
/*
dataLayer.push({ // Blindly push to the dataLayer because this fires within GTM
'event': 'ajaxComplete',
'attributes': { // Return empty strings to prevent accidental inheritance of old data
'type': opts.type || '',
'url': fullUrl.href || '',
'queryParameters': queryParameters,
'pathname': pathname || '',
'hostname': fullUrl.hostname || '',
'protocol': fullUrl.protocol || '',
'fragment': fullUrl.hash || '',
'statusCode': jqXhr.status || '',
'statusText': jqXhr.statusText || '',
'headers': headers,
'timestamp': evt.timeStamp || '',
'contentType': opts.contentType || '',
'response': (jqXhr.responseJSON || jqXhr.responseXML || jqXhr.responseText || '') // Defer to jQuery's handling of the response
}
});
*/
});
},
objMap: function(data, delim, spl, decode) {
var obj = {};
if (!data || !delim || !spl) return {}; // If one of our parameters is missing, return an empty object
var i, arr = data.split(delim);
if (arr) {
for (i = 0; i < arr.length; i++) {
var item = decode ? decodeURIComponent(arr[i]) : arr[i], // If the decode flag is present, URL decode the set
pair = item.split(spl),
key = this.trim_(pair[0]),
value = this.trim_(pair[1]);
if (key && value) {
obj[key] = value;
}
}
}
return obj;
},
trim_: function(str) {
if (str) return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
};
sl.ajaxEvent.list = function(pathname, response) {
if (pathname == '/ajax/order/make/' && response.length) {
var message,
coupon = $('#COUPON').val().substr(0, 50) || '',
resp = String(JSON.parse(response).error).replace("<nobr>", "");
switch(0) {
case resp.search(/Заказ с/):
message = 0;
break;
case resp.search(/Изменился состав/):
message = 1;
break;
case resp.search(/В корзине/):
message = 2;
break;
case resp.search(/Промокод не/):
message = 3;
break;
case resp.search(/Для пользователя/):
message = 4;
break;
case resp.search(/Данный промокод/):
message = 5;
break;
case resp.search(/Истек срок/):
message = 6;
break;
case resp.search(/Для применения/):
message = 7;
break;
case resp.search(/Промокод нельзя/):
message = 8;
break;
}
dataLayer.push({
'event': 'userEvent true',
'dataEvent': {
'category': 'Coupon',
'event': coupon,
'label': message
}
});
// console.log('pathname >', pathname, '; response >', JSON.parse(response).error);
}
};
sl.ajaxEvent.init();