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:
+14
-107
@@ -1093,8 +1093,6 @@ function renderDetail(d) {
|
|||||||
+ (r.a === undefined ? ''
|
+ (r.a === undefined ? ''
|
||||||
: '<button class="btn ico-btn" data-save="' + i + '">'
|
: '<button class="btn ico-btn" data-save="' + i + '">'
|
||||||
+ ico('down', 'Save to Downloads') + '</button>')
|
+ ico('down', 'Save to Downloads') + '</button>')
|
||||||
+ (r.e ? '<button class="btn ico-btn" data-edit="' + i + '">'
|
|
||||||
+ ico('edit', 'Edit') + '</button>' : '')
|
|
||||||
+ '</div></div>';
|
+ '</div></div>';
|
||||||
}
|
}
|
||||||
document.getElementById('fields').innerHTML = html;
|
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 === 'totp') { send('copy?f=totp'); return; }
|
||||||
if (copy === 'row') { send('copy?f=row&k=' + t.getAttribute('data-k')); 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.
|
/// 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
|
/// 'All' est ajoute d'office : c'est le dossier par defaut du poste, et il ne
|
||||||
/// figure pas toujours dans la liste.
|
/// figure pas toujours dans la liste.
|
||||||
function editorControl(k) {
|
/// La liste des dossiers du coffre, pour le champ 'folder' du formulaire.
|
||||||
var val = detailRows[k].v;
|
/// Le dossier courant y est ajoute s'il n'y figure plus - renomme ailleurs, ou
|
||||||
var style = ' style="margin:0;flex:1;min-width:0;width:auto"';
|
/// venu d'un import -, sinon l'ouvrir suffirait a le remplacer en silence.
|
||||||
// UNE ZONE DE TEXTE POUR CE QUI TIENT SUR PLUSIEURS LIGNES. Un <input>
|
function folderSelect(val) {
|
||||||
// applique la sanitisation de HTML et retire les retours a la ligne en
|
var names = ['All'], i, html;
|
||||||
// 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;
|
|
||||||
for (i = 0; i < folders.length; i++)
|
for (i = 0; i < folders.length; i++)
|
||||||
if (folders[i] && names.indexOf(folders[i]) < 0) names.push(folders[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);
|
if (val && names.indexOf(val) < 0) names.push(val);
|
||||||
|
html = '<select class="field-in" data-ef="folder" style="' + FIELD_STYLE + '">';
|
||||||
var html = '<select class="field-in" id="editval"' + style + '>';
|
|
||||||
for (i = 0; i < names.length; i++)
|
for (i = 0; i < names.length; i++)
|
||||||
html += '<option value="' + esc(names[i]) + '"'
|
html += '<option value="' + esc(names[i]) + '"'
|
||||||
+ (names[i] === val ? ' selected' : '') + '>' + esc(names[i])
|
+ (names[i] === val ? ' selected' : '') + '>' + esc(names[i])
|
||||||
+ '</option>';
|
+ '</option>';
|
||||||
// CHOISIR NE SUFFIT PAS : le premier dossier d'un coffre n'existe pas encore,
|
// 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
|
// 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>';
|
html += '<option value="' + NEW_FOLDER + '">+ new folder</option>';
|
||||||
return html + '</select>';
|
return html + '</select>';
|
||||||
}
|
}
|
||||||
@@ -1227,11 +1170,12 @@ var NEW_FOLDER = '\u0001new';
|
|||||||
// Le choix "+ new folder" remplace la liste par un champ. Delegue sur #fields
|
// Le choix "+ new folder" remplace la liste par un champ. Delegue sur #fields
|
||||||
// parce que le controle nait et meurt avec l'editeur.
|
// parce que le controle nait et meurt avec l'editeur.
|
||||||
document.getElementById('fields').addEventListener('change', function (ev) {
|
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 line = ev.target.parentNode;
|
||||||
var input = document.createElement('input');
|
var input = document.createElement('input');
|
||||||
input.className = 'field-in';
|
input.className = 'field-in';
|
||||||
input.id = 'editval';
|
input.setAttribute('data-ef', 'folder');
|
||||||
input.setAttribute('placeholder', 'folder name');
|
input.setAttribute('placeholder', 'folder name');
|
||||||
input.setAttribute('autocomplete', 'off');
|
input.setAttribute('autocomplete', 'off');
|
||||||
input.setAttribute('autocapitalize', 'none');
|
input.setAttribute('autocapitalize', 'none');
|
||||||
@@ -1256,44 +1200,6 @@ document.getElementById('fields').addEventListener('change', function (ev) {
|
|||||||
input.focus();
|
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.
|
// RIEN NE GLISSE DE COTE, sauf la bande de dossiers.
|
||||||
//
|
//
|
||||||
// overflow:hidden n'interdit que le GESTE. Le moteur, lui, garde le droit de
|
// 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;
|
if (el.tagName === 'TEXTAREA') return;
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
el.blur();
|
el.blur();
|
||||||
if (el.id !== 'editval') return;
|
// Entree sur un champ du formulaire = enregistrer, comme la coche d'avant.
|
||||||
var save = document.querySelector('[data-editsave]');
|
if (!el.getAttribute('data-ef')) return;
|
||||||
|
var save = document.getElementById('eSave');
|
||||||
if (save && !save.disabled) save.click();
|
if (save && !save.disabled) save.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1593,7 +1500,7 @@ function openEditEntry() {
|
|||||||
if (!r.e) continue;
|
if (!r.e) continue;
|
||||||
html += '<div class="field"><div class="cap">' + esc(r.c) + '</div><div class="line'
|
html += '<div class="field"><div class="cap">' + esc(r.c) + '</div><div class="line'
|
||||||
+ (r.m ? ' wrap' : '') + '">'
|
+ (r.m ? ' wrap' : '') + '">'
|
||||||
+ (r.m
|
+ (r.e === 'folder' ? folderSelect(r.v) : r.m
|
||||||
? '<textarea class="field-in" data-ef="' + esc(r.e) + '" rows="5"'
|
? '<textarea class="field-in" data-ef="' + esc(r.e) + '" rows="5"'
|
||||||
+ ' autocorrect="off" spellcheck="false" style="' + FIELD_STYLE
|
+ ' autocorrect="off" spellcheck="false" style="' + FIELD_STYLE
|
||||||
+ ';height:auto;resize:vertical">' + esc(r.v) + '</textarea>'
|
+ ';height:auto;resize:vertical">' + esc(r.v) + '</textarea>'
|
||||||
|
|||||||
Reference in New Issue
Block a user