mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-31 04:37:41 +00:00
feat(web): high-level layout op batching
Affects change of keyboards and context resets - particularly when new-context rules trigger a non-default layer
This commit is contained in:
parent
f21afb1476
commit
04df7f76c8
3 changed files with 64 additions and 10 deletions
|
|
@ -152,16 +152,32 @@ export default class KeymanEngine<
|
|||
this.osk.startHide(false);
|
||||
}
|
||||
|
||||
if(this.osk) {
|
||||
this.osk.setNeedsLayout();
|
||||
this.osk.activeKeyboard = kbd;
|
||||
this.osk.present();
|
||||
}
|
||||
|
||||
// Needed to ensure the correct layer is displayed.
|
||||
// Needs to be after the OSK has loaded for the keyboard in case the default
|
||||
// layer should be something other than "default" for the current context.
|
||||
this.core.resetContext(this.contextManager.activeTarget);
|
||||
const doContextReset = () => {
|
||||
this.contextManager.resetContext();
|
||||
}
|
||||
|
||||
/*
|
||||
This pattern is designed to minimize layout reflow during the keyboard-swap process.
|
||||
The 'default' layer is loaded by default, but some keyboards will start on different
|
||||
layers depending on the current state of the context.
|
||||
|
||||
If possible, we want to only perform layout operations once the correct layer is
|
||||
set to active.
|
||||
*/
|
||||
if(this.osk) {
|
||||
this.osk.batchLayoutAfter(() => {
|
||||
this.osk.activeKeyboard = kbd;
|
||||
// Note: when embedded within the mobile apps, the keyboard will still be visible
|
||||
// at this time.
|
||||
doContextReset();
|
||||
this.osk.present();
|
||||
});
|
||||
} else {
|
||||
doContextReset();
|
||||
}
|
||||
});
|
||||
|
||||
this.contextManager.on('keyboardasyncload', (metadata) => {
|
||||
|
|
@ -216,7 +232,15 @@ export default class KeymanEngine<
|
|||
resetContext: (target) => {
|
||||
// Could reset the target's deadkeys here, but it's really more of a 'core' task.
|
||||
// So we delegate that to keyboard-processor.
|
||||
this.core.resetContext(target);
|
||||
const doReset = () => this.core.resetContext(target);
|
||||
|
||||
if(this.osk) {
|
||||
this.osk.batchLayoutAfter(() => {
|
||||
doReset();
|
||||
})
|
||||
} else {
|
||||
doReset();
|
||||
}
|
||||
},
|
||||
predictionContext: new PredictionContext(this.core.languageProcessor, this.core.keyboardProcessor),
|
||||
keyboardCache: this.keyboardRequisitioner.cache
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ export default abstract class OSKView
|
|||
private uiStyleSheetManager: StylesheetManager;
|
||||
|
||||
private config: Configuration;
|
||||
private deferLayout: boolean;
|
||||
|
||||
private _boxBaseMouseDown: (e: MouseEvent) => boolean;
|
||||
private _boxBaseTouchStart: (e: TouchEvent) => boolean;
|
||||
|
|
@ -595,8 +596,24 @@ export default abstract class OSKView
|
|||
this.needsLayout = true;
|
||||
}
|
||||
|
||||
public batchLayoutAfter(closure: () => void) {
|
||||
try {
|
||||
this.deferLayout = true;
|
||||
if(this.vkbd) {
|
||||
this.vkbd.deferLayout = true;
|
||||
}
|
||||
closure();
|
||||
} finally {
|
||||
this.deferLayout = false;
|
||||
if(this.vkbd) {
|
||||
this.vkbd.deferLayout = false;
|
||||
}
|
||||
this.refreshLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public refreshLayout(pending?: boolean): void {
|
||||
if(!this.keyboardView) {
|
||||
if(!this.keyboardView || this.deferLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -231,11 +231,20 @@ export default class VisualKeyboard extends EventEmitter<EventMap> implements Ke
|
|||
|
||||
activeGestures: GestureHandler[] = [];
|
||||
activeModipress: Modipress = null;
|
||||
private _deferLayout: boolean;
|
||||
|
||||
// The keyboard object corresponding to this VisualKeyboard.
|
||||
public readonly layoutKeyboard: Keyboard;
|
||||
public readonly layoutKeyboardProperties: KeyboardProperties;
|
||||
|
||||
get deferLayout(): boolean {
|
||||
return this._deferLayout;
|
||||
}
|
||||
|
||||
set deferLayout(value: boolean) {
|
||||
this._deferLayout = value;
|
||||
}
|
||||
|
||||
get layerId(): string {
|
||||
return this.layerGroup?.activeLayerId ?? 'default';
|
||||
}
|
||||
|
|
@ -253,7 +262,7 @@ export default class VisualKeyboard extends EventEmitter<EventMap> implements Ke
|
|||
}
|
||||
}
|
||||
|
||||
if(changedLayer) {
|
||||
if(changedLayer && !this._deferLayout) {
|
||||
this.updateState();
|
||||
// We changed the active layer, but not any layout property of the keyboard as a whole.
|
||||
this.layerGroup.refreshLayout(this.constructLayoutParams());
|
||||
|
|
@ -1206,6 +1215,10 @@ export default class VisualKeyboard extends EventEmitter<EventMap> implements Ke
|
|||
* when needed.
|
||||
*/
|
||||
refreshLayout() {
|
||||
if(this._deferLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Phase 1: calculations possible at the start without triggering _any_ additional layout reflow.
|
||||
(A single, initial reflow may happen depending on DOM manipulations before this method...,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue