fix(android): a note can be written on several lines, and Enter means Enter
The creation form still put a note's body behind a single-line input, so one could read and edit multi-line text but never create it - the note had to be created, then reopened to be laid out. And the newline could not be typed at all: the handler that turns the validate key into "fold the keyboard" applied to every field. That rule exists because in a one-line field the key can only jump to the next one, and the next one sat on an off-screen view - which is how the unclosable keyboard happened. In a text area, Enter means Enter. It is the third time that handler has misfired by treating "any field" as one thing; it now carries its three exceptions explicitly. Two things fixed in the same code, since they lived there: Rows were recognised BY THEIR LABEL - prose. Renaming a caption would have been enough for this code to stop acting on it, silently. They go by id now. And what is already typed survives a change of kind. Replacing the control without carrying the value over would have wiped the entry for a mere change of mind between Login and Note.
This commit is contained in:
+58
-23
@@ -852,7 +852,7 @@ function editorControl(k) {
|
|||||||
// partait au depot a l'enregistrement suivant.
|
// partait au depot a l'enregistrement suivant.
|
||||||
if (detailRows[k].m)
|
if (detailRows[k].m)
|
||||||
return '<textarea class="field-in" id="editval" rows="6"'
|
return '<textarea class="field-in" id="editval" rows="6"'
|
||||||
+ ' autocorrect="off" spellcheck="false"'
|
+ ' enterkeyhint="enter" autocorrect="off" spellcheck="false"'
|
||||||
+ ' style="margin:0;flex:1;min-width:0;width:auto;height:auto;'
|
+ ' style="margin:0;flex:1;min-width:0;width:auto;height:auto;'
|
||||||
+ 'padding:10px 14px;resize:vertical"></textarea>';
|
+ 'padding:10px 14px;resize:vertical"></textarea>';
|
||||||
if (editField !== 'folder')
|
if (editField !== 'folder')
|
||||||
@@ -1013,6 +1013,11 @@ addEventListener('keydown', function (ev) {
|
|||||||
var el = ev.target;
|
var el = ev.target;
|
||||||
if (ev.key !== 'Enter' || !el.classList || !el.classList.contains('field-in'))
|
if (ev.key !== 'Enter' || !el.classList || !el.classList.contains('field-in'))
|
||||||
return;
|
return;
|
||||||
|
// DANS UNE ZONE DE TEXTE, ENTREE VEUT DIRE ENTREE. Cette regle vaut pour les
|
||||||
|
// champs d'une ligne, ou la touche ne peut que sauter au suivant ; appliquee
|
||||||
|
// au corps d'une note, elle rendait impossible d'y sauter une ligne - le
|
||||||
|
// clavier semblait ne pas en avoir la touche.
|
||||||
|
if (el.tagName === 'TEXTAREA') return;
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
el.blur();
|
el.blur();
|
||||||
if (el.id !== 'editval') return;
|
if (el.id !== 'editval') return;
|
||||||
@@ -1042,12 +1047,28 @@ function newFolderField() {
|
|||||||
return html + '</select></div></div>';
|
return html + '</select></div></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function newField(id, label, type) {
|
var FIELD_STYLE = 'margin:0;flex:1;min-width:0;width:auto';
|
||||||
return '<div class="field"><div class="cap">' + label + '</div>'
|
|
||||||
+ '<div class="line"><input class="field-in" id="' + id + '" type="'
|
function newField(id, label, rowId) {
|
||||||
+ type + '" autocomplete="off" autocorrect="off" autocapitalize="none"'
|
return '<div class="field" id="' + rowId + '"><div class="cap">' + label
|
||||||
+ ' spellcheck="false" style="margin:0;flex:1;min-width:0;width:auto">'
|
+ '</div><div class="line"><input class="field-in" id="' + id + '"'
|
||||||
+ '</div></div>';
|
+ ' type="text" autocomplete="off" autocorrect="off"'
|
||||||
|
+ ' autocapitalize="none" spellcheck="false" style="' + FIELD_STYLE
|
||||||
|
+ '"></div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// LE CORPS D'UNE NOTE SE SAISIT SUR PLUSIEURS LIGNES. Un <input> applique la
|
||||||
|
/// sanitisation de HTML et retire les retours a la ligne : on pouvait lire et
|
||||||
|
/// modifier du multiligne, mais pas en creer - il fallait creer la note puis
|
||||||
|
/// l'ouvrir pour la mettre en forme.
|
||||||
|
function newBodyControl(kind) {
|
||||||
|
if (kind === 'note')
|
||||||
|
return '<textarea class="field-in" id="nPwd" rows="6" enterkeyhint="enter"'
|
||||||
|
+ ' autocorrect="off" spellcheck="false" style="' + FIELD_STYLE
|
||||||
|
+ ';height:auto;padding:10px 14px;resize:vertical"></textarea>';
|
||||||
|
return '<input class="field-in" id="nPwd" type="text" autocomplete="off"'
|
||||||
|
+ ' autocorrect="off" autocapitalize="none" spellcheck="false"'
|
||||||
|
+ ' style="' + FIELD_STYLE + '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
function openNewEntry() {
|
function openNewEntry() {
|
||||||
@@ -1059,12 +1080,13 @@ function openNewEntry() {
|
|||||||
+ '<button class="btn main" data-kind="login">Login</button>'
|
+ '<button class="btn main" data-kind="login">Login</button>'
|
||||||
+ '<button class="btn" data-kind="note">Note</button></div></div>'
|
+ '<button class="btn" data-kind="note">Note</button></div></div>'
|
||||||
+ newFolderField()
|
+ newFolderField()
|
||||||
+ newField('nTitle', 'Name', 'text')
|
+ newField('nTitle', 'Name', 'nTitleRow')
|
||||||
+ newField('nSite', 'Site', 'text')
|
+ newField('nSite', 'Site', 'nSiteRow')
|
||||||
+ newField('nUser', 'Username', 'text')
|
+ newField('nUser', 'Username', 'nUserRow')
|
||||||
// EN CLAIR pendant la saisie, comme l'editeur : on tape un mot de passe
|
// EN CLAIR pendant la saisie, comme l'editeur : on tape un mot de passe
|
||||||
// qu'aucune confirmation ne rattrape et qu'on ne peut relire nulle part.
|
// qu'aucune confirmation ne rattrape et qu'on ne peut relire nulle part.
|
||||||
+ newField('nPwd', 'Password', 'text')
|
+ '<div class="field" id="nBodyRow"><div class="cap">Password</div>'
|
||||||
|
+ '<div class="line">' + newBodyControl('login') + '</div></div>'
|
||||||
+ '<div class="field"><div class="line">'
|
+ '<div class="field"><div class="line">'
|
||||||
// flex:1 et non .wide : .wide ne regle que le rembourrage, et la largeur
|
// flex:1 et non .wide : .wide ne regle que le rembourrage, et la largeur
|
||||||
// pleine vient d'etre etire dans son conteneur.
|
// pleine vient d'etre etire dans son conteneur.
|
||||||
@@ -1082,20 +1104,33 @@ document.getElementById('fields').addEventListener('click', function (ev) {
|
|||||||
var kind = ev.target.getAttribute('data-kind');
|
var kind = ev.target.getAttribute('data-kind');
|
||||||
if (kind) {
|
if (kind) {
|
||||||
newKind = kind;
|
newKind = kind;
|
||||||
var all = document.querySelectorAll('[data-kind]');
|
var all = document.querySelectorAll('[data-kind]'), i;
|
||||||
for (var i = 0; i < all.length; i++)
|
for (i = 0; i < all.length; i++)
|
||||||
all[i].classList.toggle('main', all[i].getAttribute('data-kind') === kind);
|
all[i].classList.toggle('main', all[i].getAttribute('data-kind') === kind);
|
||||||
|
|
||||||
|
// PAR IDENTIFIANT, PAS PAR LIBELLE. Les rangees se reconnaissaient a leur
|
||||||
|
// intitule - de la prose - donc renommer un champ aurait suffi a ce que
|
||||||
|
// ce code cesse silencieusement d'agir sur lui.
|
||||||
|
//
|
||||||
|
// Une note n'a ni site ni identifiant : les laisser proposes revient a
|
||||||
|
// demander de remplir ce que rien n'affichera.
|
||||||
|
document.getElementById('nSiteRow').hidden = (kind === 'note');
|
||||||
|
document.getElementById('nUserRow').hidden = (kind === 'note');
|
||||||
|
|
||||||
// Le corps d'une note EST son mot de passe cote stockage : meme champ,
|
// Le corps d'une note EST son mot de passe cote stockage : meme champ,
|
||||||
// autre intitule, et rien a masquer.
|
// autre intitule, et rien a masquer - mais plusieurs lignes.
|
||||||
var caps = document.querySelectorAll('#fields .cap');
|
var row = document.getElementById('nBodyRow');
|
||||||
for (i = 0; i < caps.length; i++) {
|
row.querySelector('.cap').textContent =
|
||||||
if (caps[i].textContent === 'Password' || caps[i].textContent === 'Content')
|
(kind === 'note') ? 'Content' : 'Password';
|
||||||
caps[i].textContent = (kind === 'note') ? 'Content' : 'Password';
|
var line = row.querySelector('.line');
|
||||||
// Une note n'a ni site ni identifiant. Les laisser proposes revient a
|
// CE QUI EST DEJA TAPE SURVIT AU CHANGEMENT. Remplacer le controle sans le
|
||||||
// demander de remplir ce qui ne sera jamais affiche.
|
// reporter effacerait la saisie sans un mot, pour un simple changement
|
||||||
if (caps[i].textContent === 'Site' || caps[i].textContent === 'Username')
|
// d'avis sur le genre.
|
||||||
caps[i].parentNode.hidden = (kind === 'note');
|
var old = document.getElementById('nPwd');
|
||||||
}
|
var kept = old ? old.value : '';
|
||||||
|
line.classList.toggle('wrap', kind === 'note');
|
||||||
|
line.innerHTML = newBodyControl(kind);
|
||||||
|
document.getElementById('nPwd').value = kept;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ev.target.id !== 'nSave') return;
|
if (ev.target.id !== 'nSave') return;
|
||||||
|
|||||||
Reference in New Issue
Block a user