Added password reset view and started basic styling
This commit is contained in:
@@ -1029,8 +1029,10 @@ student_account_js = [
|
||||
'js/common_helpers/edx.utils.validate.js',
|
||||
'js/student_account/models/LoginModel.js',
|
||||
'js/student_account/models/RegisterModel.js',
|
||||
'js/student_account/models/PasswordResetModel.js',
|
||||
'js/student_account/views/LoginView.js',
|
||||
'js/student_account/views/RegisterView.js',
|
||||
'js/student_account/views/PasswordResetView.js',
|
||||
'js/student_account/views/AccessView.js',
|
||||
'js/student_account/accessApp.js',
|
||||
]
|
||||
|
||||
41
lms/static/js/student_account/models/PasswordResetModel.js
Normal file
41
lms/static/js/student_account/models/PasswordResetModel.js
Normal file
@@ -0,0 +1,41 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function($, _, Backbone, gettext) {
|
||||
'use strict';
|
||||
|
||||
edx.student = edx.student || {};
|
||||
edx.student.account = edx.student.account || {};
|
||||
|
||||
edx.student.account.PasswordResetModel = Backbone.Model.extend({
|
||||
|
||||
defaults: {
|
||||
email: ''
|
||||
},
|
||||
|
||||
urlRoot: '/resetMe',
|
||||
|
||||
sync: function(method, model) {
|
||||
var headers = {
|
||||
'X-CSRFToken': $.cookie('csrftoken')
|
||||
};
|
||||
|
||||
// Is just expecting email address
|
||||
$.ajax({
|
||||
url: model.urlRoot,
|
||||
type: 'POST',
|
||||
data: model.attributes,
|
||||
headers: headers
|
||||
})
|
||||
.done(function() {
|
||||
var query = window.location.search,
|
||||
url = '/dashboard';
|
||||
|
||||
model.trigger('success');
|
||||
})
|
||||
.fail( function( error ) {
|
||||
console.log('RegisterModel.save() FAILURE!!!!!');
|
||||
model.trigger('error', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
})(jQuery, _, Backbone, gettext);
|
||||
@@ -15,6 +15,12 @@ var edx = edx || {};
|
||||
'change .form-toggle': 'toggleForm'
|
||||
},
|
||||
|
||||
subview: {
|
||||
login: {},
|
||||
register: {},
|
||||
passwordHelp: {}
|
||||
},
|
||||
|
||||
// The form currently loaded
|
||||
activeForm: '',
|
||||
|
||||
@@ -38,22 +44,38 @@ var edx = edx || {};
|
||||
postRender: function() {
|
||||
// Load the default form
|
||||
this.loadForm( this.activeForm );
|
||||
this.$header = $(this.el).find('.js-login-register-header');
|
||||
},
|
||||
|
||||
loadForm: function( type ) {
|
||||
if ( type === 'login' ) {
|
||||
console.log('load login');
|
||||
return new edx.student.account.LoginView();
|
||||
} else if ( type === 'register' ) {
|
||||
console.log('load register');
|
||||
return new edx.student.account.RegisterView();
|
||||
}
|
||||
this.subview.login = new edx.student.account.LoginView();
|
||||
|
||||
// return new app.LoginView({
|
||||
// el: $('#' + type + '-form'),
|
||||
// model: this.getModel( type ),
|
||||
// tpl: $('#' + type + '-form-tpl').html()
|
||||
// });
|
||||
// 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();
|
||||
} else if ( type === 'reset' ) {
|
||||
this.subview.passwordHelp = new edx.student.account.PasswordResetView();
|
||||
|
||||
// Listen for 'password-reset' event to toggle sub-views
|
||||
this.listenTo( this.subview.passwordHelp, 'password-reset', this.removePasswordView);
|
||||
}
|
||||
},
|
||||
|
||||
removePasswordView: function() {
|
||||
this.$header.removeClass('hidden');
|
||||
$(this.el).find('.form-type').removeClass('hidden');
|
||||
|
||||
// User should only have to submit reset once so remove view
|
||||
this.subview.passwordHelp.remove();
|
||||
},
|
||||
|
||||
resetPassword: function() {
|
||||
console.log( this.$header );
|
||||
this.$header.addClass('hidden');
|
||||
$(this.el).find('.form-type').addClass('hidden');
|
||||
this.loadForm('reset');
|
||||
},
|
||||
|
||||
toggleForm: function( e ) {
|
||||
|
||||
@@ -125,7 +125,8 @@ var edx = edx || {};
|
||||
|
||||
forgotPassword: function( event ) {
|
||||
event.preventDefault();
|
||||
console.log('forgotPassword');
|
||||
|
||||
this.trigger('password-help');
|
||||
},
|
||||
|
||||
submitForm: function( event ) {
|
||||
|
||||
155
lms/static/js/student_account/views/PasswordResetView.js
Normal file
155
lms/static/js/student_account/views/PasswordResetView.js
Normal file
@@ -0,0 +1,155 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function($, _, Backbone, gettext) {
|
||||
'use strict';
|
||||
|
||||
edx.student = edx.student || {};
|
||||
edx.student.account = edx.student.account || {};
|
||||
|
||||
edx.student.account.PasswordResetView = Backbone.View.extend({
|
||||
tagName: 'form',
|
||||
|
||||
el: '#password-reset-wrapper',
|
||||
|
||||
tpl: $('#password_reset-tpl').html(),
|
||||
|
||||
fieldTpl: $('#form_field-tpl').html(),
|
||||
|
||||
events: {
|
||||
'click .js-reset': 'submitForm'
|
||||
},
|
||||
|
||||
errors: [],
|
||||
|
||||
mode: {},
|
||||
|
||||
$form: {},
|
||||
|
||||
initialize: function( obj ) {
|
||||
var fields = this.buildForm([{
|
||||
label: 'E-mail',
|
||||
instructions: 'This is the e-mail address you used to register with edX',
|
||||
name: 'email',
|
||||
required: true,
|
||||
type: 'email',
|
||||
restrictions: []
|
||||
}]);
|
||||
console.log('PasswordResetView INIT');
|
||||
this.initModel();
|
||||
this.render( fields );
|
||||
},
|
||||
|
||||
// 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');
|
||||
|
||||
this.listenTo( this.model, 'success', this.resetComplete) ;
|
||||
},
|
||||
|
||||
initModel: function( url, method ) {
|
||||
console.log('init the password reset model');
|
||||
/*this.model = new edx.student.account.PasswordResetModel();
|
||||
|
||||
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;
|
||||
console.log('buildForm ', data);
|
||||
for ( i=0; i<len; i++ ) {
|
||||
html.push( _.template( fieldTpl, $.extend( data[i], {
|
||||
form: 'reset-password'
|
||||
}) ) );
|
||||
}
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
resetComplete: function() {
|
||||
this.trigger('password-reset');
|
||||
},
|
||||
|
||||
submitForm: function( event ) {
|
||||
var data = this.getFormData();
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
// console.log(this.model);
|
||||
|
||||
if ( !this.errors.length ) {
|
||||
console.log('save me');
|
||||
this.model.set( data );
|
||||
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);
|
||||
@@ -80,7 +80,7 @@ var edx = edx || {};
|
||||
i,
|
||||
len = data.length,
|
||||
fieldTpl = this.fieldTpl;
|
||||
|
||||
console.log('buildForm ', data);
|
||||
for ( i=0; i<len; i++ ) {
|
||||
html.push( _.template( fieldTpl, $.extend( data[i], {
|
||||
form: 'register'
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import "neat/neat"; // lib - Neat
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
|
||||
// BASE *default edX offerings*
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import "neat/neat"; // lib - Neat
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
|
||||
|
||||
// BASE *default edX offerings*
|
||||
// ====================
|
||||
|
||||
@@ -44,6 +46,7 @@
|
||||
@import 'elements/system-feedback';
|
||||
|
||||
// base - specific views
|
||||
@import 'views/login-register';
|
||||
@import 'views/verification';
|
||||
@import 'views/shoppingcart';
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import "neat/neat"; // lib - Neat
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
|
||||
// BASE *default edX offerings*
|
||||
|
||||
21
lms/static/sass/views/_login-register.scss
Normal file
21
lms/static/sass/views/_login-register.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
// lms - views - login/register view
|
||||
// ====================
|
||||
.login-register{
|
||||
|
||||
@include span-columns(6);
|
||||
@include shift(3);
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.input-block,
|
||||
.desc {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.input-inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
<header class="js-login-register-header">
|
||||
<h1>Welcome!</h1>
|
||||
<p>Please log in to continue</p>
|
||||
</header>
|
||||
|
||||
<section class="form-type">
|
||||
<h2>
|
||||
<input type="radio" name="form" id="register-option" value="register" class="form-toggle" <% if ( mode === 'register' ) { %>checked<% } %> >
|
||||
@@ -13,3 +18,5 @@
|
||||
</h2>
|
||||
<div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden<% } %>"></div>
|
||||
</section>
|
||||
|
||||
<div id="password-reset-wrapper"></div>
|
||||
@@ -11,19 +11,19 @@
|
||||
<% } %>
|
||||
|
||||
<% if ( type === 'select' ) { %>
|
||||
<select id="<%= form %>-<%= name %>" name="<%= name %>" aria-describedby="<%= form %>-<%= name %>-desc">
|
||||
<select id="<%= form %>-<%= name %>" name="<%= name %>" class="input-inline" aria-describedby="<%= form %>-<%= name %>-desc">
|
||||
<% _.each(options, function(el) { %>
|
||||
<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"
|
||||
<textarea id="<%= form %>-<%= name %>" type="<%= type %>" name="<%= name %>" class="input-block" 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"
|
||||
<input id="<%= form %>-<%= name %>" type="<%= type %>" name="<%= name %>" class="input-block" aria-describedby="<%= form %>-<%= name %>-desc"
|
||||
<% if ( restrictions.min_length ) { %> minlength="<%= restrictions.min_length %>"<% } %>
|
||||
<% if ( restrictions.max_length ) { %> maxlength="<%= restrictions.max_length %>"<% } %>
|
||||
<% if ( required ) { %> required<% } %>
|
||||
|
||||
@@ -12,16 +12,13 @@
|
||||
</%block>
|
||||
|
||||
<%block name="header_extras">
|
||||
% for template_name in ["account", "access", "form_field", "login", "register"]:
|
||||
% for template_name in ["account", "access", "form_field", "login", "register", "password_reset"]:
|
||||
<script type="text/template" id="${template_name}-tpl">
|
||||
<%static:include path="student_account/${template_name}.underscore" />
|
||||
</script>
|
||||
% endfor
|
||||
</%block>
|
||||
|
||||
<h1>Welcome!</h1>
|
||||
|
||||
<p>Please log in to continue</p>
|
||||
|
||||
## TODO: Use JavaScript to populate this div with
|
||||
## the actual registration/login forms (loaded asynchronously from the user API)
|
||||
@@ -47,6 +44,7 @@
|
||||
## Note that this list may be empty.
|
||||
##
|
||||
<div id="login-and-registration-container"
|
||||
class="login-register"
|
||||
data-initial-mode="${initial_mode}"
|
||||
data-third-party-auth-providers="${third_party_auth_providers}"
|
||||
/>
|
||||
|
||||
21
lms/templates/student_account/password_reset.underscore
Normal file
21
lms/templates/student_account/password_reset.underscore
Normal file
@@ -0,0 +1,21 @@
|
||||
<header>
|
||||
<h1>Password assistance</h1>
|
||||
</header>
|
||||
|
||||
<section class="form-type">
|
||||
<div id="password-reset-form" class="form-wrapper">
|
||||
<p>Please enter your email address below and we will send you instructions for setting a new password.</p>
|
||||
<form id="password-reset-form">
|
||||
<div class="error-msg hidden">
|
||||
<h4>An error occured.</h4>
|
||||
<div class="errors">
|
||||
<p>Please enter a valid email address</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= fields %>
|
||||
|
||||
<button class="action action-primary action-update js-reset">Create My edX Account</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user