Add querystring param "course_mode" to the login/registration page so the user can skip track selection. This supports upcoming changes to the course details page that allow the user to choose the track when clicking "enroll", which will replace the functionality of the track selection page.
361 lines
13 KiB
JavaScript
361 lines
13 KiB
JavaScript
var edx = edx || {};
|
|
|
|
(function($, _, _s, Backbone, gettext) {
|
|
'use strict';
|
|
|
|
edx.student = edx.student || {};
|
|
edx.student.account = edx.student.account || {};
|
|
|
|
// Bind to StateChange Event
|
|
History.Adapter.bind( window, 'statechange', function() {
|
|
/* Note: We are using History.getState() for legacy browser (IE) support
|
|
* using History.js plugin instead of the native event.state
|
|
*/
|
|
var State = History.getState();
|
|
});
|
|
|
|
edx.student.account.AccessView = Backbone.View.extend({
|
|
el: '#login-and-registration-container',
|
|
|
|
tpl: '#access-tpl',
|
|
|
|
events: {
|
|
'click .form-toggle': 'toggleForm'
|
|
},
|
|
|
|
subview: {
|
|
login: {},
|
|
register: {},
|
|
passwordHelp: {}
|
|
},
|
|
|
|
urls: {
|
|
dashboard: '/dashboard',
|
|
payment: '/verify_student/start-flow/',
|
|
trackSelection: '/course_modes/choose/'
|
|
},
|
|
|
|
// The form currently loaded
|
|
activeForm: '',
|
|
|
|
initialize: function( obj ) {
|
|
/* Mix non-conflicting functions from underscore.string
|
|
* (all but include, contains, and reverse) into the
|
|
* Underscore namespace
|
|
*/
|
|
_.mixin( _s.exports() );
|
|
|
|
this.tpl = $(this.tpl).html();
|
|
|
|
this.activeForm = obj.mode || 'login';
|
|
|
|
this.thirdPartyAuth = obj.thirdPartyAuth || {
|
|
currentProvider: null,
|
|
providers: []
|
|
};
|
|
|
|
this.formDescriptions = {
|
|
login: obj.loginFormDesc,
|
|
register: obj.registrationFormDesc,
|
|
reset: obj.passwordResetFormDesc
|
|
};
|
|
|
|
this.platformName = obj.platformName;
|
|
|
|
// The login view listens for 'sync' events from the reset model
|
|
this.resetModel = new edx.student.account.PasswordResetModel({}, {
|
|
method: 'GET',
|
|
url: '#'
|
|
});
|
|
|
|
this.render();
|
|
},
|
|
|
|
render: function() {
|
|
$(this.el).html( _.template( this.tpl, {
|
|
mode: this.activeForm
|
|
}));
|
|
|
|
this.postRender();
|
|
|
|
return this;
|
|
},
|
|
|
|
postRender: function() {
|
|
// Load the default form
|
|
this.loadForm( this.activeForm );
|
|
},
|
|
|
|
loadForm: function( type ) {
|
|
var loadFunc = _.bind( this.load[type], this );
|
|
loadFunc( this.formDescriptions[type] );
|
|
},
|
|
|
|
load: {
|
|
login: function( data ) {
|
|
var model = new edx.student.account.LoginModel({}, {
|
|
method: data.method,
|
|
url: data.submit_url
|
|
});
|
|
|
|
this.subview.login = new edx.student.account.LoginView({
|
|
fields: data.fields,
|
|
model: model,
|
|
resetModel: this.resetModel,
|
|
thirdPartyAuth: this.thirdPartyAuth,
|
|
platformName: this.platformName
|
|
});
|
|
|
|
// Listen for 'password-help' event to toggle sub-views
|
|
this.listenTo( this.subview.login, 'password-help', this.resetPassword );
|
|
|
|
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
|
|
this.listenTo( this.subview.login, 'auth-complete', this.authComplete );
|
|
|
|
},
|
|
|
|
reset: function( data ) {
|
|
this.resetModel.ajaxType = data.method;
|
|
this.resetModel.urlRoot = data.submit_url;
|
|
|
|
this.subview.passwordHelp = new edx.student.account.PasswordResetView({
|
|
fields: data.fields,
|
|
model: this.resetModel
|
|
});
|
|
|
|
// Listen for 'password-email-sent' event to toggle sub-views
|
|
this.listenTo( this.subview.passwordHelp, 'password-email-sent', this.passwordEmailSent );
|
|
|
|
// Focus on the form
|
|
$('.password-reset-form').focus();
|
|
},
|
|
|
|
register: function( data ) {
|
|
var model = new edx.student.account.RegisterModel({}, {
|
|
method: data.method,
|
|
url: data.submit_url
|
|
});
|
|
|
|
this.subview.register = new edx.student.account.RegisterView({
|
|
fields: data.fields,
|
|
model: model,
|
|
thirdPartyAuth: this.thirdPartyAuth,
|
|
platformName: this.platformName
|
|
});
|
|
|
|
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
|
|
this.listenTo( this.subview.register, 'auth-complete', this.authComplete );
|
|
}
|
|
},
|
|
|
|
passwordEmailSent: function() {
|
|
this.element.hide( $(this.el).find('#password-reset-anchor') );
|
|
this.element.show( $('#login-anchor') );
|
|
this.element.scrollTop( $('#login-anchor') );
|
|
},
|
|
|
|
resetPassword: function() {
|
|
window.analytics.track('edx.bi.password_reset_form.viewed', {
|
|
category: 'user-engagement'
|
|
});
|
|
|
|
this.element.hide( $(this.el).find('#login-anchor') );
|
|
this.loadForm('reset');
|
|
this.element.scrollTop( $('#password-reset-anchor') );
|
|
},
|
|
|
|
toggleForm: function( e ) {
|
|
var type = $(e.currentTarget).data('type'),
|
|
$form = $('#' + type + '-form'),
|
|
$anchor = $('#' + type + '-anchor'),
|
|
queryParams = url('?'),
|
|
queryStr = queryParams.length > 0 ? '?' + queryParams : '';
|
|
|
|
e.preventDefault();
|
|
|
|
window.analytics.track('edx.bi.' + type + '_form.toggled', {
|
|
category: 'user-engagement'
|
|
});
|
|
|
|
if ( !this.form.isLoaded( $form ) ) {
|
|
this.loadForm( type );
|
|
}
|
|
|
|
this.element.hide( $(this.el).find('.submission-success') );
|
|
this.element.hide( $(this.el).find('.form-wrapper') );
|
|
this.element.show( $form );
|
|
this.element.scrollTop( $anchor );
|
|
|
|
// Update url without reloading page
|
|
History.pushState( null, document.title, '/' + type + queryStr );
|
|
analytics.page( 'login_and_registration', type );
|
|
|
|
// Focus on the form
|
|
document.getElementById(type).focus();
|
|
},
|
|
|
|
/**
|
|
* Once authentication has completed successfully, a user may need to:
|
|
*
|
|
* - Enroll in a course.
|
|
* - Update email opt-in preferences
|
|
*
|
|
* These actions are delegated from the authComplete function to additional
|
|
* functions requiring authentication.
|
|
*
|
|
*/
|
|
authComplete: function() {
|
|
var emailOptIn = edx.student.account.EmailOptInInterface,
|
|
queryParams = this.queryParams();
|
|
|
|
// Set the email opt in preference.
|
|
if (!_.isUndefined(queryParams.emailOptIn) && queryParams.enrollmentAction) {
|
|
emailOptIn.setPreference(
|
|
decodeURIComponent(queryParams.courseId),
|
|
queryParams.emailOptIn,
|
|
this
|
|
).always(this.enrollment);
|
|
} else {
|
|
this.enrollment();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Designed to be invoked after authentication has completed. This function enrolls
|
|
* the student as requested.
|
|
*
|
|
* - Enroll in a course.
|
|
* - Add a course to the shopping cart.
|
|
* - Be redirected to the dashboard / track selection page / shopping cart.
|
|
*
|
|
* This handler is triggered upon successful authentication,
|
|
* either from the login or registration form. It checks
|
|
* query string params, performs enrollment/shopping cart actions,
|
|
* then redirects the user to the next page.
|
|
*
|
|
* The optional query string params are:
|
|
*
|
|
* ?next: If provided, redirect to this page upon successful auth.
|
|
* Django uses this when an unauthenticated user accesses a view
|
|
* decorated with @login_required.
|
|
*
|
|
* ?enrollment_action: Can be either "enroll" or "add_to_cart".
|
|
* If you provide this param, you must also provide a `course_id` param;
|
|
* otherwise, no action will be taken.
|
|
*
|
|
* ?course_id: The slash-separated course ID to enroll in or add to the cart.
|
|
*
|
|
*/
|
|
enrollment: function() {
|
|
var enrollment = edx.student.account.EnrollmentInterface,
|
|
shoppingcart = edx.student.account.ShoppingCartInterface,
|
|
redirectUrl = this.urls.dashboard,
|
|
queryParams = this.queryParams();
|
|
|
|
if ( queryParams.enrollmentAction === 'enroll' && queryParams.courseId ) {
|
|
var courseId = decodeURIComponent( queryParams.courseId );
|
|
|
|
// Determine where to redirect the user after auto-enrollment.
|
|
if ( !queryParams.courseMode ) {
|
|
/* Backwards compatibility with the original course details page.
|
|
The old implementation did not specify the course mode for enrollment,
|
|
so we'd always send the user to the "track selection" page.
|
|
The track selection page would allow the user to select the course mode
|
|
("verified", "honor", etc.) -- or, if the only course mode was "honor",
|
|
it would redirect the user to the dashboard. */
|
|
redirectUrl = this.urls.trackSelection + courseId + '/';
|
|
} else if ( queryParams.courseMode === 'honor' || queryParams.courseMode === 'audit' ) {
|
|
/* The newer version of the course details page allows the user
|
|
to specify which course mode to enroll as. If the student has
|
|
chosen "honor", we send them immediately to the dashboard
|
|
rather than the payment flow. The user may decide to upgrade
|
|
from the dashboard later. */
|
|
redirectUrl = this.urls.dashboard;
|
|
} else {
|
|
/* If the user selected any other kind of course mode, send them
|
|
to the payment/verification flow. */
|
|
redirectUrl = this.urls.payment + courseId + '/';
|
|
}
|
|
|
|
/* Attempt to auto-enroll the user in a free mode of the course,
|
|
then redirect to the next location. */
|
|
enrollment.enroll( courseId, redirectUrl );
|
|
} else if ( queryParams.enrollmentAction === 'add_to_cart' && queryParams.courseId) {
|
|
/*
|
|
If this is a paid course, add it to the shopping cart and redirect
|
|
the user to the "view cart" page.
|
|
*/
|
|
shoppingcart.addCourseToCart( decodeURIComponent( queryParams.courseId ) );
|
|
} else {
|
|
/*
|
|
Otherwise, redirect the user to the next page
|
|
Check for forwarding url and ensure that it isn't external.
|
|
If not, use the default forwarding URL.
|
|
*/
|
|
if ( !_.isNull( queryParams.next ) ) {
|
|
var next = decodeURIComponent( queryParams.next );
|
|
|
|
// Ensure that the URL is internal for security reasons
|
|
if ( !window.isExternal( next ) ) {
|
|
redirectUrl = next;
|
|
}
|
|
}
|
|
|
|
this.redirect( redirectUrl );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Redirect to a URL. Mainly useful for mocking out in tests.
|
|
* @param {string} url The URL to redirect to.
|
|
*/
|
|
redirect: function( url ) {
|
|
window.location.href = url;
|
|
},
|
|
|
|
/**
|
|
* Retrieve query params that we use post-authentication
|
|
* to decide whether to enroll a student in a course, add
|
|
* an item to the cart, or redirect.
|
|
*
|
|
* @return {object} The query params. If any param is not
|
|
* provided, it will default to null.
|
|
*/
|
|
queryParams: function() {
|
|
return {
|
|
next: $.url( '?next' ),
|
|
enrollmentAction: $.url( '?enrollment_action' ),
|
|
courseId: $.url( '?course_id' ),
|
|
courseMode: $.url( '?course_mode' ),
|
|
emailOptIn: $.url( '?email_opt_in')
|
|
};
|
|
},
|
|
|
|
form: {
|
|
isLoaded: function( $form ) {
|
|
return $form.html().length > 0;
|
|
}
|
|
},
|
|
|
|
/* Helper method to toggle display
|
|
* including accessibility considerations
|
|
*/
|
|
element: {
|
|
hide: function( $el ) {
|
|
$el.addClass('hidden');
|
|
},
|
|
|
|
scrollTop: function( $el ) {
|
|
// Scroll to top of selected element
|
|
$('html,body').animate({
|
|
scrollTop: $el.offset().top
|
|
},'slow');
|
|
},
|
|
|
|
show: function( $el ) {
|
|
$el.removeClass('hidden');
|
|
}
|
|
}
|
|
});
|
|
})(jQuery, _, _.str, Backbone, gettext);
|