/***
   KeymanWeb 2.0
   Copyright 2017 SIL International
***/

// If a UI module has been loaded, we can rely on the publically-published 'name' property
// having been set as a way to short-out a UI reload.  Its parent object always exists by
// this point in the build process.
if(!window['tavultesoft']['keymanweb']['ui']['name']) { 
  /********************************/
  /*                              */
  /* Toggle User Interface Code   */
  /*                              */
  /********************************/
      
  /**
   * Do not enclose in an anonymous function, as the compiler may create
   * global scope variables to replace true, false, null, which may collide
   * with other variables.
   * Instead, use the --output-wrapper command during optimization, which will
   * add the anonymous function to enclose all code, including those optimized
   * variables which would otherwise have global scope.
   **/  

  try {

    // Declare KeymanWeb, OnScreen Keyboard and Util objects
    var keymanweb=window['tavultesoft']['keymanweb'],osk=keymanweb['osk'],util=keymanweb['util'];
    var dbg=keymanweb['debug'];
    
    // Disable UI for touch devices
    if(util['isTouchDevice']()) throw '';

    // Initialize user interface common variables       
    var ui=keymanweb['ui'] = {
      name: 'toggle',
      initialized: false,
      shim: null,
      controller: null,
      oskButton: null,
      kbdButton: null,
      controllerHovered: false,
      keyboards: [],
      lastActiveKeyboard: -1,
      selectedMenuItem: null,
      updateList: true,
      updateTimer: null    
    }
    
    /**
     * Update the KeymanWeb user interface when an input element is focused or blurred
     * 
     * @param       {Object}            someElement     focused element
     * @param       {(boolean|number)}  focusing        true if focusing
     * @param       {Object}            activeControl   Object representing API specs for the control, if it exists and is now focused.
     */    
    ui.doFocus = function(someElement,focusing, activeControl) {
      // This callback must be ignored until UI is initialized, or for touch devices (which can never initialize the UI)
      if(!ui.initialized) {
        return;
      }
      
      if(window.event) {
        someElement=window.event.srcElement;
      }

      // Hides the Toggle interface if a control has KeymanWeb disabled by API calls.
      if(activeControl){
        if(!activeControl['LEnabled']) {
          focusing = false;
        }
      }

      if(focusing)
      {
        ui.controller.style.display = 'block';
      } 
      else 
      {
        if(!(keymanweb['getUIState']()['activationPending']) && !ui.controllerHovered)
        {
          ui.controller.style.display = 'none';   
        }
      }
      
    /* I2406 - Find an appropriate position for the controller */  
      var x, y, w, h, p;
    
      p = util['getAbsolute'](someElement); x = p['x']; y=p['y'];
      if(someElement.parentWindow && someElement.parentWindow.frameElement)
      {
        w = someElement.parentWindow.frameElement.clientWidth;
        h = someElement.parentWindow.frameElement.clientHeight;
      }
      else if(someElement.defaultView && someElement.defaultView.frameElement)
      { 
        w = someElement.defaultView.frameElement.clientWidth;
        h = someElement.defaultView.frameElement.clientHeight;
      }
      else
      {
        w = someElement.offsetWidth;
        h = someElement.offsetHeight;
      }
      if(x + w > (window.clientWidth?window.clientWidth:window.innerWidth) + document.documentElement.scrollLeft - ui.controller.offsetWidth - 1)
        y += h;
      else
      {
        x += w + 2;  
        //y += h - ui.controller.offsetHeight - 1; // ui.controller.offsetheight is returned as its prior value, which results in incorrect UI positioning
        // so better to set the offset absolutely JMD 11/2/11
        y += h - 29; //prevent UI being positioned *above* the top of the element 
      }
        
      if(isNaN(x) || isNaN(y)) return;
      ui.controller.style.left = x + 'px';
      ui.controller.style.top = y + 'px';    
    }

    keymanweb['addEventListener']('controlfocused',function(params){ui.doFocus(params.target,true, params['activeControl']);});
    keymanweb['addEventListener']('controlblurred',function(params){ui.doFocus(params.target,false, null);});

    osk['addEventListener']('show',
      function(oskPosition)
      {
        // Ensure that the ui.controller is visible if help is displayed
        ui.controller.style.display = 'block';
        ui.oskButton._setSelected(true);
      
  /* The following is probably not needed for KMW2, since OSK position is set by KMW, not by the UI        
        //TODO:  This may not be correct - may need to refer to userLocated argument, not function???
        // Check if OSK position is user-defined, return if so
        if (osk['userLocated']()) return oskPosition;
      
        // Otherwise, return the position with respect to the focussed element
        var someElement = keymanweb['getLastActiveElement'](), x, y, w, h, p;
        if(someElement != null)
        {
          p = util['getAbsolute'](someElement); x = p['x']; y = p['y'];
          if(someElement.parentWindow && someElement.parentWindow.frameElement)
          {
            w = someElement.parentWindow.frameElement.clientWidth;
            h = someElement.parentWindow.frameElement.clientHeight;
          }
          else if(someElement.defaultView && someElement.defaultView.frameElement)
          { 
            w = someElement.defaultView.frameElement.clientWidth;
            h = someElement.defaultView.frameElement.clientHeight;
          }
          else
          {
            w = someElement.offsetWidth;
            h = someElement.offsetHeight;
          }
    //TODO:  check the logic of this - it doesn't look right!!!  Signs on top, height??
          var r = osk['getRect']();
          x += 32;
          if(y + h + (r.height - r.top) > (window.clientHeight?window.clientHeight:window.innerHeight) + document.documentElement.scrollTop && 
            y - (r.height - r.top) >= document.documentElement.scrollTop)
          {
            y -= (r.height - r.top);
          }
          else
            y += h;
        }
        else
        {
          x = ui.controller.offsetLeft;
          y = ui.controller.offsetTop + ui.controller.offsetHeight;
        }
        oskPosition['x'] = x; 
        oskPosition['y'] = y; 
  */      
        return oskPosition;
      });
    
    osk['addEventListener']('hide',
      function(byUser)
      {
        if(byUser['HiddenByUser']) ui.oskButton._setSelected(false);
      });
    
    /**
     * Toggle the on screen keyboard display - KMW button control event 
     **/
    ui.switchOsk = function()
    {
      // Check that user control of OSK is allowed
      if((keymanweb['getActiveKeyboard']() == '') || keymanweb['isCJK']() ) return;  
      
      osk['show'](!osk['isEnabled']());  
    }
    
    /**
     * Toggle a single keyboard on or off - KMW button control event 
     **/
    ui.switchSingleKbd = function()
    {
      var _v = (keymanweb['getActiveKeyboard']() == ''),nLastKbd=0,kbdName='',lgCode='';
      if(_v)
      {
        if(ui.keyboards.length == 0) return;
        if(ui.lastActiveKeyboard < ui.keyboards.length && ui.lastActiveKeyboard >= 0) nLastKbd = ui.lastActiveKeyboard;
        kbdName = ui.keyboards[nLastKbd]._InternalName;
        lgCode = ui.keyboards[nLastKbd]._LanguageCode;
        keymanweb['setActiveKeyboard'](kbdName,lgCode);
        ui.lastActiveKeyboard = nLastKbd;
      }
      else
      {
        keymanweb['setActiveKeyboard']('');
      }
      if(ui.kbdButton) ui.kbdButton._setSelected(_v);
    }
    
    /**
     * Switch to the next keyboard in the list - KMW button control event 
     **/
    ui.switchNextKbd = function()
    {
      var _v = (keymanweb['getActiveKeyboard']() == ''),kbdName='',lgCode='';
      if(_v)
      {
        if(ui.keyboards.length == 0) return;
        kbdName = ui.keyboards[0]._InternalName;
        lgCode = ui.keyboards[0]._LanguageCode;
        keymanweb['setActiveKeyboard'](kbdName,lgCode);
        ui.lastActiveKeyboard = 0;
      }
      else
      {
        if(ui.lastActiveKeyboard == ui.keyboards.length-1)
        {
          keymanweb['setActiveKeyboard']('');
          _v = false;
        }
        else
        {
          kbdName = ui.keyboards[++ui.lastActiveKeyboard]._InternalName;
          lgCode = ui.keyboards[ui.lastActiveKeyboard]._LanguageCode; 
          keymanweb['setActiveKeyboard'](kbdName,lgCode);
          _v = true;
        }
      }
      if(ui.kbdButton) ui.kbdButton._setSelected(_v);
    }
    
    /**
     * Create a button object for KeymanWeb UI buttons
     * 
     * @constructor   
     * @param       {string}    _src
     * @param       {string}    _caption
     * @param       {boolean}   _selected
     * @return      {Object}    
     * 
     * @suppress {suspiciousCode}  // Closure isn't smart enough to realize that _onmouseover
     *                             // and the like are defined on individual instances later.
     *                             // It thinks they're always null.        
     **/
    ui.button = function(_src, _caption, _selected)
    {
      this._onclick = null;
      this._onmouseover = null;
      this._onmouseout = null;
      this._elem = null;
      this._down = false;
      this._over = false;
      this._selected = _selected;
    
      /*public*/ this.getElem = function()
      {
        return this._owningObject._elem;
      };
      
      /*private*/ this.__updatestyle = function()
      {
        var ss=this._owningObject._elem.style;
        if(this._owningObject._over)
        {
          ss.margin = '0px';
          if(this._owningObject._selected) {
            ss.border = 'solid 1px #ad4a28';
            ss.background = '#dfb4b4';
          }
          else {
            ss.border = 'solid 1px #dfb4b4';
            ss.background = '#f3e5de';
          }
        }
        else if(this._owningObject._selected)
        {
          ss.background = '#f3e5de';
          ss.margin = '0px';
          ss.border = 'solid 1px #ad4a28';
        }
        else
        {
          ss.background = 'none';
          ss.margin = '1px';
          ss.border = 'none';
        }
      };
      
      /*private*/ this.__mouseover = function()
      {
        ui.controllerHovered = true;
        this._owningObject._over = true;
        if(this._owningObject._onmouseover != null) this._owningObject._onmouseover();
        this._owningObject.__updatestyle();
      };
      
      /*private*/ this.__mouseout = function()
      { 
        ui.controllerHovered = false;
        this._owningObject._over = false;
        if(this._owningObject._onmouseout != null) this._owningObject._onmouseout();
        this._owningObject.__updatestyle();
      };
      
      /*private*/ this.__click = function()
      { 
        keymanweb['activatingUI'](false); // Clear activating UI flag once click is acknowledged
        if(this._owningObject._onclick != null) 
            return this._owningObject._onclick();
        return false;
      };
    
      /*private*/ this.__mousedown = function()
      {
        keymanweb['activatingUI'](true);  // Set activating UI flag (to manage focus/blur) on any UI mouse down event
        this._owningObject._down = true;
        this._owningObject.__updatestyle();
        return false;
      };
      
      /*private*/ this.__mouseup = function()
      {
        this._owningObject._down = false;
        this._owningObject.__updatestyle();
      };
      
      /*public*/ this._setSelected = function(_value)
      {
        keymanweb['activatingUI'](false); // Always clear activating UI flag after selecting UI
        this._owningObject._selected = _value;
        this._owningObject.__updatestyle();
      };
      
      /*public*/ this._getSelected = function()
      {
        return this._owningObject._selected;
      };
    
      /*public*/ this._getOver = function()
      {
        return this._owningObject._over;
      };
      
      /*public*/ this._getDown = function()
      {
        return this._owningObject._down;
      };
    
      this._owningObject = this; // simplifies meaning of 'this'
      
      var imgPath=util['getOption']('resources') + 'ui/toggle/';
      var _elemImg = util['createElement']('img');
      this._elem = util['createElement']('div');
      this._elem._owningObject = this;
      _elemImg.style.display = 'block';
      _elemImg.src = imgPath + _src;
      _elemImg.id = 'KMW_Controller_Img';
      this._elem.style.margin = '0px'; //display = 'inline';
      this._elem.style.width = '24px';
      this._elem.style.height = '24px';
      this._elem.style.zIndex = '10002';
      this._elem.style.lineHeight = '100%';
      this._elem.style.styleFloat = this._elem.style.cssFloat = 'left';
    
      _elemImg.title = _caption;
      _elemImg.alt = _caption;
      this._elem.appendChild(_elemImg);
      this._elem.onmouseover = this.__mouseover;
      this._elem.onmouseout = this.__mouseout;
      this._elem.onmousedown = this.__mousedown;
      this._elem.onmouseup = this.__mouseup;
      _elemImg._owningObject = this;
      _elemImg.onclick = this.__click;
      
      this.__updatestyle();
      
      return this;
    };
    
    /**
     * Function     Initialize
     * Scope        Private   
     * Description  Initialize Toggle User Interface
     **/   
    ui['initialize'] = ui.Initialize = function()
    { 
      //Never initialize before KMW!
      if(!keymanweb['initialized'] || util['isTouchDevice']()) return;
        
      if(!ui.initialized)  // I2403 - Allow toggle design to be loaded twice
      {
        ui.controller = util['createElement']('div');
      }
      else
        ui.controller.innerHTML = '';  // I2403 - Allow toggle design to be loaded twice
      
      var imgPath = util['getOption']('resources')+'ui/toggle/';	
      ui.controller.style.background = 'url('+imgPath+'kmwcontroller2x.gif)';    
      ui.controller.style.padding = '1px 2px';

      // Create keyboard list and OSK control buttones, and set initial styles
      var v1=util['loadCookie']('KeymanWeb_Keyboard'),kbdEnabledOnLoad=false;
      if(typeof(v1['current'])!='undefined') kbdEnabledOnLoad = (v1['current'].indexOf('---') < 0);
      ui.kbdButton = new ui.button('kmw_logo_16.gif', 'Use Web Keyboard', kbdEnabledOnLoad); 
      ui.controller.appendChild(ui.kbdButton.getElem());
    
      var v2 = util['loadCookie']('KeymanWeb_OnScreenKeyboard'),oskEnabledOnLoad=true; 
      if(typeof(v2['visible'])!='undefined') oskEnabledOnLoad=(v2['visible'] == 1); 
    
      // Add keyboard icon
      ui.oskButton = new ui.button('kmw_osk_16.gif','Show On Screen Keyboard',oskEnabledOnLoad); 
      ui.oskButton._onclick = ui.switchOsk;
      ui.controller.appendChild(ui.oskButton.getElem());

      // Hide controller unless already initialized
      if(!ui.initialized) ui.controller.style.display = 'none';
      ui.controller.style.zIndex = '10001';
      ui.controller.style.position = 'absolute';
      
      // The following three lines prevent the UI from being positioned incorrectly when the page is resized,
      // but don't fix the problem completely, as the kbd icon still moves.  probably need to insert a DIV
      // between the button and the container, and make that DIV fixed height and overflow:hidden 
      //ui.controller.style.maxHeight = '26px';  
      //ui.oskButton.getElem().style.position = 'relative';  
      //ui.oskButton.getElem().style.overflow = 'hidden';	
      
      if(!ui.initialized)  // I2403 - Allow toggle design to be loaded more than once if necessary
        document.body.appendChild(ui.controller);	   
    
      // Set initialized true  
      ui.initialized = true;  // I2403 - Allow toggle design to be loaded more than once if needed

      // Then update the keyboard list if keyboards already loaded (i.e. in page script)
      ui.updateKeyboardList();     
      
    }

    /**
     * Function     updateKeyboardList
     * Scope        Private   
     * Description  Rebuild the UI and keyboard list
     **/   
    ui.updateKeyboardList=function()
    {                 
      if(!(keymanweb['initialized'] || ui.initialized)) return; //TODO: may want to restart the timer??
                      
      ui.updateList = false;

      var _kbds=keymanweb['getKeyboards'](),imgPath=util['getOption']('resources') +'ui/toggle/';	   
  
      // Check the number of installed keyboards to determine whether or not we will have a dropdown
      if(_kbds.length > 1)
      {
        // Multiple keyboards
        var _kmw_ctrl_img=document.getElementById('KMW_Controller_Img')
        _kmw_ctrl_img.src = imgPath+'kmw_logo_16_down.gif';
        _kmw_ctrl_img.style.width = '100%';
            
        ui.controller.style.background = 'url('+imgPath+'kmwcontroller2x.gif)';
        
        ui.kbdButton.getElem().id = 'kmwico';
        ui.kbdButton.getElem().style.width = '36px';
        ui.kbdButton._onmouseover = function()
          {
            ui.keyboardMenu.className="sfhover";
            if(ui.shim)
            {
              var ss=ui.shim.style;
              ss.left = ui.keyboardMenu.style.left;
              ss.top = ui.keyboardMenu.style.top;
              ss.width = ui.keyboardMenu.offsetWidth+"px";
              ss.height = ui.keyboardMenu.offsetHeight+"px";
              ss.zIndex = ui.keyboardMenu.style.zIndex-1;
              ss.display = 'block';
            }
          };
        ui.kbdButton._onmouseout = function()
          {
            ui.keyboardMenu.className="sfunhover";
            if(ui.shim) ui.shim.style.display = 'none';
          };
        ui.kbdButton._onclick = null;
        ui.createMenu();
      }
      // Single keyboard
      else if(_kbds.length == 1)
      {
        var _kmw_ctrl_img=document.getElementById('KMW_Controller_Img')
        _kmw_ctrl_img.src = imgPath+'kmw_logo_16.gif';
        
        ui.kbdButton.getElem().id = 'kmwico';
        ui.kbdButton.getElem().style.width = '24px';

        var Lki=_kbds[0]['InternalName'];    
        var Lklc=_kbds[0]['LanguageCode'];  
        ui.controller.style.background = 'url('+imgPath+'kmwcontroller2.gif)';
        ui.keyboards.push({_InternalName: Lki, _LanguageCode: Lklc, _Index: 0});
        ui.kbdButton._onclick = ui.switchSingleKbd;
        ui.kbdButton._onmouseover = function() { };
        ui.kbdButton._onmouseout = function() { };

        // We must reconstruct the ui.keyboards array, and this done by ui.createMenu.
        ui.createMenu();

        // Must remove menu if keyboards have been removed leaving only a single keyboard
        if(typeof(ui.keyboardMenu) != 'undefined') delete ui.keyboardMenu;
      }
      
      // Highlight the last active keyboard
      var sk=keymanweb['getSavedKeyboard']().split(':');
      ui.updateMenu(sk[0],sk[1]);
    }  

    /**
     * Keyboard registration event handler
     *    
     * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, 
     * thus updating only once when only if multiple keyboards are registered together
     */   
    keymanweb['addEventListener']('keyboardregistered', 
      function(p)
      {   
          ui.updateList = true;
          if(ui.updateTimer) clearTimeout(ui.updateTimer);
          ui.updateTimer = setTimeout(ui.updateKeyboardList,200);
      });       


    /**
     * Keyboard change event handler
     *        
     * Update menu selection and control OSK display appropriately
     */
    keymanweb['addEventListener']('keyboardchange',  
      function(p)
      {
        ui.updateMenu(p['internalName'],p['languageCode']);  
      });
    
    /* ----------------------------------------
      Drop down menu
      ---------------------------------------- */
    
  //  var  _SelectedMenuItem;
    
    /**
     * Function     selecKbd
     * Scope        Private 
     * @param       {number}  _kbd         
     * Description  Select a keyboard from the drop down menu 
     **/
    ui.selectKbd = function(_kbd)
    {
        var _name,_lgCode,_index;
        if(_kbd < 0) 
        { 
          _name = ''; _lgCode='';_index = ''; 
        }
        else 
        { 
          _name = ui.keyboards[_kbd]._InternalName; _lgCode = ui.keyboards[_kbd]._LanguageCode; _index = ui.keyboards[_kbd]._Index; 
        }
        keymanweb['setActiveKeyboard'](_name,_lgCode);
        keymanweb['focusLastActiveElement']();
        ui.kbdButton._setSelected(_name != '');
        if(_kbd >= 0) ui.lastActiveKeyboard = _kbd;

        return false;
    };
    
    /**
     * Function     updateMenu
     * Scope        Private
     * @param       {string}    kbdName
     * @param       {?string=}  lgCode
     * Description  Updates the menu selection when a change is required
     **/    
    ui.updateMenu = function(kbdName,lgCode)
    {        
      var i,_k=document.getElementById('KMWSel_$');

      for(i=0; i<ui.keyboards.length; i++)
      { 
        if(ui.keyboards[i]._InternalName == kbdName && ui.keyboards[i]._LanguageCode == lgCode)
          _k=document.getElementById('KMWSel_'+ui.keyboards[i]._InternalName+'$'+ui.keyboards[i]._Index);
      }
    
      if(_k)
      {
        if(ui.selectedMenuItem != null) ui.selectedMenuItem.className='';
        _k.className='selected'; ui.selectedMenuItem=_k;
      }

      // Hide the OSK button for CJK keyboards (or non-mapped)
      if(lgCode=='cmn' || lgCode=='jpn' || lgCode=='kor')
      {
        ui.oskButton.getElem().style.display='none';
        //osk['show'](true);
      }
      else if(kbdName == '')
      {
        ui.oskButton.getElem().style.display='none';
      }
      else
      {
        ui.oskButton.getElem().style.display='block';
        //osk['show'](osk['isEnabled']());
      }
    }
    util['addStyleSheet'](
      "#KeymanWeb_KbdList {"+
        "display: block;"+
        "position: absolute;"+
        "width: auto;"+ ((util['getIEVersion']() < 8) ? "200px;" : "auto;")+
        "line-height: 100%;"+
        "margin: 0;"+
        "clear: both;"+
        "float: none;"+
        "top: auto;"+
        "border: solid 2px #ad4a28;"+
        "-moz-border-radius: 4px;"+
        "-webkit-border-radius: 4px;"+
        "border-radius: 4px;"+
        "box-shadow: 4px 4px 2px rgba(136,136,136,.5);"+
        "-webkit-box-shadow: 4px 4px 2px rgba(136,136,136,.5);"+
        "-moz-box-shadow: 4px 4px 2px rgba(136,136,136,.5);"+
        ((util['getIEVersion']() < 99) ? "filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=4,OffY=4,Color=#80646464);" : "")+
        "list-style: none;"+
        "padding: 0;"+
        "background: white;"+
        "max-height: 300px;"+
        "overflow-y: scroll;"+ 
        "overflow-x: hidden;"+
        "white-space: nowrap;"+
        "z-index: 10001; /* above the osk */"+
      "}"+
      ((util['getIEVersion']() < 7) ? 
        "* html #KeymanWeb_KbdList {height: expression(this.scrollHeight > 299 ? '300px' : 'auto');}" : "")+    
      ".sfunhover#KeymanWeb_KbdList {"+
        "display: none; left: -999px;"+
      "}"+
      ".sfhover#KeymanWeb_KbdList {"+
        "display: block;"+
        "left: auto;"+
      "}"+
      "#KeymanWeb_KbdList li {"+
        "float: none;"+
        "width: auto;"+
        "padding: 0;"+
        "margin: 0;"+
      "text-align: left;"+
      "}"+
      "#KeymanWeb_KbdList li a {"+
        "display: block; "+
        "padding: 2px 4px;"+
        "color: #404040;"+
        "font-family: Tahoma,Verdana,Arial,sans-serif;"+
        "font-size: 8pt;"+
        "text-decoration: none;"+
      "}"+
      "#KeymanWeb_KbdList li a.selected {"+
        "font-weight: bold;"+
        "color: black;"+
      "}"+
      "#KeymanWeb_KbdList li a:hover {"+
        "color: white;"+
        "background-color: #ad4a28;"+
        "text-decoration: underline;"+
      "}");
    
    /**
     * Function     createMenu
     * Scope        Private   
     * Description  Create the drop down menu and populate with loaded KeymanWeb keyboards 
     **/
    ui.createMenu = function()
    {    
      if(typeof(ui.keyboardMenu) == 'undefined')  // I2403 - Allow toggle design to be loaded twice
      {
        if (window.createPopup && !('XmlHttpRequest' in window))
        {
          ui.shim = util['createElement']('iframe');
          ui.shim.src = '';
          ui.shim.style.display = 'none';
          ui.shim.style.position = 'absolute';
          ui.shim.style.filter = 'progidXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
          ui.shim.frameBorder = '0';
          ui.shim.scrolling = 'no';
          ui.kbdButton.getElem().appendChild(ui.shim);
        }
        
        ui.keyboardMenu=util['createElement']('ul');
        ui.keyboardMenu.id='KeymanWeb_KbdList';
        ui.keyboardMenu.className='sfunhover';
      }
      else ui.keyboardMenu.innerHTML = '';  // I2403 - Allow toggle design to be loaded twice
      
      var _li=util['createElement']('li');
      var _a=util['createElement']('a');
      _a.innerHTML='English';
      _a.href="#";
      _a.onclick = function() { return ui.selectKbd(-1); };
      _a.id='KMWSel_$';
      _a.className='selected';
      _li.appendChild(_a);
      
      ui.selectedMenuItem=_a;
      ui.keyboardMenu.appendChild(_li);
        
      var _kbds=keymanweb['getKeyboards'](), _added=[];
      ui.keyboards=[];
      for(var _kbd = 0; _kbd < _kbds.length; _kbd++)
      {
          var _li1=util['createElement']('li');
          var _a1=util['createElement']('a');
          _a1.innerHTML=_kbds[_kbd]['LanguageName'] + ' - ' + _kbds[_kbd]['Name'];
          if(!_added[_kbds[_kbd]['InternalName']]) _added[_kbds[_kbd]['InternalName']]=0;
          _added[_kbds[_kbd]['InternalName']]++;
    
          var _n=_added[_kbds[_kbd]['InternalName']];
          ui.keyboards.push({_InternalName: _kbds[_kbd]['InternalName'], _LanguageCode:_kbds[_kbd]['LanguageCode'], _Index: _n});

          _a1.href="#";
          _a1.onclick = (function(x) { return function() { return ui.selectKbd(x); } })(ui.keyboards.length-1);
          _a1.id='KMWSel_'+_kbds[_kbd]['InternalName']+'$'+_n;
    
          _li1.appendChild(_a1);
          ui.keyboardMenu.appendChild(_li1);
      }
      
      //if(!ui.initialized) // I2403 - Allow toggle design to be loaded twice
      if(ui.keyboardMenu.parentNode != ui.kbdButton.getElem()) ui.kbdButton.getElem().appendChild(ui.keyboardMenu);  
    };
    
    keymanweb['addHotKey'](191,0x20,ui.switchSingleKbd);
    keymanweb['addHotKey'](191,0x30,ui.switchNextKbd);
    keymanweb['addHotKey'](191,0x40,ui.switchOsk);

    // Initialize after KMW is fully initialized
    keymanweb['addEventListener']('loaduserinterface',ui.Initialize);
    
    // but also execute here, for asynchronous UI script loading (occurring after KMW initialization)
    ui.Initialize();
      
  } catch(ex){}
}