diff --git a/common/static/js/utils/edx.utils.validate.js b/common/static/js/utils/edx.utils.validate.js index 60366c6630..de3281de6a 100644 --- a/common/static/js/utils/edx.utils.validate.js +++ b/common/static/js/utils/edx.utils.validate.js @@ -51,6 +51,8 @@ var edx = edx || {}; response.isValid = required && min && max && email; if ( !response.isValid ) { + _fn.validate.removeDefault( $el ); + response.message = _fn.validate.getMessage( $el, { required: required, min: min, @@ -162,6 +164,11 @@ var edx = edx || {}; }); return txt.join(' '); + }, + + // Removes the default HTML5 validation pop-up + removeDefault: function( $el ) { + $el.setCustomValidity(' '); } } }; diff --git a/lms/static/js/student_account/views/FormView.js b/lms/static/js/student_account/views/FormView.js index 4442d1f531..e8dcc768a9 100644 --- a/lms/static/js/student_account/views/FormView.js +++ b/lms/static/js/student_account/views/FormView.js @@ -28,6 +28,9 @@ var edx = edx || {}; // String to append to required label fields requiredStr: '*', + // Id of required footnote + requiredNote: 'register-footnote', + initialize: function( data ) { this.model = data.model; this.preRender( data ); @@ -71,7 +74,8 @@ var edx = edx || {}; var html = [], i, len = data.length, - fieldTpl = this.fieldTpl; + fieldTpl = this.fieldTpl, + requiredNote = ''; this.fields = data; @@ -80,9 +84,12 @@ var edx = edx || {}; data[i].errorMessages = this.escapeStrings( data[i].errorMessages ); } + requiredNote = data[i].required ? this.requiredNote : ''; + html.push( _.template( fieldTpl, $.extend( data[i], { form: this.formType, - requiredStr: this.requiredStr + requiredStr: this.requiredStr, + requiredNote: requiredNote }) ) ); } @@ -116,6 +123,21 @@ var edx = edx || {}; return obj; }, + focusFirstError: function() { + var $error = this.$form.find('.error').first(), + $field = {}, + $parent = {}; + + if ( $error.is('label') ) { + $parent = $error.parent('.form-field'); + $error = $parent.find('input') || $parent.find('select'); + } else { + $field = $error; + } + + $error.focus(); + }, + forgotPassword: function( event ) { event.preventDefault(); @@ -184,6 +206,9 @@ var edx = edx || {}; $('html,body').animate({ scrollTop: this.$errors.offset().top },'slow'); + + // Focus on first error field + this.focusFirstError(); }, submitForm: function( event ) { diff --git a/lms/static/js/student_account/views/RegisterView.js b/lms/static/js/student_account/views/RegisterView.js index fe8d28c013..6f20acaad5 100644 --- a/lms/static/js/student_account/views/RegisterView.js +++ b/lms/static/js/student_account/views/RegisterView.js @@ -18,6 +18,8 @@ var edx = edx || {}; formType: 'register', + requiredNote: 'register-footnote', + preRender: function( data ) { this.providers = data.thirdPartyAuth.providers || []; this.currentProvider = data.thirdPartyAuth.currentProvider || ''; diff --git a/lms/templates/student_account/form_field.underscore b/lms/templates/student_account/form_field.underscore index 46b13dd24d..42925b2ad6 100644 --- a/lms/templates/student_account/form_field.underscore +++ b/lms/templates/student_account/form_field.underscore @@ -10,8 +10,9 @@ minlength="<%= restrictions.min_length %>"<% } %> <% if ( restrictions.max_length ) { %> maxlength="<%= restrictions.max_length %>"<% } %> - <% if ( required ) { %> required<% } %> + <% if ( required ) { %> aria-required="true" required<% } %> <% if ( typeof errorMessages !== 'undefined' ) { _.each(errorMessages, function( msg, type ) {%> data-errormsg-<%= type %>="<%= msg %>" diff --git a/lms/templates/student_account/login.underscore b/lms/templates/student_account/login.underscore index 6cb07529ea..9e0b54b4d6 100644 --- a/lms/templates/student_account/login.underscore +++ b/lms/templates/student_account/login.underscore @@ -7,7 +7,7 @@ <% } %> -