diff --git a/web/src/app/browser/src/configuration.ts b/web/src/app/browser/src/configuration.ts index 5d5907cd0e..3b23ba6e72 100644 --- a/web/src/app/browser/src/configuration.ts +++ b/web/src/app/browser/src/configuration.ts @@ -40,7 +40,7 @@ export class BrowserConfiguration extends EngineConfiguration { const ruleTransform = ruleBehavior.transcription.transform; if(!isEmptyTransform(ruleTransform)) { if(outputTarget instanceof DOMOutputTarget) { - dom.DOMEventHandlers.states.changed = true; + outputTarget.changed = true; } } } diff --git a/web/src/app/browser/src/contextManager.ts b/web/src/app/browser/src/contextManager.ts index 9eeac99a71..a8f533472d 100644 --- a/web/src/app/browser/src/contextManager.ts +++ b/web/src/app/browser/src/contextManager.ts @@ -2,10 +2,12 @@ import { type Keyboard, Mock } from '@keymanapp/keyboard-processor'; import { type KeyboardStub } from 'keyman/engine/package-cache'; import { CookieSerializer } from 'keyman/engine/dom-utils'; import { PageContextAttachment } from 'keyman/engine/attachment'; +import { LegacyEventEmitter } from 'keyman/engine/events'; import { DesignIFrame, OutputTarget, nestedInstanceOf } from 'keyman/engine/element-wrappers'; import { ContextManagerBase, - type KeyboardInterface + type KeyboardInterface, + LegacyAPIEvents } from 'keyman/engine/main'; import { BrowserConfiguration } from './configuration.js'; import { FocusAssistant } from './context/focusAssistant.js'; @@ -102,6 +104,16 @@ export default class ContextManager extends ContextManagerBase LegacyEventEmitter; + + constructor(engineConfig: BrowserConfiguration, eventsClosure: () => LegacyEventEmitter) { + super(engineConfig); + } + + get apiEvents(): LegacyEventEmitter { + return this._eventsObj(); + } + initialize(): void { this.on('keyboardasyncload', (stub, completion) => { // TODO: app/browser - display the loader UI if configured? @@ -416,13 +428,19 @@ export default class ContextManager extends ContextManagerBase) { + if(target.changed) { + let event = new Event('change', {"bubbles": true, "cancelable": false}); + target.getElement().dispatchEvent(event); + } + + target.changed = false; + } } \ No newline at end of file diff --git a/web/src/app/browser/src/keymanEngine.ts b/web/src/app/browser/src/keymanEngine.ts index ef3a3a9431..587d7b4824 100644 --- a/web/src/app/browser/src/keymanEngine.ts +++ b/web/src/app/browser/src/keymanEngine.ts @@ -17,8 +17,10 @@ export class KeymanEngine extends KeymanEngineBase this.legacyAPIEvents)); // Scrolls the document-body to ensure that a focused element remains visible after the OSK appears. this.contextManager.on('targetchange', (target: OutputTarget) => { diff --git a/web/src/engine/element-wrappers/src/outputTarget.ts b/web/src/engine/element-wrappers/src/outputTarget.ts index 1ef15dd46f..e7640b36d5 100644 --- a/web/src/engine/element-wrappers/src/outputTarget.ts +++ b/web/src/engine/element-wrappers/src/outputTarget.ts @@ -5,6 +5,12 @@ export default abstract class OutputTarget = new EventEmitter(); + /** + * A field that may be used to track whether or not the represented context has changed over an + * arbitrary period of time. + */ + public changed = false; + /** * Returns the underlying element / document modeled by the wrapper. */ diff --git a/web/src/engine/main/src/index.ts b/web/src/engine/main/src/index.ts index e04b2343bc..5a7f0c60ae 100644 --- a/web/src/engine/main/src/index.ts +++ b/web/src/engine/main/src/index.ts @@ -3,4 +3,5 @@ export { ContextManagerBase, ContextManagerConfiguration } from './contextManage export { default as HardKeyboard } from './hardKeyboard.js'; export { default as KeyboardInterface } from './keyboardInterface.js'; export { default as KeymanEngine } from './keymanEngine.js'; +export { LegacyAPIEvents } from './legacyAPIEvents.js'; export { VariableStoreCookieSerializer } from './variableStoreCookieSerializer.js'; \ No newline at end of file diff --git a/web/src/engine/main/src/keymanEngine.ts b/web/src/engine/main/src/keymanEngine.ts index 54c391a49a..95e251b4ae 100644 --- a/web/src/engine/main/src/keymanEngine.ts +++ b/web/src/engine/main/src/keymanEngine.ts @@ -24,7 +24,7 @@ export default class KeymanEngine< readonly keyboardRequisitioner: KeyboardRequisitioner; readonly modelCache: ModelCache; - private legacyAPIEvents = new LegacyEventEmitter(); + protected legacyAPIEvents = new LegacyEventEmitter(); private _hardKeyboard: HardKeyboard; private _osk: OSKView; diff --git a/web/src/engine/main/src/legacyAPIEvents.ts b/web/src/engine/main/src/legacyAPIEvents.ts index aa16141726..b30957c8d1 100644 --- a/web/src/engine/main/src/legacyAPIEvents.ts +++ b/web/src/engine/main/src/legacyAPIEvents.ts @@ -26,6 +26,23 @@ export interface LegacyAPIEvents extends LegacyEventMap { languageCode: string }) => boolean; + 'controlfocused': (p: { + /** + * The element gaining focus + */ + target: HTMLElement, + /** + * The previous element to have focus + */ + activeControl: HTMLElement + }) => boolean; + + 'controlblurred': (p: { + target: HTMLElement, + event: FocusEvent, + isActivating: boolean + }) => boolean; + // TODO: more of the documented API events. Note that any remaining events not seen here // yet go unused within the mobile apps. } \ No newline at end of file diff --git a/web/src/engine/namespaced-main/dom/domEventHandlers.ts b/web/src/engine/namespaced-main/dom/domEventHandlers.ts index fdfd5946dc..912e32cbae 100644 --- a/web/src/engine/namespaced-main/dom/domEventHandlers.ts +++ b/web/src/engine/namespaced-main/dom/domEventHandlers.ts @@ -54,49 +54,6 @@ namespace com.keyman.dom { // Universal DOM event handlers (both desktop + touch) - /** - * Function doControlFocused - * Scope Private - * @param {Object} _target element gaining focus - * @param {Object} _activeControl currently active control - * @return {boolean} - * Description Execute external (UI) code needed on focus - */ - doControlFocused(_target: HTMLElement, _activeControl: HTMLElement): boolean { - var p={}; - p['target']=_target; - p['activeControl']=_activeControl; - - return this.keyman.util.callEvent('kmw.controlfocused',p); - } - - /** - * Function doControlBlurred - * Scope Private - * @param {Object} _target element losing focus - * @param {Event} _event event object - * @param {(boolean|number)} _isActivating activation state - * @return {boolean} - * Description Execute external (UI) code needed on blur - */ - doControlBlurred(_target: HTMLElement, _event: Event, _isActivating: boolean|number): boolean { - var p={}; - p['target']=_target; - p['event']=_event; - p['isActivating']=_isActivating; - - return this.keyman.util.callEvent('kmw.controlblurred',p); - } - - doChangeEvent(_target: HTMLElement) { - if(DOMEventHandlers.states.changed) { - let event = new Event('change', {"bubbles": true, "cancelable": false}); - _target.dispatchEvent(event); - } - - DOMEventHandlers.states.changed = false; - } - /** * Function _KeyDown * Scope Private