diff --git a/web/source/kmwuibutton.ts b/web/source/kmwuibutton.ts index 23958dcc3a0..1205c7b6e40 100644 --- a/web/source/kmwuibutton.ts +++ b/web/source/kmwuibutton.ts @@ -6,7 +6,7 @@ // 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['keyman']['ui']['name']) { +if(!window['keyman']['ui']['name']) { /********************************/ /* */ @@ -21,126 +21,127 @@ if(!window['keyman']['ui']['name']) { * 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['keyman'], util=keymanweb['util'],dbg=keymanweb['debug']; - + // Disable UI for touch devices if(util['isTouchDevice']()) throw ''; - - // User interface global and variables + + // User interface global and variables keymanweb['ui'] = {}; var ui=keymanweb['ui']; ui['name'] = 'button'; - - ui.init = false; + + ui.init = false; + ui.initTimer = null; ui.KeyboardSelector = null; ui.KeymanWeb_DefaultKeyboardHelp='KeymanWeb is not running. Choose a keyboard from the list'; - ui._KeymanWeb_KbdList = null; - ui._KMWSel = null; - ui._IsHelpVisible = false; + ui._KeymanWeb_KbdList = null; + ui._KMWSel = null; + ui._IsHelpVisible = false; ui._DefaultKeyboardID = ''; ui.updateTimer = null; ui.updateList = true; - + /** * Highlight the currently active keyboard in the list of keyboards - **/ + **/ ui._ShowSelected = function() { - var _rv,kbd=keymanweb['getActiveKeyboard'](),lgc=keymanweb['getActiveLanguage'](), + var _rv,kbd=keymanweb['getActiveKeyboard'](),lgc=keymanweb['getActiveLanguage'](), kList = ui._KeymanWeb_KbdList.childNodes, _r = /^KMWSel_(.*)\$(.*)$/; - + for(var i=1; i= kList.length) i=1; - kList[i].childNodes[0].className = 'selected'; - } - + } + if(i >= kList.length) i=1; + kList[i].childNodes[0].className = 'selected'; + } + /** * Select keyboard by id - * + * * @param {Event} _id keyboard selection event - * @return {boolean} + * @return {boolean} */ ui._SelectKeyboard = function(_id) - { - if(typeof(_id) == 'object') + { + if(typeof(_id) == 'object') { var t=null; if((typeof(_id.target) != 'undefined') && _id.target) t=_id.target; - else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) t=_id.srcElement; + else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) t=_id.srcElement; if(t) _id=t.id; } - - var _r=/^KMWSel_(.*)\$(.*)$/; + + var _r=/^KMWSel_(.*)\$(.*)$/; var _rv=_r.exec(_id),_lgc='',_name=''; - if(_rv !== null) + if(_rv !== null) { _name = _rv[1].split('$')[0]; //new code - _lgc = _id.split('$')[1]; + _lgc = _id.split('$')[1]; if(ui._KMWSel != null) ui._KMWSel.className = ''; - var _k = document.getElementById(_id); - if(_k) _k.className='selected'; - ui._KMWSel = _k; + var _k = document.getElementById(_id); + if(_k) _k.className='selected'; + ui._KMWSel = _k; keymanweb['setActiveKeyboard'](_name,_lgc); } - else + else _name=null; - + keymanweb['focusLastActiveElement'](); let osk = keymanweb.osk; - if(osk && osk['isEnabled']()) osk['show'](true); + if(osk && osk['isEnabled']()) osk['show'](true); ui._ShowKeyboardButton(_name); return false; - } + } /** * Set KMW UI activation state on mouse click - * + * * @param {Event} e event - */ + */ ui._SelectorMouseDown = function(e) - { - var x=keymanweb['getLastActiveElement'](); + { + var x=keymanweb['getLastActiveElement'](); // Set the focus to an input field, to get correct OSK display behaviour if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); - + if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); } /** * Set focus on mouse up - * + * * @param {Event} e event - */ + */ ui._SelectorMouseUp = function(e) - { + { var x=keymanweb['getLastActiveElement'](); - + // Set the focus to an input field, to get correct OSK display behaviour if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); } /** * Set KMW UI activation state on mouse over - * + * * @param {Event} e event - */ + */ ui._SelectorMouseOver = function(e) { // highlight the currently active keyboard @@ -155,21 +156,21 @@ if(!window['keyman']['ui']['name']) { /** * Sets the focus to the first input or textarea found on the current page - * to ensure consistent keyboard selection and OSK display behaviour - */ + * to ensure consistent keyboard selection and OSK display behaviour + */ ui._FocusFirstInput = function() { var i,ip=null,tp=null, iList=document.getElementsByTagName("input"), tList=document.getElementsByTagName("textarea"); - + for(i=0; i 0) tp = tList[0]; - + if((!ip) && (!tp)) return; else if(ip && !tp) @@ -185,12 +186,12 @@ if(!window['keyman']['ui']['name']) { else tp.focus(); } - + /** * Clear KMW UI activation state on mouse out - * + * * @param {Event} e event - */ + */ ui._SelectorMouseOut = function(e) { if(keymanweb['activatingUI']) keymanweb['activatingUI'](0); @@ -199,9 +200,9 @@ if(!window['keyman']['ui']['name']) { /** * Disable the button to show/hide the OSK if no active keyboard or active keyboard is CJK (user cannot hide) - * + * * @param {?string=} _name current keyboard name - */ + */ ui._ShowKeyboardButton = function(_name) { var kbdName = keymanweb['getActiveKeyboard'](), kbdId=document.getElementById("KMW_Keyboard"); @@ -209,17 +210,17 @@ if(!window['keyman']['ui']['name']) { if(kbdId) { if((kbdName == '') || keymanweb['isCJK']()) - { + { kbdId.className='kmw_disabled'; - } + } else { let osk = keymanweb.osk; kbdId.className = osk && osk['isEnabled']() ? 'kmw_show' : 'kmw_hide'; } } - } - + } + ui.registerEvents = function() { let osk = keymanweb.osk; if(!osk) { @@ -227,72 +228,79 @@ if(!window['keyman']['ui']['name']) { } /** * UI Functions called by KeymanWeb or OSK - */ - osk['addEventListener']('show', function(oskPosition) { + */ + osk['addEventListener']('show', function(oskPosition) { var t=keymanweb['getLastActiveElement'](); if(t) - { + { if(!oskPosition['userLocated']) { oskPosition['x'] = util['getAbsoluteX'](t); oskPosition['y'] = util['getAbsoluteY'](t)+t.offsetHeight; } - } - + } + ui._ShowKeyboardButton(); - return oskPosition; - }); + return oskPosition; + }); - /* TODO: why is this still needed??? Does it actually do anything?? */ - osk['addEventListener']('hide', function(hiddenByUser) { + /* TODO: why is this still needed??? Does it actually do anything?? */ + osk['addEventListener']('hide', function(hiddenByUser) { if((arguments.length > 0) && hiddenByUser) { var _a = document.getElementById('KMW_Keyboard'); if(_a) _a.className = 'kmw_hide'; - } - }); + } + }); } - + /** * Show or hide the OSK (always visible for CJK keyboards) - * + * * @param {Object} _anchor anchor element (?) - * @return {boolean} - **/ - ui._ShowKeymanWebKeyboard = function(_anchor) - { + * @return {boolean} + **/ + ui._ShowKeymanWebKeyboard = function(_anchor) + { var kbdId=document.getElementById("KMW_Keyboard"); let osk = keymanweb.osk; - if((kbdId.className!='kmw_disabled') && osk && osk['show']) + if((kbdId.className!='kmw_disabled') && osk && osk['show']) { if(osk['isEnabled']()) osk['hide'](); else osk['show'](true); } if(window.event) window.event.returnValue=false; - keymanweb['focusLastActiveElement'](); - return false; + keymanweb['focusLastActiveElement'](); + return false; } /** * Initialize Button User Interface - **/ + **/ ui['initialize'] = ui.Initialize = function() { + if(ui.initTimer) { + window.clearTimeout(ui.initTimer); + ui.initTimer = null; + } + //Never initialize UI before KMW (parameters will be undefined) - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,250); return; + if(!keymanweb['initialized']) { + ui.initTimer = window.setTimeout(ui.Initialize, 50); + return; + } + + if(ui.init || util['isTouchDevice']()) { + return; } - - if(ui.init || util['isTouchDevice']()) return; - + ui.init = true; - + util['addStyleSheet'](ui._Appearance); - + ui._KeymanWeb_KbdList = util['createElement']('ul'); ui._KeymanWeb_KbdList.id = 'KeymanWeb_KbdList'; - + var _elem = document.getElementById('KeymanWebControl'); if(!_elem) { @@ -305,25 +313,25 @@ if(!window['keyman']['ui']['name']) { } } } - + // Insert as first child of body if not defined by user if(!_elem && (document.body != null)) { _elem=document.createElement('DIV'); - _elem.id='KeymanWebControl'; + _elem.id='KeymanWebControl'; document.body.insertBefore(_elem,document.body.firstChild); ui._insertedElem = _elem; } - - + + var imgPath=util['getOption']('resources')+'ui/button/'; if(_elem) - { + { // Append another DIV to follow the main control with clear:both to prevent selection over entire width of window var dx=document.createElement('DIV'),ds=dx.style; ds.clear='both'; _elem.parentNode.insertBefore(dx,_elem.nextSibling); - + var _btn=util['createElement']('img'), _ul=util['createElement']('ul'),_li0=util['createElement']('li'); _btn.id = 'kmwico_a'; _btn.src = imgPath+'kmw_button.gif'; @@ -339,20 +347,20 @@ if(!window['keyman']['ui']['name']) { else return; if(!keymanweb['iOS']) - { - var _li = util['createElement']('li'); + { + var _li = util['createElement']('li'); var _a = util['createElement']('a'); var _img = util['createElement']('img'); _img.src = imgPath+'kbdicon.gif'; _a.appendChild(_img); - - var _txt1 = document.createTextNode(' Hide Keyboard'); + + var _txt1 = document.createTextNode(' Hide Keyboard'); var _txt2 = document.createTextNode(' Show Keyboard'); var _sp1 = util['createElement']('span'); _sp1.id = 'KMW_KbdVisibleMsg'; _sp1.appendChild(_txt1); _a.appendChild(_sp1); - + var _sp2 = util['createElement']('span'); _sp2.id = 'KMW_KbdHiddenMsg'; _sp2.appendChild(_txt2); @@ -366,29 +374,29 @@ if(!window['keyman']['ui']['name']) { ui._KeymanWeb_KbdList.appendChild(_li); } - var _li1 = util['createElement']('li'); - _li1.id = 'KMW_ButtonUI_KbdList'; + var _li1 = util['createElement']('li'); + _li1.id = 'KMW_ButtonUI_KbdList'; var _a1 = util['createElement']('a'); _a1.appendChild(document.createTextNode('(System keyboard)')); _a1.onclick = ui._SelectKeyboard; - _a1.href = '#'; + _a1.href = '#'; _a1.id='KMWSel_$'; _a1.className='selected'; _li1.appendChild(_a1); ui._KMWSel = _a1; ui._KeymanWeb_KbdList.appendChild(_li1); - var _kbds = keymanweb['getKeyboards'](), _added = []; + var _kbds = keymanweb['getKeyboards'](), _added = []; ui.updateKeyboardList(); - + document.getElementById('kmwico_li').appendChild(ui._KeymanWeb_KbdList); var _sfEl = document.getElementById("kmwico_li"); util['attachDOMEvent'](_sfEl,'mousedown',ui._SelectorMouseDown); util['attachDOMEvent'](_sfEl,'mouseover',ui._SelectorMouseOver); - util['attachDOMEvent'](_sfEl,'mouseout',ui._SelectorMouseOut); + util['attachDOMEvent'](_sfEl,'mouseout',ui._SelectorMouseOut); util['attachDOMEvent'](_sfEl,'mouseup',ui._SelectorMouseUp); ui.registerEvents(); @@ -404,108 +412,108 @@ if(!window['keyman']['ui']['name']) { /** * Keyboard registration event handler - * - * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, + * + * 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', + */ + keymanweb['addEventListener']('keyboardregistered', function(p) - { + { ui.updateList = true; if(ui.updateTimer) clearTimeout(ui.updateTimer); ui.updateTimer = setTimeout(ui.updateKeyboardList,20); - }); + }); /** * Update the entire menu when keyboards are registered or deregistered - **/ + **/ ui.updateKeyboardList = function() - { + { ui.updateList = false; - + if(!ui.init) return; - + // Clear existing list first (first two nodes must be preserved) for(var i:number=ui._KeymanWeb_KbdList.childNodes.length; i>2; i--) ui._KeymanWeb_KbdList.removeChild(ui._KeymanWeb_KbdList.childNodes[i-1]); - + var kbds=keymanweb['getKeyboards'](); if(kbds.length > 0) { for(var i:number=0; i 26) _t=_t.substr(0,24)+'\u2026'; - _a2.appendChild(document.createTextNode(_t)); + _a2.appendChild(document.createTextNode(_t)); _a2.onclick = ui._SelectKeyboard; _a2.href = '#'; _a2.id='KMWSel_'+Lki+'$'+Lklc; _li2.appendChild(_a2); ui._KeymanWeb_KbdList.appendChild(_li2); } - + // Define appearance of this interface - ui._Appearance = + ui._Appearance = "#kmwico, #kmwkbd {"+ "vertical-align: middle;"+ "} "+ "#KeymanWebControl {float:left;} "+ - + "#KeymanWebControl * "+ "{"+ "letter-spacing: 0px !important;"+ "line-height: 1li !important;"+ "white-space: nowrap !important;"+ "} "+ - + "#KeymanWebControl #kmwico img {"+ "vertical-align: top;"+ "padding: 0;"+ "margin: 0;"+ "border: none;"+ "} "+ - + "#KeymanWebControl #kmwico, #kmwico ul {"+ "padding: 0;"+ "margin: 0;"+ "list-style: none;"+ "} "+ - + "#KeymanWebControl #kmwico_a {"+ "display: block;"+ //"border: none !important;"+ "width: 22px; height: 23px; "+ /* sizes needed for kmw_button.gif */ "} "+ - + "#KeymanWebControl #kmwico li { "+ "text-align: left;"+ "} "+ - + "#KeymanWebControl #kmwico li ul {"+ "display: block;"+ "position: absolute;"+ @@ -516,27 +524,27 @@ if(!window['keyman']['ui']['name']) { "box-shadow: 4px 4px 2px #666;"+ "z-index: 10011;"+ /* above the osk */ "} "+ - + "#KeymanWebControl #kmwico li.sfunhover ul {"+ "display: none; left: -5999px;"+ "} "+ - + "#KeymanWebControl #kmwico li:hover ul, #kmwico li.sfhover ul {"+ "display: block;"+ "left: auto;"+ "} "+ - + "#KeymanWebControl #kmwico ul li {"+ "float: none;"+ "padding: 0 !important;"+ "margin: 0 !important;"+ "width: 136px !important;"+ "} "+ - + "#KeymanWebControl #KMW_LanguageName {"+ "font-weight: bold;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a, #kmwico ul li a:visited {"+ "display: block;"+ "padding: 2px 4px !important;"+ @@ -547,17 +555,17 @@ if(!window['keyman']['ui']['name']) { "font-size: 8pt;"+ "text-decoration: none;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a.selected {"+ "font-weight: bold;"+ "color: black;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a:hover {"+ "color: white;"+ "background-color: #ad4a28;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a.kmw_disabled, #KeymanWebControl #kmwico ul li a.kmw_disabled:hover {"+ "color: #c0c0c0; cursor: default;"+ "background-color: white;"+ @@ -581,13 +589,9 @@ if(!window['keyman']['ui']['name']) { "#KeymanWebControl #kmwico ul li#KMW_ButtonUI_KbdIcon {"+ "border-bottom: solid 1px #ad4a28;"+ - "} "; + "} "; - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading ui.Initialize(); - } catch(err){} } \ No newline at end of file diff --git a/web/source/kmwuifloat.ts b/web/source/kmwuifloat.ts index 2367fbe61be..b9313f6e2f9 100644 --- a/web/source/kmwuifloat.ts +++ b/web/source/kmwuifloat.ts @@ -48,6 +48,7 @@ if(!window['keyman']['ui']['name']) { ui.updateTimer = null; // prevent unnecessary list refreshing ui.floatRight = false; // align left by default ui.initialized = false; // initialization flag + ui.initTimer = null; /** * Display or hide the OSK from the OSK icon link @@ -71,15 +72,21 @@ if(!window['keyman']['ui']['name']) { * Scope Private * Description UI Initialization **/ - ui['initialize'] = ui.Initialize = function() - { + ui['initialize'] = ui.Initialize = function() { + if(ui.initTimer) { + window.clearTimeout(ui.initTimer); + ui.initTimer = null; + } + // Must always initialize after keymanWeb itself, otherwise options are undefined - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,50); return; + if(!keymanweb['initialized']) { + ui.initTimer = window.setTimeout(ui.Initialize, 50); + return; } - if(ui.initialized || util['isTouchDevice']()) return; + if(ui.initialized || util['isTouchDevice']()) { + return; + } var imgPath=util['getOption']('resources')+"ui/float/"; @@ -541,9 +548,6 @@ if(!window['keyman']['ui']['name']) { if(window.addEventListener) window.addEventListener('resize', ui._Resize, false); - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading ui.Initialize(); diff --git a/web/source/kmwuitoolbar.ts b/web/source/kmwuitoolbar.ts index 8d603cd5f15..0bfc00d0299 100644 --- a/web/source/kmwuitoolbar.ts +++ b/web/source/kmwuitoolbar.ts @@ -1215,9 +1215,8 @@ if(!window['keyman']['ui']['name']) { } // Initialize when everything defined (replaces unreliable onload event handler) - // ui.initToolbarUI(); - // No, initialization must not be done before KMW is ready! - // ui.initialize() is now called by keymanweb when document is ready and kmw initialization completed - + // In case the toolbar script loads a bit later than the main KMW script + // (may happen in unit testing) + ui.initToolbarUI(); // equivalent to ui.Initialize() from the other UI modules } catch(ex){} } \ No newline at end of file