Skip to content

Commit

Permalink
Work around iOS Safari's substantial delay of the `visualViewport:res…
Browse files Browse the repository at this point in the history
…ize` event

See curiousdannii/parchment#134 and https://stackoverflow.com/q/72747030/2854284
When the TextInput loses focus we now immediately set the gameport to the height of window.innerHeight, which hopefully will be accurate enough

Also remove the old iOS 15 fix
  • Loading branch information
curiousdannii committed Oct 24, 2024
1 parent c9f9e13 commit c0b1065
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 28 deletions.
8 changes: 0 additions & 8 deletions src/glkote/web/core.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,4 @@ div#gameport {
position: absolute;
top: 0;
visibility: hidden;
}

/* iOS 15: When the virtual keyboard is active, the URL bar is not correctly accounted for in visualViewport.height
https://bugs.webkit.org/show_bug.cgi?id=229876
Should be fixed in iOS 15.1
Account for it by adding some padding to the #gameport */
.ios15fix {
padding-bottom: 55px;
}
7 changes: 7 additions & 0 deletions src/glkote/web/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ export class TextInput {
}

private onblur() {
// If this input lost focus and no other input gained focus, then tell the metrics to resize the gameport
// This is to support iOS better, which delays its `visualViewport:resize` event significantly (~700ms)
const input_is_active = document.activeElement?.tagName === 'INPUT'
if (!input_is_active) {
this.window.manager.glkote.metrics_calculator.set_gameport_height(window.innerHeight)
}

scroll_window()
}

Expand Down
26 changes: 9 additions & 17 deletions src/glkote/web/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ function metrics_differ(newmetrics: protocol.NormalisedMetrics, oldmetrics: prot
oldmetrics.width !== newmetrics.width)
}

const ios15_0 = /(iPad; CPU|iPhone) OS 15_0/i.test(navigator.userAgent)

export default class Metrics {
// Shares the current_metrics and DOM of WebGlkOte
private metrics: protocol.NormalisedMetrics
Expand Down Expand Up @@ -181,26 +179,20 @@ export default class Metrics {
}, 200, {leading: false})

on_visualViewport_resize = () => {
// The iOS virtual keyboard does not change the gameport height, but it does change the viewport
// Try to account for this by setting the gameport to the viewport height
this.set_gameport_height(visualViewport!.height)
}

/** Update the gameport height and then send new metrics */
set_gameport_height(height: number) {
// Don't do anything if the window is pinch zoomed
if (is_pinch_zoomed()){
return
}

// The iOS virtual keyboard does not change the gameport height, but it does change the viewport
// Try to account for this by setting the gameport to the viewport height
const gameport = this.glkote.dom.gameport()
const input_is_active = document.activeElement?.tagName === 'INPUT'

// But first...
// iOS 15: When the virtual keyboard is active, the URL bar is not correctly accounted for in visualViewport.height
// https://bugs.webkit.org/show_bug.cgi?id=229876
// Should be fixed in iOS 15.1
// Account for it by adding some padding to the #gameport
if (ios15_0) {
gameport.toggleClass('ios15fix', input_is_active)
}
// And then set the outer height to the viewport height, accounting for any padding or margin
gameport.outerHeight(visualViewport!.height, true)
// We set the outer height to account for any padding or margin
this.glkote.dom.gameport().outerHeight(height, true)

// Safari might have scrolled weirdly, so try to put it right
window.scrollTo(0, 0)
Expand Down
2 changes: 1 addition & 1 deletion src/glkote/web/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default class WebGlkOte extends GlkOte.GlkOteBase implements GlkOte.GlkOt
prefix: '',
windowport_id: 'windowport',
})
private metrics_calculator: Metrics
metrics_calculator: Metrics
private showing_error = false
private showing_loading = true
private transcript_recorder?: TranscriptRecorder
Expand Down
4 changes: 2 additions & 2 deletions src/glkote/web/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ export default class Windows extends Map<number, Window> {
blorb?: Blorb // Note will be set after this is constructed, in WebGlkOte.init
canvasResizeObserver?: ResizeObserver // Will only be created if the browser's ResizeObserver supports devicePixelContentBoxSize
private dom: DOM
private glkote: WebGlkOte
glkote: WebGlkOte
history: string[] = []
private metrics: protocol.NormalisedMetrics
send_event: EventFunc
Expand Down Expand Up @@ -892,7 +892,7 @@ export default class Windows extends Map<number, Window> {
top: update.top,
width: update.width,
})
.toggleClass('hidden', update.hidden)
.toggleClass('hidden', !!update.hidden)
if (win.type === 'buffer') {
win.scroll_to_bottom(true)
}
Expand Down

0 comments on commit c0b1065

Please sign in to comment.