Validation on focus leave.

Reduces the amount of async calls.
Challenging revalidation scheme.
This commit is contained in:
Carlos Nihelton 2022-05-16 17:03:54 -03:00
parent dbe131fb59
commit df8b157ae8
No known key found for this signature in database
GPG Key ID: 6FE346D245197E9A
1 changed files with 21 additions and 11 deletions

View File

@ -63,11 +63,16 @@ class RealnameEditor(StringEditor, WantsToKnowFormField):
class UsernameEditor(StringEditor, WantsToKnowFormField): class UsernameEditor(StringEditor, WantsToKnowFormField):
def __init__(self): def __init__(self):
self.on_lost_focus = None
self.valid_char_pat = r'[-a-z0-9_]' self.valid_char_pat = r'[-a-z0-9_]'
self.error_invalid_char = _("The only characters permitted in this " self.error_invalid_char = _("The only characters permitted in this "
"field are a-z, 0-9, _ and -") "field are a-z, 0-9, _ and -")
super().__init__() super().__init__()
def lost_focus(self):
if self.on_lost_focus is not None:
self.on_lost_focus(self.value)
def valid_char(self, ch): def valid_char(self, ch):
if len(ch) == 1 and not re.match(self.valid_char_pat, ch): if len(ch) == 1 and not re.match(self.valid_char_pat, ch):
self.bff.in_error = True self.bff.in_error = True
@ -87,9 +92,12 @@ class IdentityForm(Form):
def __init__(self, controller, initial): def __init__(self, controller, initial):
self.controller = controller self.controller = controller
self.validation_task = None self.validation_task = None
self.validation_result = UsernameValidation.OK
super().__init__(initial=initial) super().__init__(initial=initial)
connect_signal(self.username.widget, 'change', # Server validation is only applied on focus leave.
self.on_username_change) # While editting no previous server validaiton error should be shown.
connect_signal(self.username.widget, 'change', self._reset_validation)
self.username.widget.on_lost_focus = self.on_username_edit_complete
realname = RealnameField(_("Your name:")) realname = RealnameField(_("Your name:"))
hostname = UsernameField( hostname = UsernameField(
@ -99,7 +107,10 @@ class IdentityForm(Form):
password = PasswordField(_("Choose a password:")) password = PasswordField(_("Choose a password:"))
confirm_password = PasswordField(_("Confirm your password:")) confirm_password = PasswordField(_("Confirm your password:"))
def on_username_change(self, _, value): def _reset_validation(self, _, __):
self.validation_result = UsernameValidation.OK
def on_username_edit_complete(self, value):
if len(value) < 2: if len(value) < 2:
return return
@ -107,14 +118,13 @@ class IdentityForm(Form):
self.validation_task.cancel() self.validation_task.cancel()
self.validation_task = \ self.validation_task = \
schedule_task(self.controller.validate_username(value)) schedule_task(self._validate_async(value))
def username_validation_state(self): async def _validate_async(self, value):
task = self.validation_task self.validation_result = await self.controller.validate_username(value)
if task is None or not task.done(): # Retrigger field validation because it's not guaranteed that the async
return UsernameValidation.OK # call result will be available when the form fields are validated.
self.username.validate()
return task.result()
def validate_realname(self): def validate_realname(self):
if len(self.realname.value) > REALNAME_MAXLEN: if len(self.realname.value) > REALNAME_MAXLEN:
@ -149,7 +159,7 @@ class IdentityForm(Form):
return _( return _(
"Username must match USERNAME_REGEX: " + USERNAME_REGEX) "Username must match USERNAME_REGEX: " + USERNAME_REGEX)
state = self.username_validation_state() state = self.validation_result
if state == UsernameValidation.SYSTEM_RESERVED: if state == UsernameValidation.SYSTEM_RESERVED:
return _( return _(
'The username "{username}" is reserved for use by the system.' 'The username "{username}" is reserved for use by the system.'