mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-14 14:23:14 -06:00
Directory search: don't let the platform keyboard cover our own (#275)
The directory-search widget draws its own on-screen keyboard, on by default, sized and themed to the panel. On Android it was never visible: the page autofocuses a real <input>, which is the signal to raise the system IME, and that lands over the bottom of the screen — exactly where our keyboard is. So a directory panel showed Google's keyboard instead of the one the widget ships: split across a 1920x1080 screen, with mic, GIF, emoji, clipboard and a settings key that opens Google's own UI on a kiosk. On the panel that turned this up, the system keyboard WAS voice input — the only enabled IME was Google's voice IME, so touching the search box opened a microphone, on a wall-mounted tenant directory. When we draw a keyboard, the input now carries inputmode="none", so the platform leaves its keyboard down. The buttons write input.value directly, so nothing about typing changes. Browsers that don't know inputmode ignore it, which is the right fallback — a desktop preview behaves exactly as before. Gated on the flag, not applied to the markup: with show_onscreen_keyboard off there is nothing to cover, and the platform keyboard is the only way left to type. Verified by removing the line and watching the new guard fail. 1669/1669 pass.
This commit is contained in:
parent
04a2ad99d1
commit
702e107972
|
|
@ -1206,6 +1206,14 @@ function renderDirectorySearch(c) {
|
|||
|
||||
// ----- on-screen keyboard (drives the same filter path as typing) -----
|
||||
if (cfg.show_onscreen_keyboard) {
|
||||
/* Tell the platform not to raise ITS keyboard for this field. We autofocus a real
|
||||
<input>, which on Android is the signal to throw the system IME over the bottom of
|
||||
the screen - directly on top of the keyboard we draw below, so a directory panel
|
||||
showed Google's keyboard (mic, GIF and emoji keys included) and never showed its
|
||||
own. The buttons write input.value directly, so suppressing the platform keyboard
|
||||
costs nothing here. Ignored by browsers that don't know inputmode, which is the
|
||||
right fallback: a desktop preview keeps behaving exactly as before. */
|
||||
input.setAttribute('inputmode', 'none');
|
||||
var kb = document.getElementById('keyboard');
|
||||
function press(ch) { input.value += ch; try { input.focus(); } catch(e){} onInput(); }
|
||||
['1234567890','qwertyuiop','asdfghjkl','zxcvbnm'].forEach(function(r){
|
||||
|
|
|
|||
|
|
@ -59,6 +59,24 @@ test('show_onscreen_keyboard flag is carried into the page config', async () =>
|
|||
assert.ok(html.includes('"show_onscreen_keyboard":false'), 'keyboard flag inlined (page hides the keyboard when false)');
|
||||
});
|
||||
|
||||
test('the built-in keyboard suppresses the platform one', async () => {
|
||||
// The page autofocuses a real <input>, which on Android raises the system IME over the
|
||||
// bottom of the screen - covering the keyboard this widget draws itself. A panel showed
|
||||
// Gboard, complete with a mic key, and never showed its own keyboard.
|
||||
seed('search_kb_on', 'directory-search', { source_widget_id: 'board1', show_onscreen_keyboard: true });
|
||||
const { html } = await fetchRender('search_kb_on');
|
||||
assert.ok(/setAttribute\(\s*'inputmode'\s*,\s*'none'\s*\)/.test(html),
|
||||
'page tells the platform not to raise its own keyboard');
|
||||
|
||||
// Only when we are drawing one. With the built-in keyboard off there is nothing to cover,
|
||||
// and the platform keyboard is the only way left to type.
|
||||
seed('search_kb_off2', 'directory-search', { source_widget_id: 'board1', show_onscreen_keyboard: false });
|
||||
const off = await fetchRender('search_kb_off2');
|
||||
assert.ok(off.html.includes('"show_onscreen_keyboard":false'), 'flag inlined as false');
|
||||
assert.ok(!/inputmode="none"/.test(off.html),
|
||||
'the input is not statically marked inputmode=none - suppression is gated on the flag at runtime');
|
||||
});
|
||||
|
||||
test('missing source -> friendly fallback page, not a 500', async () => {
|
||||
seed('search_missing', 'directory-search', { source_widget_id: 'does-not-exist' });
|
||||
const { status, html } = await fetchRender('search_missing');
|
||||
|
|
|
|||
Loading…
Reference in a new issue