(function(define) { 'use strict'; define([ 'jquery', 'underscore', 'backbone', 'common/js/utils/edx.utils.validate', 'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/string-utils', 'text!templates/student_account/form_errors.underscore' ], function($, _, Backbone, EdxUtilsValidate, HtmlUtils, StringUtils, formErrorsTpl) { return Backbone.View.extend({ tagName: 'form', el: '', tpl: '', fieldTpl: '#form_field-tpl', formErrorsTpl: formErrorsTpl, formErrorsJsHook: 'js-form-errors', defaultFormErrorsTitle: gettext('An error occurred.'), events: {}, errors: [], formType: '', $form: {}, fields: [], liveValidationFields: [], // String to append to required label fields requiredStr: '', /* Translators: This string is appended to optional field labels on the student login, registration, and profile forms. */ optionalStr: gettext('(optional)'), submitButton: '', initialize: function(data) { this.model = data.model; this.preRender(data); this.tpl = $(this.tpl).html(); this.fieldTpl = $(this.fieldTpl).html(); this.buildForm(data.fields); this.listenTo(this.model, 'error', this.saveError); }, /* Allows extended views to add custom * init steps without needing to repeat * default init steps */ preRender: function(data) { /* Custom code goes here */ return data; }, 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.$formFeedback = $container.find('.js-form-feedback'); this.$submitButton = $container.find(this.submitButton); }, buildForm: function(data) { var html = [], i, len = data.length, fieldTpl = this.fieldTpl; this.fields = data; for (i = 0; i < len; i++) { if (data[i].errorMessages) { data[i].errorMessages = this.escapeStrings(data[i].errorMessages); } html.push(HtmlUtils.template(fieldTpl)($.extend(data[i], { form: this.formType, requiredStr: this.requiredStr, optionalStr: this.optionalStr, supplementalText: data[i].supplementalText || '', supplementalLink: data[i].supplementalLink || '' }))); } this.render(html.join('')); }, /* Helper method to toggle display * including accessibility considerations */ element: { hide: function($el) { if ($el) { $el.addClass('hidden'); } }, scrollTop: function($el) { // Scroll to top of selected element $('html,body').animate({ scrollTop: $el.offset().top }, 'slow'); }, show: function($el) { if ($el) { $el.removeClass('hidden'); } } }, escapeStrings: function(obj) { _.each(obj, function(val, key) { obj[key] = _.escape(val); }); return obj; }, forgotPassword: function(event) { event.preventDefault(); this.trigger('password-help'); }, getFormData: function() { var obj = {}, $form = this.$form, elements = $form[0].elements, i, len = elements.length, $el, $label, key = '', errors = [], validation = {}; for (i = 0; i < len; i++) { $el = $(elements[i]); $label = $form.find('label[for=' + $el.attr('id') + ']'); key = $el.attr('name') || false; // Due to a bug in firefox, whitespaces in email type field are not removed. // TODO: Remove this code once firefox bug is resolved. if (key === 'email') { $el.val($el.val().trim()); } if (key) { validation = this.validate(elements[i]); if (validation.isValid) { obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val(); $el.removeClass('error'); $label.removeClass('error'); } else { errors.push(validation.message); $el.addClass('error'); $label.addClass('error'); } } } this.errors = _.uniq(errors); return obj; }, saveError: function(error) { this.errors = [ StringUtils.interpolate( '