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