From 34b06932e585df36de0f124b878725fb09ca7349 Mon Sep 17 00:00:00 2001 From: Awais Jibran Date: Wed, 6 Apr 2016 15:19:06 +0500 Subject: [PATCH] Safe tempaltes --- cms/static/js/views/settings/advanced.js | 16 +++-- cms/static/js/views/settings/grader.js | 19 ++++-- cms/static/js/views/settings/grading.js | 68 +++++++++++-------- cms/static/js/views/settings/main.js | 26 +++---- cms/static/js/views/validation.js | 18 +++-- .../js/course_grade_cutoff.underscore | 5 ++ cms/templates/settings_graders.html | 2 +- 7 files changed, 98 insertions(+), 56 deletions(-) create mode 100644 cms/templates/js/course_grade_cutoff.underscore diff --git a/cms/static/js/views/settings/advanced.js b/cms/static/js/views/settings/advanced.js index dd51134aa1..3c1eba2fb2 100644 --- a/cms/static/js/views/settings/advanced.js +++ b/cms/static/js/views/settings/advanced.js @@ -1,5 +1,11 @@ -define(["js/views/validation", "jquery", "underscore", "gettext", "codemirror", "js/views/modals/validation_error_modal"], - function(ValidatingView, $, _, gettext, CodeMirror, ValidationErrorModal) { +define(["js/views/validation", + "jquery", + "underscore", + "gettext", + "codemirror", + "js/views/modals/validation_error_modal", + 'edx-ui-toolkit/js/utils/html-utils'], + function(ValidatingView, $, _, gettext, CodeMirror, ValidationErrorModal, HtmlUtils) { var AdvancedView = ValidatingView.extend({ error_saving : "error_saving", @@ -13,7 +19,9 @@ var AdvancedView = ValidatingView.extend({ // TODO enable/disable save based on validation (currently enabled whenever there are changes) }, initialize : function() { - this.template = _.template($("#advanced_entry-tpl").text()); + this.template = HtmlUtils.template( + $("#advanced_entry-tpl").text() + ); this.listenTo(this.model, 'invalid', this.handleValidationError); this.render(); }, @@ -33,7 +41,7 @@ var AdvancedView = ValidatingView.extend({ _.each(_.sortBy(_.keys(this.model.attributes), function(key) { return self.model.get(key).display_name; }), function(key) { if (self.render_deprecated || !self.model.get(key).deprecated) { - listEle$.append(self.renderTemplate(key, self.model.get(key))); + HtmlUtils.append(listEle$, self.renderTemplate(key, self.model.get(key))); } }); diff --git a/cms/static/js/views/settings/grader.js b/cms/static/js/views/settings/grader.js index 3a125f67d8..cf936f4ff8 100644 --- a/cms/static/js/views/settings/grader.js +++ b/cms/static/js/views/settings/grader.js @@ -1,4 +1,10 @@ -define(["js/views/validation", "underscore", "jquery"], function(ValidatingView, _, $) { +define(["js/views/validation", + 'gettext', + 'edx-ui-toolkit/js/utils/string-utils', + "edx-ui-toolkit/js/utils/html-utils", + "underscore", + "jquery"], + function(ValidatingView, gettext, StringUtils, HtmlUtils, _, $) { var GraderView = ValidatingView.extend({ // Model class is CMS.Models.Settings.CourseGrader @@ -49,9 +55,14 @@ var GraderView = ValidatingView.extend({ if (this.setField(event) != this.oldName && !_.isEmpty(this.oldName)) { // overload the error display logic this._cacheValidationErrors.push(event.currentTarget); - $(event.currentTarget).parent().append( - this.errorTemplate({message : 'For grading to work, you must change all "' + this.oldName + - '" subsections to "' + this.model.get('type') + '".'})); + var message = StringUtils.interpolate( + gettext('For grading to work, you must change all {oldName} subsections to {newName}.'), + { + oldName: this.oldName, + newName: this.model.get('type') + } + ); + HtmlUtils.append($(event.currentTarget).parent(), this.errorTemplate({message : message})); } break; default: diff --git a/cms/static/js/views/settings/grading.js b/cms/static/js/views/settings/grading.js index 8a3bab4fc6..184cba06d2 100644 --- a/cms/static/js/views/settings/grading.js +++ b/cms/static/js/views/settings/grading.js @@ -1,5 +1,12 @@ -define(["js/views/validation", "underscore", "jquery", "jquery.ui", "js/views/settings/grader"], - function(ValidatingView, _, $, ui, GraderView) { +define(["js/views/validation", + "underscore", + "jquery", + "jquery.ui", + "js/views/settings/grader", + 'edx-ui-toolkit/js/utils/string-utils', + 'edx-ui-toolkit/js/utils/html-utils', + ], + function(ValidatingView, _, $, ui, GraderView, StringUtils, HtmlUtils) { var GradingView = ValidatingView.extend({ // Model class is CMS.Models.Settings.CourseGradingPolicy @@ -21,13 +28,12 @@ var GradingView = ValidatingView.extend({ initialize : function() { // load template for grading view var self = this; - this.template = _.template($("#course_grade_policy-tpl").text()); - this.gradeCutoffTemplate = _.template('
  • ' + - '<%= descriptor %>' + - '' + - '<% if (removable) {%>remove<% ;} %>' + - '
  • '); - + this.template = HtmlUtils.template( + $("#course_grade_policy-tpl").text() + ); + this.gradeCutoffTemplate = HtmlUtils.template( + $("#course_grade_cutoff-tpl").text() + ); this.setupCutoffs(); this.listenTo(this.model, 'invalid', this.handleValidationError); @@ -68,7 +74,7 @@ var GradingView = ValidatingView.extend({ }, this); gradeCollection.each(function(gradeModel) { - $(gradelist).append(self.template({model : gradeModel })); + HtmlUtils.append(gradelist, self.template({model : gradeModel })); var newEle = gradelist.children().last(); var newView = new GraderView({el: newEle, model : gradeModel, collection : gradeCollection }); @@ -147,7 +153,7 @@ var GradingView = ValidatingView.extend({ gradeBarWidth : null, // cache of value since it won't change (more certain) renderCutoffBar: function() { - var gradeBar =this.$el.find('.grade-bar'); + var gradeBar = this.$el.find('.grade-bar'); this.gradeBarWidth = gradeBar.width(); var gradelist = gradeBar.children('.grades'); // HACK fixing a duplicate call issue by undoing previous call effect. Need to figure out why called 2x @@ -156,15 +162,15 @@ var GradingView = ValidatingView.extend({ // Can probably be simplified to one variable now. var removable = false; var draggable = false; // first and last are not removable, first is not draggable - _.each(this.descendingCutoffs, - function(cutoff, index) { - var newBar = this.gradeCutoffTemplate({ - descriptor : cutoff['designation'] , + _.each(this.descendingCutoffs, function(cutoff) { + HtmlUtils.append(gradelist, this.gradeCutoffTemplate({ + descriptor : cutoff.designation, width : nextWidth, - removable : removable }); - gradelist.append(newBar); + contenteditable: true, + removable : removable}) + ); if (draggable) { - newBar = gradelist.children().last(); // get the dom object not the unparsed string + var newBar = gradelist.children().last(); // get the dom object not the unparsed string newBar.resizable({ handles: "e", containment : "parent", @@ -174,19 +180,18 @@ var GradingView = ValidatingView.extend({ }); } // prepare for next - nextWidth = cutoff['cutoff']; + nextWidth = cutoff.cutoff; removable = true; // first is not removable, all others are draggable = true; }, this); - // add fail which is not in data - var failBar = $(this.gradeCutoffTemplate({ + // Add fail which is not in data + HtmlUtils.append(gradelist, this.gradeCutoffTemplate({ descriptor : this.failLabel(), width : nextWidth, + contenteditable: false, removable : false })); - failBar.find("span[contenteditable=true]").attr("contenteditable", false); - gradelist.append(failBar); gradelist.children().last().resizable({ handles: "e", containment : "parent", @@ -298,10 +303,13 @@ var GradingView = ValidatingView.extend({ this.descendingCutoffs.push({designation: this.GRADES[gradeLength], cutoff: failBarWidth}); this.descendingCutoffs[gradeLength - 1]['cutoff'] = Math.round(targetWidth); - var $newGradeBar = this.gradeCutoffTemplate({ descriptor : this.GRADES[gradeLength], - width : targetWidth, removable : true }); + var newGradeHtml = this.gradeCutoffTemplate({ + descriptor : this.GRADES[gradeLength], + width : targetWidth, + contenteditable: true, + removable : true }); var gradeDom = this.$el.find('.grades'); - gradeDom.children().last().before($newGradeBar); + gradeDom.children().last().before(HtmlUtils.ensureHtml(newGradeHtml).toString()); var newEle = gradeDom.children()[gradeLength]; $(newEle).resizable({ handles: "e", @@ -313,8 +321,8 @@ var GradingView = ValidatingView.extend({ // Munge existing grade labels? // If going from Pass/Fail to 3 levels, change to Pass to A - if (gradeLength === 1 && this.descendingCutoffs[0]['designation'] === 'Pass') { - this.descendingCutoffs[0]['designation'] = this.GRADES[0]; + if (gradeLength === 1 && this.descendingCutoffs[0].designation === 'Pass') { + this.descendingCutoffs[0].designation = this.GRADES[0]; this.setTopGradeLabel(); } this.setFailLabel(); @@ -349,10 +357,10 @@ var GradingView = ValidatingView.extend({ else return 'F'; }, setFailLabel: function() { - this.$el.find('.grades .letter-grade').last().html(this.failLabel()); + this.$el.find('.grades .letter-grade').last().text(this.failLabel()); }, setTopGradeLabel: function() { - this.$el.find('.grades .letter-grade').first().html(this.descendingCutoffs[0]['designation']); + this.$el.find('.grades .letter-grade').first().text(this.descendingCutoffs[0].designation); }, setupCutoffs: function() { // Instrument grading scale diff --git a/cms/static/js/views/settings/main.js b/cms/static/js/views/settings/main.js index 74aacc24c5..333b5c3a60 100644 --- a/cms/static/js/views/settings/main.js +++ b/cms/static/js/views/settings/main.js @@ -1,9 +1,10 @@ define(["js/views/validation", "codemirror", "underscore", "jquery", "jquery.ui", "js/utils/date_utils", "js/models/uploads", "js/views/uploads", "js/views/license", "js/models/license", - "common/js/components/views/feedback_notification", "jquery.timepicker", "date", "gettext"], + "common/js/components/views/feedback_notification", "jquery.timepicker", "date", "gettext", + 'edx-ui-toolkit/js/utils/string-utils'], function(ValidatingView, CodeMirror, _, $, ui, DateUtils, FileUploadModel, FileUploadDialog, LicenseView, LicenseModel, NotificationView, - timepicker, date, gettext) { + timepicker, date, gettext, StringUtils) { var DetailsView = ValidatingView.extend({ // Model class is CMS.Models.Settings.CourseDetails @@ -25,7 +26,6 @@ var DetailsView = ValidatingView.extend({ initialize : function(options) { options = options || {}; - this.fileAnchorTemplate = _.template(' <%= filename %>'); // fill in fields this.$el.find("#course-language").val(this.model.get('language')); this.$el.find("#course-organization").val(this.model.get('org')); @@ -115,7 +115,7 @@ var DetailsView = ValidatingView.extend({ paceToggleTip.text(gettext('Course pacing cannot be changed once a course has started.')); } - this.licenseView.render() + this.licenseView.render(); return this; }, @@ -139,14 +139,16 @@ var DetailsView = ValidatingView.extend({ var now = new Date(), hours = now.getUTCHours(), minutes = now.getUTCMinutes(), - currentTimeText = gettext('%(hours)s:%(minutes)s (current UTC time)'); + currentTimeText = StringUtils.interpolate( + gettext('{hours}:{minutes} (current UTC time)'), + { + 'hours': hours, + 'minutes': minutes + } + ); - $(e.currentTarget).attr('title', interpolate(currentTimeText, { - 'hours': hours, - 'minutes': minutes - }, true)); + $(e.currentTarget).attr('title', currentTimeText); }, - updateModel: function(event) { switch (event.currentTarget.id) { case 'course-language': @@ -322,8 +324,8 @@ var DetailsView = ValidatingView.extend({ }, handleLicenseChange: function() { - this.showNotificationBar() - this.model.set("license", this.licenseModel.toString()) + this.showNotificationBar(); + this.model.set("license", this.licenseModel.toString()); } }); diff --git a/cms/static/js/views/validation.js b/cms/static/js/views/validation.js index d0b21e9810..afbe6bedc7 100644 --- a/cms/static/js/views/validation.js +++ b/cms/static/js/views/validation.js @@ -1,5 +1,13 @@ -define(["js/views/baseview", "underscore", "jquery", "gettext", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_alert", "js/views/baseview", "jquery.smoothScroll"], - function(BaseView, _, $, gettext, NotificationView, AlertView) { +define(["edx-ui-toolkit/js/utils/html-utils", + "js/views/baseview", + "underscore", + "jquery", + "gettext", + "common/js/components/views/feedback_notification", + "common/js/components/views/feedback_alert", + "js/views/baseview", + "jquery.smoothScroll"], + function(HtmlUtils, BaseView, _, $, gettext, NotificationView, AlertView) { var ValidatingView = BaseView.extend({ // Intended as an abstract class which catches validation errors on the model and @@ -10,7 +18,7 @@ var ValidatingView = BaseView.extend({ this.selectorToField = _.invert(this.fieldToSelectorMap); }, - errorTemplate : _.template('<%= message %>'), + errorTemplate : HtmlUtils.template('<%- message %>'), save_title: gettext("You've made some changes"), save_message: gettext("Your changes will not take effect until you save your progress."), @@ -34,7 +42,7 @@ var ValidatingView = BaseView.extend({ var ele = this.$el.find('#' + this.fieldToSelectorMap[field]); this._cacheValidationErrors.push(ele); this.getInputElements(ele).addClass('error'); - $(ele).parent().append(this.errorTemplate({message : error[field]})); + HtmlUtils.append($(ele).parent(), this.errorTemplate({message : error[field]})); } $('.wrapper-notification-warning').addClass('wrapper-notification-warning-w-errors'); $('.action-save').addClass('is-disabled'); @@ -60,7 +68,7 @@ var ValidatingView = BaseView.extend({ // Set model field and return the new value. this.clearValidationErrors(); var field = this.selectorToField[event.currentTarget.id]; - var newVal = '' + var newVal = ''; if(event.currentTarget.type == 'checkbox'){ newVal = $(event.currentTarget).is(":checked").toString(); }else{ diff --git a/cms/templates/js/course_grade_cutoff.underscore b/cms/templates/js/course_grade_cutoff.underscore new file mode 100644 index 0000000000..1a85dd30f7 --- /dev/null +++ b/cms/templates/js/course_grade_cutoff.underscore @@ -0,0 +1,5 @@ +
  • + <%- descriptor %> + + <% if (removable) {%>remove<% ;} %> +
  • diff --git a/cms/templates/settings_graders.html b/cms/templates/settings_graders.html index 44989d201d..20ca1bc3de 100644 --- a/cms/templates/settings_graders.html +++ b/cms/templates/settings_graders.html @@ -15,7 +15,7 @@ %> <%block name="header_extras"> -% for template_name in ["course_grade_policy"]: +% for template_name in ["course_grade_policy", "course_grade_cutoff"]: