Source: managers/nav-manager.js

/**
 * @module managers/nav-manager
 * @description This module manages common global navigation
 * @requires modules/hash
 * @requires common/view
 * @requires managers/template-manager
 * @requires managers/prsonas-manager
 * @requires jHammer
 */
 

define([
    "modules/hash",
    "common/view", 
    "managers/template-manager",
    "managers/prsonas-manager",
    "jHammer"  
], 

function (hash, view, templateManager, prsonasManager)
{

    // ---------------------------------------------------------------
    //
    // NAV MANAGER
    //
    // ---------------------------------------------------------------

    var Nav = function ()
    {
        console.log(" * <nav>");

        this.oView            = view;
        this.oHash            = hash;
        this.oTemplateManager = templateManager;
        this.oPrsonas         = prsonasManager;

        window.tEvent.eventStr.EVENT_PAGE_BACK_BTN = "EVENT_PAGE_BACK_BTN";   
        window.tEvent.eventStr.EVENT_PAGE_HOME_BTN = "EVENT_PAGE_HOME_BTN";  
        
        this.ui = {
            eventBtn       : ".js-btn-event",
            microphone     : ".js-microphone",
            licenseStatus  : ".js-license-status"
        };

        this.micActiveTimer = false;
        this.micTimer = -1;

        this.historyObj = {
            current: {
                event: "",
                data: -1
            },

            past: {
                event: "",
                data: -1
            },

            eventStack: []
        };

        this.pageHistory = [];

        this.init();
    };

    Nav.prototype =
    {    
       
        // ______________________________________________________________
        //                                                           init
        /**
            * init
            * @description Initializes class
            * @fires assignListeners()
            * @memberOf module:managers/nav-manager
            * @instance
        */
        init: function()
        {   
            this.assignListeners();            
        },


        // ______________________________________________________________
        //                                                assignListeners
        /** 
        * assignListeners
        * @description Assigns listeners to events used in this class.
        * @listens  EVENT_ADMIN_GOT_MANIFEST
        * @listens  EVENT_NEW_PAGE
        * @listens  EVENT_BACK_BUTTON
        * @listens  EVENT_BACK_BUTTON_NO_ANIM
        * @listens  EVENT_TIMER_EXPIRED
        * @listens  EVENT_TOGGLE_MIC
        * @listens  EVENT_HISTORY
        * @memberOf module:managers/template-manager
        * @instance
        */
        assignListeners: function()
        {           
            var self = this;

            // new page action
            window.tEvent.addListener("EVENT_ADMIN_GOT_MANIFEST", function(evt, manifest)
            {   
                self.onProcessManifest(manifest);
            });

            // new page action
            window.tEvent.addListener("EVENT_NEW_PAGE", function(evt, newPageData)
            {   
                self.onNewPage(newPageData);
            });

            // back button
            window.tEvent.addListener("EVENT_BACK_BUTTON", function(evt, data)
            {
                self.onBackButtonClick(data);
            });

            // back button for _NO_ANIM event append
            window.tEvent.addListener("EVENT_BACK_BUTTON_NO_ANIM", function(evt, data)
            {
                self.onBackButtonNoAnimClick(data);
            });

            // timer expired
            window.tEvent.addListener("EVENT_TIMER_EXPIRED", function(evt, data)
            {                
                window.oModal.close();
            });

            window.tEvent.addListener("EVENT_TOGGLE_MIC", function(evt, data){
                var state;
                switch(data.property){
                    case "SPEECH_ENABLED":
                        state = "on";
                        break;

                    case "SPEECH_DISABLED":
                        state = "off";
                        break;
                }
                self.onToggleMicrophone(state);
            }); 

            // page is loaded, check for anchor and scroll to anchor
            if (typeof window.oModel === "undefined" || window.oModel.jConfig === -1){
                window.tEvent.addListener("EVENT_MODEL_READY", function(evt, data)
                {
                    self.initHotkeys();
                });                
            } else {
                self.initHotkeys();
            }

            $("body").hammer().on("click", this.ui.eventBtn, function(e){
                var eventId = $(this).attr("data-event");
                var data = $(this).attr("data-id");
                self.onEventBtnClick(e, eventId, data);
            });


            $("body").hammer().on("click", this.ui.microphone, function(e){
                self.onToggleMicrophone();
            });

            window.tEvent.addListener("EVENT_HISTORY", function(evt, data){ 
                // save navigation for going back              
                self.updateHistory(data.eventId, data.data);
            });

            window.tEvent.addListener("EVENT_PAGE_BACK_BTN", function(evt, data){
                self.onGoBack();
            });

        },

        


        // --------------------------------------------------------------
        // HELPERS
        // --------------------------------------------------------------
      

        // ______________________________________________________________
        //                                                    initHotkeys
        /**
            * initHotkeys
            * @description Initializes hot key handling from project JSON document.hotkeys. Also, enables/disables nuBrowser key capture based on SDK config EnableGlobalKeyHandling
            * @memberOf module:managers/nav-manager
            * @instance
        */
        initHotkeys: function() {   

            var self = this;

            var target,
                key;

            var enableBrowserKeyCapture = false;
            if (typeof window.oPrsonas.app.getSetting !== "undefined") {
                enableBrowserKeyCapture = window.oPrsonas.app.getSetting("EnableGlobalKeyHandling");
            }
                
            $(document).keydown(function(e){

                if ($(e.target).attr("class").indexOf("input") < 0){
                    key = e.key.toLowerCase();
                    console.log(" * <nav.initHotkeys>", e);

                    for (var item in window.oModel.jConfig.document.hotkeys){
                        target = window.oModel.jConfig.document.hotkeys[item];

                        if (key === target.key && e.ctrlKey){                            
                            console.log(" * <nav.initHotkeys> firing event", target.event);
                            window.tEvent.fire(target.event);                            
                            break;
                        }                              
                    }
                }

            }); 

        },

        // ______________________________________________________________
        //                                                  updateHistory
        /**
            * updateHistory
            * @description Keeps history of the events called (used for back button)
            * @param  {String} eventId - Event ID
            * @param  {Object} data - Any data passed with the event call
            * @memberOf managers/nav-manager
            * @instance
        */
        updateHistory: function(eventId, data) { 

            eventId = eventId.split("_STOP_ANIM")[0];

            var modelData = window.oModel.jConfig;

            if (typeof data === "undefined") {
                data = "";
            };

            if (eventId === modelData.document.startEvent.split("_STOP_ANIM")[0] ||
                eventId === modelData.prsonas.timers.expiredEvent ||
                eventId === "EVENT_PAGE_HOME_BTN" ||
                (typeof modelData.proxySendkeyEvents["EVENT_PAGE_HOME_BTN"] !== "undefined" &&  eventId === modelData.proxySendkeyEvents["EVENT_PAGE_HOME_BTN"]) ) {

                this.historyObj.eventStack = [
                    {
                        event: eventId,
                        data: data
                    }
                ]
            } else {
                if (this.historyObj.eventStack[this.historyObj.eventStack.length - 1].event !== eventId) {
                    this.historyObj.eventStack.push({
                        event: eventId,
                        data: data
                    });
                }
            }

        },


        // ______________________________________________________________
        //                                                       onGoBack
        /**
            * onGoBack
            * @description Goes back in history to the previous event recorded
            * @memberOf managers/nav-manager
            * @instance
        */
        onGoBack: function() { 

            if (this.historyObj.eventStack.length === 0) {
                var evt = this.jConfig.document.startEvent;
                window.tEvent.fire(evt); 
            } else {
                 var evt = this.historyObj.eventStack[this.historyObj.eventStack.length - 2];
                 if (evt.event !== "EVENT_PAGE_HOME_BTN" && evt.event.indexOf("_STOP_ANIM") === -1){
                    evt.event += "_STOP_ANIM";
                }

                // remove last 2 items in stack
                this.historyObj.eventStack.splice(-1);
                this.historyObj.eventStack.splice(-1);

                window.tEvent.fire(evt.event, evt.data);
            }
            
        },
        // --------------------------------------------------------------
        // EVENTS
        // --------------------------------------------------------------
        
        // ______________________________________________________________
        //                                             onProcessManifest
        /**
            * onProcessManifest
            * @description Gathers data from manifest
            * @param {Object} manifest Manifest from Prsonas application
            * @fire onToggleMicrophone()
            * @memberOf module:managers/nav-manager
            * @instance
        */
        onProcessManifest: function(manifest) {   

            // set microphone state
            this.onToggleMicrophone("off", true);
        },


        /*
            Markup eg:
            <div class="microphone-toggle js-microphone" data-status="on"></div>
        */

         // ______________________________________________________________
        //                                             onToggleMicrophone
        /**
            * onToggleMicrophone
            * @description Toggles the microphone state
            * @param {Boolean} forceState Forces the microphone state
            * @param {Boolean} affectIconOnly Just affect the icon state
            * @memberOf module:managers/nav-manager
            * @instance
        */        
        onToggleMicrophone: function(forceState, affectIconOnly) {   
            
            var self = this;
            var $mic = $(this.ui.microphone);
            var micStatus = $mic.attr("data-status");   




            if (typeof forceState !== "undefined"){
                $mic.attr("data-status", forceState);   
                micStatus = forceState;
            }  else {

                if (!this.micActiveTimer && $(this.ui.licenseStatus).css("display") === "none"){                    

                    switch(micStatus){
                        case "on":
                            $mic.attr("data-status", "off");
                            
                            break;

                        case "off":
                            $mic.attr("data-status", "on");
                            break;
                    }
                }

            }  


            // do send key and timer if not just for visual status
            if (typeof affectIconOnly === "undefined" || affectIconOnly === false){

                // discourage quick consecutive clicks - prevents error
                this.micActiveTimer = true;
                this.micTimer = setTimeout(function(){
                    self.micActiveTimer = false;
                }, 3000);

            } 

        },        
        

        // ______________________________________________________________
        //                                                onEventBtnClick
        /**
            * onEventBtnClick
            * @description Module configured button click
            * @param {Event} btnEvt Button event
            * @param {String} eventId Event ID to be triggered
            * @param {Object} data Data to be passed with the event
            * @memberOf module:managers/nav-manager
            * @instance
        */ 
        onEventBtnClick: function(btnEvt, eventId, data)
        {
            console.log(" * <nav.onEventBtnClick> ", eventId, data);

            var interactionBlockedState = window.oModel.getInteractionBlockState();

            if (!interactionBlockedState){
                window.tEvent.fire("EVENT_SET_INTERACTION_BLOCK_TIMER");
                if (eventId !== ""){
                    window.tEvent.fire(eventId, data);
                }                
            } else {
                btnEvt.stopPropagation(); 
            }
        },



        // ______________________________________________________________
        //                                                      onNewPage        
        /**
            * onNewPage
            * @description Maintains page history
            * @param {Object} newPageData 
            * @memberOf module:managers/nav-manager
            * @instance
        */ 
        onNewPage: function(newPageData)
        {   
            // maintain page history for back button
            if (newPageData === "EVENT_PAGE_IDLE"){
                this.pageHistory = [];
            } else if (newPageData === "EVENT_PAGE_MAIN_MENU") {
                this.pageHistory = ["EVENT_PAGE_MAIN_MENU_STOP_TALK"];
            } else {
                this.pageHistory.push(newPageData);
            }
        },

        // ______________________________________________________________
        //                                        onBackButtonNoAnimClick        
        /**
            * onBackButtonNoAnimClick
            * @description Trigger back button with no intent/animation action by triggering history event adding _NO_ANIM to prevent redundant animation
            * @param {Object} data Data associated with event history
            * @fire EVENT_SET_INTERACTION_BLOCK_TIMER
            * @fire Page history event += "_NO_ANIM"
            * @memberOf module:managers/nav-manager
            * @instance
        */ 
        onBackButtonNoAnimClick: function(data)
        {  
            window.tEvent.fire("EVENT_SET_INTERACTION_BLOCK_TIMER");

            // remove last page
            this.pageHistory.splice(-1, 1);

            // go to previous page
            window.tEvent.fire(this.pageHistory[this.pageHistory.length-1] + "_NO_ANIM", data);
        },

        // ______________________________________________________________
        //                                               onBackButtonClick
        /**
            * onBackButtonClick
            * @description Trigger back button
            * @param {Object} data Data associated with event history
            * @fire EVENT_SET_INTERACTION_BLOCK_TIMER
            * @fire Page history event
            * @memberOf module:managers/nav-manager
            * @instance
        */ 
        onBackButtonClick: function(data)
        {  
            window.tEvent.fire("EVENT_SET_INTERACTION_BLOCK_TIMER");

            // remove last page
            this.pageHistory.splice(-1, 1);

            // go to previous page
            window.tEvent.fire(this.pageHistory[this.pageHistory.length-1], data);
        }

    };

    var oNav = window.oNav = new Nav();
        
    return (oNav);        
   
});