Source: TvTracking/tvtracking.js

/**
 * @class
 * @classdesc Plugin to track audio and video spots.
 * @name TvTracking
 * @memberof ATInternet.Tracker.Plugins
 * @type {function}
 * @param parent {object} Instance of the Tag used
 * @public
 */
window['ATInternet']['Tracker']['Plugins']['TvTracking'] = function (parent) {
    'use strict';

    var _this = this;
    var _config = {};
    var _set_cookie_method = '';
    var _get_cookie_method = '';
    var _cookieSpotValuePersist = null;
    var _cookieVisitValue = null;
    var _cookieVisitDirectValue = null;
    var _cookieVisitPersistValue = null;
    var _customTvTObject = {};
    var _done = false;
    var _timeout = false;

    /**
     * Define labels to use for unique persistence.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _defineUniquePersistence = function () {
        _set_cookie_method = 'set' + (_config.domainAttribution ? '' : 'Private');
        _get_cookie_method = 'get' + (_config.domainAttribution ? '' : 'Private');
    };

    /**
     * Helper to use the plugin Cookies.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param method {string} Method to call in the plugin
     * @param params {Array} Parameters to transmit
     * @return {*}
     * @private
     */
    var _pluginCookie = function (method, params) {
        var ret = null;
        parent['plugins']['exec']('Cookies', method, params, function (data) {
            ret = data;
        });
        return ret;
    };

    /**
     * Check if given object is empty, if not it returns false else true.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param object {object}
     * @return {boolean}
     * @private
     */
    var _objectIsEmptyOrWithNullProperties = function (object) {
        for (var p in object) {
            if (object.hasOwnProperty(p) && object[p] !== null) {
                return false;
            }
        }
        return true;
    };

    /**
     * Check if a cookie is present and with type object, if not it creates it and returns true,
     * if present but with another type it returns false.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param name {string} Name of the cookie you need to check
     * @param options {object} Options of the cookie to create
     * @return {boolean}
     * @private
     */
    var _checkCookie = function (name, options) {
        var temp = _pluginCookie(_get_cookie_method, [name]);
        if (temp !== null) {
            return (typeof temp === 'object' && !(temp instanceof Array));
        }
        else {
            _pluginCookie(_set_cookie_method, [name, {}, options]);
            return true;
        }
    };

    /**
     * Set Page context.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _setPageContext = function () {
        var contextPageObject = parent.getContext('page') || {};
        var contextCustomObject = contextPageObject['customObject'] || {};
        contextCustomObject.TvTracking = _customTvTObject;
        contextPageObject.customObject = contextCustomObject;
        // Set new custom object in page context
        parent.setContext('page', contextPageObject);
        parent.processSpecificDispatchEventFor('tvTracking');
    };

    /**
     * Get persistent and direct spot values from cookies.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _getCookieValues = function () {
        _cookieSpotValuePersist = _pluginCookie(_get_cookie_method, ['attvtreman']);
        _cookieVisitValue = _pluginCookie(_get_cookie_method, ['attvtsession']);
        _cookieVisitDirectValue = _pluginCookie(_get_cookie_method, [['attvtsession', 'direct']]);
        _cookieVisitPersistValue = _pluginCookie(_get_cookie_method, [['attvtsession', 'remanent']]);
    };

    /**
     * Check the validity of partner object.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param partnerObject {object} Object containing partner properties
     * @return {boolean}
     * @private
     */
    var _isValidPartnerObject = function (partnerObject) {
        return !!(typeof partnerObject !== 'undefined' && typeof partnerObject['channel'] !== 'undefined' && partnerObject['channel'] !== 'undefined');
    };

    /**
     * Check time format and calculate retention period.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param time {string} Value to test
     * @return {boolean}
     * @private
     */
    var _isValidDateTime = function (time) {
        if (time && typeof time === 'string') {
            var spot = new Date(_convertDateFromISO(time));
            var now = new Date();
            return ((now >= spot) && ((now - spot) <= _config.retentionPeriod * 60 * 1000)); // spot is managed for 5mn
        }
        return false;
    };

    /**
     * Convert string from ISO to Date format.
     * @memberof ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @param str {string} Value to convert
     * @return {date|number}
     * @private
     */
    var _convertDateFromISO = function (str) {
        var date, regex = /^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/, res = regex.exec(str) || [];
        if (res[1]) {
            date = res[1].split(/\D/);
            for (var i = 0; i < date.length; i++) {
                date[i] = parseInt(date[i], 10) || 0;
            }
            date[1] -= 1;
            date = new Date(Date.UTC.apply(Date, date));
            if (!date.getDate()) {
                return NaN;
            }
            if (res[5]) {
                var tz = (parseInt(res[5], 10) * 60);
                if (res[6]) {
                    tz += parseInt(res[6], 10);
                }
                if (res[4] === '+') {
                    tz *= -1;
                }
                if (tz) {
                    date.setUTCMinutes(date.getUTCMinutes() + tz);
                }
            }
            return date;
        }
        return NaN;
    };

    /**
     * Init TvTracking configuration.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _initConfig = function () {
        // Set visitLifetime value from global configuration.
        parent.setConfig('visitLifetime', dfltGlobalCfg.visitLifetime, true);
        // Set specific plugin configuration.
        // If global configuration already exists, set only undefined properties.
        parent.configPlugin('TvTracking', dfltPluginCfg || {}, function (newConf) {
            _config = newConf;
        });
    };

    /**
     * Init TvTracking info object.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _initInfoTvT = function () {
        // Create final TvTracking object
        _customTvTObject.info = {
            version: _config.version,
            message: '',
            errors: []
        };
    };

    /**
     * Run TvTracking global processing.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _run = function () {
        parent.addSpecificDispatchEventFor('tvTracking');
        var callback = function (error) {
            if (!_timeout) {
                _done = true;
                if (error !== null) {
                    _setScriptError();
                }
                _setDataTvT();
                _setPageContext();
            }
        };
        ATInternet.Utils.loadScript({url: _config.url + '&rn=' + Math.random()}, callback);
        var errorTimeout = function () {
            if (!_done) {
                _setTimeoutError();
                _setDataTvT();
                _setPageContext();
            }
        };
        setTimeout(errorTimeout, _config.timeout);
    };

    /**
     * Set TvTracking script error.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _setScriptError = function () {
        _customTvTObject.info.errors.push('noScript');
    };

    /**
     * Set TvTracking timeout error.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _setTimeoutError = function () {
        _customTvTObject.info.errors.push('timeout');
        _timeout = true;
    };

    /**
     * Set TvTracking data.
     * @memberOf ATInternet.Tracker.Plugins.TvTracking#
     * @function
     * @private
     */
    var _setDataTvT = function () {

        // Set input values.
        var isDataPresent = false;
        var spotDirectValue = {};
        var spotPersistentValue = {};
        var partnerObject = window[_config.tvtrackingcustom];

        // Get properties from partner object.
        if (_isValidPartnerObject(partnerObject)) {
            var time = partnerObject['time'];
            if (_isValidDateTime(time)) {
                isDataPresent = true;
            }
            else {
                _customTvTObject.info.errors.push('timeError');
            }
            _customTvTObject.info.message = time;
        }
        else {
            if (typeof partnerObject === 'undefined') {
                _customTvTObject.info.errors.push('noData');
            }
            else if (typeof partnerObject['channel'] === 'undefined') {
                _customTvTObject.info.errors.push('noChannel');
            }
            else if (partnerObject['channel'] === 'undefined') {
                _customTvTObject.info.message = 'channelUndefined';
            }
        }

        // New visit.
        if (_cookieVisitValue === null) {

            // Direct data.
            if (isDataPresent) {
                spotDirectValue.direct = partnerObject;
            }

            // Persistent data.
            if (_cookieSpotValuePersist !== null) {
                spotPersistentValue.remanent = _cookieSpotValuePersist;
            }

            // Last persistence or First one but without persistent data from cookie.
            if ((_config.lastPersistence === true) || (_cookieSpotValuePersist === null)) {
                // Store Direct data in persistent cookie.
                var dateExp = new Date();
                dateExp.setDate(dateExp.getDate() + _config.lifetime);
                if (isDataPresent) {
                    _pluginCookie(_set_cookie_method, ['attvtreman', spotDirectValue.direct, {
                        path: _config.path,
                        end: dateExp
                    }]);
                }
            }
        }
        else {
            spotDirectValue.direct = _cookieVisitDirectValue;
            spotPersistentValue.remanent = _cookieVisitPersistValue;
        }

        // Set session cookie for the visit.
        if (_checkCookie('attvtsession', {
                path: _config.path,
                session: parent.getConfig('visitLifetime') * 60
            }, _set_cookie_method, _get_cookie_method)) {
            if (_cookieVisitValue === null) {
                _pluginCookie(_set_cookie_method, [['attvtsession', 'direct'], spotDirectValue.direct]);
                _pluginCookie(_set_cookie_method, [['attvtsession', 'remanent'], spotPersistentValue.remanent]);
            }
        }

        // Add value 'direct' if spotDirectValue is not empty.
        if ((typeof spotDirectValue === 'object') && !_objectIsEmptyOrWithNullProperties(spotDirectValue)) {
            _customTvTObject.direct = spotDirectValue.direct;
        }

        // Add value 'remanent' if spotDirectValue is not empty.
        if ((typeof spotPersistentValue === 'object') && !_objectIsEmptyOrWithNullProperties(spotPersistentValue)) {
            _customTvTObject.remanent = spotPersistentValue.remanent;
        }

        // Update session cookie on trigger 'Tracker:Hit:Sent:Ok'.
        parent.onTrigger('Tracker:Hit:Sent:Ok', function () {
            _pluginCookie(_get_cookie_method, ['attvtsession']);
        });

        // Add cookie error message if attvtsession cookie is null.
        if (_pluginCookie(_get_cookie_method, ['attvtsession', true]) === null) {
            _customTvTObject.info.errors.push('cookieError');
        }

        /* @if debug */
        parent.debug('TvTracking:tvTracking:set', 'DEBUG', 'method ended', _customTvTObject);
        /* @endif */

    };

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.TvTracking TvTracking}] Tags to track audio and video spots.
     * @name tvTracking
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#tvTracking.set}
     * @public
     */
    parent['tvTracking'] = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.TvTracking TvTracking}] Set TvTracking parameters.
     * @alias tvTracking.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @example
     * <pre><code class="javascript">tag.tvTracking.set();
     * </code></pre>
     * @public
     */
    parent['tvTracking']['set'] = _this['set'] = function () {

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

        _initConfig();
        _initInfoTvT();
        /* @if test */
        var acceptCookie = false;
        /* @endif */
        if (!parent.getConfig('disableCookie')) {
            /* @if test */
            acceptCookie = true;
            /* @endif */
            _defineUniquePersistence();
            _getCookieValues();
            if (!_cookieVisitValue) {
                if (_config.url && typeof _config.url === 'string') {
                    _run();
                }
                else {
                    _customTvTObject.info.message = 'noURLSet';
                    _setDataTvT();
                    _setPageContext();
                }
            }
            else {
                _customTvTObject.info.message = 'sessionAlreadyActive';
                _setDataTvT();
                _setPageContext();
            }
        }
        else {
            _customTvTObject.info.message = 'disableCookie:true';
            _setPageContext();
        }
        /* @if test */
        return acceptCookie;
        /* @endif */
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.TvTracking TvTracking}] Will be called by tracker.dispatch if any TvTracking has been set.
     * @alias tvTracking.onDispatch
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @private
     */
    parent['tvTracking']['onDispatch'] = _this['onDispatch'] = function () {
        if (!parent.dispatchSubscribed('page')) {
            /* @if debug */
            parent.debug('TvTracking:tvTracking:onDispatch:Error', 'WARNING', 'TvTracking data are not sent without page information (use page.set())');
            /* @endif */
        }
    };

    // For unit tests on private elements !!!
    /* @if test */
    _this._defineUniquePersistence = _defineUniquePersistence;
    _this._pluginCookie = _pluginCookie;
    _this._objectIsEmptyOrWithNullProperties = _objectIsEmptyOrWithNullProperties;
    _this._checkCookie = _checkCookie;
    _this._setPageContext = _setPageContext;
    _this._getCookieValues = _getCookieValues;
    _this._isValidPartnerObject = _isValidPartnerObject;
    _this._isValidDateTime = _isValidDateTime;
    _this._convertDateFromISO = _convertDateFromISO;
    _this._initConfig = _initConfig;
    _this._initInfoTvT = _initInfoTvT;
    _this._run = _run;
    _this._setScriptError = _setScriptError;
    _this._setTimeoutError = _setTimeoutError;
    _this._setDataTvT = _setDataTvT;
    _this.getCookieMethods = function () {
        _this._set_cookie_method = _set_cookie_method;
        _this._get_cookie_method = _get_cookie_method;
    };
    /* @endif */

};
window['ATInternet']['Tracker']['addPlugin']('TvTracking');