Commit b70dfb07 by AlasdairSwan

ECOM-369 added registration view and front end validation

parent bd0c5f22
var edx = edx || {};
(function( $, _ ) {
'use strict';
edx.utils = edx.utils || {};
var utils = (function(){
var _fn = {
validate: {
field: function( el ) {
var $el = $(el);
return _fn.validate.required( $el ) &&
_fn.validate.charLength( $el ) &&
_fn.validate.email.valid( $el );
},
charLength: function( $el ) {
// Cannot assume there will be both min and max
var min = $el.attr('minlength') || 0,
max = $el.attr('maxlength') || false,
chars = $el.val().length,
within = false;
// if max && min && within the range
if ( min <= chars && ( max && chars <= max ) ) {
within = true;
} else if ( min <= chars && !max ) {
within = true;
}
return within;
},
required: function( $el ) {
return $el.attr('required') ? $el.val() : true;
},
email: {
// This is the same regex used to validate email addresses in Django 1.4
regex: new RegExp(
[
'(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*',
'|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"',
')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+[A-Z]{2,6}\\.?$)',
'|\\[(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\]$'
].join(''), 'i'
),
valid: function( $el ) {
return $el.data('email') ? _fn.validate.email.format( $el.val() ) : true;
},
format: function( str ) {
return _fn.validate.email.regex.test( str );
}
}
}
};
return {
validate: _fn.validate.field
};
})();
edx.utils.validate = utils.validate
})( jQuery, _ );
\ No newline at end of file
...@@ -1026,8 +1026,11 @@ instructor_dash_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/ins ...@@ -1026,8 +1026,11 @@ instructor_dash_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/ins
# These are not courseware, so they do not need many of the courseware-specific # These are not courseware, so they do not need many of the courseware-specific
# JavaScript modules. # JavaScript modules.
student_account_js = [ student_account_js = [
'js/common_helpers/edx.utils.validate.js',
'js/student_account/models/LoginModel.js', 'js/student_account/models/LoginModel.js',
'js/student_account/models/RegisterModel.js',
'js/student_account/views/LoginView.js', 'js/student_account/views/LoginView.js',
'js/student_account/views/RegisterView.js',
'js/student_account/views/AccessView.js', 'js/student_account/views/AccessView.js',
'js/student_account/accessApp.js', 'js/student_account/accessApp.js',
] ]
......
var edx = edx || {};
(function($, _, Backbone, gettext) {
'use strict';
edx.student = edx.student || {};
edx.student.account = edx.student.account || {};
edx.student.account.RegisterModel = Backbone.Model.extend({
defaults: {
email: '',
name: '',
username: '',
password: '',
level_of_education: '',
gender: '',
year_of_birth: '',
mailing_address: '',
goals: '',
termsofservice: false
},
urlRoot: '',
initialize: function( obj ) {
this.urlRoot = obj.url;
},
sync: function(method, model) {
var headers = {
'X-CSRFToken': $.cookie('csrftoken')
};
$.ajax({
url: model.urlRoot,
type: 'POST',
data: model.attributes,
headers: headers
})
.done(function() {
var query = window.location.search,
url = '/dashboard';
// model.trigger('sync');
// If query string in url go back to that page
if ( query.length > 1 ) {
url = query.substring( query.indexOf('=') + 1 );
}
window.location.href = url;
})
.fail( function( error ) {
console.log('RegisterModel.save() FAILURE!!!!!');
model.trigger('error', error);
});
}
});
})(jQuery, _, Backbone, gettext);
\ No newline at end of file
...@@ -44,6 +44,9 @@ var edx = edx || {}; ...@@ -44,6 +44,9 @@ var edx = edx || {};
if ( type === 'login' ) { if ( type === 'login' ) {
console.log('load login'); console.log('load login');
return new edx.student.account.LoginView(); return new edx.student.account.LoginView();
} else if ( type === 'register' ) {
console.log('load register');
return new edx.student.account.RegisterView();
} }
// return new app.LoginView({ // return new app.LoginView({
......
...@@ -42,8 +42,10 @@ var edx = edx || {}; ...@@ -42,8 +42,10 @@ var edx = edx || {};
}, },
postRender: function() { postRender: function() {
var $container = $(this.el);
this.$form = $(this.el).find('form'); this.$form = $container.find('form');
this.$errors = $container.find('.error-msg');
}, },
getInitialData: function() { getInitialData: function() {
...@@ -81,10 +83,6 @@ var edx = edx || {}; ...@@ -81,10 +83,6 @@ var edx = edx || {};
fieldTpl = this.fieldTpl; fieldTpl = this.fieldTpl;
for ( i=0; i<len; i++ ) { for ( i=0; i<len; i++ ) {
if ( data[i].name === 'password' ) {
data[i].type = 'password';
}
html.push( _.template( fieldTpl, $.extend( data[i], { html.push( _.template( fieldTpl, $.extend( data[i], {
form: 'login' form: 'login'
}) ) ); }) ) );
...@@ -110,17 +108,17 @@ var edx = edx || {}; ...@@ -110,17 +108,17 @@ var edx = edx || {};
key = $el.attr('name') || false; key = $el.attr('name') || false;
if ( key ) { if ( key ) {
// if ( this.validate( elements[i] ) ) { if ( this.validate( elements[i] ) ) {
obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val(); obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val();
// $el.css('border', '1px solid #ccc'); $el.css('border', '1px solid #ccc');
// } else { } else {
// errors.push( key ); errors.push( key );
// $el.css('border', '2px solid red'); $el.css('border', '2px solid red');
// } }
} }
} }
//this.errors = errors; this.errors = errors;
return obj; return obj;
}, },
...@@ -150,10 +148,14 @@ var edx = edx || {}; ...@@ -150,10 +148,14 @@ var edx = edx || {};
toggleErrorMsg: function( show ) { toggleErrorMsg: function( show ) {
if ( show ) { if ( show ) {
console.log('show'); this.$errors.removeClass('hidden');
} else { } else {
console.log('hide'); this.$errors.addClass('hidden');
} }
},
validate: function( $el ) {
return edx.utils.validate( $el );
} }
}); });
......
var edx = edx || {};
(function($, _, Backbone, gettext) {
'use strict';
edx.student = edx.student || {};
edx.student.account = edx.student.account || {};
edx.student.account.RegisterView = Backbone.View.extend({
tagName: 'form',
el: '#register-form',
tpl: $('#register-tpl').html(),
fieldTpl: $('#form_field-tpl').html(),
events: {
'click .js-register': 'submitForm'
},
errors: [],
$form: {},
initialize: function( obj ) {
this.getInitialData();
},
// 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('.error-msg');
},
getInitialData: function() {
var that = this;
$.ajax({
type: 'GET',
dataType: 'json',
url: '/user_api/v1/account/registration/',
success: function( data ) {
console.log(data);
that.buildForm( data.fields );
that.initModel( data.submit_url, data.method );
},
error: function( jqXHR, textStatus, errorThrown ) {
console.log('fail ', errorThrown);
}
});
},
initModel: function( url, method ) {
this.model = new edx.student.account.RegisterModel({
url: url
});
this.listenTo( this.model, 'error', function( error ) {
console.log(error.status, ' error: ', error.responseText);
});
},
buildForm: function( data ) {
var html = [],
i,
len = data.length,
fieldTpl = this.fieldTpl;
for ( i=0; i<len; i++ ) {
html.push( _.template( fieldTpl, $.extend( data[i], {
form: 'register'
}) ) );
}
this.render( html.join('') );
},
getFormData: function() {
var obj = {},
$form = this.$form,
elements = $form[0].elements,
i,
len = elements.length,
$el,
key = '',
errors = [];
for ( i=0; i<len; i++ ) {
$el = $( elements[i] );
key = $el.attr('name') || false;
if ( key ) {
if ( this.validate( elements[i] ) ) {
obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val();
$el.css('border', '1px solid #ccc');
} else {
errors.push( key );
$el.css('border', '2px solid red');
}
}
}
this.errors = errors;
return obj;
},
submitForm: function( event ) {
var data = this.getFormData();
event.preventDefault();
console.log(data);
// console.log(this.model);
if ( !this.errors.length ) {
console.log('save me');
this.model.set( data );
console.log(this.model);
this.model.save();
this.toggleErrorMsg( false );
} else {
console.log('here are the errors ', this.errors);
this.toggleErrorMsg( true );
}
},
toggleErrorMsg: function( show ) {
if ( show ) {
this.$errors.removeClass('hidden');
} else {
this.$errors.addClass('hidden');
}
},
validate: function( $el ) {
return edx.utils.validate( $el );
}
});
})(jQuery, _, Backbone, gettext);
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<input type="radio" name="form" id="register-option" value="register" class="form-toggle" <% if ( mode === 'register' ) { %>checked<% } %> > <input type="radio" name="form" id="register-option" value="register" class="form-toggle" <% if ( mode === 'register' ) { %>checked<% } %> >
<label for"register-option">I am a new user</label> <label for"register-option">I am a new user</label>
</h2> </h2>
<div id="register-form" class="form-wrapper <% if ( mode === 'register' ) { %>hidden<% } %>"></div> <div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden<% } %>"></div>
</section> </section>
<section class="form-type"> <section class="form-type">
......
...@@ -10,11 +10,25 @@ ...@@ -10,11 +10,25 @@
<a href="#" class="forgot-password">Forgot password?</a> <a href="#" class="forgot-password">Forgot password?</a>
<% } %> <% } %>
<input id="<%= form %>-<%= name %>" type="<%= type %>" name="<%= name %>" aria-describedby="<%= form %>-<%= name %>-desc" <% if ( type === 'select' ) { %>
<% if ( restrictions.min_length ) { %> minlength="<%= restrictions.min_length %>"<% } %> <select id="<%= form %>-<%= name %>" name="<%= name %>" aria-describedby="<%= form %>-<%= name %>-desc">
<% if ( restrictions.max_length ) { %> maxlength="<%= restrictions.max_length %>"<% } %> <% _.each(options, function(el) { %>
<% if ( required ) { %> required<% } %> <option value="<%= el.value%>"><%= el.name %></option>
/> <% }); %>
</select>
<% } else if ( type === 'textarea' ) { %>
<textarea id="<%= form %>-<%= name %>" type="<%= type %>" name="<%= name %>" aria-describedby="<%= form %>-<%= name %>-desc"
<% if ( restrictions.min_length ) { %> minlength="<%= restrictions.min_length %>"<% } %>
<% if ( restrictions.max_length ) { %> maxlength="<%= restrictions.max_length %>"<% } %>
<% if ( required ) { %> required<% } %> >
</textarea>
<% } else { %>
<input id="<%= form %>-<%= name %>" type="<%= type %>" name="<%= name %>" aria-describedby="<%= form %>-<%= name %>-desc"
<% if ( restrictions.min_length ) { %> minlength="<%= restrictions.min_length %>"<% } %>
<% if ( restrictions.max_length ) { %> maxlength="<%= restrictions.max_length %>"<% } %>
<% if ( required ) { %> required<% } %>
/>
<% } %>
<% if ( type === 'checkbox' ) { %> <% if ( type === 'checkbox' ) { %>
<label for="<%= form %>-<%= name %>"> <label for="<%= form %>-<%= name %>">
......
<form id="login"> <form id="login">
<div class="error-msg hidden">
<h4>We couldn't log you in.</h4>
<div class="errors">
<p>Email or password is incorrent. <a href="#">Forgot password?</a></p>
</div>
</div>
<%= fields %> <%= fields %>
<button class="action action-primary action-update js-login">Log in</button> <button class="action action-primary action-update js-login">Log in</button>
<button type="submit" class="button button-primary button-facebook"><span class="icon icon-facebook"></span>Sign in with Facebook</button> <button type="submit" class="button button-primary button-facebook"><span class="icon icon-facebook"></span>Sign in with Facebook</button>
......
...@@ -12,16 +12,16 @@ ...@@ -12,16 +12,16 @@
</%block> </%block>
<%block name="header_extras"> <%block name="header_extras">
% for template_name in ["account", "access", "form_field", "login"]: % for template_name in ["account", "access", "form_field", "login", "register"]:
<script type="text/template" id="${template_name}-tpl"> <script type="text/template" id="${template_name}-tpl">
<%static:include path="student_account/${template_name}.underscore" /> <%static:include path="student_account/${template_name}.underscore" />
</script> </script>
% endfor % endfor
</%block> </%block>
<h1>Login and Registration!</h1> <h1>Welcome!</h1>
<p>This is a placeholder for the combined login and registration form.</p> <p>Please log in to continue</p>
## TODO: Use JavaScript to populate this div with ## TODO: Use JavaScript to populate this div with
## the actual registration/login forms (loaded asynchronously from the user API) ## the actual registration/login forms (loaded asynchronously from the user API)
......
<form id="register">
<div class="error-msg hidden">
<h4>An error occured in your registration.</h4>
<div class="errors">
<p>Please enter a valid password</p>
</div>
</div>
<button type="submit" class="button button-primary button-facebook"><span class="icon icon-facebook"></span>Sign up with Facebook</button>
<button type="submit" class="button button-primary button-google"><span class="icon icon-google-plus"></span>Sign up with Google</button>
<%= fields %>
<input id="register-termsofservice" type="checkbox" name="termsofservice">
<label for="register-termsofservice">I agree to the <a href="#">Terms of Service and Honor Code</a> *</label>
<button class="action action-primary action-update js-register">Create My edX Account</button>
</form>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment