fix(apk): le crayon par ligne disparait, l'edition passe par le formulaire

L'editeur d'une ligne n'a plus de bouton : sa machinerie part avec lui. Seule
la liste des dossiers en est gardee (folderSelect), pour que le champ Folder du
formulaire reste un choix et non une faute de frappe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-09-25 15:05:58 +01:00
parent 0c12997ad4
commit 0f90b816fc
+14 -107
View File
@@ -1093,8 +1093,6 @@ function renderDetail(d) {
+ (r.a === undefined ? ''
: '<button class="btn ico-btn" data-save="' + i + '">'
+ ico('down', 'Save to Downloads') + '</button>')
+ (r.e ? '<button class="btn ico-btn" data-edit="' + i + '">'
+ ico('edit', 'Edit') + '</button>' : '')
+ '</div></div>';
}
document.getElementById('fields').innerHTML = html;
@@ -1136,43 +1134,6 @@ document.getElementById('fields').addEventListener('click', function (ev) {
if (copy === 'totp') { send('copy?f=totp'); return; }
if (copy === 'row') { send('copy?f=row&k=' + t.getAttribute('data-k')); return; }
var edit = t.getAttribute('data-edit');
if (edit !== null) { openEditor(edit); return; }
if (t.getAttribute('data-editshow') !== null) {
// Masque par defaut, revelable a la demande : on tape un mot de passe
// qu'on ne peut relire nulle part ailleurs, mais il n'a pas a rester
// expose a l'ecran pendant qu'on cherche le bouton.
var iv = document.getElementById('editval');
var hid = iv.type === 'password';
iv.type = hid ? 'text' : 'password';
t.innerHTML = ico(hid ? 'eyeOff' : 'eye', hid ? 'Hide' : 'Show');
return;
}
if (t.getAttribute('data-editcancel') !== null) { renderDetail(lastDetail); return; }
if (t.getAttribute('data-editsave') !== null) {
var input = document.getElementById('editval');
if (!input) return;
// VIDER EST LEGITIME sur un site ou un identifiant - pas sur un mot de
// passe, ou ce serait presque toujours une fausse manoeuvre. Le refus se
// dit, sinon le bouton semble ne pas prendre l'appui.
if (!input.value && editField === 'password') {
toast('An empty password is not saved');
return;
}
// DIRE QUE CA TRAVAILLE. L'enregistrement dechiffre, rechiffre et publie :
// une a deux secondes pendant lesquelles rien ne bougeait, et le bouton
// semblait n'avoir pas pris l'appui. La coche cede la place a un arc qui
// tourne - immobile, elle laisserait croire que c'est fini.
t.innerHTML = ico('loader', 'Saving');
t.classList.add('spin');
t.disabled = true;
var cancel = document.querySelector('[data-editcancel]');
if (cancel) cancel.disabled = true;
input.disabled = true;
send('setfield?f=' + encodeURIComponent(editField)
+ '&v=' + encodeURIComponent(input.value));
return;
}
});
/// LE DOSSIER SE CHOISIT, il ne se tape pas.
@@ -1184,40 +1145,22 @@ document.getElementById('fields').addEventListener('click', function (ev) {
///
/// 'All' est ajoute d'office : c'est le dossier par defaut du poste, et il ne
/// figure pas toujours dans la liste.
function editorControl(k) {
var val = detailRows[k].v;
var style = ' style="margin:0;flex:1;min-width:0;width:auto"';
// UNE ZONE DE TEXTE POUR CE QUI TIENT SUR PLUSIEURS LIGNES. Un <input>
// applique la sanitisation de HTML et retire les retours a la ligne en
// silence : le corps d'une note y perdait sa mise en forme, et la perte
// partait au depot a l'enregistrement suivant.
if (detailRows[k].m)
return '<textarea class="field-in" id="editval" rows="6"'
+ ' enterkeyhint="enter" autocorrect="off" spellcheck="false"'
+ ' style="margin:0;flex:1;min-width:0;width:auto;height:auto;'
+ 'padding:10px 14px;resize:vertical"></textarea>';
if (editField !== 'folder')
return '<input class="field-in" id="editval" autocomplete="off"'
+ ' type="' + (detailRows[k].s ? 'password' : 'text') + '"'
+ ' autocorrect="off" autocapitalize="none" spellcheck="false"'
+ style + '>';
var names = ['All'], i;
/// La liste des dossiers du coffre, pour le champ 'folder' du formulaire.
/// Le dossier courant y est ajoute s'il n'y figure plus - renomme ailleurs, ou
/// venu d'un import -, sinon l'ouvrir suffirait a le remplacer en silence.
function folderSelect(val) {
var names = ['All'], i, html;
for (i = 0; i < folders.length; i++)
if (folders[i] && names.indexOf(folders[i]) < 0) names.push(folders[i]);
// Le dossier courant peut ne plus figurer dans la liste - il a ete renomme
// ailleurs, ou l'entree vient d'un import. Le proposer quand meme evite de
// le remplacer silencieusement en ouvrant simplement l'editeur.
if (val && names.indexOf(val) < 0) names.push(val);
var html = '<select class="field-in" id="editval"' + style + '>';
html = '<select class="field-in" data-ef="folder" style="' + FIELD_STYLE + '">';
for (i = 0; i < names.length; i++)
html += '<option value="' + esc(names[i]) + '"'
+ (names[i] === val ? ' selected' : '') + '>' + esc(names[i])
+ '</option>';
// CHOISIR NE SUFFIT PAS : le premier dossier d'un coffre n'existe pas encore,
// et rien ne permettait de le nommer. Cette option echange la liste contre un
// champ libre, sans quitter l'editeur.
// champ libre, sans quitter le formulaire.
html += '<option value="' + NEW_FOLDER + '">+ new folder</option>';
return html + '</select>';
}
@@ -1227,11 +1170,12 @@ var NEW_FOLDER = '\u0001new';
// Le choix "+ new folder" remplace la liste par un champ. Delegue sur #fields
// parce que le controle nait et meurt avec l'editeur.
document.getElementById('fields').addEventListener('change', function (ev) {
if (ev.target.id !== 'editval' || ev.target.value !== NEW_FOLDER) return;
if (ev.target.getAttribute('data-ef') !== 'folder'
|| ev.target.value !== NEW_FOLDER) return;
var line = ev.target.parentNode;
var input = document.createElement('input');
input.className = 'field-in';
input.id = 'editval';
input.setAttribute('data-ef', 'folder');
input.setAttribute('placeholder', 'folder name');
input.setAttribute('autocomplete', 'off');
input.setAttribute('autocapitalize', 'none');
@@ -1256,44 +1200,6 @@ document.getElementById('fields').addEventListener('change', function (ev) {
input.focus();
});
// EDITEUR EN PLACE, pas window.prompt : une invite JavaScript demande au
// moteur un WebChromeClient que FMX ne fournit pas, et prompt() rend alors
// null sans un mot - le bouton semblerait ne rien faire.
//
// La valeur s'affiche EN CLAIR pendant la saisie. On tape un mot de passe
// qu'on ne peut pas relire ailleurs ; le masquer ferait valider a l'aveugle
// une frappe qu'aucune confirmation ne rattrape.
var editField = '';
function openEditor(k) {
var row = document.querySelector('[data-v="' + k + '"]');
if (!row) return;
// 'e' porte le nom du champ dans l'instantane, pas un booleen : c'est Delphi
// qui decide de ce qui se modifie, la page n'a pas a le deduire d'un libelle.
editField = detailRows[k].e || '';
if (!editField) return;
var line = row.parentNode;
line.classList.toggle('wrap', !!detailRows[k].m);
line.innerHTML = editorControl(k)
+ (editField === 'password' ? genButton('editval') : '')
// Show n'a de sens que sur un champ masque. Sur un site en clair il
// n'aurait rien a reveler - et l'inverse : il le CACHERAIT.
//
// LES TROIS EN ICONES, comme les lignes au-dessus : ils partageaient la
// rangee avec le champ de saisie, et trois mots y laissaient a peine de
// quoi lire ce qu'on tape. La croix et la coche se lisent sans traduction.
+ (detailRows[k].s ? '<button class="btn ico-btn" data-editshow>'
+ ico('eye', 'Show') + '</button>' : '')
+ '<button class="btn ico-btn" data-editcancel>'
+ ico('close', 'Cancel') + '</button>'
+ '<button class="btn ico-btn main" data-editsave>'
+ ico('check', 'Save') + '</button>';
var input = document.getElementById('editval');
input.value = detailRows[k].v;
input.focus();
send('touch');
}
// RIEN NE GLISSE DE COTE, sauf la bande de dossiers.
//
// overflow:hidden n'interdit que le GESTE. Le moteur, lui, garde le droit de
@@ -1378,8 +1284,9 @@ addEventListener('keydown', function (ev) {
if (el.tagName === 'TEXTAREA') return;
ev.preventDefault();
el.blur();
if (el.id !== 'editval') return;
var save = document.querySelector('[data-editsave]');
// Entree sur un champ du formulaire = enregistrer, comme la coche d'avant.
if (!el.getAttribute('data-ef')) return;
var save = document.getElementById('eSave');
if (save && !save.disabled) save.click();
});
@@ -1593,7 +1500,7 @@ function openEditEntry() {
if (!r.e) continue;
html += '<div class="field"><div class="cap">' + esc(r.c) + '</div><div class="line'
+ (r.m ? ' wrap' : '') + '">'
+ (r.m
+ (r.e === 'folder' ? folderSelect(r.v) : r.m
? '<textarea class="field-in" data-ef="' + esc(r.e) + '" rows="5"'
+ ' autocorrect="off" spellcheck="false" style="' + FIELD_STYLE
+ ';height:auto;resize:vertical">' + esc(r.v) + '</textarea>'