Source: TechClicks/techclicks.js

/**
 * @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 parent {object} Instance of the Tag used
 * @public
 */
window['ATInternet']['Tracker']['Plugins']['TechClicks'] = function (parent) {
    "use strict";
    var _this = this;
    // Plugin configuration.
    var _clicksAutoManagementEnabled,
        _clicksAutoManagementTimeout;
    parent.configPlugin('TechClicks', dfltPluginCfg || {}, function (newConf) {
        _clicksAutoManagementEnabled = newConf['clicksAutoManagementEnabled'];
        _clicksAutoManagementTimeout = newConf['clicksAutoManagementTimeout'];
    });

    /**
     * Deactivate the automatic management (redirection/submit/mailto) for clicks on the current page.
     * @name deactivateAutoManagement
     * @memberof ATInternet.Tracker.Plugins.TechClicks#
     * @function
     * @public
     */
    _this['deactivateAutoManagement'] = function () {
        _clicksAutoManagementEnabled = false;
    };

    //*************************************************************************************************
    // 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) {
        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) {
        var timeout = contextObject['timeout'];
        if (contextObject['mailto']) {
            setTimeout(function () {
                window.location.href = contextObject['mailto'];
            }, timeout);
        } else if (contextObject['form']) {
            setTimeout(function () {
                contextObject['form'].submit();
            }, timeout);
        } else if (contextObject['url']) {
            setTimeout(function () {
                _doRedirection({url: contextObject['url'], target: contextObject['target']});
            }, 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) {
        // checks 3 attributes (HREF,TARGET,DATA-ATCLICKREDIR) :
        // first we check the target and data-atclickmanagement because they are prior to href check
        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;
    };

    /**
     * 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,
            timeoutOnly = element['timeoutonly'];
        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) {
            if (!timeoutOnly) {
                parent.onTrigger('Tracker:Hit:Sent:Ok', function () {
                    // multihits not managed for the moment, the first hit sent will trigger the redirection
                    _doRedirection({url: url, target: target});
                });
            }
            _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,
            timeoutOnly = element['timeoutonly'];
        while (element) {
            if (element.nodeName === 'FORM') {
                break;
            }
            element = element.parentNode;
        }
        if (element) {
            if (!timeoutOnly) {
                parent.onTrigger('Tracker:Hit:Sent:Ok', function () {
                    // multihits not managed for the moment, the first hit sent will trigger the submit
                    element.submit();
                });
            }
            _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,
            timeoutOnly = element['timeoutonly'];
        while (element) {
            if (element['href'] && element['href'].indexOf('mailto:') >= 0) {
                break;
            }
            element = element.parentNode;
        }
        if (element) {
            if (!timeoutOnly) {
                parent.onTrigger('Tracker:Hit:Sent:Ok', function () {
                    // multihits not managed for the moment, the first hit sent will trigger the mailto
                    window.location.href = element['href'];
                });
            }
            _addTimeout({mailto: element['href'], timeout: _clicksAutoManagementTimeout});
        }
    };

    /**
     * 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 'mailto';
                } else if (element['href'].indexOf('http') === 0) {
                    return 'redirection';
                }
            } else if (element.nodeName === 'FORM') {
                return 'form';
            }
            element = element.parentNode;
        }
        return false;
    };

    /**
     * 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
     * @param callback {function} callback to execute
     * @return {boolean}
     * @public
     */
    _this['manageClick'] = function (DOMElement, eventObj, callback) {
        var preservePropagation = true;
        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 'mailto':
                        _manageMailto(DOMElement);
                        preservePropagation = false;
                        break;
                    case 'form':
                        _manageFormSubmit(DOMElement);
                        preservePropagation = false;
                        break;
                    case 'redirection':
                        _manageRedirection(DOMElement);
                        preservePropagation = false;
                        break;
                    default:
                        // we didn't find what we needed to manage any 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();
            }
        }
        callback && callback();
        return preservePropagation;
    };

    // For unit tests on private elements !!!
    /* @if test */
    _this['_isAction'] = _isAction;
    _this['_getCurrentCase'] = _getCurrentCase;
    _this['_manageRedirection'] = _manageRedirection;
    _this['_doRedirection'] = _doRedirection;
    _this['_manageFormSubmit'] = _manageFormSubmit;
    _this['_manageMailto'] = _manageMailto;
    _this['_addTimeout'] = _addTimeout;
    _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 */
};
window['ATInternet']['Tracker']['addPlugin']('TechClicks');