diff --git a/package.json b/package.json index 9c2c645ea2..ac72744af4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "react-dom": "^0.14.2", "react-gemini-scrollbar": "^2.0.1", "sanitize-html": "^1.11.1", - "velocity-animate": "^1.2.3" + "velocity-animate": "^1.2.3", + "velocity-ui-pack": "^1.2.2" }, "//deps": "The loader packages are here because webpack in a project that depends on us needs them in this package's node_modules folder", "//depsbuglink": "https://github.com/webpack/webpack/issues/1472", diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js index f89d65d740..7b2808c72a 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/login/Registration.js @@ -159,6 +159,15 @@ module.exports = React.createClass({ case "RegistrationForm.ERR_PASSWORD_LENGTH": errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`; break; + case "RegistrationForm.ERR_EMAIL_INVALID": + errMsg = "This doesn't look like a valid email address"; + break; + case "RegistrationForm.ERR_USERNAME_INVALID": + errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores."; + break; + case "RegistrationForm.ERR_USERNAME_BLANK": + errMsg = "You need to enter a user name"; + break; default: console.error("Unknown error code: %s", errCode); errMsg = "An unknown error occurred."; diff --git a/src/components/views/login/RegistrationForm.js b/src/components/views/login/RegistrationForm.js index 534464a4ae..d59f6556d7 100644 --- a/src/components/views/login/RegistrationForm.js +++ b/src/components/views/login/RegistrationForm.js @@ -17,8 +17,15 @@ limitations under the License. 'use strict'; var React = require('react'); +var Velocity = require('velocity-animate'); +require('velocity-ui-pack'); var sdk = require('../../../index'); +var FIELD_EMAIL = 'field_email'; +var FIELD_USERNAME = 'field_username'; +var FIELD_PASSWORD = 'field_password'; +var FIELD_PASSWORD_CONFIRM = 'field_password_confirm'; + /** * A pure UI component which displays a registration form. */ @@ -50,31 +57,14 @@ module.exports = React.createClass({ email: this.props.defaultEmail, username: this.props.defaultUsername, password: null, - passwordConfirm: null + passwordConfirm: null, + fieldValid: {} }; }, onSubmit: function(ev) { ev.preventDefault(); - var pwd1 = this.refs.password.value.trim(); - var pwd2 = this.refs.passwordConfirm.value.trim() - - var errCode; - if (!pwd1 || !pwd2) { - errCode = "RegistrationForm.ERR_PASSWORD_MISSING"; - } - else if (pwd1 !== pwd2) { - errCode = "RegistrationForm.ERR_PASSWORD_MISMATCH"; - } - else if (pwd1.length < this.props.minPasswordLength) { - errCode = "RegistrationForm.ERR_PASSWORD_LENGTH"; - } - if (errCode) { - this.props.onError(errCode); - return; - } - var promise = this.props.onRegisterClick({ username: this.refs.username.value.trim(), password: pwd1, @@ -89,13 +79,110 @@ module.exports = React.createClass({ } }, + validateField: function(field_id) { + var pwd1 = this.refs.password.value.trim(); + var pwd2 = this.refs.passwordConfirm.value.trim() + + switch (field_id) { + case FIELD_EMAIL: + this.markFieldValid( + field_id, + this.refs.email.value == '' || !!this.refs.email.value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i), + "RegistrationForm.ERR_EMAIL_INVALID" + ); + break; + case FIELD_USERNAME: + // XXX: SPEC-1 + if (encodeURIComponent(this.refs.username.value) != this.refs.username.value) { + this.markFieldValid( + field_id, + false, + "RegistrationForm.ERR_USERNAME_INVALID" + ); + } else if (this.refs.username.value == '') { + this.markFieldValid( + field_id, + false, + "RegistrationForm.ERR_USERNAME_BLANK" + ); + } else { + this.markFieldValid(field_id, true); + } + break; + case FIELD_PASSWORD: + if (pwd1 == '') { + this.markFieldValid( + field_id, + false, + "RegistrationForm.ERR_PASSWORD_MISSING" + ); + } else if (pwd1.length < this.props.minPasswordLength) { + this.markFieldValid( + field_id, + false, + "RegistrationForm.ERR_PASSWORD_MISSING" + ); + } + break; + case FIELD_PASSWORD_CONFIRM: + if (pwd1 == '') { + this.markFieldValid( + field_id, false, + "RegistrationForm.ERR_PASSWORD_MISSING" + ); + } else if (pwd1 != pwd2) { + this.markFieldValid( + field_id, false, + "RegistrationForm.ERR_PASSWORD_LENGTH" + ); + } else { + this.markFieldValid(field_id, true); + } + break; + } + }, + + markFieldValid: function(field_id, val, error_code) { + var fieldValid = this.state.fieldValid; + fieldValid[field_id] = val; + this.setState({fieldValid: fieldValid}); + if (!val) { + Velocity(this.fieldElementById(field_id), "callout.shake", 300); + this.props.onError(error_code); + } + }, + + fieldElementById(field_id) { + switch (field_id) { + case FIELD_EMAIL: + return this.refs.email; + case FIELD_USERNAME: + return this.refs.username; + case FIELD_PASSWORD: + return this.refs.password; + case FIELD_PASSWORD_CONFIRM: + return this.refs.passwordConfirm; + } + }, + + _styleField: function(field_id, baseStyle) { + var style = baseStyle || {}; + if (this.state.fieldValid[field_id] === false) { + style['borderColor'] = 'red'; + } + return style; + }, + render: function() { + var self = this; var emailSection, registerButton; if (this.props.showEmail) { emailSection = ( + defaultValue={this.state.email} + style={this._styleField(FIELD_EMAIL)} + onBlur={function() {self.validateField(FIELD_EMAIL)}} /> ); } if (this.props.onRegisterClick) { @@ -111,13 +198,19 @@ module.exports = React.createClass({



{registerButton}