/**
* @class
* @classdesc Plugin with utils methods.
* @name Utils
* @memberof ATInternet.Tracker.Plugins
* @type {function}
* @param parent {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
*/
window['ATInternet']['Tracker']['Plugins']['Utils'] = function (parent) {
"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 = {};
/**
* [Object added by plugin {@link ATInternet.Tracker.Plugins.Utils Utils}] Methods to .
* @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
*/
parent.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
*/
parent.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'),
match = regex.exec(str);
if (match !== null) {
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 containing properties to check
* @param key {string} Key word to check
* @param length {number} Number of occurence possible
* @return {string}
* @example
* <pre>
* var myObject = {
* chapter1:'one',
* chapter2:'two'
* }
* var chapters = manageChapters(myObject, 'chapter', 2);
* // chapters = 'one::two::'
* </pre>
* @public
*/
self.manageChapters = function (tagObject, key, length) {
var config = parent.getConfig('ignoreEmptyChapterValue');
var chapt = '';
if (tagObject) {
length = parseInt(length, 10);
for (var i = 1; i < length + 1; i++) {
var chapterName = tagObject[key + i] || '';
if (config) {
chapt += chapterName ? chapterName + '::' : '';
} else {
chapt += tagObject.hasOwnProperty(key + i) ? chapterName + '::' : '';
}
}
}
return chapt;
};
/**
* Get document level to use from global configuration or the default one (document.)
* @name getDocumentLevel
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {object}
* @public
*/
self.getDocumentLevel = function () {
var documentLevel = parent.getConfig('documentLevel');
if (documentLevel.indexOf('.') < 0) {
return (window[documentLevel] || document);
} else {
var tab = documentLevel.split('.');
return (window[tab[0]][tab[1]] || document);
}
};
/**
* Get the current location (URL associated with the document level configured)
* @name getLocation
* @memberof ATInternet.Tracker.Plugins.Utils#
* @function
* @return {string}
* @public
*/
parent.utils.getLocation = self.getLocation = function () {
var obj = self.getDocumentLevel();
return obj.location.href;
};
////////////////////////////// dispatch ///////////////////////////////////
parent.dispatchIndex = {};
parent.dispatchStack = [];
parent.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
*/
parent.dispatchSubscribe = function (helperName) {
if (!parent.dispatchIndex[helperName]) {
parent.dispatchStack.push(helperName);
parent.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
*/
parent.dispatchSubscribed = function (helperName) {
return parent.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
*/
parent.addSpecificDispatchEventFor = function (helperName) {
if (!parent.dispatchEventFor[helperName]) {
parent.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
*/
parent.processSpecificDispatchEventFor = function (helperName) {
if (parent.dispatchEventFor[helperName]) {
parent.dispatchEventFor[helperName] = false;
ExecWaitingSpecificDispatchCount--;
if (ExecWaitingSpecificDispatchCount === 0) {
parent.dispatchEventFor = {};
parent['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
* @public
*/
parent.dispatch = function (callback) {
var _doDispatch = function () {
var name = '';
var param = null;
while (parent.dispatchStack.length > 0) {
name = parent.dispatchStack.pop();
if (parent.dispatchStack.length === 0) {
param = callback
}
parent[name]['onDispatch'](param);
}
parent.dispatchIndex = {};
parent.delContext(undefined, 'customObject');
/* @if debug */
parent.debug('Utils:dispatch', 'DEBUG', 'method ended');
/* @endif */
};
var _processDispatch = function () {
if (!parent.plugins.isExecWaitingLazyloading()) {
_doDispatch();
} else {
// it manages both cases, lazyload plugins can finish loading after some lazyload triggers or the contrary
parent['onTrigger']('Tracker:Plugin:Lazyload:Exec:Complete', function () {
_doDispatch();
}, true);
}
};
if (!_IsExecWaitingSpecificDispatch()) {
_processDispatch();
} else {
parent['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
*/
parent.dispatchRedirect = function (tagObject) {
var preservePropagation = true;
var callback = null;
if (tagObject) {
var eventObject = tagObject.event || window.event;
if (!ATInternet.Utils.isTabOpeningAction(eventObject) && tagObject.elem) {
tagObject.elem.timeoutonly = true;
parent.plugins.exec('TechClicks', 'manageClick', [tagObject.elem, eventObject], function (data) {
preservePropagation = data;
});
}
callback = tagObject.callback;
}
parent.dispatch(callback);
return preservePropagation;
};
////////////////////////////// dispatch ///////////////////////////////////
/**
* [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
*/
var _manageSend = parent.manageSend = function (callback) {
if (!ATInternet.Utils.isPreview() || parent.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
*/
parent.processTagObject = function (hitParam, hitType, tagObject) {
var bufferObject = parent.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
*/
parent.processContextObjectAndSendHit = function (hitParam, paramOptions, contextObject, callback) {
var bufferObject = parent.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);
parent.setParam(hitParam, clonedBufferObject.value, {
hitType: paramOptions.hitType,
encode: paramOptions.encode,
separator: paramOptions.separator,
truncate: paramOptions.truncate
});
_manageSend(function () {
parent.sendHit(null, [['hitType', paramOptions.hitType]], callback, null, true);
});
var isPermanent = bufferObject.options['permanent'];
if (isPermanent) {
parent.setParam(hitParam, bufferObject.value, bufferObject.options);
}
}
else {
parent.setParam(hitParam, contextObject, {
hitType: paramOptions.hitType,
encode: paramOptions.encode,
separator: paramOptions.separator,
truncate: paramOptions.truncate
});
_manageSend(function () {
parent.sendHit(null, [['hitType', paramOptions.hitType]], callback, null, true);
});
parent.setParam(hitParam, bufferObject.value, bufferObject.options);
}
}
else {
parent.setParam(hitParam, contextObject, {
hitType: paramOptions.hitType,
encode: paramOptions.encode,
separator: paramOptions.separator,
truncate: paramOptions.truncate
});
_manageSend(function () {
parent.sendHit(null, [['hitType', paramOptions.hitType]], callback, null, true);
});
}
};
/* @if test */
self.getQueryStringValuesHash = function () {
return _queryStringValues
};
/* @endif */
};
window['ATInternet']['Tracker']['addPlugin']('Utils');