Source: ClientSideUserId/clientsideuserid.js

/**
 * @class
 * @name ClientSideUserId
 * @memberof ATInternet.Tracker.Plugins
 * @type {function}
 * @param parent {object} Instance of the Tag used
 * @description
 * Plugin to enable a visitor to be tracked by creating a user ID in cases where writing a third-party cookie is not feasible.
 * <br />For example, this might be the case on an Intranet site,
 * or when the Safari browser is used (default settings),
 * or when a visitor browses using an Apple device like iPhone, iPad or iPod.
 * It is also possible to configure the plugin to force the use of a random or custom ID.
 * This ID can be found in the idclient variable, present in all hits when the plugin is active.
 * @public
 */
window['ATInternet']['Tracker']['Plugins']['ClientSideUserId'] = function (parent) {
    "use strict";

    var _config = {};
    var _userIdFromContext = undefined;
    var _userIdFromCookie = null;
    var _id = -1;
    var _isOptOut = false;

    // Set specific plugin configuration.
    // If global configuration already exists, set only undefined properties.
    parent.configPlugin('ClientSideUserId', dfltPluginCfg || {}, function (newConf) {
        _config = newConf;
    });

    /**
     * Get user ID from context and cookie.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @private
     */
    var _getUserId = function () {
        _userIdFromContext = parent.getContext('userIdentifier');
        parent.exec('Cookies', 'get', ['atuserid'], function (data) {
            _userIdFromCookie = data;
        });
    };

    /**
     * Create or update cookie value for identifier.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @param cookieName {string} Name of the cookie
     * @param cookieValue {string|number|boolean} Value of the cookie
     * @param isFromCustomerContext {boolean} Is user ID comes from customer context ?
     * @private
     */
    var _setCookieValue = function (cookieName, cookieValue, isFromCustomerContext) {
        if (_config.userIdExpirationMode === 'relative' || (_config.userIdExpirationMode === 'fixed' && _userIdFromCookie === null) || isFromCustomerContext) {
            var expiration_date = new Date();
            expiration_date.setTime(expiration_date.getTime() + (_config.userIdCookieDuration * 24 * 60 * 60 * 1000));
            parent.exec('Cookies', 'set', [cookieName, cookieValue, {end: expiration_date, path: '/'}]);
            parent.exec('Cookies', 'get', [cookieName, true], function (data) {
                if (!isFromCustomerContext && cookieValue !== data) {
                    parent.setParam('idclient', cookieValue + '-NO', {permanent: true, hitType: ['all']});
                }
            });
        }
    };

    /**
     * Set user ID in buffer and cookie.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @param id {string|number} GUID provided or automatically generated
     * @param isfromContext {boolean} Is user ID comes from context ?
     * @param cookieName {string} Cookie name
     * @private
     */
    var _setUserId = function (id, isfromContext, cookieName) {
        parent.setParam('idclient', id, {permanent: true, hitType: ['all']});
        _setCookieValue(cookieName, id, isfromContext);
    };

    /**
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @description
     * Check if general configuration implies ClientSideUserId mode activation.
     * <br />Note : konqueror|Lunascape|midori|OmniWeb browsers are managed like Safari
     * @private
     */
    var _isClientConfiguration = function () {
        var isClient = false;
        if (_config.clientSideMode === 'required') {
            var userAgent = navigator.userAgent;
            if ((/Safari/.test(userAgent) && !/Chrome/.test(userAgent))
                || /iPhone|iPod|iPad/.test(userAgent)) {
                isClient = true;
            }
        }
        else if (_config.clientSideMode === 'always') {
            isClient = true;
        }
        return isClient;
    };

    /**
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @description
     * Check if OPT-OUT mode is activated or not.
     * @private
     */
    var _isOptedOutMode = function () {
        var isOptedOut = false;
        var cookieOptedOut = null;
        var optedOut = ATInternet.Utils.optedOut;
        if (optedOut === false) {
            parent.exec('Cookies', 'del', ['atoptedout']);
            if (parent.getParam('idclient') === _config.optOut) {
                parent.delParam('idclient');
            }
        }
        parent.exec('Cookies', 'get', ['atoptedout', true], function (data) {
            cookieOptedOut = data;
        });
        if ((optedOut === true) || (cookieOptedOut === _config.optOut)) {
            isOptedOut = true;
        }
        if (isOptedOut) {
            ATInternet.Utils.optedOut = true;
        }
        return isOptedOut;
    };

    /**
     * Get context and cookie values according to priorities or generate a new GUID.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @private
     */
    var _run = function () {
        _getUserId();
        var isClient = _isClientConfiguration();
        var isFromCustomerContext = (typeof _userIdFromContext !== 'undefined');
        _isOptOut = _isOptedOutMode();
        if (isClient || isFromCustomerContext || _isOptOut) {
            var id = '';
            var isfromContext = false;
            var cookieName = _config.userIdCookieName;
            if (_isOptOut) {
                id = _config.optOut;
                isfromContext = true;
                cookieName = _config.optOutCookieName;
            }
            else if (parent.getConfig('disableCookie')){
                id = parent.getParam('idclient');
                isfromContext = true;
            }
            else if (isFromCustomerContext) {
                id = _userIdFromContext;
                isfromContext = true;
            }
            else if (_userIdFromCookie !== null) {
                id = _userIdFromCookie;
            }
            else {
                var uuid = ATInternet.Utils.uuid();
                id = uuid.v4();
            }
            _setUserId(id, isfromContext, cookieName);
        }
        parent.emit('ClientSideUserId:Ready', {
            lvl: 'INFO',
            details: {
                clientSideMode: _config.clientSideMode,
                userIdCookieDuration: _config.userIdCookieDuration,
                userIdExpirationMode: _config.userIdExpirationMode,
                userIdFromContext: _userIdFromContext,
                userIdFromCookie: _userIdFromCookie,
                userId: id
            }
        })
    };

    /**
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @description
     * React to OPT-OUT actions.
     * @param event {object}
     * @private
     */
    var _processEvent = function (event) {
        if (event) {
            var detail = event.detail;
            if (detail && (detail.name === 'clientsideuserid') && (detail.id === _id)) {
                _run();
            }
        }
    };

    /**
     * Launch plugin when all dependencies are loaded.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @private
     */
    var _init = function () {
        var dependencies = ['Cookies'];
        parent['plugins']['waitForDependencies'](dependencies, function () {
            var uuid = ATInternet.Utils.uuid();
            _id = parseInt(uuid.num(8));
            // Attach event in order to process OPT-OUT actions
            ATInternet.Utils.removeOptOutEvent(_processEvent);
            ATInternet.Utils.addOptOutEvent(_processEvent, _id);
            _run();
        });
    };

    // Initialise global process.
    _init();

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.ClientSideUserId ClientSideUserId}] Tags to manage a user ID on client side mode.
     * @name clientSideUserId
     * @inner
     * @type {object}
     * @memberof ATInternet.Tracker.Tag
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#clientSideUserId.set}
     * @public
     */
    parent['clientSideUserId'] = {};

    /**
     *[Helper added by plugin {@link ATInternet.Tracker.Plugins.ClientSideUserId ClientSideUserId}] Add a user ID to all hits "&idclient=" and store it in the cookie "atuserid".
     * @alias clientSideUserId.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param id {string|number} User ID
     * @example
     * <pre><code class="javascript">tag.clientSideUserId.set();
     * </code></pre>
     * @public
     */
    parent['clientSideUserId']['set'] = function (id) {
        var isfromContext = true;
        var cookieName = _config.userIdCookieName;
        if (_isOptOut) {
            id = _config.optOut;
            cookieName = _config.optOutCookieName;
        }
        _setUserId(id, isfromContext, cookieName);
        /* @if debug */
        parent.debug('ClientSideUserId:clientSideUserId:set', 'DEBUG', 'method ended', {id: id});
        /* @endif */
    };

    // For unit tests on private elements !!!
    /* @if test */
    var _this = this;
    _this._getUserId = _getUserId;
    _this._setUserId = _setUserId;
    _this._setCookieValue = _setCookieValue;
    _this._isClientConfiguration = _isClientConfiguration;
    _this._isOptedOutMode = _isOptedOutMode;
    _this._processEvent = _processEvent;
    _this._run = _run;
    _this._init = _init;
    _this._userIdCookieDuration = _config.userIdCookieDuration;
    _this._userIdExpirationMode = _config.userIdExpirationMode;
    _this._optOut = _config.optOut;
    _this._userIdCookieName = _config.userIdCookieName;
    _this._optOutCookieName = _config.optOutCookieName;
    _this._userIdFromContext = _userIdFromContext;
    _this._userIdFromCookie = _userIdFromCookie;
    _this.getThemAll = function () {
        _this._userIdCookieDuration = _config.userIdCookieDuration;
        _this._userIdExpirationMode = _config.userIdExpirationMode;
        _this._optOut = _config.optOut;
        _this._userIdCookieName = _config.userIdCookieName;
        _this._optOutCookieName = _config.optOutCookieName;
        _this._userIdFromContext = _userIdFromContext;
        _this._userIdFromCookie = _userIdFromCookie;
    };
    /* @endif */

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