spiegel-keyman/web/source/kmwuibutton.js
2017-05-26 11:00:34 +07:00

573 lines
16 KiB
JavaScript

/***
KeymanWeb 2.0
Copyright 2017 SIL International
***/
/********************************/
/* */
/* Button User Interface Code */
/* */
/********************************/
/**
* Do not enclose in an anonymous function, as the compiler may create
* global scope variables to replace true, false, null, whcih can then 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'],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.KeyboardSelector = null;
ui.KeymanWeb_DefaultKeyboardHelp='<span style="font-size:7.5pt">KeymanWeb is not running. Choose a keyboard from the list</span>';
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++)
kList[i].childNodes[0].className = '';
for(var i=2; i<kList.length; i++)
{
_rv = _r.exec(kList[i].childNodes[0].id);
if(_rv && (_rv[1] == kbd) && (_rv[2] == lgc)) break;
}
if(i >= kList.length) i=1;
kList[i].childNodes[0].className = 'selected';
}
/**
* 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;
}
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;
keymanweb['focusLastActiveElement']();
if(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<iList.length; i++)
if(iList[i].type == 'text') break;
if(i < iList.length) ip=iList[i];
if(tList.length > 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
{
kbdId.className = osk['isEnabled']() ? 'kmw_show' : 'kmw_hide';
}
}
}
/**
* UI Functions called by KeymanWeb or OSK
*/
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;
});
/* 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)
{
var kbdId=document.getElementById("KMW_Keyboard");
if((kbdId.className!='kmw_disabled') && 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 = function()
{
//Never initialize UI before KMW (parameters will be undefined)
if(!keymanweb['initialized'])
{
window.setTimeout(ui.Initialize,250); 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)
{
var _elems = document.getElementsByTagName('div');
for(var _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);
}
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';
_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);
}
var _li1 = util['createElement']('li');
_li1.id = 'KMW_ButtonUI_KbdList';
var _a1 = util['createElement']('a');
_a1.appendChild(document.createTextNode('English'));
_a1.onclick = ui._SelectKeyboard;
_a1.href = '#';
_a1.id='KMWSel_$';
_a1.className='selected';
_li1.appendChild(_a1);
ui._KMWSel = _a1;
ui._KeymanWeb_KbdList.appendChild(_li1);
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,'mouseup',ui._SelectorMouseUp);
keymanweb['focusLastActiveElement'](); //TODO: this needs to be extended - if no element is active, try and identify an enabled input element
}
/**
* 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,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=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=0; i<kbds.length; i++)
ui.registerKeyboard(kbds[i]['InternalName'],kbds[i]['LanguageName'],kbds[i]['Name'],kbds[i]['LanguageCode'],kbds[i]['RegionCode']);
}
}
/**
* As each keyboard stub is registered, append it to the list
*
* @param {string} Lki internal name
* @param {string} Lkl language name
* @param {string} Lkn keyboard name
* @param {string} Lklc language code
* @param {string} Lkrc region code
**/
ui.registerKeyboard = function(Lki,Lkl,Lkn,Lklc,Lkrc)
{
var _li2 = util['createElement']('li'),
_a2 = util['createElement']('a'),
_t = Lkn.replace(/\s?keyboard/i,'');
if(Lkl)
{
var lg=Lkl.split(',')[0];
if(Lkn.search(lg) == -1)
_t = lg+' ('+_t+')';
}
if(_t.length > 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;"+
"} ";
// 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){}