diff options
author | Jiaan <3468028-jiaan@users.noreply.gitlab.com> | 2019-06-06 07:39:59 +0000 |
---|---|---|
committer | Kushal Pandya <kushalspandya@gmail.com> | 2019-06-06 07:39:59 +0000 |
commit | c38ea7e8843660ae9993ad8f515866113bbcc4f5 (patch) | |
tree | 243110d63235abff3cb8c0fcc9e4fe9be5dcc51e /app | |
parent | 5caffe48a9a8bc4d22a9949499cb5040e0f3f673 (diff) | |
download | gitlab-ce-c38ea7e8843660ae9993ad8f515866113bbcc4f5.tar.gz |
Resolve "Inline validation for user's name and username length"
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/emoji/no_emoji_validator.js | 44 | ||||
-rw-r--r-- | app/assets/javascripts/pages/sessions/new/index.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/pages/sessions/new/length_validator.js | 32 | ||||
-rw-r--r-- | app/assets/javascripts/validators/input_validator.js | 34 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/login.scss | 3 | ||||
-rw-r--r-- | app/views/devise/shared/_signup_box.html.haml | 12 |
6 files changed, 84 insertions, 43 deletions
diff --git a/app/assets/javascripts/emoji/no_emoji_validator.js b/app/assets/javascripts/emoji/no_emoji_validator.js index 0fd4dd74953..384d62a133a 100644 --- a/app/assets/javascripts/emoji/no_emoji_validator.js +++ b/app/assets/javascripts/emoji/no_emoji_validator.js @@ -1,10 +1,11 @@ import { __ } from '~/locale'; import emojiRegex from 'emoji-regex'; +import InputValidator from '../validators/input_validator'; -const invalidInputClass = 'gl-field-error-outline'; - -export default class NoEmojiValidator { +export default class NoEmojiValidator extends InputValidator { constructor(opts = {}) { + super(); + const container = opts.container || ''; this.noEmojiEmelents = document.querySelectorAll(`${container} .js-block-emoji`); @@ -19,45 +20,14 @@ export default class NoEmojiValidator { const { value } = this.inputDomElement; + this.errorMessage = __('Invalid input, please avoid emojis'); + this.validatePattern(value); this.setValidationStateAndMessage(); } validatePattern(value) { const pattern = emojiRegex(); - this.hasEmojis = new RegExp(pattern).test(value); - - if (this.hasEmojis) { - this.inputDomElement.setCustomValidity(__('Invalid input, please avoid emojis')); - } else { - this.inputDomElement.setCustomValidity(''); - } - } - - setValidationStateAndMessage() { - if (!this.inputDomElement.checkValidity()) { - this.setInvalidState(); - } else { - this.clearFieldValidationState(); - } - } - - clearFieldValidationState() { - this.inputDomElement.classList.remove(invalidInputClass); - this.inputErrorMessage.classList.add('hide'); - } - - setInvalidState() { - this.inputDomElement.classList.add(invalidInputClass); - this.setErrorMessage(); - } - - setErrorMessage() { - if (this.hasEmojis) { - this.inputErrorMessage.innerHTML = this.inputDomElement.validationMessage; - } else { - this.inputErrorMessage.innerHTML = this.inputDomElement.title; - } - this.inputErrorMessage.classList.remove('hide'); + this.invalidInput = new RegExp(pattern).test(value); } } diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js index e1a3f42a71f..3f5a3e15c2c 100644 --- a/app/assets/javascripts/pages/sessions/new/index.js +++ b/app/assets/javascripts/pages/sessions/new/index.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import LengthValidator from './length_validator'; import UsernameValidator from './username_validator'; import NoEmojiValidator from '../../../emoji/no_emoji_validator'; import SigninTabsMemoizer from './signin_tabs_memoizer'; @@ -6,6 +7,7 @@ import OAuthRememberMe from './oauth_remember_me'; import preserveUrlFragment from './preserve_url_fragment'; document.addEventListener('DOMContentLoaded', () => { + new LengthValidator(); // eslint-disable-line no-new new UsernameValidator(); // eslint-disable-line no-new new SigninTabsMemoizer(); // eslint-disable-line no-new new NoEmojiValidator(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/sessions/new/length_validator.js b/app/assets/javascripts/pages/sessions/new/length_validator.js new file mode 100644 index 00000000000..3d687ca08cc --- /dev/null +++ b/app/assets/javascripts/pages/sessions/new/length_validator.js @@ -0,0 +1,32 @@ +import InputValidator from '../../../validators/input_validator'; + +const errorMessageClass = 'gl-field-error'; + +export default class LengthValidator extends InputValidator { + constructor(opts = {}) { + super(); + + const container = opts.container || ''; + const validateLengthElements = document.querySelectorAll(`${container} .js-validate-length`); + + validateLengthElements.forEach(element => + element.addEventListener('input', this.eventHandler.bind(this)), + ); + } + + eventHandler(event) { + this.inputDomElement = event.target; + this.inputErrorMessage = this.inputDomElement.parentElement.querySelector( + `.${errorMessageClass}`, + ); + + const { value } = this.inputDomElement; + const { maxLengthMessage, maxLength } = this.inputDomElement.dataset; + + this.errorMessage = maxLengthMessage; + + this.invalidInput = value.length > parseInt(maxLength, 10); + + this.setValidationStateAndMessage(); + } +} diff --git a/app/assets/javascripts/validators/input_validator.js b/app/assets/javascripts/validators/input_validator.js new file mode 100644 index 00000000000..f37373977b8 --- /dev/null +++ b/app/assets/javascripts/validators/input_validator.js @@ -0,0 +1,34 @@ +const invalidInputClass = 'gl-field-error-outline'; + +export default class InputValidator { + constructor() { + this.inputDomElement = {}; + this.inputErrorMessage = {}; + this.errorMessage = null; + this.invalidInput = null; + } + + setValidationStateAndMessage() { + this.setValidationMessage(); + + const isInvalidInput = !this.inputDomElement.checkValidity(); + this.inputDomElement.classList.toggle(invalidInputClass, isInvalidInput); + this.inputErrorMessage.classList.toggle('hide', !isInvalidInput); + } + + setValidationMessage() { + if (this.invalidInput) { + this.inputDomElement.setCustomValidity(this.errorMessage); + this.inputErrorMessage.innerHTML = this.errorMessage; + } else { + this.resetValidationMessage(); + } + } + + resetValidationMessage() { + if (this.inputDomElement.validationMessage === this.errorMessage) { + this.inputDomElement.setCustomValidity(''); + this.inputErrorMessage.innerHTML = this.inputDomElement.title; + } + } +} diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index 297f642681b..d8aabecc036 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -73,7 +73,8 @@ .login-body { font-size: 13px; - input + p { + input + p, + input ~ p.field-validation { margin-top: 5px; } diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 383fd5130ce..5eba819172b 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -1,3 +1,5 @@ +- max_name_length = 128 +- max_username_length = 255 #register-pane.tab-pane.login-box{ role: 'tabpanel' } .login-body = form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name), html: { class: "new_new_user gl-show-field-errors", "aria-live" => "assertive" }) do |f| @@ -5,13 +7,13 @@ = render "devise/shared/error_messages", resource: resource .name.form-group = f.label :name, _('Full name'), class: 'label-bold' - = f.text_field :name, class: "form-control top qa-new-user-name js-block-emoji", required: true, title: _("This field is required.") + = f.text_field :name, class: "form-control top qa-new-user-name js-block-emoji js-validate-length", :data => { :max_length => max_name_length, :max_length_message => s_("SignUp|Name is too long (maximum is %{max_length} characters).") % { max_length: max_name_length } }, required: true, title: _("This field is required.") .username.form-group = f.label :username, class: 'label-bold' - = f.text_field :username, class: "form-control middle qa-new-user-username js-block-emoji", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.") - %p.validation-error.hide= _('Username is already taken.') - %p.validation-success.hide= _('Username is available.') - %p.validation-pending.hide= _('Checking username availability...') + = f.text_field :username, class: "form-control middle qa-new-user-username js-block-emoji js-validate-length", :data => { :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length } }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.") + %p.validation-error.field-validation.hide= _('Username is already taken.') + %p.validation-success.field-validation.hide= _('Username is available.') + %p.validation-pending.field-validation.hide= _('Checking username availability...') .form-group = f.label :email, class: 'label-bold' = f.email_field :email, class: "form-control middle qa-new-user-email", required: true, title: _("Please provide a valid email address.") |