From 64c1533eeb81fcf5e68ed25b14838e4c04c4f726 Mon Sep 17 00:00:00 2001 From: Dannii Willis Date: Sun, 24 Dec 2023 18:05:43 +1000 Subject: [PATCH] In mobile Chrome buffer windows weren't scrolled correctly after opening the virtual keyboard. After the new window metrics have been applied, we must rescroll buffer windows to the bottom. Set #gameport to overflow: clip --- src/glkote/web/core.css | 7 ++++++- src/glkote/web/input.css | 2 +- src/glkote/web/input.ts | 10 +++++++--- src/glkote/web/metrics.ts | 8 +------- src/glkote/web/web.ts | 4 ++-- src/glkote/web/windows.ts | 24 +++++++++++++++++++++--- 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/glkote/web/core.css b/src/glkote/web/core.css index b172b2b..38ab7c9 100644 --- a/src/glkote/web/core.css +++ b/src/glkote/web/core.css @@ -3,7 +3,7 @@ GlkOte core styles ================== -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk @@ -41,6 +41,11 @@ https://github.com/curiousdannii/asyncglk descent-override: 21.9%; } +/* The position of #gameport must be controlled from without, but the overflow behaviour is ours. */ +div#gameport { + overflow: clip; +} + #windowport { height: 100%; position: relative; diff --git a/src/glkote/web/input.css b/src/glkote/web/input.css index 4c5d6d8..6983135 100644 --- a/src/glkote/web/input.css +++ b/src/glkote/web/input.css @@ -3,7 +3,7 @@ GlkOte input styles =================== -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk diff --git a/src/glkote/web/input.ts b/src/glkote/web/input.ts index 1df6950..95e28a2 100644 --- a/src/glkote/web/input.ts +++ b/src/glkote/web/input.ts @@ -3,7 +3,7 @@ GlkOte input handlers ===================== -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk @@ -14,7 +14,7 @@ import {KEY_CODE_DOWN, KEY_CODE_RETURN, KEY_CODE_UP, KEY_CODES_TO_NAMES, OFFSCRE import * as protocol from '../../common/protocol.js' import {is_pinch_zoomed} from './shared.js' -import {Window, apply_text_run_styles} from './windows.js' +import {apply_text_run_styles, BufferWindow, Window} from './windows.js' const MAX_HISTORY_LENGTH = 25 @@ -60,7 +60,7 @@ export class TextInput { private onfocus() { // Ensure a buffer window is scrolled down if (this.window.type === 'buffer' && !is_pinch_zoomed()) { - this.window.frameel.scrollTop(this.window.innerel.height()!) + this.scroll_to_bottom() } // Scroll the browser window over the next 600ms scroll_window() @@ -199,6 +199,10 @@ export class TextInput { } } + private scroll_to_bottom = () => { + (this.window as BufferWindow).scroll_to_bottom() + } + private submit_char(val: string) { this.window.send_text_event({ type: 'char', diff --git a/src/glkote/web/metrics.ts b/src/glkote/web/metrics.ts index b4dcfe2..ee52039 100644 --- a/src/glkote/web/metrics.ts +++ b/src/glkote/web/metrics.ts @@ -3,7 +3,7 @@ Metrics and resize handlers =========================== -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk @@ -204,12 +204,6 @@ export default class Metrics { // Safari might have scrolled weirdly, so try to put it right window.scrollTo(0, 0) - if (input_is_active) { - const window: Window = $(document.activeElement!).data('window') - if (window && window.type === 'buffer') { - window.frameel.scrollTop(window.innerel.height()!) - } - } // Measure and send the new metrics this.on_gameport_resize() diff --git a/src/glkote/web/web.ts b/src/glkote/web/web.ts index 578520e..778fc65 100644 --- a/src/glkote/web/web.ts +++ b/src/glkote/web/web.ts @@ -3,7 +3,7 @@ Web GlkOte implementation ========================= -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk @@ -155,7 +155,7 @@ export default class WebGlkOte extends GlkOte.GlkOteBase implements GlkOte.GlkOt for (const win of this.windows.values()) { // Scroll all buffer windows if (win.type === 'buffer') { - win.frameel.scrollTop(win.innerel.height()!) + win.scroll_to_bottom() } } diff --git a/src/glkote/web/windows.ts b/src/glkote/web/windows.ts index bfce509..72738f4 100644 --- a/src/glkote/web/windows.ts +++ b/src/glkote/web/windows.ts @@ -3,7 +3,7 @@ GlkOte windows ============== -Copyright (c) 2022 Dannii Willis +Copyright (c) 2023 Dannii Willis MIT licenced https://github.com/curiousdannii/asyncglk @@ -324,9 +324,10 @@ const inline_alignment_classes: Record = { marginright: 'ImageMarginRight', } -class BufferWindow extends TextualWindow { +export class BufferWindow extends TextualWindow { type = 'buffer' as const innerel: JQuery + private is_scrolled_down = true lastline?: JQuery updatescrolltop = 0 visibleheight: number @@ -338,6 +339,7 @@ class BufferWindow extends TextualWindow { role: 'log', tabindex: -1, }) + .on('scroll', this.onscroll) this.innerel = create('div', 'BufferWindowInner') .append(this.textinput.el) .appendTo(this.frameel) @@ -363,6 +365,19 @@ class BufferWindow extends TextualWindow { } } + // When the frame element is scrolled, update whether it's scrolled to the bottom + private onscroll = () => { + const frameel = this.frameel[0] + this.is_scrolled_down = frameel.scrollHeight - frameel.scrollTop - frameel.clientHeight < 1 + } + + // Scroll to the bottom, unless `after_metrics_change` is set, in which case only scroll if we *should* be at the bottom (used after updating metrics) + scroll_to_bottom(after_metrics_change?: boolean) { + if (!after_metrics_change || this.is_scrolled_down) { + this.frameel.scrollTop(this.innerel.height()!) + } + } + update(data: protocol.BufferWindowContentUpdate) { if (data.clear) { this.innerel.children('.BufferLine').remove() @@ -875,7 +890,10 @@ export default class Windows extends Map { top: update.top, width: update.width, }) - win.measure_height() + if (win.type === 'buffer') { + win.measure_height() + win.scroll_to_bottom(true) + } } const windowstoclose: Window[] = []