From e332e7932806beef282c9594aab1fc3704cb58cc Mon Sep 17 00:00:00 2001 From: AlasdairSwan Date: Thu, 23 Oct 2014 09:21:05 -0400 Subject: [PATCH] ECOM-369 Moved to Base FormView extended by other views. --- .../js/spec_helpers/edx.utils.validate.js | 82 +++++++- lms/envs/common.py | 3 +- .../js/student_account/views/AccessView.js | 75 +++++++- .../js/student_account/views/FormView.js | 176 ++++++++++++++++++ .../js/student_account/views/LoginView.js | 151 +++------------ .../views/PasswordResetView.js | 111 ++--------- .../js/student_account/views/RegisterView.js | 140 +------------- lms/static/sass/views/_login-register.scss | 75 ++++++++ .../student_account/form_field.underscore | 4 +- .../student_account/login.underscore | 19 +- .../student_account/password_reset.underscore | 20 +- .../student_account/register.underscore | 20 +- 12 files changed, 470 insertions(+), 406 deletions(-) create mode 100644 lms/static/js/student_account/views/FormView.js diff --git a/common/static/js/spec_helpers/edx.utils.validate.js b/common/static/js/spec_helpers/edx.utils.validate.js index 2e79413c7c..db1fe96063 100644 --- a/common/static/js/spec_helpers/edx.utils.validate.js +++ b/common/static/js/spec_helpers/edx.utils.validate.js @@ -9,12 +9,37 @@ var edx = edx || {}; var _fn = { validate: { - field: function( el ) { - var $el = $(el); + msg: { + email: '

A properly formatted e-mail is required

', + min: '

<%= field %> must be a minimum of <%= length %> characters long', + max: '

<%= field %> must be a maximum of <%= length %> characters long', + password: '

A valid password is required

', + required: '

<%= field %> field is required

', + terms: '

To enroll you must agree to the Terms of Service and Honor Code

' + }, - return _fn.validate.required( $el ) && - _fn.validate.charLength( $el ) && - _fn.validate.email.valid( $el ); + field: function( el ) { + var $el = $(el), + required = _fn.validate.required( $el ), + // length = _fn.validate.charLength( $el ), + min = _fn.validate.str.minlength( $el ), + max = _fn.validate.str.maxlength( $el ), + email = _fn.validate.email.valid( $el ), + response = { + isValid: required && min && max && email + }; + + if ( !response.isValid ) { + response.message = _fn.validate.getMessage( $el, { + required: required, + // length: length, + min: min, + max: max, + email: email + }); + } + + return response; }, charLength: function( $el ) { @@ -39,11 +64,30 @@ var edx = edx || {}; return within; }, - required: function( $el ) { - if ($el.attr("type") === "checkbox") { - return $el.attr('required') ? $el.prop("checked") : true; + str: { + minlength: function( $el ) { + var min = $el.attr('minlength') || 0; + + return min <= $el.val().length; + }, + + maxlength: function( $el ) { + var max = $el.attr('maxlength') || false; + + return ( !!max ) ? max >= $el.val().length : true; + }, + + capitalizeFirstLetter: function( str ) { + str = str.replace('_', ' '); + + return str.charAt(0).toUpperCase() + str.slice(1); } - else { + }, + + required: function( $el ) { + if ( $el.attr('type') === 'checkbox' ) { + return $el.attr('required') ? $el.prop('checked') : true; + } else { return $el.attr('required') ? $el.val() : true; } }, @@ -66,6 +110,26 @@ var edx = edx || {}; format: function( str ) { return _fn.validate.email.regex.test( str ); } + }, + + getMessage: function( $el, tests ) { + var txt = [], + tpl, + name; + + _.each( tests, function( value, key ) { + if ( !value ) { + name = $el.attr('name'); + + tpl = _fn.validate.msg[key]; + + txt.push( _.template( tpl, { + field: _fn.validate.str.capitalizeFirstLetter( name ) + })); + } + }); + + return txt.join(' '); } } }; diff --git a/lms/envs/common.py b/lms/envs/common.py index 36e9986e64..9820b16ae3 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1030,6 +1030,7 @@ student_account_js = [ 'js/student_account/models/LoginModel.js', 'js/student_account/models/RegisterModel.js', 'js/student_account/models/PasswordResetModel.js', + 'js/student_account/views/FormView.js', 'js/student_account/views/LoginView.js', 'js/student_account/views/RegisterView.js', 'js/student_account/views/PasswordResetView.js', @@ -1549,7 +1550,7 @@ REGISTRATION_EXTRA_FIELDS = { 'honor_code': 'required', 'terms_of_service': 'hidden', 'city': 'hidden', - 'country': 'required', + 'country': 'hidden', } ########################## CERTIFICATE NAME ######################## diff --git a/lms/static/js/student_account/views/AccessView.js b/lms/static/js/student_account/views/AccessView.js index ec42ac8be2..dc2a45953f 100644 --- a/lms/static/js/student_account/views/AccessView.js +++ b/lms/static/js/student_account/views/AccessView.js @@ -52,18 +52,79 @@ var edx = edx || {}; }, loadForm: function( type ) { - if ( type === 'login' ) { - this.subview.login = new edx.student.account.LoginView( this.thirdPartyAuth ); + if ( type === 'reset' ) { + this.load.reset( this ); + } else { + this.getFormData( type, this.load[type], this ); + } + }, + + load: { + login: function( data, context ) { + var model = new edx.student.account.LoginModel({ + url: data.submit_url + }); + + context.subview.login = new edx.student.account.LoginView({ + fields: data.fields, + model: model, + thirdPartyAuth: context.thirdPartyAuth + }); // Listen for 'password-help' event to toggle sub-views - this.listenTo( this.subview.login, 'password-help', this.resetPassword ); - } else if ( type === 'register' ) { - this.subview.register = new edx.student.account.RegisterView( this.thirdPartyAuth ); - } else if ( type === 'reset' ) { - this.subview.passwordHelp = new edx.student.account.PasswordResetView(); + context.listenTo( context.subview.login, 'password-help', context.resetPassword ); + }, + + reset: function( context ) { + var model = new edx.student.account.PasswordResetModel(), + data = [{ + label: 'E-mail', + instructions: 'This is the e-mail address you used to register with edX', + name: 'email', + required: true, + type: 'email', + restrictions: [], + defaultValue: '' + }]; + + context.subview.passwordHelp = new edx.student.account.PasswordResetView({ + fields: data, + model: model + }); + }, + + register: function( data, context ) { + var model = new edx.student.account.RegisterModel({ + url: data.submit_url + }); + + context.subview.register = new edx.student.account.RegisterView({ + fields: data.fields, + model: model, + thirdPartyAuth: context.thirdPartyAuth + }); } }, + getFormData: function( type, callback, context ) { + var urls = { + login: 'login_session', + register: 'registration' + }; + + $.ajax({ + type: 'GET', + dataType: 'json', + url: '/user_api/v1/account/' + urls[type] + '/', + success: function( data ) { + callback( data, context ); + }, + error: function( jqXHR, textStatus, errorThrown ) { + console.log('fail ', errorThrown); + } + }); + }, + resetPassword: function() { this.$header.addClass('hidden'); $(this.el).find('.form-type').addClass('hidden'); diff --git a/lms/static/js/student_account/views/FormView.js b/lms/static/js/student_account/views/FormView.js new file mode 100644 index 0000000000..18460a9626 --- /dev/null +++ b/lms/static/js/student_account/views/FormView.js @@ -0,0 +1,176 @@ +var edx = edx || {}; + +(function($, _, Backbone, gettext) { + 'use strict'; + + edx.student = edx.student || {}; + edx.student.account = edx.student.account || {}; + + edx.student.account.FormView = Backbone.View.extend({ + tagName: 'form', + + el: '', + + tpl: '', + + fieldTpl: '#form_field-tpl', + + events: {}, + + errors: [], + + formType: '', + + $form: {}, + + fields: [], + + // String to append to required label fields + requiredStr: '*', + + initialize: function( data ) { + this.tpl = $(this.tpl).html(); + this.fieldTpl = $(this.fieldTpl).html(); + + this.buildForm( data.fields ); + this.model = data.model; + + this.listenTo( this.model, 'error', this.modelError ); + }, + + // Renders the form. + render: function( html ) { + var fields = html || ''; + + $(this.el).html( _.template( this.tpl, { + fields: fields + })); + + this.postRender(); + + return this; + }, + + postRender: function() { + var $container = $(this.el); + + this.$form = $container.find('form'); + this.$errors = $container.find('.submission-error'); + }, + + buildForm: function( data ) { + var html = [], + i, + len = data.length, + fieldTpl = this.fieldTpl; + + this.fields = data; + + for ( i=0; i <% } %> + <% if ( required && requiredStr ) { %> <%= requiredStr %><% } %> <% } %> @@ -34,7 +34,7 @@ <% if ( type === 'checkbox' ) { %> <% } %> + <% if ( required && requiredStr ) { %> <%= requiredStr %><% } %> <% } %> diff --git a/lms/templates/student_account/login.underscore b/lms/templates/student_account/login.underscore index b1ba59b49c..d92d26aa90 100644 --- a/lms/templates/student_account/login.underscore +++ b/lms/templates/student_account/login.underscore @@ -1,26 +1,21 @@
-