///
namespace com.keyman {
class CloudRequestEntry {
id: string;
language?: string;
version?: string;
constructor(id: string, language?: string) {
this.id = id;
this.language = language;
}
toString(): string {
var kbid=this.id;
var lgid='';
var kvid='';
if(this.language) {
kbid=kbid+'@'+this.language;
if(this.version) {
kbid=kbid+'@'+this.version;
}
} else {
if(this.version) {
kbid=kbid+'@@'+this.version;
}
}
//TODO: add specifier validation...
return kbid;
}
}
class KeyboardFont {
'family': string;
'files': string;
'path': string;
constructor(fontObj: any, fontPath: string) {
this['family'] = fontObj['family'];
this['files'] = fontObj['source'];
this['path'] = fontPath;
}
}
export class KeyboardStub {
'KI': string;
'KLC': string;
'KN': string;
'KL': string;
'KR': string;
'KRC': string;
'KF': string;
'KFont': KeyboardFont;
'KOskFont': KeyboardFont;
// Used when loading a stub's keyboard.
asyncLoader: any;
constructor(id: string, langCode: string) {
this['KI'] = 'Keyboard_' + id;
this['KLC'] = langCode;
}
}
export class KeyboardTag {
stores: {[text: string]: ComplexKeyboardStore} = {};
}
export class KeyboardManager {
// Language regions as defined by cloud server
static readonly regions = ['World','Africa','Asia','Europe','South America','North America','Oceania','Central America','Middle East'];
static readonly regionCodes = ['un','af','as','eu','sa','na','oc','ca','me'];
keymanweb: KeymanBase;
activeStub: KeyboardStub = null;
keyboardStubs: KeyboardStub[] = [];
deferredStubs: any[] = []; // The list of user-provided keyboard stub registration objects.
deferredKRS = []; // Array of pending keyboard stubs from KRS, to register after initialization
deferredKR = []; // Array of pending keyboards, to be installed at end of initialization
// The following was not actually utilized within KeymanWeb; I think it's handled via different logic.
// See setDefaultKeyboard() below.
dfltStub = null; // First keyboard stub loaded - default for touch-screen devices, ignored on desktops
activeKeyboard: any; // We might can define a more precise def, though...
keyboards: any[] = [];
languageList: any[] = null; // List of keyboard languages available for KeymanCloud
languagesPending: any[] = []; // Array of languages waiting to be registered
linkedScripts: HTMLScriptElement[] = [];
constructor(kmw: KeymanBase) {
this.keymanweb = kmw;
}
getActiveKeyboardName(): string {
return this.activeKeyboard ? this.activeKeyboard['KI'] : '';
}
getActiveKeyboardTag(): KeyboardTag {
return this.activeKeyboard ? this.activeKeyboard['_kmw'] : null;
}
getActiveLanguage(): string {
if(this.activeStub == null) {
return '';
} else {
return this.activeStub['KLC'];
}
}
/**
* Get an associative array of keyboard identification strings
* This was defined as an array, so is kept that way, but
* Javascript treats it as an object anyway
*
* @param {Object} Lkbd Keyboard object
* @return {Object} Copy of keyboard identification strings
*
*/
private _GetKeyboardDetail = function(Lkbd) { // I2078 - Full keyboard detail
var Lr={};
Lr['Name'] = Lkbd['KN'];
Lr['InternalName'] = Lkbd['KI'];
Lr['LanguageName'] = Lkbd['KL']; // I1300 - Add support for language names
Lr['LanguageCode'] = Lkbd['KLC']; // I1702 - Add support for language codes, region names, region codes, country names and country codes
Lr['RegionName'] = Lkbd['KR'];
Lr['RegionCode'] = Lkbd['KRC'];
Lr['CountryName'] = Lkbd['KC'];
Lr['CountryCode'] = Lkbd['KCC'];
Lr['KeyboardID'] = Lkbd['KD'];
Lr['Font'] = Lkbd['KFont'];
Lr['OskFont'] = Lkbd['KOskFont'];
return Lr;
}
/**
* Get array of available keyboard stubs
*
* @return {Array} Array of available keyboards
*
*/
getDetailedKeyboards() {
var Lr = [], Ln, Lstub, Lrn;
for(Ln=0; Ln < this.keyboardStubs.length; Ln++) // I1511 - array prototype extended
{
Lstub = this.keyboardStubs[Ln];
Lrn = this._GetKeyboardDetail(Lstub); // I2078 - Full keyboard detail
Lr=this.keymanweb._push(Lr,Lrn); // TODO: Resolve without need for the cast.
}
return Lr;
}
registerDeferredStubs() {
this.addKeyboardArray(this.deferredStubs);
// KRS stubs (legacy format registration)
for(var j=0; j 9) {
rIndex = 0;
} else {
rIndex = region-1;
}
} else if(typeof(region) == 'string') {
var list = (region.length == 2 ? KeyboardManager.regionCodes : KeyboardManager.regions);
for(var i=0; i 0) {
// Select the first stub as our active keyboard.
this._SetActiveKeyboard(this.keyboardStubs[0]['KI'], this.keyboardStubs[0]['KLC']);
return true;
} else {
return false;
}
}
/**
* Allow to change active keyboard by (internal) keyboard name
*
* @param {string} PInternalName Internal name
* @param {string} PLgCode Language code
*/
setActiveKeyboard(PInternalName: string, PLgCode: string) {
//TODO: This does not make sense: the callbacks should be in _SetActiveKeyboard, not here,
// since this is always called FROM the UI, which should not need notification.
// If UI callbacks are needed at all, they should be within _SetActiveKeyboard
// Skip on embedded which namespaces packageID::Keyboard_keyboardID
if(!this.keymanweb.isEmbedded && PInternalName && PInternalName.indexOf("Keyboard_") != 0) {
PInternalName = "Keyboard_" + PInternalName;
}
this.doBeforeKeyboardChange(PInternalName,PLgCode);
this._SetActiveKeyboard(PInternalName,PLgCode,true);
if(this.keymanweb.domManager.getLastActiveElement() != null) {
this.keymanweb.domManager.focusLastActiveElement(); // TODO: Resolve without need for the cast.
}
// If we ever allow PLgCode to be set by default, we can auto-detect the language code
// after the _SetActiveKeyboard call.
// if(!PLgCode && (keymanweb).keyboardManager.activeStub) {
// PLgCode = (keymanweb).keyboardManager.activeStub['KLC'];
// }
this.doKeyboardChange(PInternalName, PLgCode);
}
/**
* Change active keyboard to keyboard selected by (internal) name and language code
*
* Test if selected keyboard already loaded, and simply update active stub if so.
* Otherwise, insert a script to download and insert the keyboard from the repository
* or user-indicated file location.
*
* Note that the test-case oriented 'recorder' stubs this method to provide active
* keyboard stub information. If changing this function, please ensure the recorder is
* not affected.
*
* @param {string} PInternalName
* @param {string=} PLgCode
* @param {boolean=} saveCookie
*/
_SetActiveKeyboard(PInternalName: string, PLgCode?: string, saveCookie?: boolean) {
var n, Ln;
var util = this.keymanweb.util;
var osk = this.keymanweb.osk;
// Set default language code
if(arguments.length < 2 || (!PLgCode)) {
PLgCode='---';
}
// Check that the saved keyboard is currently registered
for(n=0; n < this.keyboardStubs.length; n++) {
if(PInternalName == this.keyboardStubs[n]['KI']) {
if(PLgCode == this.keyboardStubs[n]['KLC'] || PLgCode == '---') break;
}
}
// Mobile device addition: force selection of the first keyboard if none set
if(util.device.touchable && (PInternalName == '' || PInternalName == null || n >= this.keyboardStubs.length)) {
if(this.keyboardStubs.length != 0) {
PInternalName=this.keyboardStubs[0]['KI'];
PLgCode=this.keyboardStubs[0]['KLC'];
}
}
// Save name of keyboard (with language code) as a cookie
if(arguments.length > 2 && saveCookie) {
this.saveCurrentKeyboard(PInternalName,PLgCode);
}
// Check if requested keyboard and stub are currently active
if(this.activeStub && this.activeKeyboard && this.activeKeyboard['KI'] == PInternalName
&& this.activeStub['KI'] == PInternalName //this part of test should not be necessary, but keep anyway
&& this.activeStub['KLC'] == PLgCode && !this.keymanweb.mustReloadKeyboard
) return;
// Check if current keyboard matches requested keyboard, but not stub
if(this.activeKeyboard && (this.activeKeyboard['KI'] == PInternalName)) {
// If so, simply update the active stub
for(Ln=0; Ln 0) {
var Ps = this.keyboardStubs[0];
this._SetActiveKeyboard(Ps['KI'], Ps['KLC'], true);
}
}.bind(this);
loadingStub.asyncLoader.timer = window.setTimeout(loadingStub.asyncLoader.callback, 10000);
//Display the loading delay bar (Note: only append 'keyboard' if not included in name.)
if(!this.keymanweb.isEmbedded) {
util.wait('Installing keyboard
' + kbdName);
}
// Installing the script immediately does not work reliably if two keyboards are
// loaded in succession if there is any delay in downloading the script.
// It works much more reliably if deferred (KMEW-101, build 356)
// The effect of a delay can also be tested, for example, by setting the timeout to 5000
var manager = this;
window.setTimeout(function(){
manager.installKeyboard(loadingStub);
},0);
}
this.activeStub=this.keyboardStubs[Ln];
return;
}
}
this.keymanweb.domManager._SetTargDir(this.keymanweb.domManager.getLastActiveElement()); // I2077 - LTR/RTL timing
}
var Pk=this.activeKeyboard; // I3319
if(Pk !== null) // I3363 (Build 301)
String.kmwEnableSupplementaryPlane(Pk && ((Pk['KS'] && (Pk['KS'] == 1)) || (Pk['KN'] == 'Hieroglyphic'))); // I3319
// Initialize the OSK (provided that the base code has been loaded)
osk._Load();
}
/**
* Install a keyboard script that has been downloaded from a keyboard server
*
* @param {Object} kbdStub keyboard stub to be loaded.
*
**/
installKeyboard(kbdStub: KeyboardStub) {
var util = this.keymanweb.util;
var osk = this.keymanweb.osk;
var Lscript = util._CreateElement('script');
Lscript.charset="UTF-8"; // KMEW-89
Lscript.type = 'text/javascript';
// Preserve any namespaced IDs by use of the script's id tag attribute!
if(this.keymanweb.isEmbedded) {
Lscript.id = kbdStub['KI'];
}
var kbdFile = kbdStub['KF'];
var kbdLang = kbdStub['KL'];
var kbdName = kbdStub['KN'];
var manager = this;
// Add a handler for cases where the new