Commit 47f7072f by Anthony Mangano Committed by GitHub

Merge pull request #14142 from edx/ECOM-6107-fix-error-handling-for-sr

Improve screen reader support on logistration pages
parents 82647ee8 57f0999b
......@@ -356,10 +356,10 @@ class CombinedLoginAndRegisterPage(PageObject):
"""Wait for a status message to be visible following third_party registration, then return it."""
def _check_func():
"""Return third party auth status notice message."""
for selector in ['.already-authenticated-msg p', '.status p']:
msg_element = self.q(css=selector)
if msg_element.visible:
return (True, msg_element.text[0])
selector = '.js-auth-warning p'
msg_element = self.q(css=selector)
if msg_element.visible:
return (True, msg_element.text[0])
return (False, None)
return Promise(_check_func, "Result of third party auth is visible").fulfill()
......
......@@ -31,6 +31,8 @@
tpl: formViewTpl,
fieldTpl: formFieldTpl,
formType: 'financial-assistance',
successTpl: successTpl,
defaultFormErrorsTitle: gettext('Unable to submit application'),
requiredStr: '',
submitButton: '.js-submit-form',
......@@ -81,7 +83,7 @@
},
renderSuccess: function() {
this.$el.html(_.template(successTpl)({
this.$el.html(_.template(this.successTpl)({
course: this.model.get('course'),
dashboard_url: this.context.dashboard_url
}));
......@@ -102,8 +104,7 @@
}
this.errors = ['<li>' + msg + '</li>'];
this.setErrors();
this.element.hide(this.$resetSuccess);
this.renderErrors(this.defaultFormErrorsTitle, this.errors);
this.toggleDisableButton(false);
},
......@@ -112,9 +113,7 @@
},
validateCountry: function() {
var $submissionContainer = $('.submission-error'),
$errorMessageContainer = $submissionContainer.find('.message-copy'),
$countryLabel = $('#user-country-title'),
var $countryLabel = $('#user-country-title'),
txt = [
'Please go to your {link_start}profile page{link_end} ',
'and provide your country of residence.'
......@@ -130,9 +129,8 @@
if (!this.model.get('country')) {
$countryLabel.addClass('error');
$errorMessageContainer.append('<li>' + msg + '</li>');
this.renderErrors(this.defaultFormErrorsTitle, ['<li>' + msg + '</li>']);
this.toggleDisableButton(true);
$submissionContainer.removeClass('hidden');
}
},
......
......@@ -133,23 +133,23 @@ define([
failedSubmission = function() {
expect(view.$('.js-success-message').length).toEqual(0);
expect(view.$('.submission-error')).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
validSubmission();
view.model.trigger('error', {status: 500});
expect(view.$('.js-success-message').length).toEqual(0);
expect(view.$('.submission-error')).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
};
invalidCountry = function() {
expect(view.$('.js-success-message').length).toEqual(0);
expect(view.$('.submission-error')).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
expect(view.$('#user-country-title')).toHaveClass('error');
expect(view.$('.js-submit-form').prop('disabled')).toBeTruthy();
};
validCountry = function() {
expect(view.$('.js-success-message').length).toEqual(0);
expect(view.$('.submission-error')).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
expect(view.$('#user-country-title')).not.toHaveClass('error');
expect(view.$('.js-submit-form').prop('disabled')).toBeFalsy();
};
......@@ -184,10 +184,10 @@ define([
});
it('should not submit the form if the front end validation fails', function() {
expect(view.$('.submission-error')).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
view.$('.js-submit-form').click();
expect(view.model.save).not.toHaveBeenCalled();
expect(view.$('.submission-error')).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
});
it('should submit the form data and additional data if validation passes', function() {
......
......@@ -191,10 +191,10 @@
});
AjaxHelpers.expectRequest(
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(expectedData)
);
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(expectedData)
);
});
it('displays third-party auth login buttons', function() {
......@@ -212,6 +212,21 @@
expect($('.forgot-password')).toBeVisible();
});
it('displays password reset success message after password reset request', function() {
createLoginView(this);
// Verify that the success message is not visible
expect(view.$formFeedback.find('.' + view.passwordResetSuccessJsHook).length).toEqual(0);
/* After a successful password reset request, the resetModel will trigger a 'sync'
* event, which lets the LoginView know to render the password reset success message.
*/
view.resetModel.trigger('sync');
// Verify that the success message is visible
expect(view.$formFeedback.find('.' + view.passwordResetSuccessJsHook).length).toEqual(1);
});
it('validates login form fields', function() {
createLoginView(this);
......@@ -229,10 +244,11 @@
submitForm(false);
// Verify that submission errors are visible
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
// Expect auth complete NOT to have been triggered
expect(authComplete).toBe(false);
// Form button should be re-enabled when errors occur
expect(view.$submitButton).not.toHaveAttr('disabled');
});
......@@ -247,8 +263,10 @@
AjaxHelpers.respondWithError(requests);
// Expect that an error is displayed and that auth complete is not triggered
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
expect(authComplete).toBe(false);
// Form button should be re-enabled on server failure.
expect(view.$submitButton).not.toHaveAttr('disabled');
......@@ -262,17 +280,18 @@
AjaxHelpers.respondWithJson(requests, {});
// Expect that the error is hidden and auth complete is triggered
expect(view.$errors).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
expect(authComplete).toBe(true);
});
it('displays an error if there is no internet connection', function() {
var clock,
oldTimeout,
timeout;
timeout,
$error;
// We're defining "no internet connection" in this case as the
// request timing out. We use a combination of the sinon fake
// request timing out. We use a combination of the sinon fake
// timer and jQuery.ajaxSetup() to force a request timeout.
clock = sinon.useFakeTimers();
oldTimeout = $.ajaxSetup().timeout;
......@@ -288,11 +307,12 @@
clock.tick(timeout + 1);
// Expect that an error is displayed and that auth complete is not triggered
expect(view.$errors).not.toHaveClass('hidden');
$error = view.$formFeedback.find('.' + view.formErrorsJsHook);
expect($error.length).toEqual(1);
expect($error.text()).toContain(
'An error has occurred. Check your Internet connection and try again.'
);
expect(authComplete).toBe(false);
expect(view.$errors.text()).toContain(
'An error has occurred. Check your Internet connection and try again.'
);
// Finally, restore the old timeout and turn off the fake timer.
$.ajaxSetup({timeout: oldTimeout});
......@@ -300,6 +320,7 @@
});
it('displays an error if there is a server error', function() {
var $error;
createLoginView(this);
// Submit the form, with successful validation
......@@ -309,11 +330,12 @@
AjaxHelpers.respondWithError(requests, 500);
// Expect that an error is displayed and that auth complete is not triggered
expect(view.$errors).not.toHaveClass('hidden');
$error = view.$formFeedback.find('.' + view.formErrorsJsHook);
expect($error.length).toEqual(1);
expect($error.text()).toContain(
'An error has occurred. Try refreshing the page, or check your Internet connection.'
);
expect(authComplete).toBe(false);
expect(view.$errors.text()).toContain(
'An error has occurred. Try refreshing the page, or check your Internet connection.'
);
});
});
});
......
......@@ -74,26 +74,32 @@
});
it('allows the user to request a new password', function() {
var syncSpy, passwordEmailSentSpy;
createPasswordResetView(this);
// We expect these events to be triggered upon a successful password reset
syncSpy = jasmine.createSpy('syncEvent');
passwordEmailSentSpy = jasmine.createSpy('passwordEmailSentEvent');
view.listenTo(view.model, 'sync', syncSpy);
view.listenTo(view, 'password-email-sent', passwordEmailSentSpy);
// Submit the form, with successful validation
submitEmail(true);
// Verify that the client contacts the server with the expected data
AjaxHelpers.expectRequest(
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param({email: EMAIL})
);
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param({email: EMAIL})
);
// Respond with status code 200
AjaxHelpers.respondWithJson(requests, {});
// Verify that the success message is visible
expect($('.js-reset-success')).not.toHaveClass('hidden');
// Verify that login form has loaded
expect($('#login-form')).not.toHaveClass('hidden');
// Verify that the events were triggered
expect(syncSpy).toHaveBeenCalled();
expect(passwordEmailSentSpy).toHaveBeenCalled();
// Verify that password reset view has been removed
expect($(view.el).html().length).toEqual(0);
......@@ -109,7 +115,7 @@
expect(view.validate).toHaveBeenCalledWith($('#password-reset-email')[0]);
// Verify that no submission errors are visible
expect(view.$errors).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
});
it('displays password reset validation errors', function() {
......@@ -119,7 +125,7 @@
submitEmail(false);
// Verify that submission errors are visible
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
});
it('displays an error if the server returns an error while sending a password reset email', function() {
......@@ -130,7 +136,7 @@
AjaxHelpers.respondWithError(requests);
// Expect that an error is displayed
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
// If we try again and succeed, the error should go away
submitEmail();
......@@ -139,7 +145,7 @@
AjaxHelpers.respondWithJson(requests, {});
// Expect that the error is hidden
expect(view.$errors).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
});
});
});
......
......@@ -243,16 +243,17 @@
// Verify that the client contacts the server with the expected data
AjaxHelpers.expectRequest(
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(USER_DATA)
);
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(USER_DATA)
);
// Respond with status code 200
AjaxHelpers.respondWithJson(requests, {});
// Verify that auth complete is triggered
expect(authComplete).toBe(true);
// Form button should be disabled on success.
expect(view.$submitButton).toHaveAttr('disabled');
});
......@@ -278,10 +279,10 @@
$.extend(expectedData, USER_DATA);
AjaxHelpers.expectRequest(
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(expectedData)
);
requests, 'POST',
FORM_DESCRIPTION.submit_url,
$.param(expectedData)
);
});
it('displays third-party auth registration buttons', function() {
......@@ -305,7 +306,8 @@
expect(view.validate).toHaveBeenCalledWith($('#register-password')[0]);
// Verify that no submission errors are visible
expect(view.$errors).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
// Form button should be disabled on success.
expect(view.$submitButton).toHaveAttr('disabled');
});
......@@ -317,10 +319,11 @@
submitForm(false);
// Verify that submission errors are visible
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
// Expect that auth complete is NOT triggered
expect(authComplete).toBe(false);
// Form button should be re-enabled on error.
expect(view.$submitButton).not.toHaveAttr('disabled');
});
......@@ -335,7 +338,7 @@
AjaxHelpers.respondWithError(requests);
// Expect that an error is displayed and that auth complete is NOT triggered
expect(view.$errors).not.toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
expect(authComplete).toBe(false);
// If we try again and succeed, the error should go away
......@@ -345,8 +348,9 @@
AjaxHelpers.respondWithJson(requests, {});
// Expect that the error is hidden and that auth complete is triggered
expect(view.$errors).toHaveClass('hidden');
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
expect(authComplete).toBe(true);
// Form button should be disabled on success.
expect(view.$submitButton).toHaveAttr('disabled');
});
......
......@@ -4,9 +4,11 @@
'jquery',
'underscore',
'backbone',
'common/js/utils/edx.utils.validate'
'common/js/utils/edx.utils.validate',
'edx-ui-toolkit/js/utils/html-utils',
'text!templates/student_account/form_errors.underscore'
],
function($, _, Backbone, EdxUtilsValidate) {
function($, _, Backbone, EdxUtilsValidate, HtmlUtils, formErrorsTpl) {
return Backbone.View.extend({
tagName: 'form',
......@@ -16,6 +18,12 @@
fieldTpl: '#form_field-tpl',
formErrorsTpl: formErrorsTpl,
formErrorsJsHook: 'js-form-errors',
defaultFormErrorsTitle: gettext('An error occurred.'),
events: {},
errors: [],
......@@ -66,7 +74,7 @@
postRender: function() {
var $container = $(this.el);
this.$form = $container.find('form');
this.$errors = $container.find('.submission-error');
this.$formFeedback = $container.find('.js-form-feedback');
this.$submitButton = $container.find(this.submitButton);
},
......@@ -126,21 +134,6 @@
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();
......@@ -185,32 +178,34 @@
saveError: function(error) {
this.errors = ['<li>' + error.responseText + '</li>'];
this.setErrors();
this.renderErrors(this.defaultFormErrorsTitle, this.errors);
this.toggleDisableButton(false);
},
setErrors: function() {
var $msg = this.$errors.find('.message-copy'),
html = [],
errors = this.errors,
i,
len = errors.length;
for (i = 0; i < len; i++) {
html.push(errors[i]);
}
/* Wrapper for renderFormFeedback provided for convenience since the majority of
* our calls to renderFormFeedback are for rendering error messages.
*/
renderErrors: function(title, errorMessages) {
this.clearFormErrors();
$msg.html(html.join(''));
this.renderFormFeedback(this.formErrorsTpl, {
jsHook: this.formErrorsJsHook,
title: title,
messagesHtml: HtmlUtils.HTML(errorMessages.join(''))
});
},
this.element.show(this.$errors);
renderFormFeedback: function(template, context) {
var tpl = HtmlUtils.template(template);
HtmlUtils.prepend(this.$formFeedback, tpl(context));
// Scroll to error messages
// Scroll to feedback container
$('html,body').animate({
scrollTop: this.$errors.offset().top
scrollTop: this.$formFeedback.offset().top
}, 'slow');
// Focus on first error field
this.focusFirstError();
// Focus on the feedback container to ensure screen readers see the messages.
this.$formFeedback.focus();
},
/* Allows extended views to add non-form attributes
......@@ -233,9 +228,10 @@
data = this.setExtraData(data);
this.model.set(data);
this.model.save();
this.toggleErrorMsg(false);
this.clearFormErrors();
} else {
this.toggleErrorMsg(true);
this.renderErrors(this.defaultFormErrorsTitle, this.errors);
this.toggleDisableButton(false);
}
this.postFormSubmission();
......@@ -248,12 +244,15 @@
return true;
},
toggleErrorMsg: function(show) {
if (show) {
this.setErrors();
this.toggleDisableButton(false);
} else {
this.element.hide(this.$errors);
clearFormErrors: function() {
var query = '.' + this.formErrorsJsHook;
this.clearFormFeedbackItems(query);
},
clearFormFeedbackItems: function(query) {
var $items = this.$formFeedback.find(query);
if ($items.length > 0) {
$items.remove();
}
},
......
......@@ -26,15 +26,6 @@
this.listenTo(this.model, 'sync', this.saveSuccess);
},
toggleErrorMsg: function(show) {
if (show) {
this.setErrors();
this.toggleDisableButton(false);
} else {
this.element.hide(this.$errors);
}
},
saveSuccess: function() {
this.trigger('password-email-sent');
......
......@@ -3,9 +3,11 @@
define([
'jquery',
'underscore',
'js/student_account/views/FormView'
'gettext',
'js/student_account/views/FormView',
'text!templates/student_account/form_status.underscore'
],
function($, _, FormView) {
function($, _, gettext, FormView, formStatusTpl) {
return FormView.extend({
el: '#register-form',
......@@ -18,13 +20,19 @@
formType: 'register',
formStatusTpl: formStatusTpl,
authWarningJsHook: 'js-auth-warning',
defaultFormErrorsTitle: gettext('We couldn\'t create your account.'),
submitButton: '.js-register',
preRender: function(data) {
this.providers = data.thirdPartyAuth.providers || [];
this.hasSecondaryProviders = (
data.thirdPartyAuth.secondaryProviders && data.thirdPartyAuth.secondaryProviders.length
);
data.thirdPartyAuth.secondaryProviders && data.thirdPartyAuth.secondaryProviders.length
);
this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.errorMessage = data.thirdPartyAuth.errorMessage || '';
this.platformName = data.platformName;
......@@ -34,7 +42,8 @@
},
render: function(html) {
var fields = html || '';
var fields = html || '',
formErrorsTitle = gettext('An error occurred.');
$(this.el).html(_.template(this.tpl)({
/* We pass the context object to the template so that
......@@ -43,7 +52,6 @@
context: {
fields: fields,
currentProvider: this.currentProvider,
errorMessage: this.errorMessage,
providers: this.providers,
hasSecondaryProviders: this.hasSecondaryProviders,
platformName: this.platformName
......@@ -52,6 +60,13 @@
this.postRender();
// Must be called after postRender, since postRender sets up $formFeedback.
if (this.errorMessage) {
this.renderErrors(formErrorsTitle, [this.errorMessage]);
} else if (this.currentProvider) {
this.renderAuthWarning();
}
if (this.autoSubmit) {
$(this.el).hide();
$('#register-honor_code').prop('checked', true);
......@@ -76,18 +91,18 @@
saveError: function(error) {
$(this.el).show(); // Show in case the form was hidden for auto-submission
this.errors = _.flatten(
_.map(
// Something is passing this 'undefined'. Protect against this.
JSON.parse(error.responseText || '[]'),
function(error_list) {
return _.map(
error_list,
function(error) { return '<li>' + error.user_message + '</li>'; }
);
}
)
);
this.setErrors();
_.map(
// Something is passing this 'undefined'. Protect against this.
JSON.parse(error.responseText || '[]'),
function(errorList) {
return _.map(
errorList,
function(errorItem) { return '<li>' + errorItem.user_message + '</li>'; }
);
}
)
);
this.renderErrors(this.defaultFormErrorsTitle, this.errors);
this.toggleDisableButton(false);
},
......@@ -96,6 +111,22 @@
// The form did not get submitted due to validation errors.
$(this.el).show(); // Show in case the form was hidden for auto-submission
}
},
renderAuthWarning: function() {
var msgPart1 = gettext('You\'ve successfully signed into %(currentProvider)s.'),
msgPart2 = gettext(
'We just need a little more information before you start learning with %(platformName)s.'
),
fullMsg = _.sprintf(
msgPart1 + ' ' + msgPart2,
{currentProvider: this.currentProvider, platformName: this.platformName}
);
this.renderFormFeedback(this.formStatusTpl, {
jsHook: this.authWarningJsHook,
message: fullMsg
});
}
});
});
......
......@@ -7,10 +7,8 @@
</div>
<form class="financial-assistance-form" method="POST">
<div class="status submission-error hidden" aria-live="polite">
<h4 class="message-title"><%- gettext('Unable to submit application') %></h4>
<ul class="message-copy"></ul>
</div>
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div>
<div class="user-info">
<h2><%- gettext('About You') %></h2>
......
<div class="<%- jsHook %> status submission-error">
<h4 class="message-title"><%- title %></h4>
<ul class="message-copy">
<%= HtmlUtils.ensureHtml(messagesHtml) %>
</ul>
</div>
<div class="<%- jsHook %> status">
<p class="message-copy">
<%- message %>
</p>
</div>
<div class="<%- jsHook %> status submission-success">
<h4 class="message-title"><%- title %></h4>
<div class="message-copy">
<%= HtmlUtils.ensureHtml(messageHtml) %>
</div>
</div>
<div class="status already-authenticated-msg hidden">
<% if (context.currentProvider) { %>
<p class="message-copy">
<%- _.sprintf( gettext("You have successfully signed into %(currentProvider)s, but your %(currentProvider)s account does not have a linked %(platformName)s account. To link your accounts, sign in now using your %(platformName)s password."), context ) %>
</p>
<% } %>
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div>
<div aria-live="polite">
<div class="js-reset-success status submission-success hidden">
<h4 class="message-title"><%- gettext("Check Your Email") %></h4>
<div class="message-copy">
</div>
</div>
<div class="status submission-error hidden">
<h4 class="message-title"><%- gettext("We couldn't sign you in.") %></h4>
<ul class="message-copy"></ul>
</div>
</div>
<% if (context.errorMessage) { %>
<div class="status submission-error">
<h4 class="message-title"><%- _.sprintf( gettext("An error occurred when signing you in to %(platformName)s."), context ) %></h4>
<ul class="message-copy"><%- context.errorMessage %></ul>
</div>
<% } %>
<form id="login" class="login-form" tabindex="-1" method="POST">
<div class="section-title lines">
......
<div class="status submission-error hidden" aria-live="polite">
<h4 class="message-title"><%- gettext("An error occurred.") %></h4>
<ul class="message-copy"></ul>
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div>
<form id="password-reset" class="password-reset-form" tabindex="-1" method="POST">
......
<div class="status submission-error hidden" aria-live="polite">
<h4 class="message-title"><%- gettext("We couldn't create your account.") %></h4>
<ul class="message-copy"></ul>
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div>
<form id="register" class="register-form" autocomplete="off" tabindex="-1" method="POST">
<% if (!context.currentProvider) { %>
<% if (context.providers.length > 0 || context.hasSecondaryProviders) { %>
<div class="login-providers">
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Create an account using") %></span>
</h2>
</div>
<%
_.each( context.providers, function( provider) {
if ( provider.registerUrl ) { %>
<button type="button" class="button button-primary button-<%- provider.id %> login-provider register-<%- provider.id %>" data-provider-url="<%- provider.registerUrl %>">
<div class="icon <% if ( provider.iconClass ) { %>fa <%- provider.iconClass %><% } %>" aria-hidden="true">
<% if ( provider.iconImage ) { %>
<img class="icon-image" src="<%- provider.iconImage %>" alt="<%- provider.name %> icon" />
<% } %>
</div>
<span aria-hidden="true"><%- provider.name %></span>
<span class="sr"><%- _.sprintf( gettext("Create account using %(providerName)s."), {providerName: provider.name} ) %></span>
</button>
<% }
}); %>
<% if (context.errorMessage) { %>
<div class="status submission-error">
<h4 class="message-title"><%- gettext("An error occurred.") %></h4>
<ul class="message-copy"><%- context.errorMessage %></ul>
</div>
<% } %>
<% if (context.currentProvider) { %>
<div class="status" aria-hidden="false">
<p class="message-copy">
<%- _.sprintf( gettext("You've successfully signed into %(currentProvider)s."), context ) %>
<%- _.sprintf( gettext("We just need a little more information before you start learning with %(platformName)s."), context ) %>
</p>
</div>
<% } else if ( context.providers.length > 0 || context.hasSecondaryProviders ) { %>
<div class="login-providers">
<% if ( context.hasSecondaryProviders ) { %>
<button type="button" class="button-secondary-login form-toggle" data-type="institution_login">
<%- gettext("Use my institution/campus credentials") %>
</button>
<% } %>
</div>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Create an account using") %></span>
<span class="text"><%- gettext("or create a new one here") %></span>
</h2>
</div>
<%
_.each( context.providers, function( provider) {
if ( provider.registerUrl ) { %>
<button type="button" class="button button-primary button-<%- provider.id %> login-provider register-<%- provider.id %>" data-provider-url="<%- provider.registerUrl %>">
<div class="icon <% if ( provider.iconClass ) { %>fa <%- provider.iconClass %><% } %>" aria-hidden="true">
<% if ( provider.iconImage ) { %>
<img class="icon-image" src="<%- provider.iconImage %>" alt="<%- provider.name %> icon" />
<% } %>
</div>
<span aria-hidden="true"><%- provider.name %></span>
<span class="sr"><%- _.sprintf( gettext("Create account using %(providerName)s."), {providerName: provider.name} ) %></span>
</button>
<% }
}); %>
<% if ( context.hasSecondaryProviders ) { %>
<button type="button" class="button-secondary-login form-toggle" data-type="institution_login">
<%- gettext("Use my institution/campus credentials") %>
</button>
<% } %>
</div>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("or create a new one here") %></span>
</h2>
</div>
<% } else { %>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Create a new account") %></span>
</h2>
</div>
<% } else { %>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Create a new account") %></span>
</h2>
</div>
<% } %>
<% } %>
<%= context.fields %>
......
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