Browser tab keyboard: open under the field being typed into; Enter hides it
The stage TV is portrait, and the keyboard opened at the bottom of the screen — a reach to the floor to type into a search box at the top. - browser-guest-preload.cjs reports the tapped field's position (and which field it is) with the tap, and again when focus moves to another field. - browser-tab.js opens the keyboard directly under that field, centred on it and kept on screen; if there is no room under it, just above it. Focus moving to a different field (Tab, the next memorize blank) moves the keyboard with it. Re-tapping the same field leaves a dragged keyboard where it was. - The keyboard's Enter submits to the page and then hides the keyboard, so search results are not covered. Tapping a field brings it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,19 @@ function restoreOsKeyboard(el) {
|
||||
if (v === null) el.removeAttribute('inputmode'); else el.setAttribute('inputmode', v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Where the field is, so the app can open its keyboard right under it: the stage TV is portrait, and a
|
||||
* keyboard parked at the bottom of a 75" screen is a reach to the floor. `field` tells one field from
|
||||
* another, so focus moving to a different one (Tab, the next memorize blank) can move the keyboard too.
|
||||
*/
|
||||
let fieldSeq = 0;
|
||||
const fieldIds = new WeakMap();
|
||||
function fieldInfo(el) {
|
||||
if (!fieldIds.has(el)) fieldIds.set(el, ++fieldSeq);
|
||||
const r = el.getBoundingClientRect();
|
||||
return { field: fieldIds.get(el), rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } };
|
||||
}
|
||||
|
||||
/*
|
||||
* Only a TAP raises the keyboard. A page that focuses its own search box as it loads must not throw a
|
||||
* keyboard over the stage while nobody is touching it; focus moving between fields (Tab, the next
|
||||
@@ -137,10 +150,13 @@ window.addEventListener('pointerdown', (e) => {
|
||||
const el = editableFrom(e.target);
|
||||
if (!el) return;
|
||||
quietOsKeyboard(el);
|
||||
send('bibleapp:editable', { on: true, tap: true });
|
||||
send('bibleapp:editable', Object.assign({ on: true, tap: true }, fieldInfo(el)));
|
||||
}, true);
|
||||
document.addEventListener('focusin', (e) => {
|
||||
send('bibleapp:editable', { on: isEditable(e.target), tap: false });
|
||||
const el = e.target;
|
||||
if (!isEditable(el)) { send('bibleapp:editable', { on: false, tap: false }); return; }
|
||||
// Measured a frame later: focusing can scroll the field into view first.
|
||||
requestAnimationFrame(() => send('bibleapp:editable', Object.assign({ on: true, tap: false }, fieldInfo(el))));
|
||||
}, true);
|
||||
document.addEventListener('focusout', (e) => {
|
||||
restoreOsKeyboard(e.target);
|
||||
|
||||
Reference in New Issue
Block a user