Commit 4157e5c0 by Renzo Lucioni

i18n logistration

parent 63ea30da
...@@ -12,6 +12,7 @@ urlpatterns = patterns( ...@@ -12,6 +12,7 @@ urlpatterns = patterns(
url(r'^v1/', include(user_api_router.urls)), url(r'^v1/', include(user_api_router.urls)),
url(r'^v1/account/login_session/$', user_api_views.LoginSessionView.as_view(), name="user_api_login_session"), url(r'^v1/account/login_session/$', user_api_views.LoginSessionView.as_view(), name="user_api_login_session"),
url(r'^v1/account/registration/$', user_api_views.RegistrationView.as_view(), name="user_api_registration"), url(r'^v1/account/registration/$', user_api_views.RegistrationView.as_view(), name="user_api_registration"),
url(r'^v1/account/password_reset/$', user_api_views.PasswordResetView.as_view(), name="user_api_password_reset"),
url( url(
r'^v1/preferences/(?P<pref_key>{})/users/$'.format(UserPreference.KEY_REGEX), r'^v1/preferences/(?P<pref_key>{})/users/$'.format(UserPreference.KEY_REGEX),
user_api_views.PreferenceUsersListView.as_view() user_api_views.PreferenceUsersListView.as_view()
......
...@@ -73,23 +73,39 @@ class LoginSessionView(APIView): ...@@ -73,23 +73,39 @@ class LoginSessionView(APIView):
""" """
form_desc = FormDescription("post", reverse("user_api_login_session")) form_desc = FormDescription("post", reverse("user_api_login_session"))
# Translators: This label appears above a field on the login form
# meant to hold the user's email address.
email_label = _(u"Email")
# Translators: This example email address is used as a placeholder in
# a field on the login form meant to hold the user's email address.
email_placeholder = _(u"username@domain.com")
# Translators: These instructions appear on the login form, immediately
# below a field meant to hold the user's email address.
email_instructions = _(
u"The email address you used to register with {platform_name}"
).format(platform_name=settings.PLATFORM_NAME)
form_desc.add_field( form_desc.add_field(
"email", "email",
field_type="email", field_type="email",
label=_(u"Email"), label=email_label,
placeholder=_(u"username@domain.com"), placeholder=email_placeholder,
instructions=_( instructions=email_instructions,
u"The email address you used to register with {platform}"
).format(platform=settings.PLATFORM_NAME),
restrictions={ restrictions={
"min_length": account_api.EMAIL_MIN_LENGTH, "min_length": account_api.EMAIL_MIN_LENGTH,
"max_length": account_api.EMAIL_MAX_LENGTH, "max_length": account_api.EMAIL_MAX_LENGTH,
} }
) )
# Translators: This label appears above a field on the login form
# meant to hold the user's password.
password_label = _(u"Password")
form_desc.add_field( form_desc.add_field(
"password", "password",
label=_(u"Password"), label=password_label,
field_type="password", field_type="password",
restrictions={ restrictions={
"min_length": account_api.PASSWORD_MIN_LENGTH, "min_length": account_api.PASSWORD_MIN_LENGTH,
...@@ -97,10 +113,15 @@ class LoginSessionView(APIView): ...@@ -97,10 +113,15 @@ class LoginSessionView(APIView):
} }
) )
# Translators: This phrase appears next to a checkbox on the login form
# which the user can check in order to remain logged in after their
# session ends.
remember_label = _(u"Remember me")
form_desc.add_field( form_desc.add_field(
"remember", "remember",
field_type="checkbox", field_type="checkbox",
label=_("Remember me"), label=remember_label,
default=False, default=False,
required=False, required=False,
) )
...@@ -252,14 +273,26 @@ class RegistrationView(APIView): ...@@ -252,14 +273,26 @@ class RegistrationView(APIView):
return shim_student_view(create_account)(request) return shim_student_view(create_account)(request)
def _add_email_field(self, form_desc, required=True): def _add_email_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# meant to hold the user's email address.
email_label = _(u"Email")
# Translators: This example email address is used as a placeholder in
# a field on the registration form meant to hold the user's email address.
email_placeholder = _(u"username@domain.com")
# Translators: These instructions appear on the registration form, immediately
# below a field meant to hold the user's email address.
email_instructions = _(
u"The email address you used to register with {platform_name}"
).format(platform_name=settings.PLATFORM_NAME)
form_desc.add_field( form_desc.add_field(
"email", "email",
field_type="email", field_type="email",
label=_(u"Email"), label=email_label,
placeholder=_(u"username@domain.com"), placeholder=email_placeholder,
instructions=_( instructions=email_instructions,
u"The email address you want to use with {platform}"
).format(platform=settings.PLATFORM_NAME),
restrictions={ restrictions={
"min_length": account_api.EMAIL_MIN_LENGTH, "min_length": account_api.EMAIL_MIN_LENGTH,
"max_length": account_api.EMAIL_MAX_LENGTH, "max_length": account_api.EMAIL_MAX_LENGTH,
...@@ -268,10 +301,18 @@ class RegistrationView(APIView): ...@@ -268,10 +301,18 @@ class RegistrationView(APIView):
) )
def _add_name_field(self, form_desc, required=True): def _add_name_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# meant to hold the user's full name.
name_label = _(u"Full Name")
# Translators: These instructions appear on the registration form, immediately
# below a field meant to hold the user's full name.
name_instructions = _(u"The name that will appear on your certificates")
form_desc.add_field( form_desc.add_field(
"name", "name",
label=_(u"Full Name"), label=name_label,
instructions=_(u"The name that will appear on your certificates"), instructions=name_instructions,
restrictions={ restrictions={
"max_length": profile_api.FULL_NAME_MAX_LENGTH, "max_length": profile_api.FULL_NAME_MAX_LENGTH,
}, },
...@@ -279,10 +320,20 @@ class RegistrationView(APIView): ...@@ -279,10 +320,20 @@ class RegistrationView(APIView):
) )
def _add_username_field(self, form_desc, required=True): def _add_username_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# meant to hold the user's public username.
username_label = _(u"Username")
# Translators: These instructions appear on the registration form, immediately
# below a field meant to hold the user's public username.
username_instructions = _(
u"The name that will identify you in your courses"
)
form_desc.add_field( form_desc.add_field(
"username", "username",
label=_(u"Username"), label=username_label,
instructions=_(u"The name that will identify you in your courses"), instructions=username_instructions,
restrictions={ restrictions={
"min_length": account_api.USERNAME_MIN_LENGTH, "min_length": account_api.USERNAME_MIN_LENGTH,
"max_length": account_api.USERNAME_MAX_LENGTH, "max_length": account_api.USERNAME_MAX_LENGTH,
...@@ -291,9 +342,14 @@ class RegistrationView(APIView): ...@@ -291,9 +342,14 @@ class RegistrationView(APIView):
) )
def _add_password_field(self, form_desc, required=True): def _add_password_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# meant to hold the user's password.
password_label = _(u"Password")
form_desc.add_field( form_desc.add_field(
"password", "password",
label=_(u"Password"), label=password_label,
field_type="password",
restrictions={ restrictions={
"min_length": account_api.PASSWORD_MIN_LENGTH, "min_length": account_api.PASSWORD_MIN_LENGTH,
"max_length": account_api.PASSWORD_MAX_LENGTH, "max_length": account_api.PASSWORD_MAX_LENGTH,
...@@ -302,57 +358,87 @@ class RegistrationView(APIView): ...@@ -302,57 +358,87 @@ class RegistrationView(APIView):
) )
def _add_level_of_education_field(self, form_desc, required=True): def _add_level_of_education_field(self, form_desc, required=True):
# Translators: This label appears above a dropdown menu on the registration
# form used to select the user's highest completed level of education.
education_level_label = _(u"Highest Level of Education Completed")
form_desc.add_field( form_desc.add_field(
"level_of_education", "level_of_education",
label=_("Highest Level of Education Completed"), label=education_level_label,
field_type="select", field_type="select",
options=self._options_with_default(UserProfile.LEVEL_OF_EDUCATION_CHOICES), options=self._options_with_default(UserProfile.LEVEL_OF_EDUCATION_CHOICES),
required=required required=required
) )
def _add_gender_field(self, form_desc, required=True): def _add_gender_field(self, form_desc, required=True):
# Translators: This label appears above a dropdown menu on the registration
# form used to select the user's gender.
gender_label = _(u"Gender")
form_desc.add_field( form_desc.add_field(
"gender", "gender",
label=_("Gender"), label=gender_label,
field_type="select", field_type="select",
options=self._options_with_default(UserProfile.GENDER_CHOICES), options=self._options_with_default(UserProfile.GENDER_CHOICES),
required=required required=required
) )
def _add_year_of_birth_field(self, form_desc, required=True): def _add_year_of_birth_field(self, form_desc, required=True):
# Translators: This label appears above a dropdown menu on the registration
# form used to select the user's year of birth.
yob_label = _(u"Year of Birth")
options = [(unicode(year), unicode(year)) for year in UserProfile.VALID_YEARS] options = [(unicode(year), unicode(year)) for year in UserProfile.VALID_YEARS]
form_desc.add_field( form_desc.add_field(
"year_of_birth", "year_of_birth",
label=_("Year of Birth"), label=yob_label,
field_type="select", field_type="select",
options=self._options_with_default(options), options=self._options_with_default(options),
required=required required=required
) )
def _add_mailing_address_field(self, form_desc, required=True): def _add_mailing_address_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# meant to hold the user's mailing address.
mailing_address_label = _(u"Mailing Address")
form_desc.add_field( form_desc.add_field(
"mailing_address", "mailing_address",
label=_("Mailing Address"), label=mailing_address_label,
field_type="textarea", field_type="textarea",
required=required required=required
) )
def _add_goals_field(self, form_desc, required=True): def _add_goals_field(self, form_desc, required=True):
# Translators: This phrase appears above a field on the registration form
# meant to hold the user's reasons for registering with edX.
goals_label = _(
u"If you'd like, tell us why you're interested in {platform_name}"
).format(platform_name=settings.PLATFORM_NAME)
form_desc.add_field( form_desc.add_field(
"goals", "goals",
label=_("If you'd like, tell us why you're interested in edX."), label=goals_label,
field_type="textarea", field_type="textarea",
required=required required=required
) )
def _add_city_field(self, form_desc, required=True): def _add_city_field(self, form_desc, required=True):
# Translators: This label appears above a field on the registration form
# which allows the user to input the city in which they live.
city_label = _(u"City")
form_desc.add_field( form_desc.add_field(
"city", "city",
label=_("City"), label=city_label,
required=required required=required
) )
def _add_country_field(self, form_desc, required=True): def _add_country_field(self, form_desc, required=True):
# Translators: This label appears above a dropdown menu on the registration
# form used to select the country in which the user lives.
country_label = _(u"Country")
sorted_countries = sorted( sorted_countries = sorted(
countries.countries, key=lambda(__, name): unicode(name) countries.countries, key=lambda(__, name): unicode(name)
) )
...@@ -362,7 +448,7 @@ class RegistrationView(APIView): ...@@ -362,7 +448,7 @@ class RegistrationView(APIView):
] ]
form_desc.add_field( form_desc.add_field(
"country", "country",
label=_("Country"), label=country_label,
field_type="select", field_type="select",
options=self._options_with_default(options), options=self._options_with_default(options),
required=required required=required
...@@ -375,7 +461,8 @@ class RegistrationView(APIView): ...@@ -375,7 +461,8 @@ class RegistrationView(APIView):
# Combine terms of service and honor code checkboxes # Combine terms of service and honor code checkboxes
else: else:
# Translators: This is a legal document users must agree to in order to register a new account. # Translators: This is a legal document users must agree to
# in order to register a new account.
terms_text = _(u"Terms of Service and Honor Code") terms_text = _(u"Terms of Service and Honor Code")
terms_link = u"<a href=\"{url}\">{terms_text}</a>".format( terms_link = u"<a href=\"{url}\">{terms_text}</a>".format(
...@@ -383,11 +470,17 @@ class RegistrationView(APIView): ...@@ -383,11 +470,17 @@ class RegistrationView(APIView):
terms_text=terms_text terms_text=terms_text
) )
# Translators: "Terms of service" is a legal document users must agree to in order to register a new account. # Translators: "Terms of Service" is a legal document users must agree to
label = _(u"I agree to the {terms_of_service}").format(terms_of_service=terms_link) # in order to register a new account.
label = _(
u"I agree to the {terms_of_service}"
).format(terms_of_service=terms_link)
# Translators: "Terms of service" is a legal document users must agree to in order to register a new account. # Translators: "Terms of Service" is a legal document users must agree to
error_msg = _(u"You must agree to the {terms_of_service}").format(terms_of_service=terms_link) # in order to register a new account.
error_msg = _(
u"You must agree to the {terms_of_service}"
).format(terms_of_service=terms_link)
form_desc.add_field( form_desc.add_field(
"honor_code", "honor_code",
...@@ -401,17 +494,20 @@ class RegistrationView(APIView): ...@@ -401,17 +494,20 @@ class RegistrationView(APIView):
) )
def _add_terms_of_service_field(self, form_desc, required=True): def _add_terms_of_service_field(self, form_desc, required=True):
# Translators: This is a legal document users must agree to in order to register a new account. # Translators: This is a legal document users must agree to
# in order to register a new account.
terms_text = _(u"Terms of Service") terms_text = _(u"Terms of Service")
terms_link = u"<a href=\"{url}\">{terms_text}</a>".format( terms_link = u"<a href=\"{url}\">{terms_text}</a>".format(
url=marketing_link("TOS"), url=marketing_link("TOS"),
terms_text=terms_text terms_text=terms_text
) )
# Translators: "Terms of service" is a legal document users must agree to in order to register a new account. # Translators: "Terms of service" is a legal document users must agree to
# in order to register a new account.
label = _(u"I agree to the {terms_of_service}").format(terms_of_service=terms_link) label = _(u"I agree to the {terms_of_service}").format(terms_of_service=terms_link)
# Translators: "Terms of service" is a legal document users must agree to in order to register a new account. # Translators: "Terms of service" is a legal document users must agree to
# in order to register a new account.
error_msg = _("You must agree to the {terms_of_service}").format(terms_of_service=terms_link) error_msg = _("You must agree to the {terms_of_service}").format(terms_of_service=terms_link)
form_desc.add_field( form_desc.add_field(
...@@ -478,6 +574,60 @@ class RegistrationView(APIView): ...@@ -478,6 +574,60 @@ class RegistrationView(APIView):
restrictions={} restrictions={}
) )
class PasswordResetView(APIView):
"""HTTP end-point for GETting a description of the password reset form. """
# This end-point is available to anonymous users,
# so do not require authentication.
authentication_classes = []
def get(self, request):
"""Return a description of the password reset form.
This decouples clients from the API definition:
if the API decides to modify the form, clients won't need
to be updated.
See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description.
Arguments:
request (HttpRequest)
Returns:
HttpResponse
"""
form_desc = FormDescription("post", reverse("password_change_request"))
# Translators: This label appears above a field on the password reset
# form meant to hold the user's email address.
email_label = _(u"Email")
# Translators: This example email address is used as a placeholder in
# a field on the password reset form meant to hold the user's email address.
email_placeholder = _(u"username@domain.com")
# Translators: These instructions appear on the password reset form,
# immediately below a field meant to hold the user's email address.
email_instructions = _(
u"The email address you used to register with {platform_name}"
).format(platform_name=settings.PLATFORM_NAME)
form_desc.add_field(
"email",
field_type="email",
label=email_label,
placeholder=email_placeholder,
instructions=email_instructions,
restrictions={
"min_length": account_api.EMAIL_MIN_LENGTH,
"max_length": account_api.EMAIL_MAX_LENGTH,
}
)
return HttpResponse(form_desc.to_json(), content_type="application/json")
class UserViewSet(viewsets.ReadOnlyModelViewSet): class UserViewSet(viewsets.ReadOnlyModelViewSet):
authentication_classes = (authentication.SessionAuthentication,) authentication_classes = (authentication.SessionAuthentication,)
......
var edx = edx || {}; var edx = edx || {};
(function( $, _ ) { (function( $, _, gettext ) {
'use strict'; 'use strict';
edx.utils = edx.utils || {}; edx.utils = edx.utils || {};
...@@ -10,10 +10,10 @@ var edx = edx || {}; ...@@ -10,10 +10,10 @@ var edx = edx || {};
validate: { validate: {
msg: { msg: {
email: '<li>The email address you\'ve provided is invalid.</li>', email: '<li><%- gettext("The email address you\'ve provided is invalid.") %></li>',
min: '<li><%= field %> must have at least <%= count %> characters.</li>', min: '<li><%- _.sprintf(gettext("%(field)s must have at least %(count)d characters"), context) %></li>',
max: '<li><%= field %> can only contain up to <%= count %> characters.</li>', max: '<li><%- _.sprintf(gettext("%(field)s can only contain up to %(count)d characters"), context) %></li>',
required: '<li><%= field %> is required.</li>', required: '<li><%- _.sprintf(gettext("%(field)s is required"), context) %></li>',
custom: '<li><%= content %></li>' custom: '<li><%= content %></li>'
}, },
...@@ -123,13 +123,17 @@ var edx = edx || {}; ...@@ -123,13 +123,17 @@ var edx = edx || {};
tpl = _fn.validate.msg[key]; tpl = _fn.validate.msg[key];
obj = { obj = {
field: _fn.validate.str.capitalizeFirstLetter( name ) // We pass the context object to the template so that
// we can perform variable interpolation using sprintf
context: {
field: _fn.validate.str.capitalizeFirstLetter( name )
}
}; };
if ( key === 'min' ) { if ( key === 'min' ) {
obj.count = $el.attr('minlength'); obj.context.count = $el.attr('minlength');
} else if ( key === 'max' ) { } else if ( key === 'max' ) {
obj.count = $el.attr('maxlength'); obj.context.count = $el.attr('maxlength');
} }
} }
...@@ -150,4 +154,4 @@ var edx = edx || {}; ...@@ -150,4 +154,4 @@ var edx = edx || {};
edx.utils.validate = utils.validate; edx.utils.validate = utils.validate;
})( jQuery, _ ); })( jQuery, _, gettext );
\ No newline at end of file
...@@ -69,6 +69,7 @@ def login_and_registration_form(request, initial_mode="login"): ...@@ -69,6 +69,7 @@ def login_and_registration_form(request, initial_mode="login"):
'disable_courseware_js': True, 'disable_courseware_js': True,
'initial_mode': initial_mode, 'initial_mode': initial_mode,
'third_party_auth': json.dumps(_third_party_auth_context(request)), 'third_party_auth': json.dumps(_third_party_auth_context(request)),
'platform_name': settings.PLATFORM_NAME,
} }
return render_to_response('student_account/login_and_register.html', context) return render_to_response('student_account/login_and_register.html', context)
......
...@@ -275,7 +275,8 @@ ...@@ -275,7 +275,8 @@
exports: 'js/student_account/views/LoginView', exports: 'js/student_account/views/LoginView',
deps: [ deps: [
'js/student_account/models/LoginModel', 'js/student_account/models/LoginModel',
'js/student_account/views/FormView' 'js/student_account/views/FormView',
'underscore.string'
] ]
}, },
'js/student_account/models/PasswordResetModel': { 'js/student_account/models/PasswordResetModel': {
...@@ -297,7 +298,8 @@ ...@@ -297,7 +298,8 @@
exports: 'js/student_account/views/RegisterView', exports: 'js/student_account/views/RegisterView',
deps: [ deps: [
'js/student_account/models/RegisterModel', 'js/student_account/models/RegisterModel',
'js/student_account/views/FormView' 'js/student_account/views/FormView',
'underscore.string'
] ]
}, },
'js/student_account/views/AccessView': { 'js/student_account/views/AccessView': {
...@@ -305,7 +307,8 @@ ...@@ -305,7 +307,8 @@
deps: [ deps: [
'js/student_account/views/LoginView', 'js/student_account/views/LoginView',
'js/student_account/views/PasswordResetView', 'js/student_account/views/PasswordResetView',
'js/student_account/views/RegisterView' 'js/student_account/views/RegisterView',
'underscore.string'
] ]
}, },
}, },
......
...@@ -8,6 +8,7 @@ var edx = edx || {}; ...@@ -8,6 +8,7 @@ var edx = edx || {};
return new edx.student.account.AccessView({ return new edx.student.account.AccessView({
mode: $('#login-and-registration-container').data('initial-mode'), mode: $('#login-and-registration-container').data('initial-mode'),
thirdPartyAuth: $('#login-and-registration-container').data('third-party-auth') thirdPartyAuth: $('#login-and-registration-container').data('third-party-auth'),
platformName: $('#login-and-registration-container').data('platform-name')
}); });
})(jQuery); })(jQuery);
...@@ -49,4 +49,4 @@ var edx = edx || {}; ...@@ -49,4 +49,4 @@ var edx = edx || {};
}); });
} }
}); });
})(jQuery, _, Backbone, gettext); })(jQuery, _, Backbone, gettext);
\ No newline at end of file
...@@ -12,14 +12,18 @@ var edx = edx || {}; ...@@ -12,14 +12,18 @@ var edx = edx || {};
email: '' email: ''
}, },
urlRoot: '/account/password', urlRoot: '',
initialize: function( obj ) {
this.urlRoot = obj.url;
},
sync: function(method, model) { sync: function(method, model) {
var headers = { var headers = {
'X-CSRFToken': $.cookie('csrftoken') 'X-CSRFToken': $.cookie('csrftoken')
}; };
// Is just expecting email address // Only expects an email address.
$.ajax({ $.ajax({
url: model.urlRoot, url: model.urlRoot,
type: 'POST', type: 'POST',
......
...@@ -52,9 +52,8 @@ var edx = edx || {}; ...@@ -52,9 +52,8 @@ var edx = edx || {};
window.location.href = url; window.location.href = url;
}) })
.fail( function( error ) { .fail( function( error ) {
console.log('RegisterModel.save() FAILURE!!!!!');
model.trigger('error', error); model.trigger('error', error);
}); });
} }
}); });
})(jQuery, _, Backbone, gettext); })(jQuery, _, Backbone, gettext);
\ No newline at end of file
...@@ -25,12 +25,19 @@ var edx = edx || {}; ...@@ -25,12 +25,19 @@ var edx = edx || {};
activeForm: '', activeForm: '',
initialize: function( obj ) { initialize: function( obj ) {
/* Mix non-conflicting functions from underscore.string
* (all but include, contains, and reverse) into the
* Underscore namespace
*/
_.mixin(_.str.exports())
this.tpl = $(this.tpl).html(); this.tpl = $(this.tpl).html();
this.activeForm = obj.mode || 'login'; this.activeForm = obj.mode || 'login';
this.thirdPartyAuth = obj.thirdPartyAuth || { this.thirdPartyAuth = obj.thirdPartyAuth || {
currentProvider: null, currentProvider: null,
providers: [] providers: []
}; };
this.platformName = obj.platformName;
this.render(); this.render();
}, },
...@@ -52,11 +59,7 @@ var edx = edx || {}; ...@@ -52,11 +59,7 @@ var edx = edx || {};
}, },
loadForm: function( type ) { loadForm: function( type ) {
if ( type === 'reset' ) { this.getFormData( type, this.load[type], this );
this.load.reset( this );
} else {
this.getFormData( type, this.load[type], this );
}
}, },
load: { load: {
...@@ -68,27 +71,21 @@ var edx = edx || {}; ...@@ -68,27 +71,21 @@ var edx = edx || {};
context.subview.login = new edx.student.account.LoginView({ context.subview.login = new edx.student.account.LoginView({
fields: data.fields, fields: data.fields,
model: model, model: model,
thirdPartyAuth: context.thirdPartyAuth thirdPartyAuth: context.thirdPartyAuth,
platformName: context.platformName
}); });
// Listen for 'password-help' event to toggle sub-views // Listen for 'password-help' event to toggle sub-views
context.listenTo( context.subview.login, 'password-help', context.resetPassword ); context.listenTo( context.subview.login, 'password-help', context.resetPassword );
}, },
reset: function( context ) { reset: function( data, context ) {
var model = new edx.student.account.PasswordResetModel(), var model = new edx.student.account.PasswordResetModel({
data = [{ url: data.submit_url
label: 'Email', });
instructions: 'The email address you used to register with edX',
name: 'email',
required: true,
type: 'email',
restrictions: [],
defaultValue: ''
}];
context.subview.passwordHelp = new edx.student.account.PasswordResetView({ context.subview.passwordHelp = new edx.student.account.PasswordResetView({
fields: data, fields: data.fields,
model: model model: model
}); });
}, },
...@@ -101,7 +98,8 @@ var edx = edx || {}; ...@@ -101,7 +98,8 @@ var edx = edx || {};
context.subview.register = new edx.student.account.RegisterView({ context.subview.register = new edx.student.account.RegisterView({
fields: data.fields, fields: data.fields,
model: model, model: model,
thirdPartyAuth: context.thirdPartyAuth thirdPartyAuth: context.thirdPartyAuth,
platformName: context.platformName
}); });
} }
}, },
...@@ -109,7 +107,8 @@ var edx = edx || {}; ...@@ -109,7 +107,8 @@ var edx = edx || {};
getFormData: function( type, callback, context ) { getFormData: function( type, callback, context ) {
var urls = { var urls = {
login: 'login_session', login: 'login_session',
register: 'registration' register: 'registration',
reset: 'password_reset'
}; };
$.ajax({ $.ajax({
......
...@@ -44,7 +44,7 @@ var edx = edx || {}; ...@@ -44,7 +44,7 @@ var edx = edx || {};
* default init steps * default init steps
*/ */
preRender: function( data ) { preRender: function( data ) {
/* custom code goes here */ /* Custom code goes here */
return data; return data;
}, },
...@@ -89,7 +89,7 @@ var edx = edx || {}; ...@@ -89,7 +89,7 @@ var edx = edx || {};
this.render( html.join('') ); this.render( html.join('') );
}, },
/* Helper method ot toggle display /* Helper method to toggle display
* including accessibility considerations * including accessibility considerations
*/ */
element: { element: {
...@@ -143,7 +143,7 @@ var edx = edx || {}; ...@@ -143,7 +143,7 @@ var edx = edx || {};
key = $el.attr('name') || false; key = $el.attr('name') || false;
if ( key ) { if ( key ) {
test = this.validate( elements[i], this.formType ); test = this.validate( elements[i] );
if ( test.isValid ) { if ( test.isValid ) {
obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val(); obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val();
...@@ -204,8 +204,9 @@ var edx = edx || {}; ...@@ -204,8 +204,9 @@ var edx = edx || {};
this.element.hide( this.$errors ); this.element.hide( this.$errors );
} }
}, },
validate: function( $el, form ) {
return edx.utils.validate( $el, form ); validate: function( $el ) {
return edx.utils.validate( $el );
} }
}); });
......
...@@ -24,15 +24,21 @@ var edx = edx || {}; ...@@ -24,15 +24,21 @@ var edx = edx || {};
preRender: function( data ) { preRender: function( data ) {
this.providers = data.thirdPartyAuth.providers || []; this.providers = data.thirdPartyAuth.providers || [];
this.currentProvider = data.thirdPartyAuth.currentProvider || ''; this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.platformName = data.platformName;
}, },
render: function( html ) { render: function( html ) {
var fields = html || ''; var fields = html || '';
$(this.el).html( _.template( this.tpl, { $(this.el).html( _.template( this.tpl, {
fields: fields, // We pass the context object to the template so that
currentProvider: this.currentProvider, // we can perform variable interpolation using sprintf
providers: this.providers context: {
fields: fields,
currentProvider: this.currentProvider,
providers: this.providers,
platformName: this.platformName
}
})); }));
this.postRender(); this.postRender();
...@@ -94,5 +100,4 @@ var edx = edx || {}; ...@@ -94,5 +100,4 @@ var edx = edx || {};
} }
} }
}); });
})(jQuery, _, gettext); })(jQuery, _, gettext);
...@@ -43,24 +43,6 @@ var edx = edx || {}; ...@@ -43,24 +43,6 @@ var edx = edx || {};
this.element.hide( $el.find('#password-reset-form') ); this.element.hide( $el.find('#password-reset-form') );
this.element.show( $el.find('.js-reset-success') ); this.element.show( $el.find('.js-reset-success') );
},
submitForm: function( event ) {
var data = this.getFormData();
event.preventDefault();
if ( !_.compact(this.errors).length ) {
this.model.set( data );
this.model.save();
this.toggleErrorMsg( false );
} else {
this.toggleErrorMsg( true );
}
},
validate: function( $el ) {
return edx.utils.validate( $el );
} }
}); });
......
...@@ -21,15 +21,21 @@ var edx = edx || {}; ...@@ -21,15 +21,21 @@ var edx = edx || {};
preRender: function( data ) { preRender: function( data ) {
this.providers = data.thirdPartyAuth.providers || []; this.providers = data.thirdPartyAuth.providers || [];
this.currentProvider = data.thirdPartyAuth.currentProvider || ''; this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.platformName = data.platformName;
}, },
render: function( html ) { render: function( html ) {
var fields = html || ''; var fields = html || '';
$(this.el).html( _.template( this.tpl, { $(this.el).html( _.template( this.tpl, {
fields: fields, // We pass the context object to the template so that
currentProvider: this.currentProvider, // we can perform variable interpolation using sprintf
providers: this.providers context: {
fields: fields,
currentProvider: this.currentProvider,
providers: this.providers,
platformName: this.platformName
}
})); }));
this.postRender(); this.postRender();
......
...@@ -99,6 +99,11 @@ ...@@ -99,6 +99,11 @@
/** The forms **/ /** The forms **/
.form-wrapper { .form-wrapper {
padding-top: 25px; padding-top: 25px;
form {
@include clearfix;
clear: both;
}
} }
.login-form { .login-form {
......
<header class="js-login-register-header header"> <header class="js-login-register-header header">
<h1 class="headline">Welcome!</h1> <h1 class="headline"><%- gettext("Welcome!") %></h1>
<p class="tagline">Log in or register to take courses from the world's best universities.</p> <p class="tagline"><%- gettext("Log in or register to take courses from the world's best universities.") %></p>
</header> </header>
<section class="form-type"> <section class="form-type">
<h2> <h2>
<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" class="form-label">I am a new user</label> <label for="register-option" class="form-label"><%- gettext("I am a new user") %></label>
</h2> </h2>
<div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden" aria-hidden="true<% } %>"></div> <div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden" aria-hidden="true<% } %>"></div>
</section> </section>
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<section class="form-type"> <section class="form-type">
<h2> <h2>
<input type="radio" name="form" id="login-option" value="login" class="form-toggle" <% if ( mode === 'login' ) { %>checked<% } %>> <input type="radio" name="form" id="login-option" value="login" class="form-toggle" <% if ( mode === 'login' ) { %>checked<% } %>>
<label for="login-option" class="form-label">I am a returning user</label> <label for="login-option" class="form-label"><%- gettext("I am a returning user") %></label>
</h2> </h2>
<div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden" aria-hidden="true<% } %>"></div> <div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden" aria-hidden="true<% } %>"></div>
</section> </section>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<% } %> <% } %>
<% if( form === 'login' && name === 'password' ) { %> <% if( form === 'login' && name === 'password' ) { %>
<a href="#" class="forgot-password field-link">Forgot password?</a> <a href="#" class="forgot-password field-link"><%- gettext("Forgot password?") %></a>
<% } %> <% } %>
<% if ( type === 'select' ) { %> <% if ( type === 'select' ) { %>
...@@ -60,4 +60,4 @@ ...@@ -60,4 +60,4 @@
<% } %> <% } %>
<span id="<%= form %>-<%= name %>-desc" class="desc"><%= instructions %></span> <span id="<%= form %>-<%= name %>-desc" class="desc"><%= instructions %></span>
</p> </p>
\ No newline at end of file
<form id="login" class="login-form"> <form id="login" class="login-form">
<div class="status already-authenticated-msg hidden" aria-hidden="true"> <div class="status already-authenticated-msg hidden" aria-hidden="true">
<% if (currentProvider) { %> <% if (context.currentProvider) { %>
<p class="message-copy">You've successfully logged into <%- currentProvider %>, but your <%- currentProvider %> account isn't linked with an edX account. To link your accounts, go to your edX dashboard.</p> <p class="message-copy">
<%- _.sprintf(gettext("You've successfully logged into %(currentProvider)s, but your %(currentProvider)s account isn't linked with an %(platformName)s account. To link your accounts, go to your %(platformName)s dashboard."), context) %>
</p>
<% } %> <% } %>
</div> </div>
<div class="status submission-error hidden" aria-hidden="true"> <div class="status submission-error hidden" aria-hidden="true">
<h4 class="message-title">We couldn't log you in.</h4> <h4 class="message-title"><%- gettext("We couldn't log you in.") %></h4>
<ul class="message-copy"></ul> <ul class="message-copy"></ul>
</div> </div>
<%= fields %> <%= context.fields %>
<button class="action action-primary action-update js-login">Log in</button>
<button class="action action-primary action-update js-login"><%- gettext("Log in") %></button>
</form> </form>
<% _.each( providers, function( provider) { %> <% _.each( context.providers, function( provider ) { %>
<button type="submit"class="button button-primary button-<%- provider.name %> login-provider" data-provider-url="<%- provider.loginUrl %>"> <button type="submit"class="button button-primary button-<%- provider.name %> login-provider" data-provider-url="<%- provider.loginUrl %>">
<span class="icon <%- provider.iconClass %>"></span>Log in using <%- provider.name %> <span class="icon <%- provider.iconClass %>"></span><%- _.sprintf(gettext("Log in using %(name)s"), provider) %>
</button> </button>
<% }); %> <% }); %>
...@@ -6,16 +6,16 @@ ...@@ -6,16 +6,16 @@
<%block name="pagetitle">${_("Log in or Register")}</%block> <%block name="pagetitle">${_("Log in or Register")}</%block>
<%block name="js_extra"> <%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/underscore-min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<%static:js group='student_account'/> <%static:js group='student_account'/>
</%block> </%block>
<%block name="header_extras"> <%block name="header_extras">
% for template_name in ["account", "access", "form_field", "login", "register", "password_reset"]: % for template_name in ["account", "access", "form_field", "login", "register", "password_reset"]:
<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>
...@@ -24,5 +24,6 @@ ...@@ -24,5 +24,6 @@
class="login-register" class="login-register"
data-initial-mode="${initial_mode}" data-initial-mode="${initial_mode}"
data-third-party-auth='${third_party_auth}' data-third-party-auth='${third_party_auth}'
data-platform-name='${platform_name}'
/> />
</div> </div>
<header class="header"> <header class="header">
<h1 class="headline">Reset Password</h1> <h1 class="headline"><%- gettext("Reset Password") %></h1>
</header> </header>
<section class="form-type"> <section class="form-type">
<div id="password-reset-form" class="form-wrapper"> <div id="password-reset-form" class="form-wrapper">
<!-- <p class="action-label">Please enter your email address below and we will send you instructions for setting a new password.</p> --> <p class="action-label"><%- gettext("Enter the email address you used to create your account. We'll send you a link you can use to reset your password.") %></p>
<p class="action-label">Enter the email address you used to create your account. We'll send you a link you can use to reset your password.</p>
<form id="password-reset-form"> <form id="password-reset-form">
<div class="status submission-error hidden" aria-hidden="true"> <div class="status submission-error hidden" aria-hidden="true">
<h4 class="message-title">An error occurred.</h4> <h4 class="message-title"><%- gettext("An error occurred.") %></h4>
<ul class="message-copy"></ul> <ul class="message-copy"></ul>
</div> </div>
<%= fields %> <%= fields %>
<button class="action action-primary action-update js-reset">Reset password</button> <button class="action action-primary action-update js-reset"><%- gettext("Reset password") %></button>
</form> </form>
</div> </div>
<div class="js-reset-success status submission-success hidden" aria-hidden="true"> <div class="js-reset-success status submission-success hidden" aria-hidden="true">
<h4 class="message-title">Password Reset Email Sent</h4> <h4 class="message-title"><%- gettext("Password Reset Email Sent") %></h4>
<div class="message-copy"> <div class="message-copy">
<p>We've sent instructions for resetting your password to the email address you provided.</p> <p>
<%- gettext("We've sent instructions for resetting your password to the email address you provided.") %>
</p>
</div> </div>
</div> </div>
</section> </section>
<% if (currentProvider) { %> <% if (context.currentProvider) { %>
<div class="status" aria-hidden="false"> <div class="status" aria-hidden="false">
<p class="message-copy">You've successfully logged into <%- currentProvider %>. We just need a little more information before you start learning with edX.</p> <p class="message-copy">
<%- _.sprintf(gettext("You've successfully logged into %(currentProvider)s."), context) %>
<%- _.sprintf(gettext("We just need a little more information before you start learning with %(platformName)s."), context) %>
</p>
</div> </div>
<% } else { <% } else {
_.each( providers, function( provider) { %> _.each( context.providers, function( provider) { %>
<button type="submit"class="button button-primary button-<%- provider.name %> login-provider" data-provider-url="<%- provider.registerUrl %>"> <button type="submit"class="button button-primary button-<%- provider.name %> login-provider" data-provider-url="<%- provider.registerUrl %>">
<span class="icon <%- provider.iconClass %>"></span>Register using <%- provider.name %> <span class="icon <%- provider.iconClass %>"></span><%- _.sprintf(gettext("Register using %(name)s"), provider) %>
</button> </button>
<% }); <% });
} %> } %>
<form id="register" autocomplete="off"> <form id="register" autocomplete="off">
<div class="status submission-error hidden" aria-hidden="true"> <div class="status submission-error hidden" aria-hidden="true">
<h4 class="message-title">An error occurred in your registration.</h4> <h4 class="message-title"><%- gettext("An error occurred in your registration.") %></h4>
<ul class="message-copy"></ul> <ul class="message-copy"></ul>
</div> </div>
<!-- PASSWORD FIELD DISPLAYS IN PLAIN TEXT -->
<%= fields %> <%= context.fields %>
<button class="action action-primary action-update js-register">Register</button>
<button class="action action-primary action-update js-register"><%- gettext("Register") %></button>
</form> </form>
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