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 _this = this;
    var _config = {};
    var _userIdFromContext = undefined;
    var _userIdFromCookie = null;

    // 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;
        });
    };

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

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

    /**
     * @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;
    };

    /**
     * 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 id = '';
        if (isClient) {
            var isFromCustomerContext = false;
            if (typeof _userIdFromContext !== 'undefined') {
                id = _userIdFromContext;
                isFromCustomerContext = true;
            }
            else if (_userIdFromCookie !== null) {
                id = _userIdFromCookie;
            }
            else {
                var uuid = ATInternet.Utils.uuid();
                id = uuid.v4();
            }
            _setUserId(id, isFromCustomerContext);
        }
        parent.emit('ClientSideUserId:Ready', {
            lvl: 'INFO',
            details: {
                clientSideMode: _config.clientSideMode,
                userIdFromContext: _userIdFromContext,
                userIdFromCookie: _userIdFromCookie,
                userId: id
            }
        })
    };

    /**
     * Launch plugin when all dependencies are loaded.
     * @memberof ATInternet.Tracker.Plugins.ClientSideUserId#
     * @function
     * @private
     */
    var _init = function () {
        var dependencies = ['Cookies'];
        parent['plugins']['waitForDependencies'](dependencies, _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 isClient = _isClientConfiguration();
        if (isClient) {
            _setUserId(id, true);
        }
        /* @if debug */
        parent.debug('ClientSideUserId:clientSideUserId:set', 'DEBUG', 'method ended', {id: id});
        /* @endif */
    };

    // For unit tests on private elements !!!
    /* @if test */
    _this._getUserId = _getUserId;
    _this._setUserId = _setUserId;
    _this._setCookieValue = _setCookieValue;
    _this._isClientConfiguration = _isClientConfiguration;
    _this._run = _run;
    _this._init = _init;
    _this._userIdCookieDuration = _config.userIdCookieDuration;
    _this._userIdExpirationMode = _config.userIdExpirationMode;
    _this._userIdFromContext = _userIdFromContext;
    _this._userIdFromCookie = _userIdFromCookie;
    _this.getThemAll = function () {
        _this._userIdCookieDuration = _config.userIdCookieDuration;
        _this._userIdExpirationMode = _config.userIdExpirationMode;
        _this._userIdFromContext = _userIdFromContext;
        _this._userIdFromCookie = _userIdFromCookie;
    };
    /* @endif */

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