diff --git a/web/src/engine/osk/src/views/floatingOskView.ts b/web/src/engine/osk/src/views/floatingOskView.ts index 2399eefe25..7748d463b8 100644 --- a/web/src/engine/osk/src/views/floatingOskView.ts +++ b/web/src/engine/osk/src/views/floatingOskView.ts @@ -64,6 +64,7 @@ export default class FloatingOSKView extends OSKView { this.resizeBar.on('showbuild', () => this.emit('showbuild')); this.headerView = this.titleBar; + this._Box.insertBefore(this.headerView.element, this._Box.firstChild); const onListenedEvent = (eventName: keyof EventMap | keyof LegacyOSKEventMap) => { // As the following title bar buttons (for desktop / FloatingOSKView) do nothing unless a site diff --git a/web/src/engine/osk/src/views/oskView.ts b/web/src/engine/osk/src/views/oskView.ts index 4f0d6c7504..760a664e12 100644 --- a/web/src/engine/osk/src/views/oskView.ts +++ b/web/src/engine/osk/src/views/oskView.ts @@ -233,10 +233,22 @@ export default abstract class OSKView // Initializes the two constant OSKComponentView fields. this.bannerView = new BannerView(); this.bannerView.events.on('bannerchange', () => this.refreshLayout()); + this._Box.appendChild(this.bannerView.element); this._bannerController = new BannerController(this.bannerView, this.hostDevice, this.config.predictionContextManager); - this.keyboardView = null; + this.keyboardView = this._GenerateKeyboardView(null, null); + this._Box.appendChild(this.keyboardView.element); + + // Install the default OSK stylesheets - but don't have it managed by the keyboard-specific stylesheet manager. + // We wish to maintain kmwosk.css whenever keyboard-specific styles are reset/removed. + // Temp-hack: embedded products prefer their stylesheet, etc linkages without the /osk path component. + const resourcePath = getResourcePath(this.config); + + for(let sheetFile of OSKView.STYLESHEET_FILES) { + const sheetHref = `${resourcePath}${sheetFile}`; + this.uiStyleSheetManager.linkExternalSheet(sheetHref); + } this.setBaseMouseEventListeners(); if(this.hostDevice.touchable) { @@ -700,52 +712,28 @@ export default abstract class OSKView private loadActiveKeyboard() { this.setBoxStyling(); - - // Do not erase / 'shutdown' the banner-controller; we simply re-use its elements. - if(this.vkbd) { - this.vkbd.shutdown(); - } - this.keyboardView = null; this.needsLayout = true; + // Save references to the old kbd & its styles for shutdown after replacement. + const oldKbd = this.keyboardView; + const oldKbdStyleManager = this.kbdStyleSheetManager; - // Instantly resets the OSK container, erasing / delinking the previously-loaded keyboard. - this._Box.innerHTML = ''; - - // Since we cleared all inner HTML, that means we cleared the stylesheets, too. - this.uiStyleSheetManager.unlinkAll(); - this.kbdStyleSheetManager.unlinkAll(); - - // Install the default OSK stylesheets - but don't have it managed by the keyboard-specific stylesheet manager. - // We wish to maintain kmwosk.css whenever keyboard-specific styles are reset/removed. - // Temp-hack: embedded products prefer their stylesheet, etc linkages without the /osk path component. - const resourcePath = getResourcePath(this.config); - - for(let sheetFile of OSKView.STYLESHEET_FILES) { - const sheetHref = `${resourcePath}${sheetFile}`; - this.uiStyleSheetManager.linkExternalSheet(sheetHref); - } - - // Any event-cancelers would go here, after the innerHTML reset. - - // Add header element to OSK only for desktop browsers - if(this.headerView) { - this._Box.appendChild(this.headerView.element); - } - - // Add suggestion banner bar to OSK - this._Box.appendChild(this.banner.element); + // Create new ones for the new, incoming kbd. + this.kbdStyleSheetManager = new StylesheetManager(this._Box, this.config.doCacheBusting || false); + const kbdView = this.keyboardView = this._GenerateKeyboardView(this.keyboardData?.keyboard, this.keyboardData?.metadata); + // Perform the replacement. + this._Box.replaceChild(kbdView.element, oldKbd.element); + kbdView.postInsert(); this.bannerController?.configureForKeyboard(this.keyboardData?.keyboard, this.keyboardData?.metadata); - let kbdView: KeyboardView = this.keyboardView = this._GenerateKeyboardView(this.keyboardData?.keyboard, this.keyboardData?.metadata); - this._Box.appendChild(kbdView.element); - kbdView.postInsert(); - - // Add footer element to OSK only for desktop browsers - if(this.footerView) { - this._Box.appendChild(this.footerView.element); + // Now that the swap has occurred, it's safe to shutdown the old VisualKeyboard and any related stylesheets. + if(oldKbd instanceof VisualKeyboard) { + oldKbd.shutdown(); } + oldKbdStyleManager.unlinkAll(); + // END: construction of the actual internal layout for the overall OSK + // Footer element management is handled within FloatingOSKView. this.banner.appendStyles(); @@ -770,10 +758,6 @@ export default abstract class OSKView private _GenerateKeyboardView(keyboard: Keyboard, keyboardMetadata: KeyboardProperties): KeyboardView { let device = this.targetDevice; - if(this.vkbd) { - this.vkbd.shutdown(); - } - this._Box.className = ""; // Case 1: since we hide the system keyboard on touch devices, we need