ui(apk): icone et nom en tete du formulaire, arrondis unifies, retour au formulaire apres une action d'icone
L'icone se commet comme un champ : Delphi rouvrait l'entree et la vue de lecture reprenait la place au milieu d'une modification. Le formulaire est maintenant rouvert avec ce qui y etait deja tape. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -257,6 +257,9 @@ begin
|
|||||||
LRoot := TJSONObject.Create;
|
LRoot := TJSONObject.Create;
|
||||||
try
|
try
|
||||||
LRoot.AddPair('title', AEntry.Display);
|
LRoot.AddPair('title', AEntry.Display);
|
||||||
|
// L'icone du moment, pour que le formulaire montre ce qu'il va changer.
|
||||||
|
LRoot.AddPair('icon', AEntry.IconB64);
|
||||||
|
LRoot.AddPair('initial', Initial(AEntry.Display));
|
||||||
LRoot.AddPair('totp', TJSONBool.Create(AEntry.Totp <> ''));
|
LRoot.AddPair('totp', TJSONBool.Create(AEntry.Totp <> ''));
|
||||||
LArr := TJSONArray.Create;
|
LArr := TJSONArray.Create;
|
||||||
LRoot.AddPair('rows', LArr);
|
LRoot.AddPair('rows', LArr);
|
||||||
|
|||||||
+53
-10
@@ -98,7 +98,10 @@
|
|||||||
.search { flex: 1; position: relative; }
|
.search { flex: 1; position: relative; }
|
||||||
.search input {
|
.search input {
|
||||||
width: 100%; height: 46px; padding: 0 38px 0 40px;
|
width: 100%; height: 46px; padding: 0 38px 0 40px;
|
||||||
border: 0; border-radius: var(--radius-s);
|
/* MEME ARRONDI QUE LES PASTILLES DE DOSSIER. Trois rayons differents se
|
||||||
|
voyaient d'un coup d'oeil sur le meme ecran : la recherche, les
|
||||||
|
pastilles, les boutons. Les deux premiers se touchent presque. */
|
||||||
|
border: 0; border-radius: 999px;
|
||||||
background: rgba(255,255,255,.10); color: var(--text);
|
background: rgba(255,255,255,.10); color: var(--text);
|
||||||
font-size: 15px; outline: none;
|
font-size: 15px; outline: none;
|
||||||
}
|
}
|
||||||
@@ -153,8 +156,9 @@
|
|||||||
text-overflow: ellipsis; white-space: nowrap; }
|
text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.txt span { display: block; color: var(--muted); font-size: 13px;
|
.txt span { display: block; color: var(--muted); font-size: 13px;
|
||||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
/* Les boutons prennent le meme arrondi que la recherche et les pastilles. */
|
||||||
.btn {
|
.btn {
|
||||||
flex: 0 0 auto; border: 0; border-radius: var(--radius-s);
|
flex: 0 0 auto; border: 0; border-radius: 999px;
|
||||||
background: var(--raised); color: var(--text);
|
background: var(--raised); color: var(--text);
|
||||||
padding: 11px 13px; font-size: 13px; font-family: inherit;
|
padding: 11px 13px; font-size: 13px; font-family: inherit;
|
||||||
}
|
}
|
||||||
@@ -1100,6 +1104,9 @@ function renderDetail(d) {
|
|||||||
document.body.classList.add('on-detail');
|
document.body.classList.add('on-detail');
|
||||||
view = 'detail';
|
view = 'detail';
|
||||||
send('state?view=detail');
|
send('state?view=detail');
|
||||||
|
// Retour au formulaire apres une action d'icone : elle passe par un
|
||||||
|
// enregistrement, donc par ce rendu-ci.
|
||||||
|
if (editAgain) openEditEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('fields').addEventListener('click', function (ev) {
|
document.getElementById('fields').addEventListener('click', function (ev) {
|
||||||
@@ -1127,7 +1134,15 @@ document.getElementById('fields').addEventListener('click', function (ev) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var ia = t.getAttribute('data-iconact');
|
var ia = t.getAttribute('data-iconact');
|
||||||
if (ia !== null) { send('icon?a=' + ia); return; }
|
if (ia !== null) {
|
||||||
|
// L'ICONE SE COMMET COMME LE RESTE, donc Delphi rouvre l'entree et la vue
|
||||||
|
// de lecture reprenait la place - on se retrouvait dehors sans avoir fini.
|
||||||
|
// Ce drapeau dit a renderDetail de rendre la main au formulaire, avec ce
|
||||||
|
// qui y etait deja tape.
|
||||||
|
editAgain = collectEditValues();
|
||||||
|
send('icon?a=' + ia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var save = t.getAttribute('data-save');
|
var save = t.getAttribute('data-save');
|
||||||
if (save !== null) { send('savefile?k=' + save); return; }
|
if (save !== null) { send('savefile?k=' + save); return; }
|
||||||
var copy = t.getAttribute('data-copy');
|
var copy = t.getAttribute('data-copy');
|
||||||
@@ -1491,10 +1506,35 @@ function openMenu() {
|
|||||||
// La page ne connait toujours pas le schema : elle rend une ligne par champ
|
// La page ne connait toujours pas le schema : elle rend une ligne par champ
|
||||||
// que Delphi a marque modifiable ('e' porte son nom), dans l'ordre qu'il a
|
// que Delphi a marque modifiable ('e' porte son nom), dans l'ordre qu'il a
|
||||||
// choisi. Ajouter un champ modifiable cote Delphi suffit a le voir ici.
|
// choisi. Ajouter un champ modifiable cote Delphi suffit a le voir ici.
|
||||||
|
/// Ce que le formulaire porte a cet instant, par nom de champ. Sert a le
|
||||||
|
/// rouvrir tel quel apres une action d'icone, qui passe par un enregistrement.
|
||||||
|
var editAgain = null;
|
||||||
|
|
||||||
|
function collectEditValues() {
|
||||||
|
var ins = document.querySelectorAll('#fields [data-ef]'), m = {}, i;
|
||||||
|
for (i = 0; i < ins.length; i++)
|
||||||
|
m[ins[i].getAttribute('data-ef')] = ins[i].value;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
function openEditEntry() {
|
function openEditEntry() {
|
||||||
if (!lastDetail) return;
|
if (!lastDetail) return;
|
||||||
closeMenu();
|
closeMenu();
|
||||||
var html = '<div class="form">', i, r;
|
// L'ICONE ET LE NOM EN TETE : on voit ce qu'on modifie, et surtout ce que
|
||||||
|
// les trois boutons d'en dessous vont remplacer.
|
||||||
|
var d = lastDetail;
|
||||||
|
var html = '<div class="form">'
|
||||||
|
+ '<div class="field"><div class="line" style="gap:12px">'
|
||||||
|
+ '<div class="av' + (d.icon ? ' has-img' : '') + '">'
|
||||||
|
+ (d.icon ? '<img src="' + esc(d.icon) + '">' : esc(d.initial || ''))
|
||||||
|
+ '</div>'
|
||||||
|
+ '<div class="val" style="font-size:16px;font-weight:600">'
|
||||||
|
+ esc(d.title || '') + '</div></div>'
|
||||||
|
+ '<div class="line" style="margin-top:8px">'
|
||||||
|
+ '<button class="btn" data-iconact="fetch">From site</button>'
|
||||||
|
+ '<button class="btn" data-iconact="pick">Image...</button>'
|
||||||
|
+ '<button class="btn" data-iconact="clear">Remove</button>'
|
||||||
|
+ '</div></div>', i, r;
|
||||||
for (i = 0; i < detailRows.length; i++) {
|
for (i = 0; i < detailRows.length; i++) {
|
||||||
r = detailRows[i];
|
r = detailRows[i];
|
||||||
if (!r.e) continue;
|
if (!r.e) continue;
|
||||||
@@ -1515,12 +1555,7 @@ function openEditEntry() {
|
|||||||
// L'ICONE SE CHANGE OU SE CHANGENT LES CHAMPS. Elle vivait dans le menu de
|
// L'ICONE SE CHANGE OU SE CHANGENT LES CHAMPS. Elle vivait dans le menu de
|
||||||
// l'entree, a cote de Supprimer : deux actions de nature opposee au meme
|
// l'entree, a cote de Supprimer : deux actions de nature opposee au meme
|
||||||
// endroit, et rien qui montre l'icone du moment.
|
// endroit, et rien qui montre l'icone du moment.
|
||||||
html += '<div class="field"><div class="cap">Icon</div><div class="line">'
|
html += '</div>'
|
||||||
+ '<button class="btn" data-iconact="fetch">From site</button>'
|
|
||||||
+ '<button class="btn" data-iconact="pick">Image...</button>'
|
|
||||||
+ '<button class="btn" data-iconact="clear">Remove</button>'
|
|
||||||
+ '</div></div>'
|
|
||||||
+ '</div>'
|
|
||||||
+ '<div class="line" style="display:flex;gap:8px;margin-top:12px">'
|
+ '<div class="line" style="display:flex;gap:8px;margin-top:12px">'
|
||||||
+ '<button class="btn wide" id="eCancel" style="flex:1">Cancel</button>'
|
+ '<button class="btn wide" id="eCancel" style="flex:1">Cancel</button>'
|
||||||
+ '<button class="btn main wide" id="eSave" style="flex:1">Save</button>'
|
+ '<button class="btn main wide" id="eSave" style="flex:1">Save</button>'
|
||||||
@@ -1530,6 +1565,14 @@ function openEditEntry() {
|
|||||||
renderDetail(lastDetail);
|
renderDetail(lastDetail);
|
||||||
});
|
});
|
||||||
document.getElementById('eSave').addEventListener('click', saveEditEntry);
|
document.getElementById('eSave').addEventListener('click', saveEditEntry);
|
||||||
|
if (editAgain) {
|
||||||
|
var ins = document.querySelectorAll('#fields [data-ef]'), i, f;
|
||||||
|
for (i = 0; i < ins.length; i++) {
|
||||||
|
f = ins[i].getAttribute('data-ef');
|
||||||
|
if (editAgain[f] !== undefined) ins[i].value = editAgain[f];
|
||||||
|
}
|
||||||
|
editAgain = null;
|
||||||
|
}
|
||||||
send('touch');
|
send('touch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user