(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 || ''; HtmlUtils.setHtml( $(this.el), HtmlUtils.HTML( _.template(this.tpl)({ fields: fields, HtmlUtils: HtmlUtils }) ) ) 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 || '', loginIssueSupportLink: data[i].loginIssueSupportLink || '' }))); } 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, $n, tpl, len = elements.length, $el, $label, key = '', errors = [], validation = {}, $desc, $validationNode; 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) { if (this.interesting_fields($el)) { this.remove_validation_error($el, $form); } 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 { if (this.interesting_fields($el)) { $validationNode = this.get_error_validation_node($el, $form); if ($validationNode) { $n = $.parseHTML(validation.message); tpl = HtmlUtils.template(''); HtmlUtils.prepend($n, tpl()); HtmlUtils.append($validationNode, HtmlUtils.HTML($n)); } $desc = $form.find('#' + $el.attr('id') + '-desc'); $desc.remove(); } errors.push(validation.message); $el.addClass('error'); $label.addClass('error'); } } } this.errors = _.uniq(errors); return obj; }, remove_validation_error: function($el, $form) { var $validationNode = this.get_error_validation_node($el, $form); if ($validationNode && $validationNode.find('li').length > 0) { $validationNode.empty(); } }, get_error_validation_node: function($el, $form) { var $node = $form.find('#' + $el.attr('id') + '-validation-error-msg'); return $node.find('ul'); }, interesting_fields: function($el) { return ($el.attr('name') === 'email' || $el.attr('name') === 'password'); }, toggleHelp: function(event, $help) { var $el = $(event.currentTarget); var $i = $el.find('i'); if ($help.css('display') === 'block') { $help.css('display', 'none'); $i.addClass('fa-caret-right').removeClass('fa-caret-down'); } else { $help.css('display', 'block'); $i.addClass('fa-caret-down').removeClass('fa-caret-right'); } }, saveError: function(error) { this.errors = [ StringUtils.interpolate( '