/**
* @class
* @classdesc Plugin with utils methods.
* @name Utils
* @memberof ATInternet.Tracker.Plugins
* @type {function}
* @param tag {object} Instance of the Tag used
* @description
* This plugin shares specific feature methods to our helper plugins.
* For example plugins Page, Clicks and OnSiteAds have common usages.
* @public
*/
ATInternet.Tracker.Plugins.Utils = function (tag) {
'use strict';
var self = this;
// storage for the querystrings processed, key is the hash of the querystring, value is an object with all querystring parameters
var _queryStringValues = {};
var _debug = {
level: 'DEBUG',
messageEnd: 'method ended'
};
/**
* [Object added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}]
* @name utils
* @memberof ATInternet.Tracker.Tag
* @inner
* @type {object}
* @property {function} get Tag helper, see details here {@link ATInternet.Tracker.Tag#utils.getQueryStringValue}
* @property {function} getPrivate Tag helper, see details here {@link ATInternet.Tracker.Tag#utils.getLocation}
* @public
*/
tag.utils = {};
/**
* Get the value of a queryString variable
* @name getQueryStringValue
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @param name {string} Variable that you want to get
* @param str {string} String in which we will look the wanted variable (considered as queryString format)
* @return string|null|undefined {string|null|undefined} This method returns a string if the variable exists with a value,
* it returns null if the variable is not present (or not correct for a queryString) or
* it returns undefined if the variable exists but doesn't have any value (ex : '&variable=')
* @public
*/
tag.utils.getQueryStringValue = self.getQueryStringValue = function (name, str) {
var hash = ATInternet.Utils.hashcode(str).toString();
if (!_queryStringValues[hash]) {
_queryStringValues[hash] = {};
var regex = new RegExp('[&#?]{1}([^&=#?]*)=([^&#]*)?', 'g');
var match = regex.exec(str);
while (match !== null) {
_queryStringValues[hash][match[1]] = match[2];
match = regex.exec(str);
}
}
if (_queryStringValues[hash].hasOwnProperty(name)) {
return _queryStringValues[hash][name];
} else {
return null;
}
};
/**
* Check an iterative property in an object and build a specific string from it
* @name manageChapters
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @param tagObject {object} Object including properties to be checked
* @param key {string} Key to be checked
* @param length {number|string} Number of occurences
* @return {string}
* @example
* <pre>
* var myObject = {
* chapter1:'one',
* chapter2:'two'
* }
* var chapters = manageChapters(myObject, 'chapter', 2);
* // chapters = 'one::two::'
* </pre>
* @public
*/
tag.utils.manageChapters = self.manageChapters = function (tagObject, key, length) {
var fullChapter = '';
if (tagObject) {
var ignoreEmpty = tag.getConfig('ignoreEmptyChapterValue');
var chapterLabel = '';
for (var i = 1; i < parseInt(length, 10) + 1; i++) {
chapterLabel = tagObject[key + i] || '';
if (ignoreEmpty) {
fullChapter += chapterLabel ? chapterLabel + '::' : '';
} else {
fullChapter += tagObject.hasOwnProperty(key + i) ? chapterLabel + '::' : '';
}
}
}
return fullChapter;
};
/**
* Get document level to use from global configuration or the default one (document.)
* @name getDocumentLevel
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {object}
* @public
*/
tag.utils.getDocumentLevel = self.getDocumentLevel = function () {
var documentLevel = tag.getConfig('documentLevel');
if (documentLevel) {
if (documentLevel.indexOf('.') < 0) {
return (window[documentLevel] || document);
} else {
var tab = documentLevel.split('.');
return (window[tab[0]][tab[1]] || document);
}
}
return document;
};
/**
* Get the current location (URL associated with the document level configured)
* @name getLocation
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {string}
* @public
*/
tag.utils.getLocation = self.getLocation = function () {
var obj = self.getDocumentLevel();
return obj.location.href;
};
/**
* Get the current location (URL associated with the document level configured)
* @name getLocation
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {string}
* @public
*/
tag.utils.getHostName = self.getHostName = function () {
var obj = self.getDocumentLevel();
return obj.location.hostname;
};
////////////////////////////// dispatch ///////////////////////////////////
tag.dispatchIndex = {};
tag.dispatchStack = [];
tag.dispatchEventFor = {};
var ExecWaitingSpecificDispatchCount = 0;
/**
* [Function added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Add a helper plugin into a list telling which ones have been used before dispatching
* @name dispatchSubscribe
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param helperName {string} Plugin name to add
* @return {boolean}
* @private
*/
tag.dispatchSubscribe = function (helperName) {
if (!tag.dispatchIndex[helperName]) {
tag.dispatchStack.push(helperName);
tag.dispatchIndex[helperName] = true;
return true;
}
return false;
};
/**
* [Function added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Return a boolean which tell if the helper plugin concerned is waiting for a dispatch
* @name dispatchSubscribed
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param helperName {string} Plugin name to check
* @return {boolean}
* @private
*/
tag.dispatchSubscribed = function (helperName) {
return tag.dispatchIndex[helperName] === true;
};
/**
* [Function added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Add a specific event for dispatching
* @name addSpecificDispatchEventFor
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param helperName {string} Plugin name to check
* @return {boolean}
* @private
*/
tag.addSpecificDispatchEventFor = function (helperName) {
if (!tag.dispatchEventFor[helperName]) {
tag.dispatchEventFor[helperName] = true;
ExecWaitingSpecificDispatchCount++;
return true;
}
return false;
};
/**
* Test if specific dispatch are being processed
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {boolean}
* @private
*/
var _IsExecWaitingSpecificDispatch = function () {
return ExecWaitingSpecificDispatchCount !== 0;
};
/**
* [Function added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Process a specific event for dispatching
* @name processSpecificDispatchEventFor
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param helperName {string} Plugin name to check
* @private
*/
tag.processSpecificDispatchEventFor = function (helperName) {
if (tag.dispatchEventFor[helperName]) {
tag.dispatchEventFor[helperName] = false;
ExecWaitingSpecificDispatchCount--;
if (ExecWaitingSpecificDispatchCount === 0) {
tag.dispatchEventFor = {};
tag.emit('Tracker:Plugin:SpecificEvent:Exec:Complete', {lvl: 'INFO'});
}
}
};
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Dispatch all tags.
* @name dispatch
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param callback {function} Callback to execute
* @param elementType {string} Element type (mailto, form, redirection)
* @public
*/
tag.dispatch = function (callback, elementType) {
var _doDispatch = function () {
var name = '';
var cb = null;
while (tag.dispatchStack.length > 0) {
name = tag.dispatchStack.pop();
if (tag.dispatchStack.length === 0) {
cb = callback;
}
tag[name].onDispatch(cb, elementType);
}
tag.dispatchIndex = {};
tag.delContext(undefined, 'customObject');
/* @if debug */
tag.debug('Utils:dispatch', _debug.level, _debug.messageEnd);
/* @endif */
};
var _processDispatch = function () {
if (!tag.plugins.isExecWaitingLazyloading()) {
_doDispatch();
} else {
// it manages both cases, lazyload plugins can finish loading after some lazyload triggers or the contrary
tag['onTrigger']('Tracker:Plugin:Lazyload:Exec:Complete', function () {
_doDispatch();
}, true);
}
};
if (!_IsExecWaitingSpecificDispatch()) {
_processDispatch();
} else {
tag.onTrigger('Tracker:Plugin:SpecificEvent:Exec:Complete', function () {
_processDispatch();
}, true);
}
};
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Dispatch all tags (with automatic redirect management).
* @name dispatchRedirect
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param tagObject {object} Tag object, used here to tell how we have to do the redirection (url/target)
* @return {boolean}
* @public
*/
tag.dispatchRedirect = function (tagObject) {
var preservePropagation = true;
var elementType = '';
var callback = null;
if (tagObject) {
var eventObject = null;
if (tagObject.hasOwnProperty('event')) {
eventObject = tagObject.event || window.event;
}
if (!ATInternet.Utils.isTabOpeningAction(eventObject) && tagObject.elem) {
tag.plugins.exec('TechClicks', 'manageClick', [tagObject.elem, eventObject], function (data) {
preservePropagation = data.preservePropagation;
elementType = data.elementType;
});
}
callback = tagObject.callback;
}
tag.dispatch(callback, elementType);
return preservePropagation;
};
////////////////////////////// send ///////////////////////////////////
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Manage send depending on Safari previewing and Chrome/IE prerendering.
* @name manageSend
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param callback {function} Function to execute when not in prerendering mode or on "visibilityChangeEvent"
* @private
*/
tag.manageSend = function (callback) {
if (!ATInternet.Utils.isPreview() || tag.getConfig('preview')) {
if (!ATInternet.Utils.isPrerender(function (event) {
callback(event);
})) {
callback();
}
}
};
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Merge Tag object with the corresponding permanent buffered object if exists.
* @name processTagObject
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param hitParam {string} Hit parameter
* @param hitType {array} Hit types
* @param tagObject {object} Tag object
* @return {object}
* @private
*/
tag.processTagObject = function (hitParam, hitType, tagObject) {
var bufferObject = tag.getParam(hitParam, true);
if (bufferObject && bufferObject._options['permanent']) {
var isValidType = false;
var bufferObjectType = bufferObject._options['hitType'] || [];
for (var i = 0; i < bufferObjectType.length; i++) {
if (ATInternet.Utils.arrayIndexOf(hitType.concat('all'), bufferObjectType[i]) !== -1) {
isValidType = true;
break;
}
}
if (isValidType) {
tagObject = ATInternet.Utils.completeFstLevelObj((bufferObject._value || {}), tagObject, true);
}
}
return tagObject;
};
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Merge object from Context with the corresponding buffered object if exists before sending hit.
* @name processContextObjectAndSendHit
* @memberof ATInternet.Tracker.Tag
* @inner
* @function
* @param hitParam {string} Hit parameter
* @param paramOptions {object} Parameter options
* @param contextObject {object} Context object
* @param callback {function} Callback to execute
* @private
*/
tag.processContextObjectAndSendHit = function (hitParam, paramOptions, contextObject, callback) {
var setParamOptions = {
hitType: paramOptions.hitType,
encode: paramOptions.encode,
separator: paramOptions.separator,
truncate: paramOptions.truncate
};
var bufferObject = tag.getParam(hitParam, true);
if (bufferObject) {
var isValidType = false;
var bufferObjectType = bufferObject._options['hitType'] || [];
for (var i = 0; i < bufferObjectType.length; i++) {
if (ATInternet.Utils.arrayIndexOf(paramOptions.hitType.concat('all'), bufferObjectType[i]) !== -1) {
isValidType = true;
break;
}
}
if (isValidType) {
var clonedBufferObject = ATInternet.Utils.cloneSimpleObject(bufferObject);
clonedBufferObject._value = ATInternet.Utils.completeFstLevelObj((clonedBufferObject._value || {}), contextObject, true);
tag.setParam(hitParam, clonedBufferObject._value, setParamOptions);
tag.manageSend(function () {
tag.sendHit(null, [['hitType', paramOptions.hitType]], callback, paramOptions.requestMethod, paramOptions.elementType);
});
var isPermanent = bufferObject._options['permanent'];
if (isPermanent) {
tag.setParam(hitParam, bufferObject._value, bufferObject._options);
}
} else {
tag.setParam(hitParam, contextObject, setParamOptions);
tag.manageSend(function () {
tag.sendHit(null, [['hitType', paramOptions.hitType]], callback, paramOptions.requestMethod, paramOptions.elementType);
});
tag.setParam(hitParam, bufferObject._value, bufferObject._options);
}
} else {
tag.setParam(hitParam, contextObject, setParamOptions);
tag.manageSend(function () {
tag.sendHit(null, [['hitType', paramOptions.hitType]], callback, paramOptions.requestMethod, paramOptions.elementType);
});
}
};
///////////////////////////////////////////////////////////////////////////////////////
/* @if test */
self.getQueryStringValuesHash = function () {
return _queryStringValues
};
/* @endif */
};
ATInternet.Tracker.addPlugin('Utils');