Source: managers/language-manager.js

/**
 * @module managers/language-manager
 * @description This module manages language handling
 * @requires jHammer
 */
define([
    "common/view",
    "jHammer"  
], 

function (View)
{

    // ---------------------------------------------------------------
    //
    // Language
    //
    // ---------------------------------------------------------------

    var Language = function ()
    {

        console.log(" * <language>");        

        this.oView = View;       

        window.tEvent.eventStr.EVENT_LANGUAGE_SET           = "EVENT_LANGUAGE_SET";
        window.tEvent.eventStr.EVENT_LANGUAGE_RESET         = "EVENT_LANGUAGE_RESET";
        window.tEvent.eventStr.EVENT_SET_LANGUAGE           = "EVENT_SET_LANGUAGE";
        window.tEvent.eventStr.EVENT_APPLY_LANGUAGE         = "EVENT_APPLY_LANGUAGE";
        window.tEvent.eventStr.EVENT_LANGUAGE_CONFIG_LOADED = "EVENT_LANGUAGE_CONFIG_LOADED";

        this.ui = {
            body                       : "body",
            autoText                   : "[data-auto-lang-source-id]",
            dynamicText                : "[data-lang-copy-id]",
            dynamicImg                 : "[data-lang-img-id]",
            langRotationItem           : ".js-lang-rotation-item",
            langIcon                   : ".js-complex-lang-icon",
            langBtn                    : ".js-complex-lang-btn",
            micToggle                  : ".js-complex-mic",
            persistentLangContainer    : ".js-complex-persistent-lang",
            persistentLangRotationItem : ".js-complex-persistent-lang-btn",
            autoTranslate              : ".js-auto-translate"
        };        

        this.def = -1;

        // project.json
        this.jConfig = -1;
        this.jLangConfig = -1;

        // enable first load events
        this.firstLoad = true;

        this.currentLang = -1;

        this.langAnimDelayedCall = -1;
        this.langPersistentAnimDelayedCall = -1;

        this.init();

    };

    Language.prototype =
    {    
       
        // ______________________________________________________________
        //                                                           init
        /**
            * init
            * @description Initializes class. Sets data-lang attribute of <body>
            * @fires loadLanguageFile()
            * @memberOf module:managers/language-manager
            * @instance
        */
        init: function() { 

            var self = this;

            // in case there no unit connection so there is no "GAP"
            $(this.ui.body).attr(this.def.DATA_LANGUAGE, "_English");

            // is model ready?
            if (typeof window.oModel === "undefined" || window.oModel.modelReady === false){
                window.tEvent.addListener("EVENT_MODEL_READY", function(evt, data) {
                    self.loadLanguageFile();                                     
                });                
            } else {
                self.loadLanguageFile(); 
            }
                       
        },


        // ______________________________________________________________
        //                                                assignListeners
        /** 
        * assignListeners
        * @description Assigns listeners to events used in this class.
        * @listens  EVENT_ADMIN_GOT_MANIFEST
        * @listens  EVENT_LANGUAGE_RESET
        * @listens  EVENT_PRSONAS_MESSAGE_STATUS
        * @listens  EVENT_APPLY_LANGUAGE
        * @listens  EVENT_TEMPLATE_LOADED
        * @listens  langBtn
        * @memberOf module:managers/language-manager
        * @instance
        */
        assignListeners: function() {           
            var self = this;

            // got manifest with language options
            window.tEvent.addListener("EVENT_ADMIN_GOT_MANIFEST", function(evt, manifest) {                
                self.onReceivedManifest(manifest); 
            });

            // got language status - make sure we are synced
            window.tEvent.addListener("EVENT_PRSONAS_MESSAGE_STATUS", function(evt,  data) {
                if (data.property === "language"){
                    self.onLanguageStatus(data);
                }
            });   

            // set a language
            window.tEvent.addListener(window.tEvent.eventStr.EVENT_APPLY_LANGUAGE, function(evt, languageData) {   
                languageData.fromUnit = false;           
                self.onSetLanguage(languageData);
            });  

            // lang btn
            $("body").hammer().on("click", this.ui.langBtn, function(e){  
                var lang = $(this).attr("data-id");            
                self.onSetLanguage({
                    language: lang
                }, "button");
            });

            // choose a lang btn
            $("body").hammer().on("click", this.ui.persistentLangContainer, function(e){  
                window.tEvent.fire(window.tEvent.eventStr.EVENT_PAGE_LANGUAGES);
            }); 

            window.tEvent.addListener(window.tEvent.eventStr.EVENT_TEMPLATE_LOADED_DETAILS, function(evt, eventData){ 
                self.onPageLoad(eventData);                
            });

            window.tEvent.addListener("EVENT_ADMIN_GOT_MANIFEST", function(evt, data){                
                self.resetLanguage();  
            });

            window.tEvent.addListener(window.tEvent.eventStr.EVENT_LANGUAGE_RESET, function(evt, data){                
                self.resetLanguage();  
            });

        },        


        // --------------------------------------------------------------
        // HELPERS
        // --------------------------------------------------------------
        
        // ______________________________________________________________
        //                                                   getProjectId
        /**
            * getProjectId
            * @description Returns the project ID. First trying the commandline then falling back to project JSON prsonas.projectId
            * @return {String} Returns the project ID
            * @memberOf module:managers/language-manager
            * @instance
        */
        getProjectId: function() { 
            var projectId = this.jConfig.prsonas.projectId;

            if (typeof this.oPrsonas !== "undefined" &&
                typeof this.oPrsonas.app !== "undefined" &&
                this.oPrsonas.app.getCommandLineParameters() !== null){
                
                if (typeof this.oPrsonas.app.getCommandLineParameters().experience !== "undefined"){
                    projectId = this.oPrsonas.app.getCommandLineParameters().experience;
                }  
            }

            return (projectId);
        },


        // ______________________________________________________________
        //                                                  initLanguages
        /**
            * initLanguages
            * @description Initializes languages
            * @fires resetLanguage()
            * @memberOf module:managers/language-manager
            * @instance
        */
        initLanguages: function() {   
            this.resetLanguage();  
        },


        // ______________________________________________________________
        //                                                  resetLanguage
        /**
            * resetLanguage
            * @description Resets the language to defaults.
            * @fires onSetLanguage()
            * jConfig.document.language
            * @memberOf module:managers/language-manager
            * @instance
        */
        resetLanguage: function() {  
            var defaultLang = this.jConfig.document.language;

            this.onSetLanguage({
                language: defaultLang
            }, "reset");
        },


        // ______________________________________________________________
        //                                               loadLanguageFile
        /**
            * loadLanguageFile
            * @description Loads language file content/json/langCopy.json
            * @fires jConfig.document.startEvent
            * @memberOf module:managers/language-manager
            * @instance
        */
        loadLanguageFile: function() { 
            var self = this;

            this.oView.oServices.loadProjectJson("langCopy.json", function(evt){
                self.jLangConfig = evt.data;
                self.onModelReady();

                window.tEvent.fire(window.tEvent.eventStr.EVENT_LANGUAGE_CONFIG_LOADED, self.jLangConfig); 

                // hack to resolve race condition with onPageLoad being called before the language file is ready.
                self.firstLoad = true;
                
                // start program
                window.tEvent.fire(self.jConfig.document.startEvent);
            });
        },



        // ______________________________________________________________
        //                                                 initLanguageUX
        /**
            * initLanguageUX
            * @description Loads language file content/json/langCopy.json
            * @fires jConfig.document.startEvent
            * @memberOf module:managers/language-manager
            * @instance
        */
        initLanguageUX: function() { 

            // populate persistent languages
            if (typeof this.jConfig.modules["m-persistent-languages"] !== "undefined"){
                var module = this.jConfig.modules["m-persistent-languages"];
                var templateObj = window.oDxpTemplates["complex-template-persistent-languages"](module);
                $(this.ui.persistentLangContainer).html(templateObj);
                this.doPersistentLangAnim();
            }

        },


        // ______________________________________________________________
        //                                           doPersistentLangAnim
        /**
            * doPersistentLangAnim
            * @description Animates the rotation of the persistent language panel
            * @memberOf module:managers/language-manager
            * @instance
        */  
        doPersistentLangAnim: function() { 
            
            if (typeof this.jConfig.modules["m-persistent-languages"] === "undefined"){
                return;
            }

            var self = this;
            var config = this.jConfig.modules["m-persistent-languages"].config;
            var itemHeight = $(this.ui.persistentLangRotationItem)[0].getBoundingClientRect().height + this.jConfig.language.languageRotation.persistentRotationElementHeightOffset;
            var imgs = window.gsap.utils.toArray(this.ui.persistentLangRotationItem);
            var itemCount = $(this.ui.persistentLangRotationItem).length;
            var delay = config.delay; // time to change
            var rotationList = [];
            var activeIndex = 0;

            function crossfade(){

                

                action = window.gsap.timeline()
                .to(imgs, {y: '-=' + itemHeight, duration: config.duration, ease: "expo"})
                .to(imgs[0], {y: '+=' + itemHeight*itemCount, duration: 0});

                imgs.push( imgs.shift() ); // the first (shift) to the end (push) from the array

                // start endless run
                self.langPersistentAnimDelayedCall = window.gsap.delayedCall(delay, crossfade);
            }

            // kill delay if it exists to resume properly
            if (typeof this.langPersistentAnimDelayedCall.kill !== "undefined"){
                this.langPersistentAnimDelayedCall.kill();
            }

            // start the crossfade after delay = 3 sec
            this.langPersistentAnimDelayedCall = window.gsap.delayedCall(delay, crossfade);

        },


        // ______________________________________________________________
        //                                                 doLangPageAnim
        /**
            * doLangPageAnim
            * @description Animates the rotation of the language page
            * @memberOf module:managers/language-manager
            * @instance
        */  
        doLangPageAnim: function() { 
            //return;
            var self = this;
            var config = this.jConfig.modules["m-page-languages"].config;
            var itemHeight = $(this.ui.langRotationItem)[0].getBoundingClientRect().height + this.jConfig.language.languageRotation.pageRotationElementHeightOffset;
            var imgs = window.gsap.utils.toArray(this.ui.langRotationItem)
            var itemCount = $(this.ui.langRotationItem).length;
            var delay = config.delay; // time to change
            var rotationList = [];
            var activeIndex = 0;

            // get rotation list
            $(this.ui.langRotationItem).each(function(){
                rotationList.push($(this).attr("data-id"));
            });


            function crossfade(){
                
                if ($("body").attr("data-module-id") !== "m-page-languages"){
                    self.langAnimDelayedCall.kill();
                    return;
                }

                action = window.gsap.timeline()
                .to(imgs, {y: '-=' + itemHeight, duration: config.duration, ease: "expo"})
                .to(imgs[0], {y: '+=' + itemHeight*itemCount, duration: 0});

                imgs.push( imgs.shift() ); // the first (shift) to the end (push) from the array

                // start endless run
                self.langAnimDelayedCall = window.gsap.delayedCall(delay, crossfade);

                // get active index and trigger other anim
                activeIndex++;               
                if (activeIndex > rotationList.length-1){
                    activeIndex = 0;
                }

                TweenLite.to($(self.ui.langIcon + "[data-id='" + rotationList[activeIndex] + "'"), 0.4, {scale: 1.2})
                TweenLite.to($(self.ui.langIcon + "[data-id='" + rotationList[activeIndex] + "'"), 1, {scale: 1, delay: 0.4, ease: "elastic"});
            }

            // kill delay if it exists to resume properly
            if (typeof this.langAnimDelayedCall.kill !== "undefined"){
                this.langAnimDelayedCall.kill();
            }
            

            // start the crossfade after delay = 3 sec
            this.langAnimDelayedCall = window.gsap.delayedCall(delay, crossfade);
        },      
        

        // ______________________________________________________________
        //                                           applyCurrentLanguage
        /**
            * applyCurrentLanguage
            * @description Applies the current language based on $("body").attr("data-lang");
            * @memberOf module:managers/language-manager
            * @instance
        */ 
        applyCurrentLanguage: function() { 

            var self = this;
            var config = this.jLangConfig.languageCopy;
            var lang = $("body").attr("data-lang");
            var id,
                copy,
                path;

            $(this.ui.langBtn).removeClass(this.def.CLASS_IS_ACTIVE);
            $(this.ui.langBtn + "[data-id='" + lang + "']").addClass(this.def.CLASS_IS_ACTIVE);

            // translate text
            $(this.ui.dynamicText).each(function(){
                id = $(this).attr("data-lang-copy-id");
                if (id !== "" && typeof id !== "undefined"){
                    copy = config[id][lang];
                    $(this).html(copy);                    
                }
            });

            // translate images
            path = "content/images/" + lang + "/"; 
            $(this.ui.dynamicImg).each(function(){
                id = $(this).attr("data-lang-img-id");  
                if (id !== "" && typeof id !== "undefined"){
                    $(this).attr("src", path + id);  
                }    
            });

            // auto translate text
            $(this.ui.autoText).each(function(){

                if (!window.oPrsonas.avatar.isConnected()) {
                    return;
                }

                var textArray = $(this).attr("data-copy");
                var srcLangId = $(this).attr("data-auto-lang-source-id");
                var destLangId = window.oModel.jConfig.language.nuBrowserIds[lang];
                var translation = window.oPrsonas.avatar.translateText(destLangId, textArray, srcLangId);

                if (translation.success){
                    $(this).html(translation.data[0]);    
                } else {
                    console.warn(" ! <language.applyCurrentLanguage> Error in " + self.ui.autoText, translation.message);
                }

                
            });

            
        },


        // --------------------------------------------------------------
        // EVENTS
        // --------------------------------------------------------------

        // ______________________________________________________________
        //                                                   onModelReady
        /**
            * onModelReady
            * @description Called when project.json is loaded
            * @fires initIha()
            * @fires assignListeners()
            * @fires initMappedIn()
            * @memberOf module:managers/language-manager
            * @instance
        */
        onModelReady: function() { 

            // set defines
            this.def = window.helpers.clone(window.oModel.def);
            this.def.CLASS_HIDE_ME = "hide-me";
            this.def.DATA_LANGUAGE = "data-lang";

            // set jConfig data
            this.jConfig = window.oModel.jConfig;
            this.initLanguageUX();
            this.assignListeners();   
        },


        // ______________________________________________________________
        //                                             onReceivedManifest
        /** 
        * onReceivedManifest
        * @description Process manifest data from Prsonas manifest
        * @param {Object} manifest
        * @memberOf module:managers/language-manager
        * @instance
        */
        onReceivedManifest: function(manifest) {   


        },


        // ______________________________________________________________
        //                                               onLanguageStatus
        /** 
        * onLanguageStatus
        * @description Applies current language from Prsonas message event EVENT_PRSONAS_MESSAGE_STATUS
        * @memberOf module:managers/language-manager
        * @instance
        */
        onLanguageStatus: function() {   
            
            this.currentLang = $("body").attr("data-lang");
            
            console.log(" * <language.onLanguageStatus> this.currentLang:", this.currentLang);

            this.onSetLanguage({
                fromUnit: true,
                language: this.currentLang
            });
        },


        // ______________________________________________________________
        //                                               onLanguageStatus
        /** 
        * onSetLanguage
        * @description Applies current language from user event EVENT_SET_LANGUAGE
        * @param {Object} langObj - Language data
        * @fires EVENT_LANGUAGE_SET
        * @memberOf module:managers/language-manager
        * @instance
        */
        onSetLanguage: function(langObj, fromSource){       

            var lang = langObj.language;

            var projectId = this.getProjectId();

            if (typeof lang === "undefined"){
                lang = $("body").attr("data-lang");
            } else {
                $("body").attr("data-lang", lang);
            }

            switch(fromSource){
                case "reset":
                    break;
            }

            // set unit, Q&A services, and mappedin language
            window.tEvent.fire(window.tEvent.eventStr.EVENT_SET_LANGUAGE, {
                language: lang
            });

            switch(fromSource){
                case "reset":
                    break;

                case "button":
                    // tagging 
                    window.oPrsonas.sdk.logStat("", projectId, "LanguageSelected", lang, "touch");

                    if (typeof window.oIha !== "undefined" && window.oIha.isIha) {
                        window.tEvent.fire("EVENT_PAGE_HOME_BTN");
                    }                    
                    break;
            }


        },

        // ______________________________________________________________
        //                                                     onPageLoad
        /**
            * onPageLoad
            * @description Called when a page is loaded 
            * @param {String} eventId - Event ID
            * @param {Object} data - Event data
            * @memberOf module:managers/language-manager
            * @instance
        */
        onPageLoad: function(eventData, data) {  

            var self = this;

            if (this.firstLoad){
                this.firstLoad = false;
                
                // set language
                this.initLanguages();
            }

            switch(eventData.event){

                case "EVENT_PAGE_LANGUAGES":

                    if (typeof window.oIha !== "undefined" && window.oIha.isIha) {
                        // hide interactive
                        $(this.ui.micToggle).css("display", "none");   
                        
                        // disable speech recognition
                        window.oSpeech.toggleSpeech("disable");   
                        
                        // hide map
                        window.oIha.onShowMap(false);                                           
                    }

                    if (typeof eventData._proxyEvtStr !== "undefined" && eventData._proxyEvtStr !== "" && typeof this.jConfig.sendKeyEvents[eventData._proxyEvtStr] !== "undefined" && this.jConfig.sendKeyEvents[eventData._proxyEvtStr].toLowerCase() === "walkaway"){
                    } else {
                        // reset language
                        this.onSetLanguage({
                            language: this.jConfig.document.language
                        }, "reset");                        
                    }

                    this.doLangPageAnim();  

                    break;

                default: 
                    if (this.jConfig.speech.showMicToggle){
                        $(this.ui.micToggle).css("display", "block");  
                    }

            }          

            // set language
            this.applyCurrentLanguage();
             
        }


    };
    
    /** 
    * @global 
    */
    window.oLang = new Language();   
    return (window.oLang);        
   
});