/// 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