define([
'jquery',
'underscore',
'backbone',
'backbone_apps/models/school',
'jquery_plugins/jquery.formparams',
'jquery_plugins/jquery.blockUI-2.3.7'
],
function($, _, Backbone, School){
$.blockUI.defaults.css = {};
var SchoolSelectorView = Backbone.View.extend({
newSchoolForm : $($('#new-school-form-tpl').html()).html(),
stateDefs : {
'schools-found' : function() {
$(this.el).addClass('schools-found').removeClass('schools-not-found');
},
'schools-not-found' : function() {
$(this.el).addClass('schools-not-found').removeClass('schools-found');
},
'adding-school' : function() {
$(this.el).addClass('adding-school').removeClass('cancelled-school-edit');
},
'editing-school' : function() {
$(this.el).addClass('editing-school').removeClass('cancelled-school-edit');
},
'cancelled-school-edit' : function() {
$(this.el).addClass('cancelled-school-edit').removeClass('adding-school editing-school');
},
'new-school-exists' : function() {
$(this.el).addClass('new-school-exists').removeClass('adding-school editing-school');
},
'new-school-updated' : function() {
$(this.el).addClass('new-school-updated').removeClass('adding-school editing-school');
}
},
events : {
'click a[href="#add-new-school"]' : 'addNewSchool',
'click a[href="#edit-new-school"]' : 'editNewSchool',
'click a[href*="cancel-edit-school"]' : 'cancelEditSchool', // the *= attribute portion of the selector is necessary for IE7
'click a[href="#select-new-school"]' : 'selectNewSchool',
'click #school_submit' : 'submitSchool'
},
initialize : function(opts) {
var self = this;
_.bindAll(this,
'validateZipcode',
'handleSchoolsFound',
'handleSchoolsNotFound',
'handleNewSchoolSaved',
'handleAudienceChange',
'addSchoolFields',
'setState',
'detach',
'reattach',
'populateSchoolsSelect');
// used later when we detach and reattach this view element to the DOM
this.$prevEl = $(this.el).prev();
// handle changes in the audience field. show the school selector if audience is educator
this.$audienceField = opts.audienceField;
if( opts.audienceField.length ) {
this.$audienceField.live('change', this.handleAudienceChange);
this.handleAudienceChange();
}
// intialize zipcode validation and Ajax posting
this.validateZipcode = _.debounce(this.validateZipcode, 500);
this.$('#school-select-zipcode').bind('keydown', function(e) {
self.supressFormSubmission(e);
self.validateZipcode();
});
// search for a zipcode if one is pre-populated in the form; run this once per page load
var $zipcodeField = this.$('#school-select-zipcode');
var zipcode = $zipcodeField.val();
if(zipcode && zipcode.search(/\d{5}/) >= 0) {
$zipcodeField.trigger('keydown');
}
this.school = new School();
},
addNewSchool : function(e) {
var $newSchoolForm;
e.preventDefault();
this.disableSelection();
this.disableZipcodeInput();
// $('#new-school-form').show();
this.showNewSchoolForm() // a jQuery ref to the form is returned
.find('#school_zipcode')
.val( $('#school-select-zipcode').val() );
this.setState('adding-school');
},
editNewSchool : function(e) {
e.preventDefault();
this.disableSelection();
this.disableZipcodeInput();
this.showEditSchoolForm();
this.setState('editing-school');
},
selectNewSchool : function(e) {
e.preventDefault();
var zipcode = this.school.get('zipcode');
this.$('#school-select-zipcode').val(zipcode);
this.getSchoolsForZipcode(zipcode, this.school.id);
},
cancelEditSchool : function(e) {
e.preventDefault();
this.hideNewSchoolForm();
if(this.schoolsFound) { this.enableSelection(); }
this.enableZipcodeInput();
this.setState('cancelled-school-edit');
},
showSchoolForm : function(action) {
return $('#new-school-form').empty()
.append(this[action + 'SchoolForm'])
.show()
.find('#school_name')
.focus()
.end();
},
showNewSchoolForm : function() {
return this.showSchoolForm('new');
},
showEditSchoolForm : function() {
return this.showSchoolForm('edit');
},
hideNewSchoolForm : function() {
$('#new-school-form').fadeOut('slow',function(){
$(this).empty();
});
},
selectedSchoolIdFromServer : function() {
return $('#school-id').data('selected-id');
},
populateSchoolsSelect : function(optionsHTML) {
var $schoolSelect = $('#school-id'),
selectedId = this.selectedSchoolIdFromServer();
$schoolSelect.html(optionsHTML);
if( !(_.isUndefined(selectedId) || selectedId === '') ) {
$schoolSelect.val(selectedId);
}
this.populateSchoolsSelect = function(optionsHTML) {
$schoolSelect.html(optionsHTML);
};
},
enableSelection : function() {
$('#school-id').removeAttr('disabled');
},
enableZipcodeInput : function() {
$('#school-select-zipcode').removeAttr('disabled');
},
disableZipcodeInput : function() {
$('#school-select-zipcode').attr('disabled', 'disabled');
},
disableSelection : function() {
$('#school-id').attr('disabled', 'disabled');
},
supressFormSubmission : function(e) {
if(e.which == 13) {
e.stopPropagation();
e.preventDefault();
}
},
validateZipcode : function(e) {
var $zipcode = $("#school-select-zipcode");
var isValid = $zipcode.prop('validity').valid;
if(isValid) {
this.getSchoolsForZipcode($('#school-select-zipcode').val(), this.school.id || this.selectedSchoolIdFromServer());
} else {
this.disableSelection();
}
},
handleSchoolsFound : function(schoolsOptionsHTML) {
this.schoolsFound = true;
this.enableSelection();
this.enableZipcodeInput();
this.populateSchoolsSelect(schoolsOptionsHTML);
this.setState('schools-found');
},
handleSchoolsNotFound : function() {
this.schoolsFound = false;
this.enableZipcodeInput();
this.populateSchoolsSelect('');
this.setState('schools-not-found');
},
handleNewSchoolSaved : function(saveOp) {
var context = this,
schoolsOptionsCache = this.getSchoolsForZipcode,
zipcode = this.school.get('zipcode'),
id = this.school.id;
/* update the DOM after we've fetched the new edit form so the old edit
form isn't accidentally used if the user *quickly* clicks the edit link
*/
this.fetchEditSchoolForm( function() {
if(saveOp == 'update') {
delete schoolsOptionsCache[zipcode + id];
context.setState('new-school-updated');
} else {
context.setState('new-school-exists');
}
$('#school-id-input .inline-errors').remove();
context.$('#school-select-zipcode').val(zipcode).trigger('refreshCustomValidityRules');
context.getSchoolsForZipcode(zipcode, id);
$('#new-school-form').unblock({fadeOut: 0});
context.hideNewSchoolForm();
} );
},
handleNewSchoolSavedError : function(model, response) {
var errors = $.parseJSON(response.responseText);
this.editSchoolForm = errors.html;
this.showEditSchoolForm();
},
handleAudienceChange : function() {
var selectedText = this.$audienceField.find(':selected').text();
if( selectedText.toLowerCase() != 'educator' ) {
this.detach();
} else {
this.addSchoolFields();
}
},
addSchoolFields : function() {
// if not already in DOM, add it
if(!$($(this.el).selector).length) {
this.reattach();
}
},
fetchEditSchoolForm : function(success_callback) {
$.ajax({
url : '/schools/' + this.school.id + '/edit',
context: this,
success : function(response, textStatus, jqXHR) {
if(success_callback) { success_callback(); }
this.editSchoolForm = response;
}
});
},
setState : function(state) {
this.stateDefs[state].call(this);
},
getSchoolsForZipCodeXhr : function(zipcode, selectedId) {
this.enableSelection();
$('#school-id option').first().text('Searching...');
$.ajax('/schools', {
context : this,
data : {
zipcode : zipcode,
new_school_id : selectedId
},
success : function(response, textStatus, jqXHR) {
if(response.html) {
this.handleSchoolsFound(response.html);
} else {
this.handleSchoolsNotFound();
}
// memoize the response html on the getSchoolsForZipCode function
this.getSchoolsForZipcode[zipcode + (this.school.id || '')] = response.html;
}
});
},
getSchoolsForZipcode : function(zipcode, selectedId) {
this.disableZipcodeInput();
var schoolOptionsHTML = arguments.callee[zipcode + ( selectedId || '' )];
if(_.isUndefined(schoolOptionsHTML)) {
this.getSchoolsForZipCodeXhr(zipcode, selectedId);
} else {
if(schoolOptionsHTML === '') {
this.handleSchoolsNotFound();
} else {
this.handleSchoolsFound(schoolOptionsHTML);
}
}
return schoolOptionsHTML;
},
clearSchoolQueryCacheFor : function(zipcode, id) {
var schoolsQueryCache = this.getSchoolsForZipcode;
delete schoolsQueryCache[zipcode + id];
},
submitSchool : function(e) {
e.preventDefault();
var formParamsConvertTypes = false,
formParams = this.$('#new-school-form').formParams(formParamsConvertTypes),
saveOp = this.school.id ? 'update' : 'create';
$('#new-school-form').block({
message: 'Saving educational institution ',
overlayCSS: {
backgroundColor: null,
opacity: null
}
});
// Clear the cached search result related to the new school, as the user is now changing the zipcode
if(saveOp == 'update' && formParams.school.zipcode != this.school.get('zipcode')) {
this.clearSchoolQueryCacheFor(this.school.get('zipcode'), this.school.id);
}
this.school.save(formParams, {
success : _.bind(this.handleNewSchoolSaved, this, saveOp),
error : _.bind(this.handleNewSchoolSavedError, this)
});
},
detach : function() {
$(this.el).detach();
},
reattach : function() {
$(this.el).insertAfter(this.$prevEl);
}
});
// called when plugin is loaded and document is ready
return function($) {
var $schoolSelectorEl = $('#profile-school');
if($schoolSelectorEl.length) {
new SchoolSelectorView({
el : $schoolSelectorEl.get(),
audienceField : $('#user_profile_attributes_audience_id')
});
}
return SchoolSelectorView;
}; // anonymous define return function
}); // define