fix(android): the keyboard closes, and the write test is gone
Same origin as the sideways slide. The keyboard's validate key asks for the next field, and the next one in the document sits on a view parked outside the frame. Focus landed there unseen: the keyboard changed shape - numeric for the code, alphabetic for the search - and would not close, because the field holding it open was off screen. No field of a resting view keeps the focus now, and the validate key closes the keyboard instead of jumping. In the editor it saves, which is what the key is for after typing a password. The write test goes with it: it proved the write path before the first real PUT, that path now carries the vault itself, and the button, its handler, the probe and the debug hook that revealed it were only ever scaffolding.
This commit is contained in:
+26
-21
@@ -224,10 +224,6 @@
|
|||||||
<button class="btn" id="btnCfg">⚙ Server settings</button>
|
<button class="btn" id="btnCfg">⚙ Server settings</button>
|
||||||
<button class="btn" id="btnLog">≡ Log</button>
|
<button class="btn" id="btnLog">≡ Log</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Essai du chemin d'ecriture, visible uniquement en build de debogage :
|
|
||||||
Delphi appelle PM.setDebug(true). Il ecrit dans un AUTRE fichier du
|
|
||||||
depot, jamais dans le coffre. -->
|
|
||||||
<button class="btn wide" id="btnWriteTest" hidden>Write test (debug)</button>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- UNE CROIX PAR CHAMP. Vider par la touche retour demande une quarantaine
|
<!-- UNE CROIX PAR CHAMP. Vider par la touche retour demande une quarantaine
|
||||||
d'appuis sur un jeton, et laisse facilement un caractere - ce qui donne
|
d'appuis sur un jeton, et laisse facilement un caractere - ce qui donne
|
||||||
@@ -399,14 +395,6 @@ document.getElementById('btnLog').addEventListener('click', function () {
|
|||||||
var l = document.getElementById('log');
|
var l = document.getElementById('log');
|
||||||
l.hidden = !l.hidden;
|
l.hidden = !l.hidden;
|
||||||
});
|
});
|
||||||
document.getElementById('btnWriteTest').addEventListener('click', function () {
|
|
||||||
// pushConfig D'ABORD, comme Sync. Sans cela, un jeton qui vient d'etre colle
|
|
||||||
// et dont le champ n'a pas encore perdu le focus n'est pas parti vers Delphi,
|
|
||||||
// qui agit alors avec l'ancien - et rend un 403 parfaitement trompeur.
|
|
||||||
pushConfig();
|
|
||||||
document.getElementById('log').hidden = false;
|
|
||||||
send('writetest');
|
|
||||||
});
|
|
||||||
|
|
||||||
function esc(s) {
|
function esc(s) {
|
||||||
return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) {
|
return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) {
|
||||||
@@ -593,12 +581,6 @@ function openEditor(k) {
|
|||||||
var input = document.getElementById('editval');
|
var input = document.getElementById('editval');
|
||||||
input.value = detailRows[k].v;
|
input.value = detailRows[k].v;
|
||||||
input.focus();
|
input.focus();
|
||||||
input.addEventListener('keydown', function (ev) {
|
|
||||||
if (ev.key !== 'Enter') return;
|
|
||||||
ev.preventDefault();
|
|
||||||
var save = document.querySelector('[data-editsave]');
|
|
||||||
if (save && !save.disabled) save.click();
|
|
||||||
});
|
|
||||||
send('touch');
|
send('touch');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,6 +600,32 @@ addEventListener('scroll', function (ev) {
|
|||||||
if (box && box.scrollLeft && box.id !== 'folders') box.scrollLeft = 0;
|
if (box && box.scrollLeft && box.id !== 'folders') box.scrollLeft = 0;
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
// AUCUN CHAMP D'UNE VUE AU REPOS NE GARDE LE FOCUS.
|
||||||
|
//
|
||||||
|
// Meme origine que le glissement ci-dessus. La touche de validation du clavier
|
||||||
|
// demande "champ suivant", et le suivant dans le document est sur une vue
|
||||||
|
// rangee hors du cadre. On y atterrissait sans rien voir : le clavier changeait
|
||||||
|
// de forme - numerique pour le code, alphabetique pour la recherche - et ne se
|
||||||
|
// refermait plus, puisque le champ qui le tenait ouvert etait hors de l'ecran.
|
||||||
|
addEventListener('focusin', function (ev) {
|
||||||
|
var scr = ev.target.closest && ev.target.closest('.screen');
|
||||||
|
if (scr && scr.id !== view) ev.target.blur();
|
||||||
|
});
|
||||||
|
|
||||||
|
// La validation ferme le clavier au lieu de sauter au champ suivant. Dans
|
||||||
|
// l'editeur, elle enregistre : c'est ce qu'on attend de cette touche apres
|
||||||
|
// avoir tape un mot de passe.
|
||||||
|
addEventListener('keydown', function (ev) {
|
||||||
|
var el = ev.target;
|
||||||
|
if (ev.key !== 'Enter' || !el.classList || !el.classList.contains('field-in'))
|
||||||
|
return;
|
||||||
|
ev.preventDefault();
|
||||||
|
el.blur();
|
||||||
|
if (el.id !== 'editval') return;
|
||||||
|
var save = document.querySelector('[data-editsave]');
|
||||||
|
if (save && !save.disabled) save.click();
|
||||||
|
});
|
||||||
|
|
||||||
function goList() {
|
function goList() {
|
||||||
document.body.classList.remove('on-detail');
|
document.body.classList.remove('on-detail');
|
||||||
document.body.classList.add('on-list');
|
document.body.classList.add('on-list');
|
||||||
@@ -644,9 +652,6 @@ var PM = {
|
|||||||
renderRows();
|
renderRows();
|
||||||
},
|
},
|
||||||
|
|
||||||
setDebug: function (on) {
|
|
||||||
document.getElementById('btnWriteTest').hidden = !on;
|
|
||||||
},
|
|
||||||
/// Sort du mode edition sans rien demander a Delphi. Sert aux refus
|
/// Sort du mode edition sans rien demander a Delphi. Sert aux refus
|
||||||
/// immediats : l'editeur y restait ouvert, boutons desactives, et Cancel
|
/// immediats : l'editeur y restait ouvert, boutons desactives, et Cancel
|
||||||
/// lui-meme ne repondait plus.
|
/// lui-meme ne repondait plus.
|
||||||
|
|||||||
-65
@@ -196,7 +196,6 @@ type
|
|||||||
{$IFDEF DEBUG}
|
{$IFDEF DEBUG}
|
||||||
procedure CryptoSelfCheck;
|
procedure CryptoSelfCheck;
|
||||||
procedure PatchSelfCheck;
|
procedure PatchSelfCheck;
|
||||||
procedure WriteTest;
|
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
procedure OpenEntry(AVaultIndex: Integer);
|
procedure OpenEntry(AVaultIndex: Integer);
|
||||||
procedure SaveEntryPassword(const ANewValue: string);
|
procedure SaveEntryPassword(const ANewValue: string);
|
||||||
@@ -302,7 +301,6 @@ begin
|
|||||||
ShowUnlock;
|
ShowUnlock;
|
||||||
|
|
||||||
{$IFDEF DEBUG}
|
{$IFDEF DEBUG}
|
||||||
WebCall('PM.setDebug(true)');
|
|
||||||
// VERIFICATION DU CHIFFREMENT AVANT TOUTE ECRITURE REELLE (§4). Elle depose
|
// VERIFICATION DU CHIFFREMENT AVANT TOUTE ECRITURE REELLE (§4). Elle depose
|
||||||
// aussi un conteneur sur le disque prive, pour qu'il soit relu par l'AUTRE
|
// aussi un conteneur sur le disque prive, pour qu'il soit relu par l'AUTRE
|
||||||
// implementation : un aller-retour avec soi-meme ne prouve que la coherence
|
// implementation : un aller-retour avec soi-meme ne prouve que la coherence
|
||||||
@@ -708,65 +706,6 @@ begin
|
|||||||
end).Start;
|
end).Start;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
/// Essai du chemin d'ecriture, VERS UN AUTRE FICHIER que le coffre.
|
|
||||||
///
|
|
||||||
/// Le premier PUT est le moment ou une erreur de transport se paie en donnees
|
|
||||||
/// perdues : un corps mal forme, un sha mal place, et vault-sync.json est
|
|
||||||
/// remplace par quelque chose que personne ne sait relire. L'ecrire d'abord
|
|
||||||
/// sous un autre nom prouve exactement les memes choses - enveloppe, jeton,
|
|
||||||
/// droits, sha rendu - sans mettre le coffre en jeu une seule fois.
|
|
||||||
procedure TForm8.WriteTest;
|
|
||||||
var
|
|
||||||
LUrl: string;
|
|
||||||
begin
|
|
||||||
if FBusy then Exit;
|
|
||||||
SetBusy(True);
|
|
||||||
// Meme depot, autre fichier : on remplace le dernier segment du chemin.
|
|
||||||
LUrl := FUrl.Substring(0, FUrl.LastIndexOf('/') + 1) + 'write-test.json';
|
|
||||||
TThread.CreateAnonymousThread(
|
|
||||||
procedure
|
|
||||||
var
|
|
||||||
LClient: TSyncClient;
|
|
||||||
LRes, LGet: TSyncResult;
|
|
||||||
LBody, LSha: string;
|
|
||||||
begin
|
|
||||||
LClient := TSyncClient.Create(LUrl, FToken);
|
|
||||||
try
|
|
||||||
LBody := EncryptContainer(
|
|
||||||
Format('{"probe":"write path","at":"%s"}',
|
|
||||||
[FormatDateTime('yyyy-mm-dd"T"hh:nn:ss"Z"',
|
|
||||||
TTimeZone.Local.ToUniversalTime(Now))]),
|
|
||||||
FSyncPwd, 1000);
|
|
||||||
// LIRE D'ABORD, ECRIRE ENSUITE - la sequence reelle. Un sha vide veut
|
|
||||||
// dire « cree », et Gitea refuse alors en 422 si le fichier est deja
|
|
||||||
// la ; c'est le cas de mise a jour qui compte, et il exige le sha
|
|
||||||
// courant. Un 404 au GET signifie simplement qu'il n'existe pas
|
|
||||||
// encore : on cree, sha vide.
|
|
||||||
LGet := LClient.Fetch;
|
|
||||||
if LGet.Status = ssOK then
|
|
||||||
LSha := LGet.ETag
|
|
||||||
else
|
|
||||||
LSha := '';
|
|
||||||
Log(Format('GET first: HTTP %d, sha %s', [LGet.HttpCode,
|
|
||||||
IfThen(LSha = '', '(aucun - creation)', LSha)]));
|
|
||||||
|
|
||||||
Log('PUT ' + LUrl);
|
|
||||||
Log(Format(' token %s (%d chars), body %d chars',
|
|
||||||
[Fingerprint(FToken), Length(FToken), Length(LBody)]));
|
|
||||||
LRes := LClient.Put(LBody, LSha, 'write path probe from phone');
|
|
||||||
case LRes.Status of
|
|
||||||
ssOK: Log(' OK ' + LRes.HttpCode.ToString + ' - new sha ' + LRes.ETag);
|
|
||||||
ssConflict: Log(' 409 - file already there, concurrency control works');
|
|
||||||
else
|
|
||||||
Log(' failed: ' + LRes.HttpCode.ToString + ' ' + LRes.Error);
|
|
||||||
end;
|
|
||||||
finally
|
|
||||||
LClient.Free;
|
|
||||||
TThread.Queue(nil, procedure begin SetBusy(False); end);
|
|
||||||
end;
|
|
||||||
end).Start;
|
|
||||||
end;
|
|
||||||
|
|
||||||
/// Descend les coordonnees du serveur dans les champs de la page.
|
/// Descend les coordonnees du serveur dans les champs de la page.
|
||||||
procedure TForm8.PushConfig;
|
procedure TForm8.PushConfig;
|
||||||
var
|
var
|
||||||
@@ -896,10 +835,6 @@ begin
|
|||||||
// porte est detruite, et HandleWebCommand ne journalise que l'action.
|
// porte est detruite, et HandleWebCommand ne journalise que l'action.
|
||||||
else if LAction = 'setpwd' then
|
else if LAction = 'setpwd' then
|
||||||
SaveEntryPassword(TNetEncoding.URL.Decode(Param('v')))
|
SaveEntryPassword(TNetEncoding.URL.Decode(Param('v')))
|
||||||
{$IFDEF DEBUG}
|
|
||||||
else if LAction = 'writetest' then
|
|
||||||
WriteTest
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
else if LAction = 'copy' then
|
else if LAction = 'copy' then
|
||||||
begin
|
begin
|
||||||
|
|||||||
Reference in New Issue
Block a user