mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-06 00:45:32 +00:00
chore(web): initial connection of attachment engine to ContextManager
This commit is contained in:
parent
69673bc291
commit
fe16d0ce45
5 changed files with 82 additions and 49 deletions
|
|
@ -2,6 +2,14 @@
|
|||
"name": "keyman",
|
||||
"description": "Facilitates text input in any language.",
|
||||
"exports": {
|
||||
"./engine/attachment": {
|
||||
"types": "./build/engine/attachment/obj/index.d.ts",
|
||||
"import": "./build/engine/attachment/obj/index.js"
|
||||
},
|
||||
"./engine/attachment/lib": {
|
||||
"types": "./build/engine/attachment/obj/index.d.ts",
|
||||
"import": "./build/engine/attachment/lib/index.mjs"
|
||||
},
|
||||
"./engine/paths": {
|
||||
"types": "./build/engine/paths/obj/index.d.ts",
|
||||
"import": "./build/engine/paths/obj/index.js"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { type Keyboard, Mock } from '@keymanapp/keyboard-processor';
|
|||
import { type KeyboardStub } from 'keyman/engine/package-cache';
|
||||
import { CookieSerializer } from 'keyman/engine/dom-utils';
|
||||
import { OutputTarget } from 'keyman/engine/element-wrappers';
|
||||
import { PageContextAttachment } from 'keyman/engine/attachment';
|
||||
import {
|
||||
ContextManagerBase,
|
||||
type KeyboardInterface
|
||||
|
|
@ -18,6 +19,23 @@ export default class ContextManager extends ContextManagerBase<BrowserConfigurat
|
|||
private config: BrowserConfiguration;
|
||||
private cookieManager = new CookieSerializer<KeyboardCookie>('KeymanWeb_Keyboard');
|
||||
readonly focusAssistant = new FocusAssistant();
|
||||
readonly page: PageContextAttachment;
|
||||
|
||||
constructor(engineConfig: BrowserConfiguration) {
|
||||
super(engineConfig);
|
||||
|
||||
this.page = new PageContextAttachment(window.document, {
|
||||
hostDevice: this.config.hostDevice,
|
||||
isTopLevel: true
|
||||
});
|
||||
|
||||
this.engineConfig.deferForInitialization.then(() => {
|
||||
// TODO: set up attachment-listeners here that can add necessary event-hooks
|
||||
// for focus management here!
|
||||
|
||||
this.page.install(this.engineConfig.attachType == 'manual');
|
||||
});
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
this.on('keyboardasyncload', (stub, completion) => {
|
||||
|
|
|
|||
|
|
@ -36,16 +36,22 @@ export default class DefaultBrowserRules extends DefaultRules {
|
|||
|
||||
const contextManager = this.contextManager;
|
||||
|
||||
let elem: HTMLElement;
|
||||
switch(code) {
|
||||
// This method will be transplanted to the specific `ContextManager` module stored above.
|
||||
// This method will be handled between `ContextManager` and PageContextAttachment:
|
||||
// pageContextAttachment.findNeighboringInput(contextManager.activeTarget.getElement(), <same flag>)
|
||||
case Codes.keyCodes['K_TAB']:
|
||||
domManager.moveToNext((Lkc.Lmodifiers & Codes.modifierCodes['SHIFT']) != 0);
|
||||
const bBack = (Lkc.Lmodifiers & Codes.modifierCodes['SHIFT']) != 0;
|
||||
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), bBack);
|
||||
elem.focus();
|
||||
break;
|
||||
case Codes.keyCodes['K_TABBACK']:
|
||||
domManager.moveToNext(true);
|
||||
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), true);
|
||||
elem.focus();
|
||||
break;
|
||||
case Codes.keyCodes['K_TABFWD']:
|
||||
domManager.moveToNext(false);
|
||||
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), false);
|
||||
elem.focus();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,11 +136,6 @@ export interface PageAttachmentOptions {
|
|||
*/
|
||||
hostDevice: DeviceSpec;
|
||||
|
||||
/**
|
||||
* The KMW init() option, as set for the page.
|
||||
*/
|
||||
attachType: 'manual' | 'auto';
|
||||
|
||||
/**
|
||||
* Should only be set to `true` for the top-level page. Should be `false` for
|
||||
* any pages embedded in another page via iframe.
|
||||
|
|
@ -199,6 +194,8 @@ export class PageContextAttachment extends EventEmitter<EventMap> {
|
|||
return this._sortedInputs;
|
||||
}
|
||||
|
||||
private manualAttach: boolean;
|
||||
|
||||
/**
|
||||
* Tracks the attachment MutationObserver.
|
||||
*/
|
||||
|
|
@ -239,7 +236,10 @@ export class PageContextAttachment extends EventEmitter<EventMap> {
|
|||
* Call this method **once**, when the page is fully loaded, to attach to all page elements
|
||||
* eligible to serve as context for Keyman keyboard input.
|
||||
*/
|
||||
install() {
|
||||
install(manualAttach: boolean) {
|
||||
// Do before _SetupDocument!
|
||||
this.manualAttach = manualAttach;
|
||||
|
||||
this._SetupDocument(document.documentElement);
|
||||
|
||||
// KMW 16.0 and before: these were only ever established for the top-level doc, and so for
|
||||
|
|
@ -247,7 +247,7 @@ export class PageContextAttachment extends EventEmitter<EventMap> {
|
|||
//
|
||||
// That said, for future consideration: enable it within iframe-internal documents too.
|
||||
if(this.options.isTopLevel) {
|
||||
this.initMutationObservers(this.document, this.options.attachType == 'manual');
|
||||
this.initMutationObservers(this.document, manualAttach);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,7 +558,7 @@ export class PageContextAttachment extends EventEmitter<EventMap> {
|
|||
embeddedPageAttachment.on('enabled', (elem) => this.emit('enabled', elem));
|
||||
embeddedPageAttachment.on('disabled', (elem) => this.emit('disabled', elem));
|
||||
|
||||
embeddedPageAttachment.install();
|
||||
embeddedPageAttachment.install(this.manualAttach);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -737,6 +737,44 @@ export class PageContextAttachment extends EventEmitter<EventMap> {
|
|||
this._sortedInputs=tList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to next (or previous) input or text area element on TAB
|
||||
* Uses list of actual input elements
|
||||
*
|
||||
* Note that activeElement() on touch devices returns the DIV that overlays
|
||||
* the input element, not the element itself.
|
||||
*
|
||||
* @param {number|boolean} bBack Direction to move (0 or 1)
|
||||
*/
|
||||
findNeighboringInput(activeBase: HTMLElement, bBack: number|boolean) {
|
||||
var i,t=this.sortedInputs;
|
||||
|
||||
if(t.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Identify the active element in the list of inputs ordered by position
|
||||
for(i=0; i<t.length; i++) {
|
||||
if(t[i] == activeBase) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the array is empty or does not hold the element, reverse by one so that
|
||||
// either the last (bBack: true) or the first (bBack: false) element is selected.
|
||||
if(i == t.length && !bBack) { // otherwise, ... "or the second".
|
||||
i--;
|
||||
}
|
||||
|
||||
// Find the next (or previous) element in the list
|
||||
i = bBack ? i-1 : i+1;
|
||||
// Treat the list as circular, wrapping the index if necessary.
|
||||
i = i >= t.length ? i-t.length : i;
|
||||
i = i < 0 ? i+t.length : i;
|
||||
|
||||
return t[i];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function _GetDocumentEditables
|
||||
|
|
|
|||
|
|
@ -453,43 +453,6 @@ namespace com.keyman.dom {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to next (or previous) input or text area element on TAB
|
||||
* Uses list of actual input elements
|
||||
*
|
||||
* Note that activeElement() on touch devices returns the DIV that overlays
|
||||
* the input element, not the element itself.
|
||||
*
|
||||
* @param {number|boolean} bBack Direction to move (0 or 1)
|
||||
*/
|
||||
moveToNext(bBack: number|boolean) {
|
||||
var i,t=this.sortedInputs, activeBase = this.activeElement;
|
||||
var touchable = this.keyman.util.device.touchable;
|
||||
|
||||
if(t.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For touchable devices, get the base element of the DIV
|
||||
if(touchable) {
|
||||
activeBase=activeBase.base;
|
||||
}
|
||||
|
||||
// Identify the active element in the list of inputs ordered by position
|
||||
for(i=0; i<t.length; i++) {
|
||||
if(t[i] == activeBase) break;
|
||||
}
|
||||
|
||||
// Find the next (or previous) element in the list
|
||||
i = bBack ? i-1 : i+1;
|
||||
// Treat the list as circular, wrapping the index if necessary.
|
||||
i = i >= t.length ? i-t.length : i;
|
||||
i = i < 0 ? i+t.length : i;
|
||||
|
||||
// Move to the selected element
|
||||
t[i].focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to user-specified element
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue