Source: Page/page.js

/**
 * @class
 * @name Page
 * @memberof ATInternet.Tracker.Plugins
 * @type {function}
 * @param tag {object} Instance of the Tag used
 * @description
 * This plugin allows you to define page tag data :
 * <ul>
 *     <li><b>Page values</b>: to declare name, level2, chapters and custom object parameters.
 *     <li><b>Site variables</b>: to associate information specific to your activity (interface language, load times, number of articles per page, etc.) with your site.</li>
 *     <li><b>Page variables</b>: to evaluate the performance of specific pages of your site, notably those offering fields to be filled out.</li>
 *     <li><b>Dynamic labels</b>: to track the history of a page whose content has been modified.</li>
 *     <li><b>Tags (or keywords)</b>: to define the theme(s) of the content your users visit.</li>
 *     <li><b>Custom tree structure</b>: to obtain a completely customised view of all your traffic to completely match your analysis criteria.</li>
 * </ul>
 * It also processes Campaigns and Internal Search contexts.
 * @public
 */
ATInternet.Tracker.Plugins.Page = function (tag) {

    'use strict';

    var self = this;

    var _confPage = {
        dynamicLabel: {
            properties: ['pageId', 'chapterLabel', 'update'],
            parameters: ['pid', 'pchap', 'pidt']
        },
        customVars: {
            properties: ['page', 'site'],
            parameters: ['f', 'x']
        }
    };

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

    /**
     * Get page name with chapters.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param tagObject {object} Page object containing properties to use
     * @returns {string}
     * @private
     */
    var _getFullName = function (tagObject) {
        return tag.utils.manageChapters(tagObject, 'chapter', 3) + (tagObject['name'] ? tagObject['name'] : '');
    };

    /**
     * Set context with tag object value or default value.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param context {object} Context property to process
     * @param tagProp {object} Tag property to use
     * @param def {string} Default value to use if context value is not defined
     * @returns {string}
     * @private
     */
    var _magic = function (context, tagProp, def) {
        if (tagProp) {
            context = tagProp;
        } else if (!context && typeof def !== 'undefined') {
            context = def;
        }
        return context;
    };

    /**
     * Set value if property has been declared.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param context {object} Context to process
     * @param tagObject {object} Page object containing properties to use
     * @param key {string} Name of the property to set
     * @private
     */
    var _setDeclaredProperty = function (context, tagObject, key) {
        if (tagObject.hasOwnProperty(key)) {
            context[key] = _magic(context[key], tagObject[key], undefined);
        }
    };

    /**
     * Add site or page indicators to a local buffer object or global tag buffer.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param buffer {object} Local buffer from helper send
     * @param object {object} Object from tag or page context
     * @param isLocal {boolean} True if local buffer, false otherwise
     * @private
     */
    var _setIndicatorVariables = function (buffer, object, isLocal) {
        if (object) {
            var props = _confPage.customVars.properties;
            var params = _confPage.customVars.parameters;
            for (var i = 0; i < props.length; i++) {
                if (object.hasOwnProperty(props[i]) && object[props[i]]) {
                    for (var p in object[props[i]]) {
                        if (object[props[i]].hasOwnProperty(p)) {
                            if (isLocal) {
                                buffer[params[i] + p] = object[props[i]][p];
                            } else {
                                tag.setParam(params[i] + p, object[props[i]][p]);
                            }
                        }
                    }
                }
            }
        }
    };

    /**
     * Add dynamic label to a local buffer object or global tag buffer.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param buffer {object} Local buffer from helper send
     * @param object {object} Object from tag or page context
     * @param isLocal {boolean} True if local buffer, false otherwise
     * @private
     */
    var _setDynamicLabel = function (buffer, object, isLocal) {
        if (object) {
            var data = tag.utils.manageChapters(object, 'chapter', 3);
            if (data) {
                object.chapterLabel = data.replace(/::$/gi, '');
            }
            var props = _confPage.dynamicLabel.properties;
            var params = _confPage.dynamicLabel.parameters;
            for (var i = 0; i < params.length; i++) {
                if (object.hasOwnProperty(props[i])) {
                    if (isLocal) {
                        buffer[params[i]] = object[props[i]];
                    } else {
                        tag.setParam(params[i], object[props[i]]);
                    }
                }
            }
        }
    };

    /**
     * Add tags (keywords) to a local buffer object or global tag buffer.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param buffer {object} Local buffer from helper send
     * @param object {object} Object from tag or page context
     * @param isLocal {boolean} True if local buffer, false otherwise
     * @private
     */
    var _setTags = function (buffer, object, isLocal) {
        if (object && object.keywords instanceof Array) {
            var tabLenght = object.keywords.length;
            if (tabLenght > 0) {
                var str = '';
                for (var i = 0; i < tabLenght; i++) {
                    str += '[' + object.keywords[i] + ']' + (i < (tabLenght - 1) ? '|' : '');
                }
                if (isLocal) {
                    buffer.tag = str;
                } else {
                    tag.setParam('tag', str);
                }
            }
        }
    };

    /**
     * Add a custom tree structure to a local buffer object or global tag buffer.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param buffer {object} Local buffer from helper send
     * @param object {object} Object from tag or page context
     * @param isLocal {boolean} True if local buffer, false otherwise
     * @private
     */
    var _setCustomTreeStructure = function (buffer, object, isLocal) {
        if (object) {
            var str = '';
            var checkCategory = function (property) {
                return (property ? property : '0');
            };
            str += checkCategory(object.category1) + '-';
            str += checkCategory(object.category2) + '-';
            str += checkCategory(object.category3);
            if (isLocal) {
                buffer.ptype = str;
            } else {
                tag.setParam('ptype', str);
            }
        }
    };

    /**
     * Add campaign variables to a local buffer object or global tag buffer.
     * @memberof ATInternet.Tracker.Plugins.Page#
     * @function
     * @param buffer {object} Local buffer from helper send
     * @param object {object} Object from campaign context
     * @param isLocal {boolean} True if local buffer, false otherwise
     * @private
     */
    var _setCampaignsVariables = function (buffer, object, isLocal) {
        if (object) {
            for (var key in object) {
                if (object.hasOwnProperty(key) && typeof object[key] !== 'undefined') {
                    if (isLocal) {
                        buffer[key] = object[key];
                    } else {
                        tag.setParam(key, object[key]);
                    }
                }
            }
        }
    };

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.Page Page}]  Tags to associate page and site variables specific to your activity.
     * @name customVars
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#customVars.set}
     * @public
     */
    tag.customVars = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Set page and site variables.
     * @alias customVars.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 2 properties : site, page
     * @example
     * <pre><code class="javascript">tag.customVars.set({
     *      site: {
     *          1: 'site1',
     *          5: 'site5',
     *          20: 'site20'
     *      },
     *      page: {
     *          1: 'page1',
     *          5: 'page5',
     *          20: 'page20'
     *      }
     *  });
     * </code></pre>
     * @public
     */
    tag.customVars.set = function (tagObject) {
        var _getCustomVars = function (target, source) {
            if (target) {
                if (source) {
                    for (var key in source) {
                        if (source.hasOwnProperty(key)) {
                            target[key] = ATInternet.Utils.completeFstLevelObj(target[key], source[key], true);
                        }
                    }
                }
            } else {
                target = source;
            }
            return target;
        };
        var contextPageObject = tag.getContext('page') || {};
        //Indicators
        contextPageObject.customVars = _getCustomVars(contextPageObject.customVars, tagObject);
        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:customVars:set', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
    };

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Tags to track the history of a page whose content has been modified.
     * @name dynamicLabel
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#dynamicLabel.set}
     * @public
     */
    tag.dynamicLabel = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Set dynamic label.
     * @alias dynamicLabel.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 5 properties : pageId, chapter1, chapter2, chapter3, update
     * @example
     * <pre><code class="javascript">tag.dynamicLabel.set({
     *      pageId: '123456',
     *      chapter1: 'mychapter1',
     *      chapter2: 'mychapter2',
     *      chapter3: 'mychapter3',
     *      update: '200910031045'
     *  });
     * </code></pre>
     * @public
     */
    tag.dynamicLabel.set = function (tagObject) {
        var contextPageObject = tag.getContext('page') || {};
        contextPageObject.dynamicLabel = ATInternet.Utils.completeFstLevelObj(contextPageObject.dynamicLabel, tagObject, true);
        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:dynamicLabel:set', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
    };

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Tags to define the theme(s) of the content your users visit.
     * @name tags
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#tags.set}
     * @public
     */
    tag.tags = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Set keywords.
     * @alias tags.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 1 property : keywords
     * @example
     * <pre><code class="javascript">tag.tags.set({
     *      keywords: ['tag','Key']
     *  });
     * </code></pre>
     * @public
     */
    tag.tags.set = function (tagObject) {
        var contextPageObject = tag.getContext('page') || {};
        contextPageObject.tags = ATInternet.Utils.completeFstLevelObj(contextPageObject.tags, tagObject, true);
        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:tags:set', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
    };

    /**
     * [Object added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Tags to obtain a completely customised view of all your traffic.
     * @name customTreeStructure
     * @memberof ATInternet.Tracker.Tag
     * @inner
     * @type {object}
     * @property {function} set Tag helper, see details here {@link ATInternet.Tracker.Tag#customTreeStructure.set}
     * @public
     */
    tag.customTreeStructure = {};

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Set custom tree structure.
     * @alias customTreeStructure.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 3 properties : category1, category2, category3
     * @example
     * <pre><code class="javascript">tag.customTreeStructure.set({
     *      mycategory1: 1,
     *      mycategory2: 2,
     *      mycategory3: 3
     *  });
     * </code></pre>
     * @public
     */
    tag.customTreeStructure.set = function (tagObject) {
        var contextPageObject = tag.getContext('page') || {};
        contextPageObject.customTreeStructure = ATInternet.Utils.completeFstLevelObj(contextPageObject.customTreeStructure, tagObject, true);
        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:customTreeStructure:set', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
    };

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

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Reset page context.
     * @alias page.reset
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @example
     * <pre><code class="javascript">tag.page.reset();
     * </code></pre>
     * @public
     */
    tag.page.reset = function () {
        tag.delContext('page');
        /* @if debug */
        tag.debug('Page:page:reset', _debug.level, _debug.messageEnd);
        /* @endif */
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Set page properties.
     * @alias page.set
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 5 properties : name, chapter1, chapter2, chapter3, customObject
     * @example
     * <pre><code class="javascript">tag.page.set({
     *      name: 'pageName',
     *      chapter1: 'mychapter1',
     *      chapter2: 'mychapter2',
     *      chapter3: 'mychapter3',
     *      customObject: {
     *          one: 1,
     *          two: 2
     *      }
     *  });
     * </code></pre>
     * @public
     */
    tag.page.set = function (tagObject) {

        tagObject = tagObject || {};

        tag.dispatchSubscribe('page');

        var contextPageObject = tag.getContext('page') || {};

        contextPageObject.name = _magic(contextPageObject.name, tagObject.name, '');
        contextPageObject.level2 = _magic(contextPageObject.level2, tagObject.level2, '');

        //Cas particulier: Dans le cas des chapitres, on ajoute les propriétés dans le contexte de page ssi elles ont été déclarées explicitement par l'utilisateur.
        //Explication: La méthode Utils de gestion des chapitres créée un chapitre vide si le paramètre existe et que sa valeur est undefined.

        _setDeclaredProperty(contextPageObject, tagObject, 'chapter1');
        _setDeclaredProperty(contextPageObject, tagObject, 'chapter2');
        _setDeclaredProperty(contextPageObject, tagObject, 'chapter3');

        //customObject
        contextPageObject.customObject = ATInternet.Utils.completeFstLevelObj(contextPageObject.customObject, tagObject.customObject, true);

        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:page:set', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Tagging method for page (helper).
     * @alias page.send
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param tagObject {object} 5 properties : name, chapter1, chapter2, chapter3, customObject
     * @example
     * <pre><code class="javascript">tag.page.send({
     *      name: 'pageName',
     *      chapter1: 'mychapter1',
     *      chapter2: 'mychapter2',
     *      chapter3: 'mychapter3',
     *      customObject: {
     *          one: 1,
     *          two: 2
     *      },
     *      customVars: {
     *          page: {
     *              1: 'page1',
     *              5: 'page5',
     *              20: 'page20'
     *          },
     *          site: {
     *              1: 'site1',
     *              5: 'site5',
     *              20: 'site20'
     *          }
     *      },
     *      dynamicLabel: {
     *          pageId: '123456',
     *          chapter1: 'mychapter1',
     *          chapter2: 'mychapter2',
     *          chapter3: 'mychapter3',
     *          update: '200910031045'
     *      },
     *      tags: {
     *          keywords: ['tag','Key']
     *      },
     *      customTreeStructure: {
     *          category1: mycategory1,
     *          category2: mycategory2,
     *          category3: mycategory3
     *      }
     *  });
     * </code></pre>
     * @public
     */
    tag.page.send = function (tagObject) {

        tagObject = tagObject || {};

        var preservePropagation = true;
        var elementType = '';
        var buffer = {
            'p': _getFullName(tagObject),
            's2': (tagObject['level2'] || '')
        };

        // customObject: If you pass a customObject when there is potentially a permanent one in the buffer, you have to merge them.
        // Explanation: The builder ALWAYS sends the permanent elements as long as they are of the right type.
        // If there is a permanent stc, it is necessary to recover its value and use it to complete the customObject (priority) passed as parameter.
        // If there is no permanent stc in the buffer, we simply send the customObject passed as parameter.
        var customObjectValue = tagObject.customObject;
        if (customObjectValue) {
            var hitParam = 'stc';
            var hitType = ['page'];
            customObjectValue = tag.processTagObject(hitParam, hitType, customObjectValue);
            buffer[hitParam] = {
                _value: ATInternet.Utils.jsonSerialize(customObjectValue),
                _options: {
                    hitType: hitType,
                    encode: true,
                    separator: ',',
                    truncate: true
                }
            };
        }

        //vrn management.
        var contextPageObject = tag.getContext('page') || {};
        if (contextPageObject.vrn) {
            buffer.vrn = contextPageObject.vrn;
            tag.delContext('page', 'vrn');
        }

        // internalSearch management.
        var contextInternalSearch = tag.getContext('InternalSearch') || {};
        if (typeof contextInternalSearch.keyword !== 'undefined') {
            buffer.mc = ATInternet.Utils.cloneSimpleObject(contextInternalSearch.keyword);
            if (typeof contextInternalSearch.resultPageNumber !== 'undefined') {
                buffer.np = ATInternet.Utils.cloneSimpleObject(contextInternalSearch.resultPageNumber);
            }
            tag.delContext('InternalSearch');
        }

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

        //Indicators.
        _setIndicatorVariables(buffer, tagObject.customVars, true);

        //Dynamic label.
        _setDynamicLabel(buffer, tagObject.dynamicLabel, true);

        //Tags.
        _setTags(buffer, tagObject.tags, true);

        //Custom Tree Structure.
        _setCustomTreeStructure(buffer, tagObject.customTreeStructure, true);

        //Campaigns variables.
        var contextCampaignsObject = tag.getContext('campaigns') || {};
        _setCampaignsVariables(buffer, contextCampaignsObject, true);
        tag.delContext('campaigns');

        var eventObject = null;
        if (tagObject && tagObject.hasOwnProperty('event')) {
            eventObject = tagObject.event || window.event;
        }
        if (!ATInternet.Utils.isTabOpeningAction(eventObject) && tagObject.elem) {
            var manage = tag.techClicks.manageClick(tagObject.elem, eventObject);
            preservePropagation = manage.preservePropagation;
            elementType = manage.elementType;
        }

        tag.manageSend(function () {
            tag.sendHit(buffer, null, tagObject.callback, null, elementType);
        });

        contextPageObject.name = _magic(contextPageObject.name, tagObject.name, '');
        contextPageObject.level2 = _magic(contextPageObject.level2, tagObject.level2, '');

        //Create chapters keys with undefined value is not wanted here.
        _setDeclaredProperty(contextPageObject, tagObject, 'chapter1');
        _setDeclaredProperty(contextPageObject, tagObject, 'chapter2');
        _setDeclaredProperty(contextPageObject, tagObject, 'chapter3');

        tag.setContext('page', contextPageObject);
        /* @if debug */
        tag.debug('Page:page:send', _debug.level, _debug.messageEnd, tagObject);
        /* @endif */
        return preservePropagation;
    };

    /**
     * [Helper added by plugin {@link ATInternet.Tracker.Plugins.Page Page}] Will be called by tracker.dispatch if any page has been set.
     * @alias page.onDispatch
     * @memberof! ATInternet.Tracker.Tag#
     * @function
     * @param callback {function} Callback to execute
     * @param elementType {string} Element type (mailto, form, redirection)
     * @private
     */
    tag.page.onDispatch = function (callback, elementType) {

        var contextPageObject = tag.getContext('page') || {};
        var contextInternalSearch = tag.getContext('InternalSearch') || {};

        tag.setParam('p', _getFullName(contextPageObject));
        tag.setParam('s2', (contextPageObject.level2 || ''));

        //vrn management
        if (contextPageObject.vrn) {
            tag.setParam('vrn', contextPageObject.vrn);
            tag.delContext('page', 'vrn');
        }
        // internalSearch management
        if (typeof contextInternalSearch.keyword !== 'undefined') {
            tag.setParam('mc', ATInternet.Utils.cloneSimpleObject(contextInternalSearch.keyword));
            if (typeof contextInternalSearch.resultPageNumber !== 'undefined') {
                tag.setParam('np', ATInternet.Utils.cloneSimpleObject(contextInternalSearch.resultPageNumber));
            }
            tag.delContext('InternalSearch');
        }

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

        //Indicators.
        _setIndicatorVariables(null, contextPageObject.customVars, false);

        //Dynamic label.
        _setDynamicLabel(null, contextPageObject.dynamicLabel, false);

        //Tags.
        _setTags(null, contextPageObject.tags, false);

        //Custom Tree Structure.
        _setCustomTreeStructure(null, contextPageObject.customTreeStructure, false);

        //Campaigns variables.
        var contextCampaignsObject = tag.getContext('campaigns') || {};
        _setCampaignsVariables(null, contextCampaignsObject, false);
        tag.delContext('campaigns');

        var hitType = ['page'];
        var contextObject = contextPageObject.customObject;
        if (contextObject) {
            var hitParam = 'stc';
            var paramOptions = {
                'hitType': hitType,
                'encode': true,
                'separator': ',',
                'truncate': true,
                'elementType': elementType
            };
            tag.processContextObjectAndSendHit(hitParam, paramOptions, contextObject, callback);
        } else {
            tag.manageSend(function () {
                tag.sendHit(null, [['hitType', hitType]], callback, null, elementType);
            });
        }
    };

    // For unit tests on private elements !!!
    /* @if test */
    self._getFullName = _getFullName;
    self._magic = _magic;
    self._setDeclaredProperty = _setDeclaredProperty;
    self._setIndicatorVariables = _setIndicatorVariables;
    self._setDynamicLabel = _setDynamicLabel;
    self._setTags = _setTags;
    self._setCustomTreeStructure = _setCustomTreeStructure;
    self._setCampaignsVariables = _setCampaignsVariables;
    /* @endif */
};
ATInternet.Tracker.addPlugin('Page');