/**
* @class
* @classdesc Plugin used to manage technical side of clicks : redirections, forms submit and mailto actions.
* @name TechClicks
* @memberof ATInternet.Tracker.Plugins
* @type {function}
* @param tag {object} Instance of the Tag used
* @public
*/
ATInternet.Tracker.Plugins.TechClicks = function (tag) {
'use strict';
var _this = this;
var _triggers = ['Tracker:Hit:Sent:Ok', 'Tracker:Hit:Sent:Error', 'Tracker:Hit:Sent:NoTrack'];
// Plugin configuration.
var _clicksAutoManagementEnabled,
_clicksAutoManagementTimeout;
var _redirectionInProgress = false;
tag.configPlugin('TechClicks', dfltPluginCfg || {}, function (newConf) {
_clicksAutoManagementEnabled = newConf['clicksAutoManagementEnabled'];
_clicksAutoManagementTimeout = newConf['clicksAutoManagementTimeout'];
});
//*************************************************************************************************
// PART FOR MANAGING REDIRECTION/SUBMIT/MAILTO ACTIONS AND LISTENER
//*************************************************************************************************
/**
* Do a redirection with a given url & target.
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param contextObj {object} Redirection's url and target (properties url & target)
* @private
*/
var _doRedirection = function (contextObj) {
if (!_redirectionInProgress) {
_redirectionInProgress = true;
switch (contextObj.target) {
case '_top':
window.top.location.href = contextObj.url;
break;
case '_parent':
window.parent.location.href = contextObj.url;
break;
default:
window.location.href = contextObj.url;
break;
}
}
};
/**
* Do a setTimeout with the action concerned with the current process (redirection/submit/mailto).
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param contextObject {object} Context object containing data for the case it must be done (redirection/submit/mailto) Properties timeout, mailto, form, url, target
* @private
*/
var _addTimeout = function (contextObject) {
if (contextObject.mailto) {
_this.timeout = setTimeout(function () {
window.location.href = contextObject.mailto;
}, contextObject.timeout);
} else if (contextObject.form) {
_this.timeout = setTimeout(function () {
contextObject.form.submit();
}, contextObject.timeout);
} else if (contextObject.url) {
_this.timeout = setTimeout(function () {
_doRedirection({url: contextObject.url, target: contextObject.target});
}, contextObject.timeout);
}
};
/**
* Allow to know if this is an action case (nothing should happen).
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @return {boolean}
* @private
*/
var _isAction = function (DOMElement) {
// Check 3 attributes ('href', 'target', 'atclickmanagement') :
// First we check the 'target' and 'data-atclickmanagement' because they have priority over the 'href'
var element = DOMElement;
while (element) {
if (typeof element.getAttribute === 'function') {
if (element.getAttribute('target') === '_blank') {
return true;
}
if (element.getAttribute('data-atclickmanagement') === 'no') {
return true;
}
}
element = element.parentNode;
}
// Then we check 'href'
element = DOMElement;
var currentUrl = window.location.href,
newUrl;
while (element) {
// do not use getAttribute here, it gets the value exactly as it is and not the URL complete (so you will get '#anchor' instead of 'http....#anchor'
newUrl = element.href;
if (newUrl &&
newUrl.indexOf('#') >= 0 &&
currentUrl.substring(0, (currentUrl.indexOf('#') >= 0 ? currentUrl.indexOf('#') : currentUrl.length)) ===
newUrl.substring(0, newUrl.indexOf('#'))) {
// same base URL until anchor (#), if no anchor in the new url, it will do a navigation
return true;
}
element = element.parentNode;
}
return false;
};
/**
* Execute callback when a hit event is triggered
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param callback {function} Callback to execute
* @private
*/
var _reactToTriggers = function (callback) {
for (var i = 0; i < _triggers.length; i++) {
tag.onTrigger(_triggers[i], function (_, data) {
callback && callback(data);
});
}
};
/**
* Get redirection data and wait for the hit to be sent to trigger the redirection (a timeout will trigger it if it's too long).
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @private
*/
var _manageRedirection = function (DOMElement) {
var url, target = '_self';
var element = DOMElement;
while (element) {
if (element.href && (element.href.indexOf('http') === 0)) {
url = element.href.split('"').join('\\"');
target = (element.target ? element.target : target);
break;
}
element = element.parentNode;
}
if (url) {
var callback = function (data) {
// If isMultiHit then we wait for the end of the 500ms delay.
if (!data.details.isMultiHit && data.details.elementType === ATInternet.Utils.CLICKS_REDIRECTION) {
_this.timeout && clearTimeout(_this.timeout);
_doRedirection({url: url, target: target});
}
};
_reactToTriggers(callback);
_addTimeout({url: url, target: target, timeout: _clicksAutoManagementTimeout});
}
};
/**
* Get form data and wait for the hit to be sent to trigger the submit (a timeout will trigger it if it's too long).
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @private
*/
var _manageFormSubmit = function (DOMElement) {
var element = DOMElement;
while (element) {
if (element.nodeName === 'FORM') {
break;
}
element = element.parentNode;
}
if (element) {
var callback = function (data) {
// If isMultiHit then we wait for the end of the 500ms delay.
if (!data.details.isMultiHit && data.details.elementType === ATInternet.Utils.CLICKS_FORM) {
_this.timeout && clearTimeout(_this.timeout);
element.submit();
}
};
_reactToTriggers(callback);
_addTimeout({form: element, timeout: _clicksAutoManagementTimeout});
}
};
/**
* Get mailto data and wait for the hit to be sent to trigger the mailto (a timeout will trigger it if it's too long).
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @private
* @param DOMElement {object} The clicked element
*/
var _manageMailto = function (DOMElement) {
var element = DOMElement;
while (element) {
if (element.href && element.href.indexOf('mailto:') >= 0) {
break;
}
element = element.parentNode;
}
if (element) {
var callback = function (data) {
// If isMultiHit then we wait for the end of the 500ms delay.
if (!data.details.isMultiHit && data.details.elementType === ATInternet.Utils.CLICKS_MAILTO) {
_this.timeout && clearTimeout(_this.timeout);
window.location.href = element.href;
}
};
_reactToTriggers(callback);
_addTimeout({mailto: element.href, timeout: _clicksAutoManagementTimeout});
}
};
/**
* Check if the DOM element should be submitted
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @return {boolean}
* @private
*/
var _toSubmit = function (DOMElement) {
var toSubmit = false;
if (DOMElement) {
var tagName = DOMElement.tagName || '';
tagName = tagName.toLowerCase();
if (tagName === 'form') {
toSubmit = true;
} else {
var tagType = DOMElement.getAttribute('type') || '';
tagType = tagType.toLowerCase();
if (tagName === 'button') {
// submit: The button submits the form data to the server.
// This is the default if the attribute is not specified,
// or if the attribute is dynamically changed to an empty or invalid value.
if ((tagType !== 'reset') && (tagType !== 'button')) {
toSubmit = true;
}
} else if (tagName === 'input') {
// If this attribute is not specified, the default type adopted is text
if (tagType === 'submit') {
toSubmit = true;
}
}
}
}
return toSubmit;
};
/**
* Return the case we should consider ('mailto', 'form' or 'redirection'). Return false if we don't find the minimum requirement
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @return {string|false}
* @private
*/
var _getCurrentCase = function (DOMElement) {
var element = DOMElement;
while (element) {
if (element.href) {
if (element.href.indexOf('mailto:') >= 0) {
return ATInternet.Utils.CLICKS_MAILTO;
} else if (element.href.indexOf('http') === 0) {
return ATInternet.Utils.CLICKS_REDIRECTION;
}
} else if (element.nodeName === 'FORM') {
if (_toSubmit(DOMElement)) {
return ATInternet.Utils.CLICKS_FORM;
} else {
return '';
}
}
element = element.parentNode;
}
return '';
};
/**
* Check if it is a form submission action.
* @name isFormSubmit
* @memberof ATInternet.Tracker.Tag
* @type {boolean}
* @param DOMElement {object} DOM element clicked
* @public
*/
_this.isFormSubmit = function (DOMElement) {
var element = DOMElement;
while (element) {
if (element.nodeName === 'FORM') {
return true;
}
element = element.parentNode;
}
return false;
};
/**
* [Object added by plugin {@link ATInternet.Tracker.Plugins.techClicks Clicks}] Tags for clicks.
* @name techClicks
* @memberof ATInternet.Tracker.Tag
* @inner
* @type {object}
* @property {function} manageClick Method for managing redirection after a click, see details here {@link ATInternet.Tracker.Tag#techClicks.manageClick}
* @property {function} deactivateAutoManagement Method for managing redirection after a click, see details here {@link ATInternet.Tracker.Tag#techClicks.deactivateAutoManagement}
* @public
*/
tag.techClicks = {};
/**
* Take a DOM element (possibly with an event), check if this is a case that should be managed, return false if this is the case
* (or preventdefault for the event) and call the manager corresponding to the current case (redirection/mailto/submit).
* Return true if nothing will be done.
* @name manageClick
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @param DOMElement {object} The clicked element
* @param eventObj {object} The event object provided when triggered
* @return {object}
* @public
*/
tag.techClicks.manageClick = _this.manageClick = function (DOMElement, eventObj) {
var preservePropagation = true;
var elementType = '';
if (_clicksAutoManagementEnabled && DOMElement) { // process activated and element provided
var action = _isAction(DOMElement);
elementType = _getCurrentCase(DOMElement);
if (!action && elementType) { // priority is to know if this is an action, if not, we check mailto then submit then redirection
switch (elementType) {
case ATInternet.Utils.CLICKS_MAILTO:
_manageMailto(DOMElement);
preservePropagation = false;
break;
case ATInternet.Utils.CLICKS_FORM:
_manageFormSubmit(DOMElement);
preservePropagation = false;
break;
case ATInternet.Utils.CLICKS_REDIRECTION:
_manageRedirection(DOMElement);
preservePropagation = false;
break;
default:
// We couldn't find what we needed to manage a case
break;
}
// Code to deactivate the event (click/submit)
if (eventObj) {
var defaultPrevented = eventObj.defaultPrevented;
if (typeof eventObj.isDefaultPrevented === 'function') {
defaultPrevented = eventObj.isDefaultPrevented();
}
if (!defaultPrevented) {
eventObj.preventDefault && eventObj.preventDefault();
}
}
}
}
return {"preservePropagation": preservePropagation, "elementType": elementType};
};
/**
* Deactivate the automatic management (redirection/submit/mailto) for clicks on the current page.
* @name deactivateAutoManagement
* @memberof ATInternet.Tracker.Plugins.TechClicks#
* @function
* @public
*/
tag.techClicks.deactivateAutoManagement = function () {
_clicksAutoManagementEnabled = false;
};
// For unit tests on private elements !!!
/* @if test */
_this._doRedirection = _doRedirection;
_this._addTimeout = _addTimeout;
_this._isAction = _isAction;
_this._reactToTriggers = _reactToTriggers;
_this._manageRedirection = _manageRedirection;
_this._manageFormSubmit = _manageFormSubmit;
_this._manageMailto = _manageMailto;
_this._toSubmit = _toSubmit;
_this._getCurrentCase = _getCurrentCase;
_this._clicksAutoManagementEnabled = _clicksAutoManagementEnabled;
_this._clicksAutoManagementTimeout = _clicksAutoManagementTimeout;
_this.getThemAll = function () {
_this._clicksAutoManagementEnabled = _clicksAutoManagementEnabled;
_this._clicksAutoManagementTimeout = _clicksAutoManagementTimeout;
};
_this.setInternalVar = function (name, val) {
if (name === '_clicksAutoManagementEnabled') _clicksAutoManagementEnabled = val;
if (name === '_clicksAutoManagementTimeout') _clicksAutoManagementTimeout = val;
};
/* @endif */
};
ATInternet.Tracker.addPlugin('TechClicks');