From 3d4f9268dafda7df0decd049cb24eea9deec8364 Mon Sep 17 00:00:00 2001 From: Peter Fogg Date: Fri, 28 Jun 2013 10:42:40 -0400 Subject: [PATCH] Make sure that changing grading cutoffs triggers a save confirmation, and reliable reverting of changes. --- cms/static/js/views/settings/advanced_view.js | 19 +++-- .../js/views/settings/main_settings_view.js | 24 ++++++- .../views/settings/settings_grading_view.js | 71 +++++++++++++------ cms/static/js/views/validating_view.js | 7 +- 4 files changed, 84 insertions(+), 37 deletions(-) diff --git a/cms/static/js/views/settings/advanced_view.js b/cms/static/js/views/settings/advanced_view.js index 7be45959a6..65aed2a3c8 100644 --- a/cms/static/js/views/settings/advanced_view.js +++ b/cms/static/js/views/settings/advanced_view.js @@ -61,7 +61,10 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({ var message = gettext("Your changes will not take effect until you save your progress. Take care with key and value formatting, as validation is not implemented."); self.showNotificationBar(message, _.bind(self.saveView, self), - _.bind(self.revertView, self)); + function() { + self.model.deleteKeys = []; + self.revertView(); + }); if(self.saved) { self.saved.hide(); } @@ -112,25 +115,19 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({ { success : function() { self.render(); + var title = gettext("Your policy changes have been saved."); var message = gettext("Please note that validation of your policy key and value pairs is not currently in place yet. If you are having difficulties, please review your policy pairs."); - self.saved = new CMS.Views.Alert.Confirmation({ - title: gettext("Your policy changes have been saved."), - message: message, - closeIcon: false - }); - self.saved.show(); + self.showSavedBar(title, message); analytics.track('Saved Advanced Settings', { 'course': course_location_analytics }); } }); }, - revertView : function() { + revertView: function() { var self = this; - this.model.deleteKeys = []; - this.model.clear({silent : true}); this.model.fetch({ - success : function() { self.render(); }, + success: function() { self.render(); }, reset: true }); }, diff --git a/cms/static/js/views/settings/main_settings_view.js b/cms/static/js/views/settings/main_settings_view.js index e15bcfd9eb..27194dba3b 100644 --- a/cms/static/js/views/settings/main_settings_view.js +++ b/cms/static/js/views/settings/main_settings_view.js @@ -144,7 +144,8 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({ } var self = this; this.showNotificationBar(this.save_message, - _.bind(this.saveModel, this)); + _.bind(this.saveView, this), + _.bind(this.revertView, this)); }, removeSyllabus: function() { @@ -185,12 +186,29 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({ if (cachethis.model.get(field) != newVal) { cachethis.model.set(field, newVal); cachethis.showNotificationBar(cachethis.save_message, - _.bind(cachethis.saveModel, cachethis)); + _.bind(cachethis.saveView, cachethis), + _.bind(cachethis.revertView, cachethis)); } } }); } - } + }, + revertView: function() { + // Make sure that the CodeMirror instance has the correct + // data from its corresponding textarea + var self = this; + this.model.fetch({ + success: function() { + self.render(); + _.each(self.codeMirrors, + function(mirror) { + var ele = mirror.getTextArea(); + var field = self.selectorToField[ele.id]; + mirror.setValue(self.model.get(field)); + }); + }, + reset: true}); + } }); diff --git a/cms/static/js/views/settings/settings_grading_view.js b/cms/static/js/views/settings/settings_grading_view.js index c997c15f6f..e5e5c52086 100644 --- a/cms/static/js/views/settings/settings_grading_view.js +++ b/cms/static/js/views/settings/settings_grading_view.js @@ -23,14 +23,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ '<% if (removable) {%>remove<% ;} %>' + ''); - // Instrument grading scale - // convert cutoffs to inversely ordered list - var modelCutoffs = this.model.get('grade_cutoffs'); - for (var cutoff in modelCutoffs) { - this.descendingCutoffs.push({designation: cutoff, cutoff: Math.round(modelCutoffs[cutoff] * 100)}); - } - this.descendingCutoffs = _.sortBy(this.descendingCutoffs, - function (gradeEle) { return -gradeEle['cutoff']; }); + this.setupCutoffs(); // Instrument grace period this.$el.find('#course-grading-graceperiod').timepicker(); @@ -45,7 +38,6 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ } ); this.listenTo(this.model, 'invalid', this.handleValidationError); - this.model.get('graders').on('remove', this.render, this); this.model.get('graders').on('reset', this.render, this); this.model.get('graders').on('add', this.render, this); this.selectorToField = _.invert(this.fieldToSelectorMap); @@ -61,11 +53,25 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ // Undo the double invocation error. At some point, fix the double invocation $(gradelist).empty(); var gradeCollection = this.model.get('graders'); + // We need to bind the 'remove' event here (rather than in + // initialize), or else we can only press the delete button + // once due to the graders collection changing when we cancel + // our changes. + gradeCollection.on('remove', function() { + this.showNotificationBar(); + this.render(); + }, this); gradeCollection.each(function(gradeModel) { $(gradelist).append(self.template({model : gradeModel })); var newEle = gradelist.children().last(); var newView = new CMS.Views.Settings.GraderView({el: newEle, model : gradeModel, collection : gradeCollection }); + // Listen in order to rerender when the 'cancel' button is + // pressed + self.listenTo(newView, 'revert', _.bind(self.render, self)); + self.listenTo(gradeModel, 'change', function() { + self.showNotificationBar(); + }); }); // render the grade cutoffs @@ -83,6 +89,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ addAssignmentType : function(e) { e.preventDefault(); this.model.get('graders').push({}); + this.showNotificationBar(); }, fieldToSelectorMap : { 'grace_period' : 'course-grading-graceperiod' @@ -92,8 +99,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ self.clearValidationErrors(); var newVal = self.model.dateToGracePeriod($(event.currentTarget).timepicker('getTime')); self.model.set('grace_period', newVal, {validate: true}); - self.showNotificationBar(self.save_message, - _.bind(self.saveModel, self)); + self.showNotificationBar(); }, updateModel : function(event) { if (!this.selectorToField[event.currentTarget.id]) return; @@ -106,9 +112,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ this.setField(event); break; } - var self = this; - this.showNotificationBar(this.save_message, - _.bind(self.saveModel, self)); + this.showNotificationBar(); }, // Grade sliders attributes and methods @@ -234,8 +238,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ }, {}), {validate: true}); - this.showNotificationBar(this.save_message, - _.bind(this.saveModel, this)); + this.showNotificationBar(); }, addNewGrade: function(e) { @@ -310,8 +313,36 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ }, setTopGradeLabel: function() { this.$el.find('.grades .letter-grade').first().html(this.descendingCutoffs[0]['designation']); + }, + setupCutoffs: function() { + // Instrument grading scale + // convert cutoffs to inversely ordered list + var modelCutoffs = this.model.get('grade_cutoffs'); + for (var cutoff in modelCutoffs) { + this.descendingCutoffs.push({designation: cutoff, cutoff: Math.round(modelCutoffs[cutoff] * 100)}); + } + this.descendingCutoffs = _.sortBy(this.descendingCutoffs, + function (gradeEle) { return -gradeEle['cutoff']; }); + }, + revertView: function() { + var self = this; + this.model.fetch({ + success: function() { + self.descendingCutoffs = []; + self.setupCutoffs(); + self.render(); + self.renderCutoffBar(); + }, + reset: true}); + }, + showNotificationBar: function() { + // We always call showNotificationBar with the same args, just + // delegate to superclass + CMS.Views.ValidatingView.prototype.showNotificationBar.call(this, + this.save_message, + _.bind(this.saveView, this), + _.bind(this.revertView, this)); } - }); CMS.Views.Settings.GraderView = CMS.Views.ValidatingView.extend({ @@ -368,13 +399,9 @@ CMS.Views.Settings.GraderView = CMS.Views.ValidatingView.extend({ this.setField(event); break; } - var self = this; - this.showNotificationBar(this.save_message, - _.bind(this.saveModel, this)); }, deleteModel : function(e) { - this.model.destroy(); e.preventDefault(); + this.collection.remove(this.model); } - }); diff --git a/cms/static/js/views/validating_view.js b/cms/static/js/views/validating_view.js index e9c5678a93..ede4a0b123 100644 --- a/cms/static/js/views/validating_view.js +++ b/cms/static/js/views/validating_view.js @@ -92,6 +92,11 @@ CMS.Views.ValidatingView = Backbone.View.extend({ if(secondaryClick) { secondaryClick(); } + self.model.clear({silent : true}); + /*self.model.fetch({ + success : function() { self.render(); }, + reset: true + });*/ self.confirmation.hide(); self.notificationBarShowing = false; } @@ -111,7 +116,7 @@ CMS.Views.ValidatingView = Backbone.View.extend({ this.saved.show(); }, - saveModel: function() { + saveView: function() { var self = this; this.model.save({}, {success: function() {