Source: EventRoot/eventroot.js

/**
 * @class
 * @classdesc Plugin used to manage event sending.
 * @name EventRoot
 * @memberof ATInternet.Tracker.Plugins
 * @type {function}
 * @param tag {object} Instance of the Tag used
 * @public
 */
ATInternet.Tracker.Plugins.EventRoot = function (tag) {

    'use strict';

    var _config = {};
    var _debug = {
        level: 'DEBUG',
        messageEnd: 'method ended',
        messageCall: 'method called'
    };

    /**
     * Get events data.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param eventArray {array} Object from tag or event context
     * @return {String}
     * @private
     */
    var _getEventsData = function (eventArray) {
        var events = [];
        var data;
        for (var i = 0; i < eventArray.length; i++) {
            for (var key in eventArray[i]) {
                if (eventArray[i].hasOwnProperty(key)) {
                    if (ATInternet.Utils.isObject(eventArray[i][key])) {
                        data = ATInternet.Utils.objectToLowercase(eventArray[i][key]);
                    } else {
                        data = eventArray[i][key];
                    }
                    events.push({
                        'name': key.toLowerCase(),
                        'data': data
                    });
                }
            }
        }
        return ATInternet.Utils.jsonSerialize(events);
    };

    /**
     * Set events param.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param eventArray {array} Object from tag or event context
     * @param origin {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @private
     */
    var _setEventsParam = function (eventArray, origin) {
        var _origin = origin || 'event';
        tag.setParam('events', _getEventsData(eventArray), {
            hitType: [_origin],
            encode: true,
            truncate: true,
            separator: ','
        });
    };

    /**
     * Get 'page' data from page context depending on Tracker configuration.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param pageContext {Object} Page context
     * @return {Object}
     * @private
     */
    var _getPageValues = function (pageContext) {
        // Page
        var pageValues = {};
        if (pageContext.name) {
            pageValues['$'] = pageContext.name;
        }
        // Chapters
        var ignoreEmpty = tag.getConfig('ignoreEmptyChapterValue');
        var chapterLabel = '';
        var chapterKey = '';
        for (var i = 1; i <= 3; i++) {
            chapterKey = 'chapter' + i;
            chapterLabel = pageContext[chapterKey] || '';
            if ((ignoreEmpty && chapterLabel) || (!ignoreEmpty && pageContext.hasOwnProperty(chapterKey))) {
                pageValues[chapterKey] = chapterLabel;
            }
        }
        // url
        if (pageContext.url) {
            pageValues['url'] = pageContext.url;
        }
        return pageValues;
    };

    /**
     * Get 'site' data from page context depending on Tracker configuration.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param pageContext {Object} Page context
     * @return {Object}
     * @private
     */
    var _getSiteValues = function (pageContext) {
        var siteValues = {};
        // Level2
        if (typeof pageContext.level2 === 'string') {
            var level2Trim = ATInternet.Utils.trim(pageContext.level2);
            if (level2Trim.length > 0) {
                if (!isNaN(level2Trim)) {
                    siteValues['level2_id'] = Number(level2Trim);
                } else {
                    siteValues['level2'] = level2Trim;
                }
            }
        } else if (typeof pageContext.level2 === 'number') {
            siteValues['level2_id'] = pageContext.level2;
        }
        return siteValues;
    };

    /**
     * Get context data.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param pageContext {object} Page context
     * @return {String}
     * @private
     */
    var _getContextData = function (pageContext, campaignsEventsContext) {

        var contextData = '';
        var pageObject = {};
        var siteObject = {};

        if (typeof pageContext !== 'undefined') {
            pageObject = _getPageValues(pageContext);
            siteObject = _getSiteValues(pageContext);
        }

        var data = {};
        if (!ATInternet.Utils.isEmptyObject(pageObject)) {
            data.page = pageObject;
        }
        if (!ATInternet.Utils.isEmptyObject(siteObject)) {
            data.site = siteObject;
        }
        // Complete all events with campaigns_events context
        if (typeof campaignsEventsContext !== 'undefined') {
            data.src = campaignsEventsContext;
        }
        if (!ATInternet.Utils.isEmptyObject(data)) {
            contextData = ATInternet.Utils.jsonSerialize([{'data': data}]);
        }
        return contextData;
    };

    /**
     * Set context param.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param pageContext {object} Page context
     * @param origin {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @private
     */
    var _setContextParam = function (pageContext, campaignsEventsContext, origin) {
        var _origin = origin || 'event';
        var contextData = _getContextData(pageContext, campaignsEventsContext);
        if (contextData !== '') {
            tag.setParam('context', contextData, {
                truncate: true,
                hitType: [_origin],
                encode: true
            });
        }
    };

    /**
     * Merge context with tag object.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @param tagContext {object} Object from event context
     * @param tagData {object|Array} Object from tag
     * @return {object|array|string}
     * @private
     */
    var _mergeValues = function (tagContext, tagData) {
        var mergedContext;
        if (tagContext instanceof Array && tagData instanceof Array) {
            mergedContext = tagContext.concat(tagData);
        } else if (ATInternet.Utils.isObject(tagContext) && ATInternet.Utils.isObject(tagData)) {
            mergedContext = ATInternet.Utils.completeFstLevelObj(tagContext, tagData, true);
        } else {
            mergedContext = tagData;
        }
        return mergedContext;
    };

    /**
     * Init plugin.
     * @memberof ATInternet.Tracker.Plugins.EventRoot#
     * @function
     * @private
     */
    var _init = function () {
        var dependencies = ['Utils'];
        tag.plugins.waitForDependencies(dependencies, function () {
            // Set specific plugin configuration.
            // If global configuration already exists, set only undefined properties.
            tag.configPlugin('EventRoot', dfltPluginCfg || {}, function (newConf) {
                _config = newConf;
            });
        });
    };

    // **************** EVENT (public technical helpers) ***************** //

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Tags to manage event sending.
     * @name event
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} reset Tag helper, see details here {@link ATInternet.Tracker.Tag#event.reset}
     * @property {function} send Tag helper, see details here {@link ATInternet.Tracker.Tag#event.send}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#event.set}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#event.add}
     * @public
     */
    tag.event = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Reset event context.
     * @alias event.reset
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param origin {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @example
     * <pre><code class="javascript">tag.event.reset();
     * </code></pre>
     * @public
     */
    tag.event.reset = function (origin) {
        var _origin = origin || 'event';
        var contextEventObject = tag.getContext(_origin) || [];
        /* @if debug */
        tag.debug('EventRoot:event:reset', _debug.level, _debug.messageCall, {
            'context': contextEventObject,
            'origin': _origin
        });
        /* @endif */
        tag.delContext(_origin);
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Tagging method for event sending (helper).
     * @alias event.send
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param name {String} Event name
     * @param data {object|Array} Event value
     * @param options {object} (optional) Technical configuration of the tag
     * @examples
     * <pre><code class="javascript">
     tag.event.send('product.display',
     {
        's:placement': 'homepage_slider',
        'a:product': [{
            's:id': 'id1',
            's:name': 'name1',
            's:brand': 'brand1',
            'f:original_price': 16.50,
            'f:price': 14.00,
            's:currency': 'EUR',
            'b:stock': 1,
            's:category1': 'category1',
            's:category2': 'category2',
            's:category3': 'category3',
            's:category4': 'category4',
            's:category5': 'category5',
            's:category6': 'category6',
            'n:position': 1
        }]
     },
     {
        elem: this, // (optional) Tagged DOM element
        event: event, // (optional) JavaScript event (prevent event propagation)
        callback: callback, // (optional) function to execute
        origin: 'event', // (optional)  Type origin. Ex: 'salesTracker', 'click', etc.
     });
     * </code></pre>
     * @public
     */
    tag.event.send = function (name, data, options) {

        var preservePropagation = true;
        var elementType = '';

        var _origin = 'event';
        if (options && options.origin) {
            _origin = options.origin;
        }

        var eventObject = {};
        eventObject[name] = data;

        var hitObject = {};

        // 1. Set &col=2 parameter
        hitObject[_config.hitParameter] = {
            _value: _config.hitValue,
            _options: {
                multihit: true
            }
        };

        // 2. Set Page context
        var pageContext = tag.getContext('page');
        var campaignsEventsContext = tag.getContext('campaigns_events');
        if (typeof pageContext !== 'undefined' || typeof campaignsEventsContext !== 'undefined') {
            hitObject.context = {
                _value: _getContextData(pageContext, campaignsEventsContext),
                _options: {
                    truncate: true,
                    encode: true
                }
            };
        }

        // 3. Set events parameter (truncable param at the end)
        hitObject.events = {
            _value: _getEventsData([eventObject]),
            _options: {
                encode: true,
                truncate: true,
                separator: ','
            }
        };

        // Set Safari preview.
        if (ATInternet.Utils.isPreview() && tag.getConfig('preview')) {
            hitObject.pvw = 1;
        }

        // Manage click propagation
        var domEventObject = null;
        if (options && options.hasOwnProperty('event')) {
            domEventObject = options.event || window.event;
        }
        if (!ATInternet.Utils.isTabOpeningAction(domEventObject) && options && options.elem) {
            var manage = tag.techClicks.manageClick(options.elem, domEventObject);
            preservePropagation = manage.preservePropagation;
            elementType = manage.elementType;
        }

        tag.manageSend(function () {
            var callback;
            if (options) {
                callback = options.callback;
            }
            tag.sendHit(hitObject, [['hitType', [_origin]]], callback, null, elementType);
        });

        /* @if debug */
        tag.debug('EventRoot:event:send', _debug.level, _debug.messageEnd, {
            'name': name,
            'data': data,
            'origin': _origin
        });
        /* @endif */

        return preservePropagation;
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Set events.
     * @alias event.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param name {String} Event name
     * @param data {object|Array} Event value
     * @param [key] {object} Event key
     * @param [origin] {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @examples
     * <pre><code class="javascript">
     tag.event.set('product.display', {
        's:placement': 'homepage_slider',
        'a:product': [{
            's:id': 'id1',
            's:name': 'name1',
            's:brand': 'brand1',
            'f:original_price': 16.50,
            'f:price': 14.00,
            's:currency': 'EUR',
            'b:stock': 1,
            's:category1': 'category1',
            's:category2': 'category2',
            's:category3': 'category3',
            's:category4': 'category4',
            's:category5': 'category5',
            's:category6': 'category6',
            'n:position': 1
        }]
     });
     * </code></pre>
     * @public
     */
    tag.event.set = function (name, data, key, origin) {

        var _origin = origin || 'event';

        // 1. Set &col=2 parameter
        tag.setParam(_config.hitParameter, _config.hitValue, {multihit: true, hitType: [_origin]});

        // Register helper to final call in order to send messages.
        tag.dispatchSubscribe(_origin);

        var contextEventObject = tag.getContext(_origin) || [];
        var foundType = false;

        for (var i = 0; i < contextEventObject.length; i++) {
            if (contextEventObject[i][name]) {
                foundType = true;
                if (key) {
                    if (ATInternet.Utils.isObject(contextEventObject[i][name])) {
                        contextEventObject[i][name][key] = _mergeValues(contextEventObject[i][name][key], data);
                    }
                } else {
                    contextEventObject[i][name] = _mergeValues(contextEventObject[i][name], data);
                }
            }
        }

        if (!foundType) {
            var defaultValue = {};
            if (key) {
                defaultValue[name] = {};
                defaultValue[name][key] = data;
            } else {
                defaultValue[name] = data;
            }
            contextEventObject.push(defaultValue);
        }

        tag.setContext(_origin, contextEventObject);

        /* @if debug */
        var debugData = {};
        if (key) {
            debugData[key] = data;
        } else {
            debugData = data;
        }
        tag.debug('EventRoot:event:set', _debug.level, _debug.messageEnd, {
            'name': name,
            'data': debugData,
            'origin': _origin
        });
        /* @endif */
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Add events.
     * @alias event.add
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param name {String} Event name
     * @param data {object|Array} Event value
     * @param [origin] {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @examples
     * <pre><code class="javascript">
     tag.event.add('product.display', {
        's:placement': 'homepage_slider',
        'a:product': [{
            's:id': 'id1',
            's:name': 'name1',
            's:brand': 'brand1',
            'f:original_price': 16.50,
            'f:price': 14.00,
            's:currency': 'EUR',
            'b:stock': 1,
            's:category1': 'category1',
            's:category2': 'category2',
            's:category3': 'category3',
            's:category4': 'category4',
            's:category5': 'category5',
            's:category6': 'category6',
            'n:position': 1
        }]
     });
     * </code></pre>
     * @public
     */
    tag.event.add = function (name, data, origin) {
        var _origin = origin || 'event';
        var contextEventObject = tag.getContext(_origin) || [];
        var defaultValue = {};
        defaultValue[name] = data;
        contextEventObject.push(defaultValue);
        tag.setContext(_origin, contextEventObject);
        /* @if debug */
        tag.debug('EventRoot:event:add', _debug.level, _debug.messageEnd, {
            'name': name,
            'data': data,
            'origin': _origin
        });
        /* @endif */
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.EventRoot EventRoot}] Will be called by tracker.dispatch if any event has been set.
     * @alias event.onDispatch
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param callback {function} Callback to execute
     * @param elementType {string} Element type (mailto, form, redirection)
     * @param origin {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @private
     */
    tag.event.onDispatch = function (callback, elementType, origin) {

        var _origin = origin || 'event';

        // 2. Set Page /campaigns_events context
        var pageContext = tag.getContext('page');
        var campaignsEventsContext = tag.getContext('campaigns_events');
        if (typeof pageContext !== 'undefined' || typeof campaignsEventsContext !== 'undefined') {
            _setContextParam(pageContext, campaignsEventsContext, _origin);
        }

        // 3. Set Event context  (truncable param at the end)
        var contextEventObject = tag.getContext(_origin);
        if (typeof contextEventObject !== 'undefined') {
            _setEventsParam(contextEventObject, _origin);
        }
        tag.delContext(_origin);

        // Safari preview.
        if (ATInternet.Utils.isPreview() && tag.getConfig('preview')) {
            tag.setParam('pvw', 1, {hitType: [_origin]});
        }

        tag.manageSend(function () {
            tag.sendHit(null, [['hitType', [_origin]]], callback, null, elementType);
        });
    };

    _init();

    // For unit tests on private elements !!!
    /* @if test */
    var _this = this;
    _this._getEventsData = _getEventsData;
    _this._setEventsParam = _setEventsParam;
    _this._getPageValues = _getPageValues;
    _this._getSiteValues = _getSiteValues;
    _this._getContextData = _getContextData;
    _this._setContextParam = _setContextParam;
    _this._mergeValues = _mergeValues;
    _this._init = _init;
    /* @endif */
};
ATInternet.Tracker.addPlugin('EventRoot');