/**
* @class
* @classdesc Utility methods.
* @name Utils
* @public
*/
var Utils = function () {
var self = this;
var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
var whitespace = "[\\x20\\t\\r\\n\\f]";
var rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g");
/**
* Serialize any element.
* @memberof Utils#
* @param obj {Object} Object to serialize
* @return {String}
* @private
*/
function serialJSON(obj) {
var t = typeof obj;
if (t !== 'object' || obj === null) {
if (t === 'string') {
obj = '"' + obj + '"';
}
return String(obj);
} else {
var n, v, json = [],
arr = (obj.constructor === Array);
for (n in obj) {
if (obj.hasOwnProperty(n)) {
v = obj[n];
t = typeof (v);
if (t !== 'function' && t !== 'undefined') {
if (t === 'string') {
v = '"' + v.replace(/[^\\]"/g, '\\"') + '"';
} else if (t === 'object' && v !== null) {
v = serialJSON(v);
}
json.push((arr ? '' : '"' + n + '":') + String(v));
}
}
}
return (arr ? '[' : '{') + String(json) + (arr ? ']' : '}');
}
}
/**
* Trim JSON string.
* @memberof Utils#
* @param text {String} Text to trim
* @return {String}
* @private
*/
function trimJSONString(text) {
return text === null ?
'' :
(text + '').replace(rtrim, '');
}
/**
* Parse any string.
* @memberof Utils#
* @param data {string} String to parse
* @return {*}
* @private
*/
function parseJSON(data) {
var requireNonComma,
depth = null,
str = trimJSONString(data + '');
// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
// after removing valid tokens
return str && !trimJSONString(str.replace(rvalidtokens, function (token, comma, open, close) {
// Force termination if we see a misplaced comma
if (requireNonComma && comma) {
depth = 0;
}
// Perform no more replacements after returning to outermost depth
if (depth === 0) {
return token;
}
// Commas must not follow "[", "{", or ","
requireNonComma = open || comma;
// Determine new depth
// array/object open ("[" or "{"): depth += true - false (increment)
// array/object close ("]" or "}"): depth += false - true (decrement)
// other cases ("," or primitive): depth += true - true (numeric cast)
depth += !close - !open;
// Remove this token
return '';
})) ?
(Function('return ' + str))() :
null;
}
/**
* Check if local storage is both supported and available
* @name isLocalStorageAvailable
* @memberof Utils#
* @return {boolean}
* @public
*/
self.isLocalStorageAvailable = function () {
try {
var storage = localStorage,
x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
} catch (e) {
return false;
}
};
/**
* Check if beacon method is supported and available
* @name isBeaconMethodAvailable
* @memberof Utils#
* @return {boolean}
* @public
*/
self.isBeaconMethodAvailable = function () {
return (window.navigator && typeof window.navigator.sendBeacon === "function");
};
/**
* Get a stored value from name
* @name getStorageData
* @memberof Utils#
* @function
* @param name {String} Name of the stored data
* @return {*} Return null if the stored data does not exist
* @private
*/
function getStorageData(name) {
var storedData = null;
if (self.isLocalStorageAvailable()) {
storedData = localStorage.getItem(name)
}
if (storedData === null) {
var cookies = document.cookie;
var regExp = new RegExp('(?:^| )' + name + '=([^;]+)');
var result = regExp.exec(cookies);
if (result !== null) {
storedData = result[1];
}
}
if (storedData !== null) {
try {
storedData = decodeURIComponent(storedData);
} catch (e) {
}
}
return storedData;
}
/**
* Base64 encode / decode
* *http://www.webtoolkit.info/
* @memberof Utils#
* @Object
* @public
*/
self.Base64 = {
// private property
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode: function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = self.Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode: function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = self.Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode: function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode: function (utftext) {
var string = "";
var i = 0;
var c, c2, c3;
c = c2 = c3 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
/**
* Load a script.
* @name loadScript
* @memberof Utils#
* @function
* @param scriptObj {object} Object containing script properties (url)
* @param callback {function} Function to call on success or on error
* @public
*/
self.loadScript = function (scriptObj, callback) {
var newScript;
callback = callback || function () {
};
var errorCallback = function (event) {
newScript.onload = newScript.onreadystatechange = newScript.onerror = null;
callback({msg: 'script not loaded', event: event}); // first param not null means an error has occured
};
var onloadCallback = function (event) {
event = event || window.event;
// Check for different events in IEs
if (event.type === "load" || (/loaded|complete/.test(newScript.readyState) && (!document.documentMode || document.documentMode < 9))) {
newScript.onload = newScript.onreadystatechange = newScript.onerror = null;
callback(null, event);
}
};
newScript = document.createElement("script");
newScript.type = "text/javascript";
newScript.src = scriptObj.url;
newScript.async = false;
newScript.defer = false;
newScript.onload = newScript.onreadystatechange = onloadCallback;
newScript.onerror = errorCallback;
var head = document.head || document.getElementsByTagName("head")[0];
head.insertBefore(newScript, head.lastChild);
};
// We deliberately ignore the second parameter reserved for us :)
/**
* Copy an object which doesnt' contain functions/objects.
* @name cloneSimpleObject
* @memberof Utils#
* @inner
* @function
* @param inst {Object} Item that you want to clone
* @param delUndefined {boolean} If true, undefined properties are not cloned
* @return {Object} clone of the instance
* @public
*/
self.cloneSimpleObject = function (inst, delUndefined) {
/*Si l'instance source n'est pas un objet ou qu'elle ne vaut rien c'est une feuille donc on la retourne*/
if (typeof (inst) !== 'object' || inst === null || inst instanceof Date) {
return inst;
}
/*On appelle le constructeur de l'instance source pour créer une nouvelle instance de la même classe*/
var newInst = new inst.constructor;
/*On parcourt les propriétés de l'objet et on les recopie dans la nouvelle instance*/
for (var i in inst) {
if (inst.hasOwnProperty(i)) {
//On gère le cas où il a été demandé (delUndefined) de ne pas copier les propriétés undefined
if (i !== undefined && (!delUndefined || inst[i] !== undefined)) {
newInst[i] = self.cloneSimpleObject(inst[i]);
}
}
}
/*On retourne la nouvelle instance*/
return newInst;
};
/**
* Check if object is empty.
* @name isEmptyObject
* @memberof Utils#
* @function
* @param tagObject {Object}
* @return {boolean}
* @public
*/
self.isEmptyObject = function (tagObject) {
for (var p in tagObject) {
if (tagObject.hasOwnProperty(p)) {
return false;
}
}
return true;
};
/**
* Check if parameter is an object.
* @name isObject
* @memberof Utils#
* @function
* @param contextualObject {*}
* @return {boolean}
* @public
*/
self.isObject = function (contextualObject) {
return ((contextualObject !== null) && (typeof contextualObject === 'object') && !(contextualObject instanceof Array));
};
// Constants to manage flattening
self.ATVALUE = '_ATVALUE';
self.ATPREFIX = '_ATPREFIX';
/**
* Adding flatten property with value from source object into destination.
* @memberof Utils#
* @function
* @param source {Object} Source object
* @param parentPath {string|null} Path from parent
* @param destination {Object} Final object
* @param parentPrefix {string|null} Prefix from parent
* @param toLower {boolean} Put the key to the property in lower case
* @public
*/
self.object2Flatten = function (source, parentPath, destination, parentPrefix, toLower) {
var splittedObject = {};
var prefix = '';
var path = '';
var levels = [];
var newPath = '';
var i = 0;
for (var sourceKey in source) {
if (source.hasOwnProperty(sourceKey)) {
splittedObject = self.splitProtocolAndKey(sourceKey, toLower);
prefix = splittedObject.prefix || parentPrefix || '';
path = (parentPath ? parentPath + '_' : '') + splittedObject.key;
if (self.isObject(source[sourceKey])) {
self.object2Flatten(source[sourceKey], path, destination, prefix, toLower);
} else {
levels = path.split('_');
newPath = '';
for (i = 0; i < levels.length; i++) {
splittedObject = self.splitProtocolAndKey(levels[i], toLower);
prefix = splittedObject.prefix || prefix;
newPath += splittedObject.key + ((i < levels.length - 1) ? '_' : '');
}
path = newPath || path;
destination[path] = destination[path] || {};
destination[path][self.ATVALUE] = source[sourceKey];
destination[path][self.ATPREFIX] = prefix;
}
}
}
};
/**
* Create object from flatten property.
* @memberof Utils#
* @function
* @param destination {Object} Final object
* @param sourceKey {string} Key to process
* @param sourceValue {Object} Value to set
* @public
*/
self.flatten2Object = function (destination, sourceKey, sourceValue) {
var levels = sourceKey.split('_');
var parentObject = destination;
var currentLevel;
// Scrolling through data object
var i;
for (i = 0; i < levels.length - 1; i++) {
currentLevel = levels[i];
if (!parentObject[currentLevel]) {
parentObject[currentLevel] = {};
}
parentObject = parentObject[currentLevel];
}
// Update parent object if necessary
if (parentObject.hasOwnProperty(self.ATVALUE)) {
var parentValue = parentObject[self.ATVALUE];
var parentPrefix = parentObject[self.ATPREFIX];
delete parentObject[self.ATVALUE];
delete parentObject[self.ATPREFIX];
parentObject['$'] = {};
parentObject['$'][self.ATVALUE] = parentValue;
parentObject['$'][self.ATPREFIX] = parentPrefix;
}
// Adding current value
var sourceCopyValue = self.cloneSimpleObject(sourceValue);
if (parentObject[levels[i]]) {
parentObject[levels[i]]['$'] = sourceCopyValue;
} else {
parentObject[levels[i]] = sourceCopyValue;
}
};
/**
* Get formatted content object from flatten source.
* @memberof ATInternet.Tracker.Plugins.AvInsights#
* @function
* @param source {Object} Source object
* @public
*/
self.getFormattedObject = function (source) {
var content = {};
var newKey;
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (!source[key].hasOwnProperty(self.ATVALUE)) {
content[key] = self.getFormattedObject(source[key]);
} else {
newKey = source[key][self.ATPREFIX] ? source[key][self.ATPREFIX] + ':' + key : key;
content[newKey] = source[key][self.ATVALUE];
}
}
}
return content;
};
/**
* Complete the first level of an object with another.
* @name completeFstLevelObj
* @memberof Utils#
* @function
* @param target {object}
* @param source {object}
* @param overload {boolean} If true, properties of the target will be overloaded by source ones if they exist
* @return {object}
* @public
*/
self.completeFstLevelObj = function (target, source, overload) {
if (target) {
if (source) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (!target[key] || overload) {
target[key] = source[key];
}
}
}
}
} else {
target = source;
}
return target;
};
/**
* Get all keys from object.
* @name getObjectKeys
* @memberof Utils#
* @function
* @param object {object}
* @return {Array}
* @public
*/
self.getObjectKeys = function (object) {
var keys = [];
for (var elem in object) {
if (object.hasOwnProperty(elem)) {
keys.push(elem);
}
}
return keys;
};
/**
* Change the keys of object to lowercase
* @name objectToLowercase
* @memberof Utils#
* @function
* @param tagObject {Object} Object from tag
* @return {Object}
* @public
*/
self.objectToLowercase = function (tagObject) {
var objUtil = {};
for (var key in tagObject) {
if (tagObject.hasOwnProperty(key)) {
if (self.isObject(tagObject[key])) {
objUtil[key.toLowerCase()] = self.objectToLowercase(tagObject[key]);
} else {
objUtil[key.toLowerCase()] = tagObject[key];
}
}
}
return objUtil;
};
/**
* Process event key.
* @name splitProtocolAndKey
* @memberof Utils#
* @function
* @param key {String} Event key to split
* @param toLower {boolean} Put the key to the property in lower case
* @return {Object}
* @public
*/
self.splitProtocolAndKey = function (key, toLower) {
var _prefix, _key;
if ((key.length < 2) || (key[1] !== ':')) {
_prefix = '';
_key = key;
} else if ((key.length < 4) || (key[3] !== ':')) {
_prefix = key.substring(0, 1);
_key = key.substring(2, key.length);
} else {
_prefix = key.substring(0, 3);
_key = key.substring(4, key.length);
}
if (toLower) {
_prefix = _prefix.toLowerCase();
_key = _key.toLowerCase();
}
return {
'prefix': _prefix,
'key': _key
};
};
/**
* Serialize any element. Use JSON.stringify if possible.
* @name jsonSerialize
* @memberof Utils#
* @function
* @param obj {Object} Javascript object that you want to serialize to JSON
* @return {Object|String} Serialized JSON
* @public
*/
self.jsonSerialize = function (obj) {
try {
if (typeof JSON !== 'undefined' && JSON.stringify) {
return JSON.stringify(obj);
} else {
return serialJSON(obj);
}
} catch (e) {
return null;
}
};
/**
* Parse a string. Use JSON.parse if possible.
* @name jsonParse
* @memberof Utils#
* @function
* @param str {String} JSON string that you want to parse to Javascript object
* @return {Object}
* @public
*/
self.jsonParse = function (str) {
try {
if (typeof JSON !== 'undefined' && JSON.parse) {
return JSON.parse(str + '');
} else {
return parseJSON(str);
}
} catch (e) {
return null;
}
};
/**
* Trim a string. Use String.prototype.trim if possible.
* @name trim
* @memberof Utils#
* @function
* @param str {String} string to trim
* @return {String}
* @public
*/
self.trim = function (str) {
try {
if (!String.prototype.trim) {
// Polyfill
return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
return str.trim();
} catch (e) {
return str;
}
};
/**
* Search an element in an array. Use Array.indexOf if possible.
* @name arrayIndexOf
* @memberof Utils#
* @function
* @param arr {Array}
* @param elemToSearch {*}
* @return {number}
* @public
*/
self.arrayIndexOf = function (arr, elemToSearch) {
if (Array.prototype.indexOf) {
var index = -1;
if (typeof arr.indexOf(elemToSearch) !== 'undefined') {
index = arr.indexOf(elemToSearch)
}
return index;
} else {
return (function (searchElement) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}).apply(arr, [elemToSearch]);
}
};
/**
* Generate UUID.
* @name uuid
* @memberof Utils#
* @function
* @return {function}
* @public
*/
self.uuid = function () {
var _cryptoObj = window.crypto || window.msCrypto; // IE11
var _isCryptoAvailable = (_cryptoObj !== null && typeof _cryptoObj === 'object');
/* @if test */
if (typeof self.isCryptoAvailable === 'boolean') {
_isCryptoAvailable = self.isCryptoAvailable;
}
/* @endif */
/**
* Generate GUID with alphanumeric characters (v4 format) with Crypto or Math random.
* @name _crypto
* @memberof Utils#
* @function
* @return {string}
* @public
*/
function _v4() {
try {
if (_isCryptoAvailable) {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) {
return (c ^ _cryptoObj.getRandomValues(new Uint32Array(1))[0] & 15 >> c / 4).toString(16);
});
}
} catch (e) {
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Generate a random number of n digits with Crypto or Math random.
* @name _mathRand
* @memberof Utils#
* @function
* @return {number}
* @public
*/
function _rand(n) {
var rand = Math.random();
try {
if (_isCryptoAvailable) {
rand = _cryptoObj.getRandomValues(new Uint32Array(1))[0] / Math.pow(2, 32);
}
} catch (e) {
}
return Math.floor((rand * 9 + 1) * Math.pow(10, n - 1));
}
/**
* Generate GUID with numeric characters.
* @name _num
* @memberof Utils#
* @function
* @param len {number} Length of the generated GUID
* @return {string}
* @public
*/
function _num(len) {
var d = new Date();
var format = function (a) {
a = a - Math.floor(a / 100) * 100;
if (a < 10) {
return '0' + a;
} else {
return String(a);
}
};
return format(d.getHours()) + '' + format(d.getMinutes()) + '' + format(d.getSeconds()) + '' + _rand(len - 6);
}
return {
v4: _v4,
num: _num
};
};
/**
* Check if we are in Safari previewing case.
* @name isPreview
* @memberof Utils#
* @function
* @return {boolean}
* @public
*/
self.isPreview = function () {
return (window.navigator && window.navigator.loadPurpose === 'preview');
};
/**
* Check if we are in Chrome or IE prerendering case.
* @name isPrerender
* @memberof Utils#
* @function
* @param callback {function}
* @return {boolean}
* @public
*/
self.isPrerender = function (callback) {
var visibilityChangeEvent;
var isPrerender = false;
//Prefixes: Chrome, IE
var prefixes = ['webkit', 'ms'];
if (document.visibilityState === 'prerender') {
//Opera 12.10 and Firefox 18 and later support
visibilityChangeEvent = 'visibilitychange';
} else {
for (var i = 0; i < prefixes.length; i++) {
if (document[prefixes[i] + 'VisibilityState'] === 'prerender') {
visibilityChangeEvent = prefixes[i] + 'visibilitychange';
}
}
}
if (typeof visibilityChangeEvent !== 'undefined') {
var _manageCallback = function (event) {
callback(event);
self.removeEvtListener(document, visibilityChangeEvent, _manageCallback);
};
self.addEvtListener(document, visibilityChangeEvent, _manageCallback);
isPrerender = true;
}
return isPrerender;
};
/**
* Add an event listener to an object.
* @name addEvtListener
* @memberof Utils#
* @function
* @param obj {Object} DOM Element on which you want to add the event listener
* @param event {string} Event you need to listen
* @param callback {function} When event is triggered, it takes one parameter which is the event object
* @public
*/
self.addEvtListener = function (obj, event, callback) {
if (obj.addEventListener) {
obj.addEventListener(event, callback, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + event, callback);
}
};
/**
* Remove an event listener from an object.
* @name removeEvtListener
* @memberof Utils#
* @function
* @param obj {Object} DOM Element on which you want to add the event listener
* @param event {string} Event you need to listen
* @param callback {function}
* @public
*/
self.removeEvtListener = function (obj, event, callback) {
if (obj.removeEventListener) {
obj.removeEventListener(event, callback, false);
} else if (obj.detachEvent) {
obj.detachEvent('on' + event, callback);
}
};
/**
* Make a unique number with a given string.
* @name hashcode
* @memberof Utils#
* @function
* @param str
* @return {number}
* @public
*/
self.hashcode = function (str) {
var hash = 0;
if (str.length === 0) return hash;
for (var i = 0; i < str.length; i++) {
var character = str.charCodeAt(i);
hash = ((hash << 5) - hash) + character;
hash |= 0;
}
return hash;
};
/**
* Force document location.
* @name setLocation
* @memberof Utils#
* @function
* @param contextObj {Object} Redirection's url and target (properties location & target)
* @public
*/
self.setLocation = function (contextObj) {
var loc = contextObj['location'];
var obj = window[contextObj['target']] || window;
if (loc) {
obj.location.href = loc;
}
};
/****************************** Callback management *************************/
/**
* Dispatch event for callbacks
* @name dispatchCallbackEvent
* @memberof Utils#
* @function
* @param name {string} Callback's name
* @public
*/
self.dispatchCallbackEvent = function (name) {
// Create the event.
var event;
if (typeof window.Event === 'function') {
event = new Event('ATCallbackEvent');
} else {
try {
event = document.createEvent('Event');
// Define that the event name is 'ATCallbackEvent'.
// Deprecated.
event.initEvent && event.initEvent('ATCallbackEvent', true, true);
} catch (e) {
}
}
if (event && (typeof document.dispatchEvent === 'function')) {
event.name = name;
document.dispatchEvent(event);
}
};
/**
* Add callback event
* @name addCallbackEvent
* @memberof Utils#
* @function
* @param func {function} function to execute
* @public
*/
self.addCallbackEvent = function (func) {
// Listen to the event.
self.addEvtListener(document, 'ATCallbackEvent', func);
};
/**
* Remove callback event
* @name removeCallbackEvent
* @memberof Utils#
* @param func {function} function to remove
* @function
* @public
*/
self.removeCallbackEvent = function (func) {
self.removeEvent('ATCallbackEvent', func);
};
/****************************** Custom Event management *************************/
/**
* Polyfill the CustomEvent() constructor functionality in Internet Explorer 9 and higher
* @memberof Utils#
* @function
* @private
*/
(function () {
if (typeof window.CustomEvent === 'function') {
window.ATCustomEvent = window.CustomEvent;
return;
}
function ATCustomEvent(evt, params) {
params = params || {bubbles: false, cancelable: false, detail: undefined};
var event;
try {
event = document.createEvent('CustomEvent');
event.initCustomEvent(evt, params.bubbles, params.cancelable, params.detail);
} catch (e) {
}
return event;
}
if (typeof window.Event === "function") {
ATCustomEvent.prototype = window.Event.prototype;
}
window.ATCustomEvent = ATCustomEvent;
})();
/**
* Add custom event
* @name addEvent
* @memberof Utils#
* @param eventName {string} event name
* @param detailName {string} detail name
* @param detailID {number} detail uuid
* @param func {function} function to execute
* @function
* @public
*/
self.addEvent = function (eventName, detailName, detailID, func) {
self[eventName] = new ATCustomEvent(eventName, {
detail: {
name: detailName,
id: detailID
}
});
// Listen to the event.
self.addEvtListener(document, eventName, func);
};
/**
* Remove custom event
* @name removeEvent
* @memberof Utils#
* @param eventName {string} event name
* @param func {function} function to execute
* @function
* @public
*/
self.removeEvent = function (eventName, func) {
// Remove the event listener.
self.removeEvtListener(document, eventName, func);
};
/**
* Dispatch custom event
* @name dispatchEvent
* @memberof Utils#
* @param eventName {string} event name
* @param detailName {string} detail name
* @function
* @public
*/
self.dispatchEvent = function (eventName, detailName) {
// Init the event.
self[eventName] = self[eventName] || new ATCustomEvent(eventName, {
detail: {
name: detailName,
id: -1
}
});
try {
document.dispatchEvent(self[eventName]);
} catch (e) {
}
};
/****************************** Privacy management *************************/
/**
* Object used to manage authority
* @name Privacy
* @memberof Utils#
* @inner
* @constructor
* @property {function} processStorageParam Authority helper, see details here {@link Utils#Privacy.processStorageParam}
* @property {function} processBufferParam Authority helper, see details here {@link Utils#Privacy.processBufferParam}
* @property {function} setParameters Authority helper, see details here {@link Utils#Privacy.setParameters}
* @property {function} getParameters Authority helper, see details here {@link Utils#Privacy.getParameters}
* @property {function} resetParameters Authority helper, see details here {@link Utils#Privacy.resetParameters}
* @private
*/
var Privacy = function () {
/* -------- Privacy properties -------- */
var _thisPrivacy = this;
var _privacyParameters = {
storageParams: null,
bufferParams: null
};
var _privacyMode = '';
_thisPrivacy.CONSENTNO = 'Consent-NO';
_thisPrivacy.ALL = '*';
/* -------- Privacy internal methods -------- */
/**
* Test if parameter can be stored
* @memberof Utils#
* @param param {string} Parameter to store
* @param prop {string} Property to store
* @param toInclude {Object} Object containing parameters and properties to be included
* @function
* @return {Object}
* @private
* @example
* // param
* // "atredir"
* //
* // prop
* // 'at'
* //
* // toInclude
* // {"atredir":["at"]}
*/
function _testStorageParamObject(param, prop, toInclude) {
var _storageParamsArray;
for (var storageObjectProperty in toInclude) {
if (toInclude.hasOwnProperty(storageObjectProperty)) {
if (param === storageObjectProperty) {
if (!prop) {
return {"toSetInStorage": true};
}
_storageParamsArray = [];
if (toInclude[storageObjectProperty] instanceof Array) {
_storageParamsArray = toInclude[storageObjectProperty];
} else {
_storageParamsArray.push(toInclude[storageObjectProperty]);
}
for (var j = 0; j < _storageParamsArray.length; j++) {
if (_storageParamsArray[j] === prop) {
return {"toSetInStorage": true};
}
}
}
}
}
return {"toSetInStorage": false};
}
/**
* Process storage parameters
* @memberof Utils#
* @param param {string} Parameter to store
* @param value {Object} Parameter value to process
* @param toInclude {string|Array} Properties to be included
* @param delCallback {function} Callback to delete in storage
* @param getCallback {function} Callback to get from storage
* @function
* @private
* @example
* // param :
* // "atidvisitor"
* //
* // value :
* // {
* // "vrn": "-410501--123456-",
* // "at": "abcd123",
* // "ac": "21"
* // }
* //
* // toInclude :
* // "an"
* // ["an", "at"]
*/
function _processStorageParamObject(param, value, toInclude, delCallback, getCallback) {
if (typeof toInclude !== 'undefined') {
var _toIncludeArray = [];
if (toInclude instanceof Array) {
_toIncludeArray = toInclude;
} else {
_toIncludeArray.push(toInclude);
}
// We browse the list of keys contained in the value
for (var key in value) {
// An entry is deleted if it is not part of the inclusion list
if (value.hasOwnProperty(key) && self.arrayIndexOf(_toIncludeArray, key) === -1) {
delCallback && delCallback([param, key]);
}
}
// A parameter is completely deleted if its value is empty
if (delCallback && getCallback && self.isEmptyObject(getCallback(param))) {
delCallback(param);
}
}
}
/**
* Get a cleaned array
* @memberof Utils#
* @param value {Array} Parameter value to process
* @param toInclude {Array} Parameters to include
* @function
* @return {Array}
* @private
*/
function _getCleanedArray(value, toInclude) {
var _newArray = [];
var _flattenObject;
var _temporaryObject;
var _finalObject = {};
for (var i = 0; i < value.length; i++) {
_flattenObject = {};
self.object2Flatten(value[i], null, _flattenObject, null, true);
// We browse the list of keys contained in the value
for (var flattenObjectKey1 in _flattenObject) {
// An entry is deleted if it is not part of the inclusion list
if (_flattenObject.hasOwnProperty(flattenObjectKey1) && self.arrayIndexOf(toInclude, flattenObjectKey1) === -1) {
delete _flattenObject[flattenObjectKey1];
}
}
// A parameter cannot be set if its value is empty
if (!self.isEmptyObject(_flattenObject)) {
_temporaryObject = {};
for (var flattenObjectKey2 in _flattenObject) {
if (_flattenObject.hasOwnProperty(flattenObjectKey2)) {
self.flatten2Object(_temporaryObject, flattenObjectKey2, _flattenObject[flattenObjectKey2]);
}
}
_finalObject = self.getFormattedObject(_temporaryObject);
_newArray.push(_finalObject);
}
}
return _newArray;
}
/**
* Recursive function, complete a provided object (creating deep properties) using flattened keys and their value
* @param keys {String} Deep property to create. Ex : ['rootProp','subProp','subSubProp'] -> {rootProp:{subProp:{subSubProp:'value'}}}
* @param obj {Object} Object which should be completed
* @param value {*} Value of the deep property to create. It is always a native Type, we don't care for empty objects here. Result would be like -> {rootProp:{subProp:'value'}}
* @function
* @private
*/
function _createDeepProperty(keys, obj, value) {
if (keys.length > 1) {
if (typeof obj[keys[0]] === 'undefined') {
obj[keys[0]] = {};
}
_createDeepProperty(keys.slice(1, keys.length), obj[keys[0]], value);
} else {
obj[keys[0]] = value;
}
}
/**
* Function which parses a given flattened object (using provided separator) and return the object constructed in normal format
* @param flattenObject {Object} Object which will be completed
* @param separator {String} Parameters to include
* @function
* @return {Object}
* @private
*/
function _fromFlatten(flattenObject, separator) {
var result = {};
for (var flattenKey in flattenObject) {
if (flattenObject.hasOwnProperty(flattenKey)) {
var keys = flattenKey.split(separator);
_createDeepProperty(keys, result, flattenObject[flattenKey])
}
}
return result;
}
/**
* Recursive function, return a provided object as a flattened object.
* It filters flattened keys using the parameter 'toInclude'.
* An example would be providing a root object (parameter value) like {prop1:'value1', prop2:'value2', prop3:{sub1:'subvalue1', sub2:'subvalue2'}}
* Then providing what is to include and separator, ex : ['prop1','prop3:sub2'] with separator ':'
* Result returned would be {'prop1':'value1, 'prop3:sub2':'subvalue2'}
* @param value {*} Root object to process at the beginning ex : {prop1:'value1,prop2:{sub1:'value1'}}. Then it becomes the current value of the current key parsed
* @param separator {Array} Separator used to flatten properties at same level. Example using ':' will do 'prop:sub:deepsub'
* @param toInclude {Array} Flattened properties to include, ex : ['prop1', 'prop2:sub1']
* @param obj {Object|undefined} Must not be provided, it is a private parameter. It becomes the object which will be completed while processing
* @param keyTree {String|undefined} Must not be provided, it is a private parameter. It becomes the current level of property depth using given separator. Ex: 'prop2:sub1'
* @function
* @return {Object}
* @private
*/
function _toFlatten(value, separator, toInclude, obj, keyTree) {
var result = obj ? obj : {};
if (value && typeof value === 'object' && !(value instanceof Array)) {
for (var valueKey in value) {
if (value.hasOwnProperty(valueKey)) {
_toFlatten(value[valueKey], separator, toInclude, result, (keyTree ? keyTree + separator : '') + valueKey);
}
}
} else if (typeof value !== 'undefined' && (toInclude.indexOf(keyTree) >= 0) || typeof toInclude === 'undefined') {
result[keyTree] = value;
} else {
// this checks if our current depth is included in a key allowed
for (var i = 0; i < toInclude.length; i++) {
if (keyTree && keyTree.indexOf(toInclude[i]) === 0) {
result[keyTree] = value;
break;
}
}
}
if (obj === undefined) return result
}
/**
* Get a cleaned array specific to stc
* @memberof Utils#
* @param value {Array} Parameter value to process
* @param toInclude {Array} Parameters to include
* @function
* @return {Array}
* @private
*/
function _getComplexObjectCleanedArray(value, toInclude, separator) {
var _newArray = [];
for (var i = 0; i < value.length; i++) {
var flattenFiltered = _toFlatten(value[i], separator, toInclude);
var _filteredResult = _fromFlatten(flattenFiltered, separator);
if (!self.isEmptyObject(_filteredResult)) {
_newArray.push(_filteredResult);
}
}
return _newArray;
}
/**
* Test if parameter can be can be saved in the buffer
* @memberof Utils#
* @param param {string} Parameter to buffer
* @param value {string} Parameter value to process
* @param toInclude {Object} Object containing parameters and properties to be included
* @function
* @return {Object}
* @private
* @example
* // param
* // "stc"
* //
* // value
* // '"{\"key1\":\"val1\",\"key2\":\"val2\"}"'
* // '"[\"key1\",\"key2\"]"'
* //
* // toInclude
* // {"stc":["key1"]}
*/
function _testBufferParamObject(param, value, toInclude) {
if (self.isObject(toInclude)) {
var _value;
var _valueArray = [];
var _isArray = false;
var _cleanedArray;
var _newValue;
for (var bufferProperty in toInclude) {
if (toInclude.hasOwnProperty(bufferProperty) && (param === bufferProperty)) {
_value = value;
if (typeof _value === 'string') {
_value = self.jsonParse(_value) || _value;
}
if (typeof _value === 'object') {
if (_value instanceof Array) {
_valueArray = _value;
_isArray = true
} else {
_valueArray.push(_value);
}
if (param === 'stc') {
_cleanedArray = _getComplexObjectCleanedArray(_valueArray, toInclude[bufferProperty], '/');
} else if (param === 'events' || param === 'context') {
_cleanedArray = _getComplexObjectCleanedArray(_valueArray, toInclude[bufferProperty], '_');
} else {
_cleanedArray = _getCleanedArray(_valueArray, toInclude[bufferProperty]);
}
// A parameter cannot be set if its value is empty
if (_cleanedArray.length === 0) {
return {"toSetInBuffer": false};
} else {
// Otherwise we update its value
_newValue = _isArray ? _cleanedArray : _cleanedArray[0];
return {"toSetInBuffer": true, "value": self.jsonSerialize(_newValue)};
}
}
}
}
}
return {"toSetInBuffer": false};
}
/**
* Process buffer parameters
* @memberof Utils#
* @param param {Object} Parameter to buffer
* @param value {Object} Parameter value to process
* @param toInclude {string|Array} Properties to be included
* @param delCallback {function} Callback to delete in buffer
* @param setCallback {function} Callback to set in buffer
* @function
* @private
* @example
* // param :
* // "stc"
* //
* // value :
* // {
* // "_value": "{\"key1\":\"val1\",\"key2\":\"val2\"}",
* // "_options": {
* // "hitType": ["page"],
* // "encode": true,
* // "separator": ",",
* // "truncate": true
* // }
* // }
* //
* // toInclude :
* // "key1"
* // ["key1", "key2"]
*/
function _processBufferParamObject(param, value, toInclude, delCallback, setCallback) {
if (typeof toInclude !== 'undefined' && typeof value !== 'undefined') {
var _toIncludeArray = [];
var _value = value._value;
var _valueArray = [];
var _isArray = false;
var _cleanedArray;
var _newValue;
if (toInclude instanceof Array) {
_toIncludeArray = toInclude;
} else {
_toIncludeArray.push(toInclude);
}
if (typeof _value === 'string') {
_value = self.jsonParse(_value) || _value;
}
if (typeof _value === 'object') {
if (_value instanceof Array) {
_valueArray = _value;
_isArray = true
} else {
_valueArray.push(_value);
}
if (param === 'stc') {
_cleanedArray = _getComplexObjectCleanedArray(_valueArray, _toIncludeArray, '/');
} else if (param === 'events' || param === 'context') {
_cleanedArray = _getComplexObjectCleanedArray(_valueArray, _toIncludeArray, '_');
} else {
_cleanedArray = _getCleanedArray(_valueArray, _toIncludeArray);
}
// A parameter cannot be set if its value is empty
if (_cleanedArray.length === 0) {
delCallback && delCallback(param);
} else {
// Otherwise we update its value
_newValue = _isArray ? _cleanedArray : _cleanedArray[0];
setCallback && setCallback(param, self.jsonSerialize(_newValue), value._options);
}
}
}
}
/**
* Check for specific parameters (stc/events/context)
* @memberof Utils#
* @param value {string} Parameter to extend
* @param privacyParams {Array} global list of parameters to extend
* @function
* @return {Object}
* @private
* @example
* var example = _checkForSpecificProperties('stc/prop1/sub',['stc/prop1/sub','stc/prop2'])
* {
* key:'stc',
* flattenedProperty: 'prop1/sub'
* }
*/
function _checkForSpecificProperties(value, privacyParams) {
var FLAG_LEGACY_STC = 'stc_';
var FLAG_STC = 'stc/';
var FLAG_EVENTS = 'events_';
var FLAG_CONTEXT = 'context_';
var isFlagPresent = '';
var result = {
key: '',
flattenedProperty: ''
};
switch (true) {
case value.indexOf(FLAG_LEGACY_STC) === 0:
isFlagPresent = FLAG_LEGACY_STC;
break;
case value.indexOf(FLAG_STC) === 0:
isFlagPresent = FLAG_STC;
break;
case value.indexOf(FLAG_EVENTS) === 0:
isFlagPresent = FLAG_EVENTS;
break;
case value.indexOf(FLAG_CONTEXT) === 0:
isFlagPresent = FLAG_CONTEXT;
break;
default:
result.key = value;
break;
}
if (isFlagPresent) {
var key = isFlagPresent.substring(0, isFlagPresent.length - 1);
result.key = key;
if (privacyParams.indexOf(key) < 0) result.flattenedProperty = value.substring(isFlagPresent.length);
}
return result;
}
/**
* Get keys and values from parameters
* @memberof Utils#
* @param privacyParams {Array} Parameters to include
* @function
* @return {Object}
* @private
*/
function _getParamKeysAndValues(privacyParams) {
// Listing of the main keys of the privacy table
var _paramsMainKeys = [];
// Listing of the values of the objects in the privacy table
var _paramsMainObjectValues = {};
for (var i = 0; i < privacyParams.length; i++) {
if (typeof privacyParams[i] === 'string') {
var propertyToAdd = {};
var isModePresent = privacyParams[i].indexOf('#') > -1;
if (isModePresent) {
var modeAndKey = privacyParams[i].split('#');
if (modeAndKey[0] === _privacyMode) {
propertyToAdd = _checkForSpecificProperties(modeAndKey[1], privacyParams)
}
} else {
propertyToAdd = _checkForSpecificProperties(privacyParams[i], privacyParams)
}
if (propertyToAdd.key) {
if (_paramsMainKeys.indexOf(propertyToAdd.key) < 0) _paramsMainKeys.push(propertyToAdd.key);
}
if (propertyToAdd.flattenedProperty) {
_paramsMainObjectValues[propertyToAdd.key] = (_paramsMainObjectValues[propertyToAdd.key] || []).concat(propertyToAdd.flattenedProperty);
}
} else {
// legacy method, we don't manage the modes for the complex variables by default, they are applied in all modes (we don't want to use them anymore)
for (var key in privacyParams[i]) {
if (privacyParams[i].hasOwnProperty(key)) {
if (_paramsMainKeys.indexOf(key) < 0) _paramsMainKeys.push(key);
if (privacyParams.indexOf(key) < 0) {
_paramsMainObjectValues[key] = (_paramsMainObjectValues[key] || []).concat(privacyParams[i][key]);
}
}
}
}
}
return {
"keys": _paramsMainKeys,
"values": _paramsMainObjectValues
};
}
/* -------- Privacy helpers -------- */
/**
* Test if parameter can be stored
* @alias Privacy.testStorageParam
* @memberof Utils#
* @param param {string} Parameter to store
* @param prop {string} Property to store
* @function
* @return {Object}
* @public
* @example
* ATInternet.Utils.privacy.testStorageParam(param, prop);
* // param
* // "atredir"
* //
* // prop
* // 'at'
* //
* // _privacyParameters.storageParams
* // ["atidvisitor",{"atredir":["at"]}]
*/
_thisPrivacy.testStorageParam = function (param, prop) {
if (_privacyParameters.storageParams instanceof Array) {
var _storageParam, _toSetInStorageObject;
for (var i = _privacyParameters.storageParams.length - 1; i >= 0; i--) {
_storageParam = _privacyParameters.storageParams[i];
if (typeof _storageParam === 'string') {
if (_storageParam === param || _storageParam === _thisPrivacy.ALL) {
return {"toSetInStorage": true};
}
} else {
_toSetInStorageObject = _testStorageParamObject(param, prop, _storageParam);
if (_toSetInStorageObject.toSetInStorage) {
return {"toSetInStorage": true};
}
}
}
return {"toSetInStorage": false};
}
return {"toSetInStorage": true};
};
/**
* Process storage parameters
* @alias Privacy.processStorageParams
* @memberof Utils#
* @param delCallback {function} Callback to delete in storage
* @param getCallback {function} Callback to get from storage
* @param getAllCallback {function} Callback to get all from storage
* @function
* @return {Object}
* @public
* @example
* ATInternet.Utils.privacy.processStorageParams(delCallback, getCallback, getAllCallback);
* // _allParams :
* // {
* // "atidvisitor": {
* // "name": "atidvisitor",
* // "val": {
* // "vrn": "-410501--123456-",
* // "at": "abcd123",
* // "ac": "21"
* // },
* // "options": {
* // "path": "/",
* // "session": 15724800,
* // "end": 15724800
* // }
* // }
* // }
* //
* // "_privacyParameters.storageParams": [
* // "atuserid",
* // {
* // "atidvisitor": ["an", "at"]
* // }
* // ]
*/
_thisPrivacy.processStorageParams = function (delCallback, getCallback, getAllCallback) {
if (getAllCallback) {
// Listing of parameters stored in cookie or localStorage
var _allParams = getAllCallback();
// Listing of parameters and values to be included
var _params = _getParamKeysAndValues(_privacyParameters.storageParams);
if (_params.keys[0] !== _thisPrivacy.ALL) {
for (var param in _allParams) {
if (_allParams.hasOwnProperty(param) && _allParams[param] !== undefined) {
// If the parameter is not part of the inclusion list then it is deleted.
if (self.arrayIndexOf(_params.keys, param) === -1) {
delCallback && delCallback(param);
} else if (self.isObject(_allParams[param])) {
// Otherwise you check its keys
_processStorageParamObject(param, _allParams[param].val, _params.values[param], delCallback, getCallback);
}
}
}
}
}
};
/**
* Test if parameter can be can be saved in the buffer
* @alias Privacy.testBufferParam
* @memberof Utils#
* @param param {string} Parameter to buffer
* @param value {string} Parameter value to process
* @function
* @return {Object}
* @public
* @example
* ATInternet.Utils.privacy.testBufferParam(param, value);
* // param
* // "stc"
* //
* // value
* // '"{\"key1\":\"val1\",\"key2\":\"val2\"}"'
* // '"[\"key1\",\"key2\"]"'
*/
_thisPrivacy.testBufferParam = function (param, value) {
if (_privacyParameters.bufferParams instanceof Array) {
var _params = _getParamKeysAndValues(_privacyParameters.bufferParams);
for (var i = 0; i < _params.keys.length; i++) {
if (_params.keys[i] === param || _params.keys[i] === _thisPrivacy.ALL) {
if (_params.values.hasOwnProperty(_params.keys[i])) {
var temp = {};
temp[_params.keys[i]] = _params.values[_params.keys[i]];
var _toSetInBufferObject2 = _testBufferParamObject(param, value, temp);
if (_toSetInBufferObject2.toSetInBuffer) {
return {"toSetInBuffer": true, "value": _toSetInBufferObject2.value};
}
break;
} else {
return {"toSetInBuffer": true, "value": value};
}
}
}
return {"toSetInBuffer": false};
}
return {"toSetInBuffer": true, "value": value};
};
/**
* Process buffer parameters
* @alias Privacy.processBufferParams
* @memberof Utils#
* @param delCallback {function} Callback to delete in buffer
* @param getAllCallback {function} Callback to get all from buffer
* @param setCallback {function} Callback to set in buffer
* @function
* @public
* @example
* ATInternet.Utils.privacy.processBufferParams(delCallback, getAllCallback, setCallback);
* // _allParams :
* // {
* // "stc": {
* // "_value": "{\"key1\":\"val1\",\"key2\":\"val2\"}",
* // "_options": {
* // "hitType": ["page"],
* // "encode": true,
* // "separator": ",",
* // "truncate": true
* // }
* // }
* //
* // "_privacyParameters.bufferParams": [
* // "an",
* // {
* // "stc": [
* // "key1",
* // "key2"
* // ]
* // }
* // ]
*/
_thisPrivacy.processBufferParams = function (delCallback, getAllCallback, setCallback) {
if (getAllCallback) {
// Listing of parameters stored in the buffer
var _allParams = getAllCallback();
// Listing of parameters and values to be included
var _params = _getParamKeysAndValues(_privacyParameters.bufferParams);
if (_params.keys[0] !== _thisPrivacy.ALL) {
for (var param in _allParams) {
if (_allParams.hasOwnProperty(param)) {
// If the parameter is not part of the inclusion list then it is deleted.
if (self.arrayIndexOf(_params.keys, param) === -1) {
delCallback && delCallback(param);
} else {
_processBufferParamObject(param, _allParams[param], _params.values[param], delCallback, setCallback);
}
}
}
}
}
};
/**
* Set privacy current mode
* @alias Privacy.setMode
* @memberof Utils#
* @param privacyMode {String} Privacy mode to set
* @function
* @private
* @example
* ATInternet.Utils.privacy.setMode('optout');
*/
_thisPrivacy.setMode = function (privacyMode) {
_privacyMode = privacyMode;
};
/**
* Set privacy parameters values
* @alias Privacy.setParameters
* @memberof Utils#
* @param privacyParameters {Object} Privacy parameters to set
* @function
* @public
* @example
* ATInternet.Utils.privacy.setParameters(privacyParameters);
*/
_thisPrivacy.setParameters = function (privacyParameters) {
_privacyParameters = privacyParameters;
};
/**
* Get privacy parameters values
* @alias Privacy.getParameters
* @memberof Utils#
* @function
* @return {Object}
* @public
* @example
* ATInternet.Utils.privacy.getParameters();
*/
_thisPrivacy.getParameters = function () {
return _privacyParameters;
};
/**
* Reset privacy parameters values
* @alias Privacy.resetParameters
* @memberof Utils#
* @function
* @public
* @example
* ATInternet.Utils.privacy.resetParameters();
*/
_thisPrivacy.resetParameters = function () {
_privacyParameters = {
storageParams: null,
bufferParams: null
};
};
// For unit tests on private elements !!!
/* @if test */
_thisPrivacy._getPrivacyParameters = function () {
return _privacyParameters;
};
_thisPrivacy._setPrivacyParameters = function (privacyParameters) {
_privacyParameters = privacyParameters;
};
_thisPrivacy._testStorageParamObject = _testStorageParamObject;
_thisPrivacy._processStorageParamObject = _processStorageParamObject;
_thisPrivacy._getCleanedArray = _getCleanedArray;
_thisPrivacy._testBufferParamObject = _testBufferParamObject;
_thisPrivacy._processBufferParamObject = _processBufferParamObject;
_thisPrivacy._getParamKeysAndValues = _getParamKeysAndValues;
/* @endif */
};
/**
* Privacy object
* @name privacy
* @memberof Utils#
* @public
*/
self.privacy = new Privacy();
/****************************** OPT-OUT management *************************/
/**
* OPT-OUT value
* @name optedOut
* @memberof Utils#
* @private
*/
self.optedOut = null;
/**
* Test value from OPT-OUT stored object
* @memberof Utils#
* @function
* @return {Boolean}
* @private
*/
function isOptoutInStorage() {
var sItem = getStorageData('atuserid');
if (sItem) {
var item = self.jsonParse(sItem) || self.jsonParse(self.Base64.decode(sItem));
if (item !== null) {
return item.val === 'OPT-OUT';
}
}
return false;
}
/**
* Add OPT-OUT event
* @name addOptOutEvent
* @memberof Utils#
* @param eventID {number} uuid
* @param func {function} function to associate
* @function
* @public
*/
self.addOptOutEvent = function (eventID, func) {
self.addEvent('ATOptOutEvent', 'clientsideuserid', eventID, func);
};
/**
* Remove OPT-OUT event
* @name removeOptOutEvent
* @memberof Utils#
* @param func {function} function to remove
* @function
* @public
*/
self.removeOptOutEvent = function (func) {
self.removeEvent('ATOptOutEvent', func);
};
/**
* Dispatch event for OPT-OUT
* @name dispatchOptOutEvent
* @memberof Utils#
* @param active {boolean} Activate or deactivate OPT-OUT
* @function
* @private
*/
self.dispatchOptOutEvent = function (active) {
self.optedOut = active;
self.dispatchEvent('ATOptOutEvent', 'clientsideuserid');
};
/**
* Activate OPT-OUT mode adding OPT-OUT value in hit and storage for idclient parameter
* @name userOptedOut
* @memberof Utils#
* @function
* @public
*/
self.userOptedOut = function () {
self.dispatchOptOutEvent(true);
};
/**
* Deactivate OPT-OUT mode
* @name userOptedIn
* @memberof Utils#
* @function
* @public
*/
self.userOptedIn = function () {
self.dispatchOptOutEvent(false);
};
/**
* Get OPTOUT activation status
* @name isOptedOut
* @memberof Utils#
* @function
* @public
*/
self.isOptedOut = function () {
if (self.optedOut === null) {
self.optedOut = isOptoutInStorage();
}
return !!self.optedOut;
};
/****************************** Consent Page management *************************/
/**
* Specify whether consent has been obtained preventing or allowing data to be stored in cookies or local storage
* @name consentReceived
* @memberof Utils#
* @param active {boolean} false to prevent data to be stored, true to allow data to be stored
* @function
* @public
*/
self.consentReceived = function (active) {
self.consent = !!active;
};
/**
* Consent page option value
* @name consent
* @memberof Utils#
* @private
*/
self.consent = true;
/****************************** Click event management *************************/
/**
* Check if a key allowing a tab opening is pressed during a click
* @name isTabOpeningAction
* @memberof Utils#
* @param event {Object} event object
* @function
* @public
* @return {boolean}
*/
self.isTabOpeningAction = function (event) {
var isTabOpening = false;
if (event && (event.ctrlKey ||
event.shiftKey ||
event.metaKey ||
(event.button && event.button === 1))
) {
isTabOpening = true;
}
return isTabOpening;
};
// Constants for managing click actions according to the DOM Element
self.CLICKS_REDIRECTION = 'redirection';
self.CLICKS_FORM = 'form';
self.CLICKS_MAILTO = 'mailto';
/*******************************************************************************/
// For unit tests on private elements !!!
/* @if test */
self.serialJSON = serialJSON;
self.parseJSON = parseJSON;
self.getStorageData = getStorageData;
self.isOptoutInStorage = isOptoutInStorage;
/* @endif */
};
/**
* Module with utility methods.
* @name ATInternet.Utils
* @memberof ATInternet
* @type {Utils}
* @public
* @see {@link Utils}
*/
ATInternet.Utils = new Utils();