Source: Event/event.js

/**
 * @class
 * @classdesc Plugin used to manage event sending.
 * @name Event
 * @memberof ATInternet.Tracker.Plugins
 * @type {function}
 * @param parent {object} Instance of the Tag used
 * @public
 */
window['ATInternet']['Tracker']['Plugins']['Event'] = function (parent) {

    'use strict';

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

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

    /**
     * Set events param.
     * @memberof ATInternet.Tracker.Plugins.Event#
     * @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';
        parent.setParam('events', _getEventsData(eventArray), {
            hitType: [_origin],
            encode: true,
            truncate: true,
            separator: ','
        });
    };

    /**
     * Get chapter context depending on Tracker configuration.
     * @memberof ATInternet.Tracker.Plugins.Event#
     * @function
     * @param pageContext {object} Page context
     * @return {object}
     * @private
     */
    var _getChapterContext = function (pageContext) {
        var chapterContext = {};
        var ignoreEmpty = parent.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))) {
                chapterContext[chapterKey] = chapterLabel;
            }
        }
        return chapterContext;
    };

    /**
     * Get context data.
     * @memberof ATInternet.Tracker.Plugins.Event#
     * @function
     * @param pageContext {object} Page context
     * @return {String}
     * @private
     */
    var _getContextData = function (pageContext) {
        var pageObject = _getChapterContext(pageContext);
        pageObject['$'] = pageContext.name || '';

        var level2Key = 'level2';
        var level2Value = pageContext.level2 || '';
        if (level2Value !== '' && !isNaN(level2Value)) {
            level2Key = 'level2_id';
            level2Value = Number(level2Value);
        }
        var siteObject = {};
        siteObject[level2Key] = level2Value;

        return ATInternet.Utils.jsonSerialize([{'data': {'page': pageObject, 'site': siteObject}}]);
    };

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

    /**
     * Check if type of tag is object.
     * @memberof ATInternet.Tracker.Plugins.Event#
     * @function
     * @param tagObject {object} Object from tag
     * @return {boolean}
     * @private
     */
    var _isObject = function (tagObject) {
        return ((typeof tagObject === 'object') && !(tagObject instanceof Array));
    };

    /**
     * Merge context with tag object.
     * @memberof ATInternet.Tracker.Plugins.Event#
     * @function
     * @param tagContext {object} Object from event context
     * @param tagData {object} 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 (_isObject(tagContext) && _isObject(tagData)) {
            mergedContext = ATInternet.Utils.completeFstLevelObj(tagContext, tagData, true);
        } else {
            mergedContext = tagData;
        }
        return mergedContext;
    };

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

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] 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
     */
    parent.event = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] 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
     */
    parent.event.reset = function (origin) {

        var _origin = origin || 'event';

        var contextEventObject = parent.getContext(_origin) || [];
        /* @if debug */
        parent.debug('Event:event:reset', _debug.level, _debug.messageCall, {
            'context': contextEventObject,
            'origin': _origin
        });
        /* @endif */
        parent.setContext(_origin, undefined);
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] Tagging method for event sending (helper).
     * @alias event.send
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagType {String} Event type
     * @param tagData {object} Event value
     * @param tagConfig {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
     */
    parent.event.send = function (tagType, tagData, tagConfig) {

        var preservePropagation = true;

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

        var eventObject = {};
        eventObject[tagType] = tagData;

        var hitObject = {};

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

        // 2. Set Page context
        var pageContext = parent.getContext('page');
        if (typeof pageContext !== 'undefined') {
            hitObject.context = {
                _value: _getContextData(pageContext),
                _options: {
                    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() && parent.getConfig('preview')) {
            hitObject.pvw = 1;
        }

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

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

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

        return preservePropagation;
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] Set events.
     * @alias event.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagType {String} Event type
     * @param tagData {object} Event value
     * @param tagKey {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
     */
    parent.event.set = function (tagType, tagData, tagKey, origin) {

        var _origin = origin || 'event';

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

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

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

        for (var i = 0; i < contextEventObject.length; i++) {
            if (contextEventObject[i][tagType]) {
                foundType = true;
                if (tagKey) {
                    if (_isObject(contextEventObject[i][tagType])) {
                        contextEventObject[i][tagType][tagKey] = _mergeValues(contextEventObject[i][tagType][tagKey], tagData);
                    }
                } else {
                    contextEventObject[i][tagType] = _mergeValues(contextEventObject[i][tagType], tagData);
                }
            }
        }

        if (!foundType) {
            var defaultValue = {};
            if (tagKey) {
                defaultValue[tagType] = {};
                defaultValue[tagType][tagKey] = tagData;
            } else {
                defaultValue[tagType] = tagData;
            }
            contextEventObject.push(defaultValue);
        }

        parent.setContext(_origin, contextEventObject);

        /* @if debug */
        var data;
        if (tagKey) {
            data = {};
            data[tagKey] = tagData;
        } else {
            data = tagData;
        }
        parent.debug('Event:event:set', _debug.level, _debug.messageEnd, {
            'name': tagType,
            'data': data,
            'origin': _origin
        });
        /* @endif */

    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] Add events.
     * @alias event.add
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagType {String} Event type
     * @param tagData {object} 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
     */
    parent.event.add = function (tagType, tagData, origin) {
        var _origin = origin || 'event';
        var contextEventObject = parent.getContext(_origin) || [];
        var defaultValue = {};
        defaultValue[tagType] = tagData;
        contextEventObject.push(defaultValue);
        parent.setContext(_origin, contextEventObject);
        /* @if debug */
        parent.debug('Event:event:add', _debug.level, _debug.messageEnd, {
            'name': tagType,
            'data': tagData,
            'origin': _origin
        });
        /* @endif */

    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Event Event}] 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 origin {String} Type origin. Ex: 'salesTracker', 'click', etc.
     * @private
     */
    parent.event.onDispatch = function (callback, origin) {

        var _origin = origin || 'event';

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

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

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

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

    _init();

    // For unit tests on private elements !!!
    /* @if test */
    var _this = this;
    _this._getEventsData = _getEventsData;
    _this._setEventsParam = _setEventsParam;
    _this._getChapterContext = _getChapterContext;
    _this._getContextData = _getContextData;
    _this._setContextParam = _setContextParam;
    _this._isObject = _isObject;
    _this._mergeValues = _mergeValues;
    _this._init = _init;
    /* @endif */
};
window['ATInternet']['Tracker']['addPlugin']('Event');