From d578981a30eb3e56dfaeec97708e7c67b756ddf1 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 16 May 2023 12:34:34 +0700 Subject: [PATCH 1/6] fix(web): restores Button UI keyboard-selection as TS ES-module --- web/src/app/ui/build-bundler.js | 2 +- web/src/app/ui/kmwuibutton.ts | 1126 +++++++++-------- web/src/app/ui/tsconfig.json | 2 +- web/src/test/auto/integrated/cases/basics.js | 32 +- .../test/manual/web/desktop-ui/button.html | 5 +- 5 files changed, 624 insertions(+), 543 deletions(-) diff --git a/web/src/app/ui/build-bundler.js b/web/src/app/ui/build-bundler.js index bfc57b20b0..df0ecbafb0 100644 --- a/web/src/app/ui/build-bundler.js +++ b/web/src/app/ui/build-bundler.js @@ -30,7 +30,7 @@ let es5ClassAnnotationAsPurePlugin = { } } -const modules = ['kmwuitoggle', 'kmwuitoolbar']; +const modules = ['kmwuibutton', 'kmwuitoggle', 'kmwuitoolbar']; for(let module of modules) { await esbuild.build({ diff --git a/web/src/app/ui/kmwuibutton.ts b/web/src/app/ui/kmwuibutton.ts index 1205c7b6e4..6fe4ac219e 100644 --- a/web/src/app/ui/kmwuibutton.ts +++ b/web/src/app/ui/kmwuibutton.ts @@ -1,12 +1,14 @@ /*** - KeymanWeb 11.0 - Copyright 2019 SIL International + KeymanWeb 17.0 + Copyright 2019-2023 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['keyman']['ui']['name']) { +import type { KeymanEngine, KeyboardCookie, UIModule } from 'keyman/app/browser'; +import type { FloatingOSKViewCookie } from 'keyman/engine/osk'; + +declare var keyman: KeymanEngine + +if(!keyman?.ui?.name) { /********************************/ /* */ @@ -25,390 +27,635 @@ if(!window['keyman']['ui']['name']) { try { // Declare KeymanWeb, OnScreen keyboard and Util objects - var keymanweb=window['keyman'], - util=keymanweb['util'],dbg=keymanweb['debug']; + const keymanweb = keyman; + const util=keymanweb.util; + // var dbg=keymanweb['debug']; // Disable UI for touch devices - if(util['isTouchDevice']()) throw ''; - - // User interface global and variables - keymanweb['ui'] = {}; - var ui=keymanweb['ui']; - ui['name'] = 'button'; - - 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._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'](), - kList = ui._KeymanWeb_KbdList.childNodes, - _r = /^KMWSel_(.*)\$(.*)$/; - - for(var i=1; i= kList.length) i=1; - kList[i].childNodes[0].className = 'selected'; + if(util.isTouchDevice()) { + throw ''; } - /** - * Select keyboard by id - * - * @param {Event} _id keyboard selection event - * @return {boolean} - */ - ui._SelectKeyboard = function(_id) - { - 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; - if(t) _id=t.id; - } + class UIButton implements UIModule { + // User interface global and variables + readonly name = 'button'; - var _r=/^KMWSel_(.*)\$(.*)$/; - var _rv=_r.exec(_id),_lgc='',_name=''; - if(_rv !== null) - { - _name = _rv[1].split('$')[0]; //new code - _lgc = _id.split('$')[1]; - if(ui._KMWSel != null) ui._KMWSel.className = ''; - var _k = document.getElementById(_id); - if(_k) _k.className='selected'; - ui._KMWSel = _k; - keymanweb['setActiveKeyboard'](_name,_lgc); - } - else - _name=null; + init = false; - keymanweb['focusLastActiveElement'](); - let osk = keymanweb.osk; - 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'](); - - // 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 - ui._ShowSelected(); - - if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); - document.getElementById("kmwico_li").className="sfhover"; - - // Conditionally display keyboard button - ui._ShowKeyboardButton(); - } - - /** - * Sets the focus to the first input or textarea found on the current page - * 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) - ip.focus(); - else if(tp && !ip) - tp.focus(); - else if(ip.offsetTop < tp.offsetTop) - ip.focus(); - else if(ip.offsetTop > tp.offsetTop) - tp.focus(); - else if(ip.offsetLeft < tp.offsetLeft) - ip.focus(); - 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); - document.getElementById("kmwico_li").className="sfunhover"; - } - - /** - * 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"); - if(arguments.length > 0) kbdName = _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) { - return; - } /** - * UI Functions called by KeymanWeb or OSK + * Initialization timeout handle. */ - 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; + private initTimer: number = null; + private keyboardSelector = null; // not referenced + + // not referenced + private KeymanWeb_DefaultKeyboardHelp='KeymanWeb is not running. Choose a keyboard from the list'; + + + private _KeymanWeb_KbdList: HTMLUListElement = null; + + /** + * Tracks the element corresponding to the active keyboard on the keyboard list. + * + * Is also set when activating it due to user interaction. + */ + private _KMWSel: HTMLElement = null; + private _IsHelpVisible = false; + private _DefaultKeyboardID = ''; + + updateTimer: number = 0; + updateList = true; + + /** + * If no id == 'KeymanWebControl' element exists during init, this UI module + * will make its own, auto-insert it, and track the element here. + */ + private _insertedElem: HTMLElement = null; + + /** + * Highlight the currently active keyboard in the list of keyboards + **/ + private _ShowSelected() { + let kbd=keymanweb.getActiveKeyboard(); + let lgc=keymanweb.getActiveLanguage(); + let kList = this._KeymanWeb_KbdList.childNodes; + let _r = /^KMWSel_(.*)\$(.*)$/; + + for(let i=1; i= kList.length) { + i=1; + } + (kList[i].childNodes[0] as HTMLElement).className = 'selected'; + } + + /** + * Select keyboard by id + * + * @param {Event} _id keyboard selection event + * @return {boolean} + */ + readonly _SelectKeyboard = (_id: Event) => { + let id: string = ''; + if(typeof(_id) == 'object') { + let t: HTMLElement = null; + if((typeof(_id.target) != 'undefined') && _id.target) { + t=_id.target as HTMLElement; + } else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) { + t=_id.srcElement as HTMLElement; + } + + if(t) { + id=t.id; } } - ui._ShowKeyboardButton(); - return oskPosition; - }); - - /* 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'; + let _r=/^KMWSel_(.*)\$(.*)$/; + let _rv=_r.exec(id),_lgc='',_name=''; + if(_rv !== null) { + _name = _rv[1].split('$')[0]; //new code + _lgc = id.split('$')[1]; + if(this._KMWSel != null) { + this._KMWSel.className = ''; + } + let _k = document.getElementById(id); + if(_k) { + _k.className='selected'; + } + this._KMWSel = _k; + keymanweb.setActiveKeyboard(_name,_lgc); + } else { + _name=null; } - }); - } - /** - * Show or hide the OSK (always visible for CJK keyboards) - * - * @param {Object} _anchor anchor element (?) - * @return {boolean} - **/ - ui._ShowKeymanWebKeyboard = function(_anchor) - { - var kbdId=document.getElementById("KMW_Keyboard"); - let osk = keymanweb.osk; + keymanweb.focusLastActiveElement(); + let osk = keymanweb.osk; + if(osk && osk.isEnabled()) { + osk.show(true); + } - 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; - } - - /** - * Initialize Button User Interface - **/ - ui['initialize'] = ui.Initialize = function() { - if(ui.initTimer) { - window.clearTimeout(ui.initTimer); - ui.initTimer = null; + this._ShowKeyboardButton(_name); + return false; } - //Never initialize UI before KMW (parameters will be undefined) - if(!keymanweb['initialized']) { - ui.initTimer = window.setTimeout(ui.Initialize, 50); - return; + /** + * Set KMW UI activation state on mouse click + * + * @param {Event} e event + */ + readonly _SelectorMouseDown = (e: MouseEvent) => { + const x=keymanweb.getLastActiveElement(); + + // Set the focus to an input field, to get correct OSK display behaviour + if(!x) { + this._FocusFirstInput(); + } else { + keymanweb.focusLastActiveElement(); + } + + if(keymanweb.activatingUI) { + keymanweb.activatingUI(1); + } } - if(ui.init || util['isTouchDevice']()) { - return; + /** + * Set focus on mouse up + * + * @param {Event} e event + */ + readonly _SelectorMouseUp = (e: MouseEvent) => { + const x=keymanweb.getLastActiveElement(); + + // Set the focus to an input field, to get correct OSK display behaviour + if(!x) { + this._FocusFirstInput(); + } else { + keymanweb.focusLastActiveElement(); + } } - ui.init = true; + /** + * Set KMW UI activation state on mouse over + * + * @param {Event} e event + */ + readonly _SelectorMouseOver = (e: MouseEvent) => { + // highlight the currently active keyboard + this._ShowSelected(); - util['addStyleSheet'](ui._Appearance); + if(keymanweb.activatingUI) { + keymanweb.activatingUI(1); + } - ui._KeymanWeb_KbdList = util['createElement']('ul'); - ui._KeymanWeb_KbdList.id = 'KeymanWeb_KbdList'; + document.getElementById("kmwico_li").className="sfhover"; - var _elem = document.getElementById('KeymanWebControl'); - if(!_elem) - { - var _elems = document.getElementsByTagName('div'); - for(var _i = 0; _i < _elems.length; _i++) - { - if(_elems[_i].className == 'KeymanWebControl') - { - _elem = _elems[_i]; break; + // Conditionally display keyboard button + this._ShowKeyboardButton(); + } + + /** + * Sets the focus to the first input or textarea found on the current page + * to ensure consistent keyboard selection and OSK display behaviour + */ + private _FocusFirstInput() { + let ip: HTMLInputElement = null; + let tp: HTMLTextAreaElement = null; + const iList=document.getElementsByTagName("input"); + const tList=document.getElementsByTagName("textarea"); + + let i: number; + for(i=0; i 0) { + tp = tList[0]; + } + + if((!ip) && (!tp)) { + return; + } else if(ip && !tp) { + ip.focus(); + } else if(tp && !ip) { + tp.focus(); + } else if(ip.offsetTop < tp.offsetTop) { + ip.focus(); + } else if(ip.offsetTop > tp.offsetTop) { + tp.focus(); + } else if(ip.offsetLeft < tp.offsetLeft) { + ip.focus(); + } else { + tp.focus(); + } + } + + /** + * Clear KMW UI activation state on mouse out + * + * @param {Event} e event + */ + readonly _SelectorMouseOut = (e: MouseEvent) => { + if(keymanweb.activatingUI) { + keymanweb.activatingUI(0); + } + document.getElementById("kmwico_li").className="sfunhover"; + } + + /** + * 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 + */ + private _ShowKeyboardButton(_name?: string) { + let kbdName = keymanweb.getActiveKeyboard(); + let kbdId = document.getElementById("KMW_Keyboard"); + if(arguments.length > 0) { + kbdName = _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'; } } } - // Insert as first child of body if not defined by user - if(!_elem && (document.body != null)) - { - _elem=document.createElement('DIV'); - _elem.id='KeymanWebControl'; - document.body.insertBefore(_elem,document.body.firstChild); - ui._insertedElem = _elem; + registerEvents() { + let osk = keymanweb.osk; + if(!osk) { + return; + } + /** + * UI Functions called by KeymanWeb or OSK + */ + osk.addEventListener('show', (oskPosition) => { + const t=keymanweb.getLastActiveElement(); + if(t) { + if(!oskPosition['userLocated']) { + oskPosition['x'] = util.getAbsoluteX(t); + oskPosition['y'] = util.getAbsoluteY(t)+t.offsetHeight; + } + } + + this._ShowKeyboardButton(); + return oskPosition; + }); + + /* TODO: why is this still needed??? Does it actually do anything?? */ + osk.addEventListener('hide', function(obj) { + if((arguments.length > 0) && obj['hiddenByUser']) { + let _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} + **/ + readonly _ShowKeymanWebKeyboard = () => { + const kbdId=document.getElementById("KMW_Keyboard"); + let osk = keymanweb.osk; - 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); + if((kbdId.className!='kmw_disabled') && osk && osk.show) { + if(osk.isEnabled()) { + osk.hide(); + } else { + osk.show(true); + } + } + if(window.event) { + window.event.returnValue=false; + } - var _btn=util['createElement']('img'), _ul=util['createElement']('ul'),_li0=util['createElement']('li'); - _btn.id = 'kmwico_a'; - _btn.src = imgPath+'kmw_button.gif'; - _btn.onclick = function(){return false;} //may want to use this in iOS ***** - _li0.appendChild(_btn); - _li0.id = 'kmwico_li'; - _ul.appendChild(_li0); - _ul.id = 'kmwico'; - _ul.style.display = 'block'; - _elem.appendChild(_ul); - } - // Do not define any UI behaviour if no controller element can be found - else return; - - if(!keymanweb['iOS']) - { - 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 _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); - _a.appendChild(_sp2); - _a.onmousedown = ui._ShowKeymanWebKeyboard; - _a.href = '#'; - _a.id = 'KMW_Keyboard'; - _li.id = 'KMW_ButtonUI_KbdIcon'; - _li.appendChild(_a); - ui._KMWSel = _a; - ui._KeymanWeb_KbdList.appendChild(_li); + keymanweb.focusLastActiveElement(); + return false; } - var _li1 = util['createElement']('li'); - _li1.id = 'KMW_ButtonUI_KbdList'; - var _a1 = util['createElement']('a'); - _a1.appendChild(document.createTextNode('(System keyboard)')); + /** + * Initialize Button User Interface + **/ + readonly initialize = () => { + if(this.initTimer) { + window.clearTimeout(this.initTimer); + this.initTimer = null; + } - _a1.onclick = ui._SelectKeyboard; - _a1.href = '#'; - _a1.id='KMWSel_$'; - _a1.className='selected'; - _li1.appendChild(_a1); - ui._KMWSel = _a1; - ui._KeymanWeb_KbdList.appendChild(_li1); + //Never initialize UI before KMW (parameters will be undefined) + if(!keymanweb.initialized) { + this.initTimer = window.setTimeout(this.initialize, 50); + return; + } - var _kbds = keymanweb['getKeyboards'](), _added = []; + if(this.init || util.isTouchDevice()) { + return; + } - ui.updateKeyboardList(); + this.init = true; - document.getElementById('kmwico_li').appendChild(ui._KeymanWeb_KbdList); + util.addStyleSheet(this._Appearance); - 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,'mouseup',ui._SelectorMouseUp); + this._KeymanWeb_KbdList = util.createElement('ul'); + this._KeymanWeb_KbdList.id = 'KeymanWeb_KbdList'; - ui.registerEvents(); - keymanweb['focusLastActiveElement'](); //TODO: this needs to be extended - if no element is active, try and identify an enabled input element + let _elem = document.getElementById('KeymanWebControl'); + if(!_elem) { + const _elems = document.getElementsByTagName('div'); + for(let _i = 0; _i < _elems.length; _i++) { + if(_elems[_i].className == 'KeymanWebControl') { + _elem = _elems[_i]; { + break; + } + } + } + } + + // Insert as first child of body if not defined by user + if(!_elem && (document.body != null)) { + _elem=document.createElement('DIV'); + _elem.id='KeymanWebControl'; + document.body.insertBefore(_elem,document.body.firstChild); + this._insertedElem = _elem; + } + + + let 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 + const dx=document.createElement('DIV') + const ds=dx.style; + ds.clear='both'; + _elem.parentNode.insertBefore(dx,_elem.nextSibling); + + const _btn=util.createElement('img'); + const _ul=util.createElement('ul'); + const _li0=util.createElement('li'); + + _btn.id = 'kmwico_a'; + _btn.src = imgPath+'kmw_button.gif'; + _btn.onclick = function() { + return false; + } //may want to use this in iOS ***** + _li0.appendChild(_btn); + _li0.id = 'kmwico_li'; + _ul.appendChild(_li0); + _ul.id = 'kmwico'; + _ul.style.display = 'block'; + _elem.appendChild(_ul); + } else { + // Do not define any UI behaviour if no controller element can be found + return; + } + + // ... wait, what? I can't find any evidence of this reference point existing. + // Even tag `release-web-stable-2.0` turns up results only for this specific sourcefile. + // Thus, in essence: if(true) { /* ... */ } + if(!keymanweb['iOS']) { + var _li = util.createElement('li'); + var _a = util.createElement('a'); + var _img = util.createElement('img'); + _img.src = imgPath+'kbdicon.gif'; + _a.appendChild(_img); + + const _txt1 = document.createTextNode(' Hide Keyboard'); + const _txt2 = document.createTextNode(' Show Keyboard'); + const _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); + _a.appendChild(_sp2); + _a.onmousedown = this._ShowKeymanWebKeyboard; + _a.href = '#'; + _a.id = 'KMW_Keyboard'; + _li.id = 'KMW_ButtonUI_KbdIcon'; + _li.appendChild(_a); + this._KMWSel = _a; + this._KeymanWeb_KbdList.appendChild(_li); + } + + var _li1 = util.createElement('li'); + _li1.id = 'KMW_ButtonUI_KbdList'; + var _a1 = util.createElement('a'); + _a1.appendChild(document.createTextNode('(System keyboard)')); + + _a1.onclick = this._SelectKeyboard; + _a1.href = '#'; + _a1.id='KMWSel_$'; + _a1.className='selected'; + _li1.appendChild(_a1); + this._KMWSel = _a1; + this._KeymanWeb_KbdList.appendChild(_li1); + + this.updateKeyboardList(); + + document.getElementById('kmwico_li').appendChild(this._KeymanWeb_KbdList); + + var _sfEl = document.getElementById("kmwico_li"); + util.attachDOMEvent(_sfEl,'mousedown',this._SelectorMouseDown); + util.attachDOMEvent(_sfEl,'mouseover',this._SelectorMouseOver); + util.attachDOMEvent(_sfEl,'mouseout',this._SelectorMouseOut); + util.attachDOMEvent(_sfEl,'mouseup',this._SelectorMouseUp); + + this.registerEvents(); + keymanweb.focusLastActiveElement(); //TODO: this needs to be extended - if no element is active, try and identify an enabled input element + } + + shutdown() { + const root = this._insertedElem; + if(root) { + root.parentNode.removeChild(root); + } + } + + /** + * Update the entire menu when keyboards are registered or deregistered + **/ + readonly updateKeyboardList = () => { + this.updateList = false; + + if(!this.init) { + return; + } + + // Clear existing list first (first two nodes must be preserved) + for(let i = this._KeymanWeb_KbdList.childNodes.length; i>2; i--) { + this._KeymanWeb_KbdList.removeChild(this._KeymanWeb_KbdList.childNodes[i-1]); + } + + const 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.onclick = this._SelectKeyboard; + _a2.href = '#'; + _a2.id='KMWSel_'+Lki+'$'+Lklc; + _li2.appendChild(_a2); + this._KeymanWeb_KbdList.appendChild(_li2); + } + + // Define appearance of this interface + private _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; + left: -5999px; + border: solid 2px #ad4a28; + background: white; + border-radius: 4px; + 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; + border: none !important; + /* width: auto; */ + color: #404040; + font-family: Tahoma,Verdana,Arial,sans-serif; + 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; +} + +#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdHiddenMsg, #KeymanWebControl #kmwico ul li a.kmw_disabled span#KMW_KbdVisibleMsg { + display: none; +} + +#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdVisibleMsg { + display: inline; +} + +#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdHiddenMsg { + display: inline; +} + +#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdVisibleMsg { + display: none; +} + +#KeymanWebControl #kmwico ul li#KMW_ButtonUI_KbdIcon { + border-bottom: solid 1px #ad4a28; +} +` } - ui.shutdown = function() { - var root = ui._insertedElem; - if(root) { - root.parentNode.removeChild(root); - } - } + const ui = keymanweb['ui'] = new UIButton(); /** * Keyboard registration event handler @@ -416,182 +663,15 @@ if(!window['keyman']['ui']['name']) { * 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,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.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 = - "#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;"+ - "left: -5999px;"+ - "border: solid 2px #ad4a28;"+ - "background: white;"+ - "border-radius: 4px;"+ - "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;"+ - "border: none !important;"+ - // "width: auto;"+ - "color: #404040;"+ - "font-family: Tahoma,Verdana,Arial,sans-serif;"+ - "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;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdHiddenMsg, #KeymanWebControl #kmwico ul li a.kmw_disabled span#KMW_KbdVisibleMsg {"+ - "display: none;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdVisibleMsg {"+ - "display: inline;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdHiddenMsg {"+ - "display: inline;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdVisibleMsg {"+ - "display: none;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li#KMW_ButtonUI_KbdIcon {"+ - "border-bottom: solid 1px #ad4a28;"+ - "} "; + ui.updateTimer = window.setTimeout(ui.updateKeyboardList, 20); + }); // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading - ui.Initialize(); + ui.initialize(); } catch(err){} } \ No newline at end of file diff --git a/web/src/app/ui/tsconfig.json b/web/src/app/ui/tsconfig.json index 84f3b46025..84f27a365e 100644 --- a/web/src/app/ui/tsconfig.json +++ b/web/src/app/ui/tsconfig.json @@ -9,7 +9,7 @@ }, "extends": "../../tsconfig.base.json", "files": [ - // "kmwuibutton.ts", + "kmwuibutton.ts", // "kmwuifloat.ts", "kmwuitoggle.ts", "kmwuitoolbar.ts" diff --git a/web/src/test/auto/integrated/cases/basics.js b/web/src/test/auto/integrated/cases/basics.js index ac99e9f830..a19bdc51a8 100644 --- a/web/src/test/auto/integrated/cases/basics.js +++ b/web/src/test/auto/integrated/cases/basics.js @@ -73,26 +73,26 @@ Modernizr.on('touchevents', function(result) { }) }); -// describe('Basic Button UI', function() { + describe('Basic Button UI', function() { -// beforeEach(function() { -// this.timeout(testconfig.timeouts.uiLoad); -// fixture.setBase('fixtures'); -// fixture.load('singleInput.html'); + beforeEach(function() { + this.timeout(testconfig.timeouts.uiLoad); + fixture.setBase('fixtures'); + fixture.load('singleInput.html'); -// // Loads two scripts in parallel, but just in case, 2x timeout. -// return setupKMW('button', testconfig.timeouts.uiLoad); -// }); + // Loads two scripts in parallel, but just in case, 2x timeout. + return setupKMW('button', testconfig.timeouts.uiLoad); + }); -// afterEach(function() { -// fixture.cleanup(); -// teardownKMW(); -// }); + afterEach(function() { + fixture.cleanup(); + teardownKMW(); + }); -// it('The Button UI initializes correctly.', function() { -// assert(keyman.ui.init, 'Initialization flag is set to false!'); -// }) -// }); + it('The Button UI initializes correctly.', function() { + assert(keyman.ui.init, 'Initialization flag is set to false!'); + }) + }); // describe('Basic Float UI', function() { diff --git a/web/src/test/manual/web/desktop-ui/button.html b/web/src/test/manual/web/desktop-ui/button.html index 73f058e494..a52dbfc0c5 100644 --- a/web/src/test/manual/web/desktop-ui/button.html +++ b/web/src/test/manual/web/desktop-ui/button.html @@ -23,7 +23,7 @@ - + - +