/*** KeymanWeb 10.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, 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; } 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"; }; ui.kbdButton._onmouseout = function() { ui.keyboardMenu.className="sfunhover"; }; 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 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 { 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){} }