mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-15 05:09:25 +00:00
change(web): webview context configuration + connections
This commit is contained in:
parent
7be31d0372
commit
8a13a4e64d
17 changed files with 247 additions and 104 deletions
|
|
@ -85,7 +85,7 @@ export default class InputProcessor {
|
|||
* @returns {Object} A RuleBehavior object describing the cumulative effects of
|
||||
* all matched keyboard rules
|
||||
*/
|
||||
processNewContextEvent(outputTarget: OutputTarget): RuleBehavior {
|
||||
processNewContextEvent(outputTarget: OutputTarget): RuleBehavior {
|
||||
const ruleBehavior = this.keyboardProcessor.processNewContextEvent(this.contextDevice, outputTarget);
|
||||
|
||||
if(ruleBehavior) {
|
||||
|
|
@ -365,13 +365,7 @@ export default class InputProcessor {
|
|||
}
|
||||
|
||||
public resetContext(outputTarget?: OutputTarget) {
|
||||
this.keyboardProcessor.resetContext();
|
||||
this.keyboardProcessor.resetContext(outputTarget);
|
||||
this.languageProcessor.invalidateContext(outputTarget, this.keyboardProcessor.layerId);
|
||||
|
||||
// Let the keyboard do its initial group processing
|
||||
//console.log('processNewContextEvent called from resetContext');
|
||||
if(outputTarget) {
|
||||
this.processNewContextEvent(outputTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
|
|||
if(originalTarget != target) {
|
||||
// Note: should be triggered after the corresponding new-context event rule has been processed,
|
||||
// as that may affect the value of layerId here.
|
||||
return this.langProcessor.invalidateContext(target, this.kbdProcessor.layerId);
|
||||
return this.resetContext();
|
||||
} else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
|
@ -337,4 +337,16 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
|
|||
public sendUpdateEvent() {
|
||||
this.emit('update', this.currentSuggestions);
|
||||
}
|
||||
|
||||
public resetContext(): Promise<Suggestion[]> {
|
||||
const target = this.currentTarget;
|
||||
|
||||
if(target) {
|
||||
// Note: should be triggered after the corresponding new-context event rule has been processed,
|
||||
// as that may affect the value of layerId here.
|
||||
return this.langProcessor.invalidateContext(target, this.kbdProcessor.layerId);
|
||||
} else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -554,9 +554,15 @@ export default class KeyboardProcessor extends EventEmitter<EventMap> {
|
|||
return false;
|
||||
}
|
||||
|
||||
resetContext() {
|
||||
resetContext(target?: OutputTarget) {
|
||||
this.layerId = 'default';
|
||||
this.keyboardInterface.resetContextCache();
|
||||
|
||||
// May be null if it's a keyboard swap.
|
||||
if(target) {
|
||||
this.processNewContextEvent(this.contextDevice, target);
|
||||
}
|
||||
|
||||
if(!this.contextDevice.touchable) {
|
||||
this._UpdateVKShift(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { OutputTarget } from '@keymanapp/keyboard-processor';
|
||||
import { type Keyboard, Mock, OutputTarget } from '@keymanapp/keyboard-processor';
|
||||
import { type KeyboardStub } from 'keyman/engine/keyboard-cache';
|
||||
import {
|
||||
ContextManager as ContextManagerBase,
|
||||
type KeyboardInterface
|
||||
} from 'keyman/engine/main';
|
||||
import { BrowserConfiguration } from './configuration.js';
|
||||
|
||||
export default class ContextManager extends ContextManagerBase {
|
||||
private _activeKeyboard: {keyboard: Keyboard, metadata: KeyboardStub};
|
||||
private config: BrowserConfiguration;
|
||||
|
||||
initialize(): void {
|
||||
// TBD: keyman.domManager.init (the page-integration parts)
|
||||
// CTRL+F: `// Exit initialization here if we're using an embedded code path.`
|
||||
|
|
@ -18,6 +23,17 @@ export default class ContextManager extends ContextManagerBase {
|
|||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
get activeKeyboard() {
|
||||
return this._activeKeyboard;
|
||||
}
|
||||
|
||||
set activeKeyboard(kbd: {keyboard: Keyboard, metadata: KeyboardStub}) {
|
||||
throw new Error('Method not implemented.');
|
||||
// depends on the target
|
||||
// if not set with an "independent keyboard", changes the global.
|
||||
// if set with an "independent keyboard", changes only the active target's keyboard.
|
||||
}
|
||||
|
||||
insertText(kbdInterface: KeyboardInterface, Ptext: string, PdeadKey: number) {
|
||||
// Find the correct output target to manipulate.
|
||||
const outputTarget = this.activeTarget;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { EngineConfiguration, InitOptionSpec, InitOptionDefaults } from "keyman/engine/main";
|
||||
|
||||
import { type OnInsertTextFunc } from "./contextManager.js";
|
||||
|
||||
export class WebviewConfiguration extends EngineConfiguration {
|
||||
private _embeddingApp: string;
|
||||
private _oninserttext: OnInsertTextFunc;
|
||||
|
||||
initialize(options: Required<WebviewInitOptionSpec>) {
|
||||
this.initialize(options);
|
||||
|
|
@ -13,6 +16,10 @@ export class WebviewConfiguration extends EngineConfiguration {
|
|||
return this._embeddingApp;
|
||||
}
|
||||
|
||||
get oninserttext() {
|
||||
return this._oninserttext;
|
||||
}
|
||||
|
||||
debugReport(): Record<string, any> {
|
||||
const baseReport = super.debugReport();
|
||||
baseReport.embeddingApp = this.embeddingApp;
|
||||
|
|
@ -26,10 +33,16 @@ export interface WebviewInitOptionSpec extends InitOptionSpec {
|
|||
/**
|
||||
* May be used to denote the name of the embedding application
|
||||
*/
|
||||
embeddingApp?: string;
|
||||
embeddingApp: string;
|
||||
|
||||
/**
|
||||
* Accepts a callback used for updating the host application's context.
|
||||
*/
|
||||
oninserttext?: OnInsertTextFunc;
|
||||
}
|
||||
|
||||
export const WebviewInitOptionDefaults: Required<WebviewInitOptionSpec> = {
|
||||
embeddingApp: '',
|
||||
oninserttext: null,
|
||||
...InitOptionDefaults
|
||||
}
|
||||
|
|
@ -1,24 +1,69 @@
|
|||
import { Mock } from '@keymanapp/keyboard-processor';
|
||||
import { ContextManager as ContextManagerBase } from 'keyman/engine/main';
|
||||
import { type Keyboard, Mock } from '@keymanapp/keyboard-processor';
|
||||
import { type KeyboardStub } from 'keyman/engine/keyboard-cache';
|
||||
import { ContextManagerBase, ContextManagerConfiguration } from 'keyman/engine/main';
|
||||
import { WebviewConfiguration } from './configuration.js';
|
||||
|
||||
export type OnInsertTextFunc = (deleteLeft: number, text: string, deleteRight: number) => void;
|
||||
|
||||
class ContextHost extends Mock {
|
||||
readonly oninserttext?: OnInsertTextFunc;
|
||||
|
||||
constructor(oninserttext: OnInsertTextFunc) {
|
||||
super();
|
||||
this.oninserttext = oninserttext;
|
||||
}
|
||||
|
||||
apply(transform: Transform): void {
|
||||
super.apply(transform);
|
||||
|
||||
// Signal the necessary text changes to the embedding app, if it exists.
|
||||
if(this.oninserttext) {
|
||||
this.oninserttext(transform.deleteLeft, transform.insert, transform.deleteRight);
|
||||
}
|
||||
}
|
||||
|
||||
// ... selected text is actually looking kinda tricky here.
|
||||
}
|
||||
|
||||
export default class ContextManager extends ContextManagerBase {
|
||||
// Change of context? Just replace the Mock. Context will be ENTIRELY controlled
|
||||
// by whatever is hosting the WebView. (Some aspects of this context replacement have
|
||||
// yet to be modularized at this time, though.)
|
||||
private _rawContext: Mock;
|
||||
private _rawContext: ContextHost;
|
||||
private config: WebviewConfiguration;
|
||||
|
||||
constructor() {
|
||||
private _activeKeyboard: {keyboard: Keyboard, metadata: KeyboardStub};
|
||||
|
||||
constructor(engineConfig: WebviewConfiguration) {
|
||||
super();
|
||||
this._rawContext = new Mock();
|
||||
|
||||
this.config = engineConfig;
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
// There's little distinct to do on page-load for the WebView-hosted version of KMW.
|
||||
// We don't do page integration here. That said...
|
||||
// TBD: keyman.domManager.init (there probably are a few embedding-specific aspects worth note)
|
||||
this._rawContext = new ContextHost(this.config.oninserttext);
|
||||
this.resetContext();
|
||||
}
|
||||
|
||||
get activeTarget(): Mock {
|
||||
return this._rawContext;
|
||||
}
|
||||
|
||||
get activeKeyboard() {
|
||||
return this._activeKeyboard;
|
||||
}
|
||||
|
||||
set activeKeyboard(kbd: {keyboard: Keyboard, metadata: KeyboardStub}) {
|
||||
const priorEntry = this._activeKeyboard;
|
||||
this._activeKeyboard = kbd;
|
||||
|
||||
if(priorEntry.keyboard != kbd.keyboard || priorEntry.metadata != kbd.metadata) {
|
||||
this.emit('keyboardchange', kbd);
|
||||
|
||||
// Differs from the standard 'resetContext' by not using new-context rules; this IS
|
||||
// a keyboard change, not a true context change.
|
||||
this.resetKeyState();
|
||||
this.predictionContext.resetContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ export class KeymanEngine extends KeymanEngineBase<ContextManager, PassthroughKe
|
|||
}
|
||||
}
|
||||
|
||||
super(worker, config, new ContextManager());
|
||||
super(worker, config, new ContextManager(config));
|
||||
|
||||
this.hardKeyboard = new PassthroughKeyboard(config.hardDevice);
|
||||
}
|
||||
|
|
@ -34,14 +34,17 @@ export class KeymanEngine extends KeymanEngineBase<ContextManager, PassthroughKe
|
|||
|
||||
super.init({...WebviewInitOptionDefaults, ...options});
|
||||
|
||||
this.contextManager.initialize();
|
||||
|
||||
const oskConfig: ViewConfiguration = {
|
||||
hostDevice: this.config.hostDevice,
|
||||
pathConfig: this.config.paths,
|
||||
// When hosted in a WebView, we never hide the Web OSK without hiding the hosting WebView.
|
||||
activator: new StaticActivator(),
|
||||
embeddedGestureConfig: buildEmbeddedGestureConfig(this.config.softDevice),
|
||||
doCacheBusting: true
|
||||
}
|
||||
doCacheBusting: true,
|
||||
predictionContextManager: this.contextManager.predictionContext
|
||||
};
|
||||
|
||||
this.osk = new AnchoredOSKView(oskConfig);
|
||||
setupEmbeddedListeners(this, this.osk);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,8 @@
|
|||
import { OutputTarget as OutputTargetBase } from "@keymanapp/keyboard-processor";
|
||||
import EventEmitter from 'eventemitter3';
|
||||
|
||||
export interface BaseEventMap {
|
||||
/**
|
||||
* Meant to facilitate the following code that existed pre-modularization:
|
||||
```
|
||||
// This class has non-integrated unit tests in which the `singleton` object doesn't exist.
|
||||
// Thus, we need to test for this case.
|
||||
let keyman = com.keyman['singleton'];
|
||||
|
||||
// Signal the necessary text changes to the embedding app, if it exists.
|
||||
if(keyman && keyman['oninserttext'] && keyman.isEmbedded) {
|
||||
keyman['oninserttext'](transform.deleteLeft, transform.insert, transform.deleteRight);
|
||||
}
|
||||
```
|
||||
*/
|
||||
'oninserttext': (deleteLeft: number, insert: string, deleteRight: number) => void;
|
||||
}
|
||||
|
||||
export default abstract class OutputTarget<EventMap extends BaseEventMap = BaseEventMap> extends OutputTargetBase {
|
||||
// JS/TS can't do multiple inheritance, so we maintain class events on a readonly field.
|
||||
export default abstract class OutputTarget<EventMap extends EventEmitter.ValidEventTypes> extends OutputTargetBase {
|
||||
// JS/TS can't do true multiple inheritance, so we maintain class events on a readonly field.
|
||||
public readonly events: EventEmitter<EventMap, this> = new EventEmitter<EventMap, this>();
|
||||
|
||||
/**
|
||||
|
|
@ -53,10 +36,5 @@ export default abstract class OutputTarget<EventMap extends BaseEventMap = BaseE
|
|||
|
||||
apply(transform: Transform) {
|
||||
super.apply(transform);
|
||||
|
||||
// The TS compiler can't quite handle this typing scenario properly; the following cast
|
||||
// allows us to work around its type inference limitations.
|
||||
const baseEvents = (this.events as unknown as EventEmitter<BaseEventMap, this>);
|
||||
baseEvents.emit('oninserttext', transform.deleteLeft, transform.insert, transform.deleteRight);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3';
|
||||
import { type Keyboard, type KeyboardInterface, type KeyboardProperties, type OutputTarget } from '@keymanapp/keyboard-processor';
|
||||
|
||||
interface EventMap {
|
||||
'changedcontext': (target: OutputTarget, keyboard: Keyboard) => void;
|
||||
}
|
||||
|
||||
export default abstract class ContextManager extends EventEmitter<EventMap> {
|
||||
private _activeKeyboard: {keyboard: Keyboard, metadata: KeyboardProperties};
|
||||
|
||||
abstract initialize(): void;
|
||||
|
||||
abstract get activeTarget(): OutputTarget;
|
||||
// activeKeyboard: Keyboard; // probably belongs here.
|
||||
|
||||
insertText(kbdInterface: KeyboardInterface, Ptext: string, PdeadKey: number) {
|
||||
// Find the correct output target to manipulate.
|
||||
const outputTarget = this.activeTarget;
|
||||
|
||||
if(outputTarget != null) {
|
||||
if(Ptext != null) {
|
||||
kbdInterface.output(0, outputTarget, Ptext);
|
||||
}
|
||||
|
||||
if((typeof(PdeadKey)!=='undefined') && (PdeadKey !== null)) {
|
||||
kbdInterface.deadkeyOutput(0, outputTarget, PdeadKey);
|
||||
}
|
||||
|
||||
outputTarget.invalidateSelection();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
get activeKeyboard(): {keyboard: Keyboard, metadata: KeyboardProperties} {
|
||||
return this._activeKeyboard;
|
||||
}
|
||||
}
|
||||
|
||||
// Intended design:
|
||||
// - SiteContextManager - for website, document-aware context management
|
||||
// - app/embed
|
||||
// - PassthroughContextManager - for WebView-hosted, app-embedded context management.
|
||||
// - app/web
|
||||
88
web/src/engine/main/src/contextManagerBase.ts
Normal file
88
web/src/engine/main/src/contextManagerBase.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import EventEmitter from 'eventemitter3';
|
||||
import { type Keyboard, type KeyboardInterface, type OutputTarget } from '@keymanapp/keyboard-processor';
|
||||
import { type KeyboardStub } from 'keyman/engine/keyboard-cache';
|
||||
import { PredictionContext } from '@keymanapp/input-processor';
|
||||
|
||||
interface EventMap {
|
||||
// target, then keyboard.
|
||||
'targetchange': (target: OutputTarget) => void;
|
||||
'keyboardchange': (kbd: {keyboard: Keyboard, metadata: KeyboardStub}) => void;
|
||||
}
|
||||
|
||||
export interface ContextManagerConfiguration {
|
||||
/**
|
||||
* A function that resets any state-dependent keyboard key-state information such as
|
||||
* emulated modifier state and layer id. Also purges the context cache.
|
||||
* If an `outputTarget` is specified, it will also trigger new-context rule processing.
|
||||
*
|
||||
* Does not reset option-stores, variable-stores, etc.
|
||||
*/
|
||||
readonly resetKeyState: (outputTarget?: OutputTarget) => void;
|
||||
|
||||
/**
|
||||
* A predictive-state management object that interfaces the predictive-text banner
|
||||
* with the active context.
|
||||
*/
|
||||
readonly predictionContext: PredictionContext;
|
||||
}
|
||||
|
||||
export abstract class ContextManagerBase extends EventEmitter<EventMap> {
|
||||
abstract initialize(): void;
|
||||
|
||||
abstract get activeTarget(): OutputTarget;
|
||||
|
||||
private _predictionContext: PredictionContext;
|
||||
private _resetKeyState: (outputTarget?: OutputTarget) => void;
|
||||
|
||||
get predictionContext(): PredictionContext {
|
||||
return this._predictionContext;
|
||||
}
|
||||
|
||||
protected get resetKeyState(): (outputTarget?: OutputTarget) => void {
|
||||
return this._resetKeyState;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
configure(config: ContextManagerConfiguration) {
|
||||
// TODO: Set in followup configuration method. Part of initialization?
|
||||
this._resetKeyState = config.resetKeyState;
|
||||
this._predictionContext = config.predictionContext;
|
||||
}
|
||||
|
||||
insertText(kbdInterface: KeyboardInterface, Ptext: string, PdeadKey: number) {
|
||||
// Find the correct output target to manipulate.
|
||||
const outputTarget = this.activeTarget;
|
||||
|
||||
if(outputTarget != null) {
|
||||
if(Ptext != null) {
|
||||
kbdInterface.output(0, outputTarget, Ptext);
|
||||
}
|
||||
|
||||
if((typeof(PdeadKey)!=='undefined') && (PdeadKey !== null)) {
|
||||
kbdInterface.deadkeyOutput(0, outputTarget, PdeadKey);
|
||||
}
|
||||
|
||||
outputTarget.invalidateSelection();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resetContext() {
|
||||
this._resetKeyState(this.activeTarget);
|
||||
this.predictionContext.resetContext();
|
||||
}
|
||||
|
||||
abstract get activeKeyboard(): {keyboard: Keyboard, metadata: KeyboardStub};
|
||||
abstract set activeKeyboard(kbd: {keyboard: Keyboard, metadata: KeyboardStub});
|
||||
}
|
||||
|
||||
// Intended design:
|
||||
// - SiteContextManager - for website, document-aware context management
|
||||
// - app/embed
|
||||
// - PassthroughContextManager - for WebView-hosted, app-embedded context management.
|
||||
// - app/web
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
export { EngineConfiguration, InitOptionDefaults, InitOptionSpec } from './engineConfiguration.js';
|
||||
export { default as ContextManager } from './contextManager.js';
|
||||
export { ContextManagerBase, ContextManagerConfiguration } from './contextManagerBase.js';
|
||||
export { default as HardKeyboard } from './hardKeyboard.js';
|
||||
export { default as KeyboardInterface } from './keyboardInterface.js';
|
||||
export { default as KeymanEngine } from './keymanEngine.js';
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ import {
|
|||
} from "@keymanapp/keyboard-processor";
|
||||
import { KeyboardStub, RawKeyboardStub, StubAndKeyboardCache } from 'keyman/engine/keyboard-cache';
|
||||
|
||||
import ContextManager from './contextManager.js';
|
||||
import { ContextManagerBase } from './contextManagerBase.js';
|
||||
import { VariableStoreCookieSerializer } from "./variableStoreCookieSerializer.js";
|
||||
|
||||
export default class KeyboardInterface extends KeyboardInterfaceBase {
|
||||
private readonly contextManager: ContextManager;
|
||||
private readonly contextManager: ContextManagerBase;
|
||||
private stubAndKeyboardCache: StubAndKeyboardCache;
|
||||
private stubNamespacer?: (stub: RawKeyboardStub) => void;
|
||||
|
||||
constructor(
|
||||
_jsGlobal: any,
|
||||
keymanGlobal: KeyboardKeymanGlobal,
|
||||
contextManager: ContextManager,
|
||||
contextManager: ContextManagerBase,
|
||||
stubNamespacer?: (stub: RawKeyboardStub) => void
|
||||
) {
|
||||
super(_jsGlobal, keymanGlobal, new VariableStoreCookieSerializer());
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { KeyboardRequisitioner } from "keyman/engine/keyboard-cache";
|
|||
|
||||
import { EngineConfiguration, InitOptionDefaults, InitOptionSpec } from "./engineConfiguration.js";
|
||||
import KeyboardInterface from "./keyboardInterface.js";
|
||||
import ContextManagerBase from "./contextManager.js";
|
||||
import { ContextManagerBase } from "./contextManagerBase.js";
|
||||
import { KeyEventHandler } from './keyEventSource.interface.js';
|
||||
import HardKeyboardBase from "./hardKeyboard.js";
|
||||
import { LegacyAPIEventEngine } from "./legacyAPIEvents.js";
|
||||
|
|
@ -66,6 +66,9 @@ export default class KeymanEngine<ContextManager extends ContextManagerBase, Har
|
|||
defaultOutputRules: new DefaultRules()
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* @param worker A configured WebWorker to serve as the predictive-text engine's main thread.
|
||||
* Available in the following variants:
|
||||
|
|
@ -88,6 +91,16 @@ export default class KeymanEngine<ContextManager extends ContextManagerBase, Har
|
|||
|
||||
this.processor = new InputProcessor(config.hostDevice, worker, this.processorConfiguration());
|
||||
|
||||
this.contextManager.configure({
|
||||
resetKeyState: (target) => {
|
||||
this.processor.keyboardProcessor.resetContext(target);
|
||||
},
|
||||
predictionContext: new PredictionContext(this.processor.languageProcessor, this.processor.keyboardProcessor)
|
||||
});
|
||||
|
||||
// TODO: configure that context-manager!
|
||||
|
||||
// #region Event handler wiring
|
||||
cache.on('stubAdded', (stub) => {
|
||||
let eventRaiser = () => {
|
||||
// The corresponding event is needed in order to update UI modules as new keyboard stubs "come online".
|
||||
|
|
@ -121,6 +134,13 @@ export default class KeymanEngine<ContextManager extends ContextManagerBase, Har
|
|||
this.config.deferForInitialization.then(eventRaiser);
|
||||
}
|
||||
});
|
||||
|
||||
contextManager.on('keyboardchange', (kbd) => {
|
||||
if(this.osk) {
|
||||
this.osk.activeKeyboard = kbd;
|
||||
}
|
||||
});
|
||||
// #endregion
|
||||
}
|
||||
|
||||
init(optionSpec: Required<InitOptionSpec>): void {
|
||||
|
|
|
|||
|
|
@ -423,8 +423,10 @@ export class SuggestionBanner extends Banner {
|
|||
|
||||
// connect the new one!
|
||||
this._predictionContext = context;
|
||||
context.on('update', this.onSuggestionUpdate);
|
||||
this.onSuggestionUpdate(context.currentSuggestions);
|
||||
if(context) {
|
||||
context.on('update', this.onSuggestionUpdate);
|
||||
this.onSuggestionUpdate(context.currentSuggestions);
|
||||
}
|
||||
}
|
||||
|
||||
public onSuggestionUpdate = (suggestions: Suggestion[]): void => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import OSKViewComponent from '../components/oskViewComponent.interface.js';
|
|||
import { ParsedLengthStyle } from '../lengthStyle.js';
|
||||
|
||||
import { DeviceSpec } from '@keymanapp/web-utils';
|
||||
import type { StateChangeEnum } from '@keymanapp/input-processor';
|
||||
import type { PredictionContext, StateChangeEnum } from '@keymanapp/input-processor';
|
||||
import { createUnselectableElement } from 'keyman/engine/dom-utils';
|
||||
|
||||
/**
|
||||
|
|
@ -158,6 +158,8 @@ export class BannerController {
|
|||
private alwaysShow: boolean;
|
||||
private imagePath?: string = "";
|
||||
|
||||
private predictionContext?: PredictionContext;
|
||||
|
||||
private readonly hostDevice: DeviceSpec;
|
||||
|
||||
public static readonly DEFAULT_OPTIONS: BannerOptions = {
|
||||
|
|
@ -165,10 +167,11 @@ export class BannerController {
|
|||
imagePath: ""
|
||||
}
|
||||
|
||||
constructor(bannerView: BannerView, hostDevice: DeviceSpec) {
|
||||
constructor(bannerView: BannerView, hostDevice: DeviceSpec, predictionContext?: PredictionContext) {
|
||||
// Step 1 - establish the container element. Must come before this.setOptions.
|
||||
this.hostDevice = hostDevice;
|
||||
this.container = bannerView;
|
||||
this.predictionContext = predictionContext;
|
||||
|
||||
// Initialize with the default options - any 'manually set' options come post-construction.
|
||||
// This will also automatically set the default banner in place.
|
||||
|
|
@ -281,8 +284,8 @@ export class BannerController {
|
|||
} else {
|
||||
this.setBanner('blank');
|
||||
}
|
||||
} else if(state == 'configured') {
|
||||
// TODO: refresh PredictionContext once available.
|
||||
} else if(state == 'configured' && this.activeBanner instanceof SuggestionBanner) {
|
||||
this.activeBanner.predictionContext = this.predictionContext || null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { type PredictionContext } from "@keymanapp/input-processor";
|
||||
import type Activator from "../views/activator.js";
|
||||
import CommonConfiguration from "./commonConfiguration.js";
|
||||
|
||||
|
|
@ -33,4 +34,10 @@ export default interface Configuration extends CommonConfiguration {
|
|||
* Defaults to 'false'.
|
||||
*/
|
||||
doCacheBusting?: boolean;
|
||||
|
||||
/**
|
||||
* A predictive-state management object that interfaces the predictive-text banner
|
||||
* with the active context.
|
||||
*/
|
||||
predictionContextManager?: PredictionContext;
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ export default abstract class OSKView extends EventEmitter<EventMap> implements
|
|||
this.bannerView = new BannerView();
|
||||
this.bannerView.events.on('bannerchange', () => this.refreshLayout());
|
||||
|
||||
this._bannerController = new BannerController(this.bannerView, this.hostDevice);
|
||||
this._bannerController = new BannerController(this.bannerView, this.hostDevice, this.config.predictionContextManager);
|
||||
|
||||
this.keyboardView = null;
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ export default abstract class OSKView extends EventEmitter<EventMap> implements
|
|||
}
|
||||
|
||||
public get bannerController(): BannerController {
|
||||
return this.bannerController;
|
||||
return this._bannerController;
|
||||
}
|
||||
|
||||
public get hostDevice(): DeviceSpec {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue