Files
edx-platform/lms/static/js/student_account/views/FormView.js

271 lines
7.1 KiB
JavaScript

var edx = edx || {};
(function($, _, Backbone, gettext) {
'use strict';
edx.student = edx.student || {};
edx.student.account = edx.student.account || {};
edx.student.account.FormView = Backbone.View.extend({
tagName: 'form',
el: '',
tpl: '',
fieldTpl: '#form_field-tpl',
events: {},
errors: [],
formType: '',
$form: {},
fields: [],
// String to append to required label fields
requiredStr: '*',
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.$errors = $container.find('.submission-error');
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( _.template( fieldTpl, $.extend( data[i], {
form: this.formType,
requiredStr: this.requiredStr
}) ) );
}
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;
},
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();
this.trigger('password-help');
},
getFormData: function() {
var obj = {},
$form = this.$form,
elements = $form[0].elements,
i,
len = elements.length,
$el,
$label,
key = '',
errors = [],
test = {};
for ( i=0; i<len; i++ ) {
$el = $( elements[i] );
$label = $form.find('label[for=' + $el.attr('id') + ']');
key = $el.attr('name') || false;
if ( key ) {
test = this.validate( elements[i] );
if ( test.isValid ) {
obj[key] = $el.attr('type') === 'checkbox' ? $el.is(':checked') : $el.val();
$el.removeClass('error');
$label.removeClass('error');
} else {
errors.push( test.message );
$el.addClass('error');
$label.addClass('error');
}
}
}
this.errors = _.uniq( errors );
return obj;
},
saveError: function( error ) {
this.errors = ['<li>' + error.responseText + '</li>'];
this.setErrors();
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] );
}
$msg.html( html.join('') );
this.element.show( this.$errors );
// Scroll to error messages
$('html,body').animate({
scrollTop: this.$errors.offset().top
},'slow');
// Focus on first error field
this.focusFirstError();
},
submitForm: function( event ) {
var data = this.getFormData();
if (!_.isUndefined(event)) {
event.preventDefault();
}
this.toggleDisableButton(true);
if ( !_.compact(this.errors).length ) {
this.model.set( data );
this.model.save();
this.toggleErrorMsg( false );
} else {
this.toggleErrorMsg( true );
}
this.postFormSubmission();
},
/* Allows extended views to add custom
* code after form submission
*/
postFormSubmission: function() {
return true;
},
toggleErrorMsg: function( show ) {
if ( show ) {
this.setErrors();
this.toggleDisableButton(false);
} else {
this.element.hide( this.$errors );
}
},
/**
* If a form button is defined for this form, this will disable the button on
* submit, and re-enable the button if an error occurs.
*
* Args:
* disabled (boolean): If set to TRUE, disable the button.
*
*/
toggleDisableButton: function ( disabled ) {
if (this.$submitButton) {
this.$submitButton.attr('disabled', disabled);
}
},
validate: function( $el ) {
return edx.utils.validate( $el );
}
});
})(jQuery, _, Backbone, gettext);