code serveur pour la validation à la volée (#76632) #241
Loading…
Reference in New Issue
No description provided.
Delete Branch "wip/76632-error-live-check"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
1dff943bc8
to5157128421
5157128421
to5d91ca6e95
5d91ca6e95
to6e1c78d9e1
6e1c78d9e1
to4ffc69908c
4ffc69908c
toe442cfba16
e442cfba16
to6af0c162f8
6af0c162f8
to6d432eeaa1
6d432eeaa1
to21a8f4af13
21a8f4af13
to740bc5ebea
740bc5ebea
to205117eea4
205117eea4
to79e34bbb27
79e34bbb27
tof5ed99c0d1
f5ed99c0d1
tofbf9ddcab1
fbf9ddcab1
tocf2920d0de
@ -2357,3 +2357,3 @@
assert len(rsps.calls) == 1
assert '?xxx=FOO%20BAR%2030' in rsps.calls[-1].request.url
assert 'invalid value' not in resp
assert len(resp.pyquery('.error:not(#form_error_fieldname)')) == 0
Il y a toute une série de changements de ce type dans les tests, c'est parce que l'HTML incorpore désormais un
<template>
avec dedans une classe "error", qui se trouvait donc matchée.@ -538,3 +538,3 @@
formdef.data_class().wipe()
next_page = page.forms[0].submit('submit') # but the field is required
assert next_page.pyquery('div.error').text() == 'required field'
assert next_page.pyquery('#form_error_f0').text() == 'required field'
Ou pour la même raison, plutôt que viser le div.error, viser le div du champ précis.
@ -1974,1 +1974,4 @@
assert live_resp.json['result']['3']['content'] == '<p>Xbar {{ form_var_foo }}Ybar plopZ</p>'
def test_field_live_validation(pub):
C'est ici les vrais nouveaux tests.
@ -876,6 +876,7 @@ class WidgetField(Field):
prefill = {}
widget_class = None
widget_supports_live_validation = True
attribut pour déterminer qu'un champ gère la validation à la volée, ça permet derrière d'exclure les champs dépréciés type tableaux, exclus du périmètre.
@ -1639,6 +1641,7 @@ class FileField(WidgetField):
key = 'file'
description = _('File Upload')
allow_complex = True
widget_supports_live_validation = False
Les champs fichier aussi sont exclus mais c'est parce que la validation a déjà lieu lors du chargement du fichier.
@ -940,6 +949,16 @@ class FormPage(FormdefDirectoryBase, FormTemplateMixin):
def create_form(self, *args, **kwargs):
form = self.formdef.create_form(*args, **kwargs)
form.attrs['data-live-url'] = self.formdef.get_url(language=get_publisher().current_language) + 'live'
form.attrs['data-live-validation-url'] = (
C'est la présence de cet attribut qui détermine la prise en charge, ou pas, de la validation à la volée. (un moment j'ai hésité à partager data-live-url pour également y faire la validation, mais non).
@ -1670,0 +1702,4 @@
if not field_ref:
return result_error('missing ?field parameter')
parts = field_ref.split('__')
En paramètre c'est ?field={{widget.get_name_for_id}} qui est une méthode qui fournit le nom avec les $ (invalides dans les id) remplacés par des
__
, ici on fait la conversion inverse.@ -1670,0 +1703,4 @@
return result_error('missing ?field parameter')
parts = field_ref.split('__')
if len(parts) not in (1, 3):
S'il y a un morceau, c'est un champ normal, s'il y a trois morceaux, c'est un champ d'un bloc (f0$element0$f1).
@ -1670,0 +1721,4 @@
form = Form()
widget = field.add_to_form(form)
error = widget.get_error()
On crée un formulaire avec uniquement le champ qui nous intéresse, c'est pour ça que juste au-dessus pour le champ d'un bloc on modifie l'id, pour faire comme si c'était un champ direct.
On gagne du temps ici à ne pas créer de formdata temporaire etc. c'est possible parce que les validations sur les champs sont limitées aux données de celui-ci.
@ -1670,0 +1726,4 @@
resp = {'err': 1, 'msg': str(error)}
if hasattr(widget, 'error_code'):
error_message = ErrorMessage(widget.error_code, '')
resp[error_message.camel_code()] = True
On répond ici avec un format qui mime ce que l'API de validation javascript propose.
@ -181,0 +185,4 @@
self.message = message
def camel_code(self):
return ''.join(x.lower() if i == 0 else x.capitalize() for i, x in enumerate(self.code.split('_')))
C'est pour faire value_missing -> valueMissing, pour correspondre à l'API javascript.
@ -189,0 +223,4 @@
Widget.get_value_missing_message = lambda x: Widget.REQUIRED_ERROR
Widget.get_invalid_value_message = lambda x: _('Invalid value')
Widget.set_error = widget_set_error
Widget.set_error_code = widget_set_error_code
Introduction de cette série de méthodes sur Widget, on est toujours à monkeypatcher ainsi la classe de base dans quixote (il y aurait #5790 pour revoir ça).
@ -585,3 +623,3 @@
self.value = self.value.strip()
if self.maxlength and len(self.value) > self.maxlength:
self.error = _('Too long, value must be at most %d characters.') % self.maxlength
self.set_error_code('too_long')
Pour les codes connus de l'API javascript on les fournit comme ça.
@ -593,0 +635,4 @@
def get_error_message_codes(self):
yield from super().get_error_message_codes()
if self.maxlength:
yield 'too_long'
Et les messages et la liste des messages possibles (qui se trouveront posés en
<template>
) sont définis ici.@ -881,3 +939,3 @@
token = get_session().add_tempfile(self.get('file'), storage=self.storage)['token']
except UploadStorageError:
self.error = _('failed to store file (system error)')
self.set_error(_('failed to store file (system error)'))
Il y a des endroits où error était positionné directement, comme set_error() fait désormais un peu plus, on les change pour bien passer partout par set_error.
WIP: code serveur pour la validation à la volée (#76632)to code serveur pour la validation à la volée (#76632)cbbf9b8556
toa4a7b4c97f
@ -181,0 +210,4 @@
# always add codes that may be generated by javascript validation API
yield 'value_missing'
yield 'bad_input'
yield 'type_mismatch'
Il y a typeMismatch qui est généré en sortie d'un champ date dont le contenu est partiel (type j'ai juste mis le jour) et en regardant https://developer.mozilla.org/en-US/docs/Web/API/ValidityState j'ai vu badInput et j'ai décidé de remplacer ce que j'avais nommé "invalid_value" par "bad_input".