Commit 34b06932 by Awais Jibran

Safe tempaltes

parent f7ec039b
define(["js/views/validation", "jquery", "underscore", "gettext", "codemirror", "js/views/modals/validation_error_modal"], define(["js/views/validation",
function(ValidatingView, $, _, gettext, CodeMirror, ValidationErrorModal) { "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({ var AdvancedView = ValidatingView.extend({
error_saving : "error_saving", error_saving : "error_saving",
...@@ -13,7 +19,9 @@ var AdvancedView = ValidatingView.extend({ ...@@ -13,7 +19,9 @@ var AdvancedView = ValidatingView.extend({
// TODO enable/disable save based on validation (currently enabled whenever there are changes) // TODO enable/disable save based on validation (currently enabled whenever there are changes)
}, },
initialize : function() { 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.listenTo(this.model, 'invalid', this.handleValidationError);
this.render(); this.render();
}, },
...@@ -33,7 +41,7 @@ var AdvancedView = ValidatingView.extend({ ...@@ -33,7 +41,7 @@ var AdvancedView = ValidatingView.extend({
_.each(_.sortBy(_.keys(this.model.attributes), function(key) { return self.model.get(key).display_name; }), _.each(_.sortBy(_.keys(this.model.attributes), function(key) { return self.model.get(key).display_name; }),
function(key) { function(key) {
if (self.render_deprecated || !self.model.get(key).deprecated) { 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)));
} }
}); });
......
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({ var GraderView = ValidatingView.extend({
// Model class is CMS.Models.Settings.CourseGrader // Model class is CMS.Models.Settings.CourseGrader
...@@ -49,9 +55,14 @@ var GraderView = ValidatingView.extend({ ...@@ -49,9 +55,14 @@ var GraderView = ValidatingView.extend({
if (this.setField(event) != this.oldName && !_.isEmpty(this.oldName)) { if (this.setField(event) != this.oldName && !_.isEmpty(this.oldName)) {
// overload the error display logic // overload the error display logic
this._cacheValidationErrors.push(event.currentTarget); this._cacheValidationErrors.push(event.currentTarget);
$(event.currentTarget).parent().append( var message = StringUtils.interpolate(
this.errorTemplate({message : 'For grading to work, you must change all "' + this.oldName + gettext('For grading to work, you must change all {oldName} subsections to {newName}.'),
'" subsections to "' + this.model.get('type') + '".'})); {
oldName: this.oldName,
newName: this.model.get('type')
}
);
HtmlUtils.append($(event.currentTarget).parent(), this.errorTemplate({message : message}));
} }
break; break;
default: default:
......
define(["js/views/validation", "underscore", "jquery", "jquery.ui", "js/views/settings/grader"], define(["js/views/validation",
function(ValidatingView, _, $, ui, GraderView) { "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({ var GradingView = ValidatingView.extend({
// Model class is CMS.Models.Settings.CourseGradingPolicy // Model class is CMS.Models.Settings.CourseGradingPolicy
...@@ -21,13 +28,12 @@ var GradingView = ValidatingView.extend({ ...@@ -21,13 +28,12 @@ var GradingView = ValidatingView.extend({
initialize : function() { initialize : function() {
// load template for grading view // load template for grading view
var self = this; var self = this;
this.template = _.template($("#course_grade_policy-tpl").text()); this.template = HtmlUtils.template(
this.gradeCutoffTemplate = _.template('<li class="grade-specific-bar" style="width:<%= width %>%"><span class="letter-grade" contenteditable="true">' + $("#course_grade_policy-tpl").text()
'<%= descriptor %>' + );
'</span><span class="range"></span>' + this.gradeCutoffTemplate = HtmlUtils.template(
'<% if (removable) {%><a href="#" class="remove-button">remove</a><% ;} %>' + $("#course_grade_cutoff-tpl").text()
'</li>'); );
this.setupCutoffs(); this.setupCutoffs();
this.listenTo(this.model, 'invalid', this.handleValidationError); this.listenTo(this.model, 'invalid', this.handleValidationError);
...@@ -68,7 +74,7 @@ var GradingView = ValidatingView.extend({ ...@@ -68,7 +74,7 @@ var GradingView = ValidatingView.extend({
}, },
this); this);
gradeCollection.each(function(gradeModel) { gradeCollection.each(function(gradeModel) {
$(gradelist).append(self.template({model : gradeModel })); HtmlUtils.append(gradelist, self.template({model : gradeModel }));
var newEle = gradelist.children().last(); var newEle = gradelist.children().last();
var newView = new GraderView({el: newEle, var newView = new GraderView({el: newEle,
model : gradeModel, collection : gradeCollection }); model : gradeModel, collection : gradeCollection });
...@@ -147,7 +153,7 @@ var GradingView = ValidatingView.extend({ ...@@ -147,7 +153,7 @@ var GradingView = ValidatingView.extend({
gradeBarWidth : null, // cache of value since it won't change (more certain) gradeBarWidth : null, // cache of value since it won't change (more certain)
renderCutoffBar: function() { renderCutoffBar: function() {
var gradeBar =this.$el.find('.grade-bar'); var gradeBar = this.$el.find('.grade-bar');
this.gradeBarWidth = gradeBar.width(); this.gradeBarWidth = gradeBar.width();
var gradelist = gradeBar.children('.grades'); var gradelist = gradeBar.children('.grades');
// HACK fixing a duplicate call issue by undoing previous call effect. Need to figure out why called 2x // 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({ ...@@ -156,15 +162,15 @@ var GradingView = ValidatingView.extend({
// Can probably be simplified to one variable now. // Can probably be simplified to one variable now.
var removable = false; var removable = false;
var draggable = false; // first and last are not removable, first is not draggable var draggable = false; // first and last are not removable, first is not draggable
_.each(this.descendingCutoffs, _.each(this.descendingCutoffs, function(cutoff) {
function(cutoff, index) { HtmlUtils.append(gradelist, this.gradeCutoffTemplate({
var newBar = this.gradeCutoffTemplate({ descriptor : cutoff.designation,
descriptor : cutoff['designation'] ,
width : nextWidth, width : nextWidth,
removable : removable }); contenteditable: true,
gradelist.append(newBar); removable : removable})
);
if (draggable) { 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({ newBar.resizable({
handles: "e", handles: "e",
containment : "parent", containment : "parent",
...@@ -174,19 +180,18 @@ var GradingView = ValidatingView.extend({ ...@@ -174,19 +180,18 @@ var GradingView = ValidatingView.extend({
}); });
} }
// prepare for next // prepare for next
nextWidth = cutoff['cutoff']; nextWidth = cutoff.cutoff;
removable = true; // first is not removable, all others are removable = true; // first is not removable, all others are
draggable = true; draggable = true;
}, },
this); this);
// add fail which is not in data // Add fail which is not in data
var failBar = $(this.gradeCutoffTemplate({ HtmlUtils.append(gradelist, this.gradeCutoffTemplate({
descriptor : this.failLabel(), descriptor : this.failLabel(),
width : nextWidth, width : nextWidth,
contenteditable: false,
removable : false removable : false
})); }));
failBar.find("span[contenteditable=true]").attr("contenteditable", false);
gradelist.append(failBar);
gradelist.children().last().resizable({ gradelist.children().last().resizable({
handles: "e", handles: "e",
containment : "parent", containment : "parent",
...@@ -298,10 +303,13 @@ var GradingView = ValidatingView.extend({ ...@@ -298,10 +303,13 @@ var GradingView = ValidatingView.extend({
this.descendingCutoffs.push({designation: this.GRADES[gradeLength], cutoff: failBarWidth}); this.descendingCutoffs.push({designation: this.GRADES[gradeLength], cutoff: failBarWidth});
this.descendingCutoffs[gradeLength - 1]['cutoff'] = Math.round(targetWidth); this.descendingCutoffs[gradeLength - 1]['cutoff'] = Math.round(targetWidth);
var $newGradeBar = this.gradeCutoffTemplate({ descriptor : this.GRADES[gradeLength], var newGradeHtml = this.gradeCutoffTemplate({
width : targetWidth, removable : true }); descriptor : this.GRADES[gradeLength],
width : targetWidth,
contenteditable: true,
removable : true });
var gradeDom = this.$el.find('.grades'); var gradeDom = this.$el.find('.grades');
gradeDom.children().last().before($newGradeBar); gradeDom.children().last().before(HtmlUtils.ensureHtml(newGradeHtml).toString());
var newEle = gradeDom.children()[gradeLength]; var newEle = gradeDom.children()[gradeLength];
$(newEle).resizable({ $(newEle).resizable({
handles: "e", handles: "e",
...@@ -313,8 +321,8 @@ var GradingView = ValidatingView.extend({ ...@@ -313,8 +321,8 @@ var GradingView = ValidatingView.extend({
// Munge existing grade labels? // Munge existing grade labels?
// If going from Pass/Fail to 3 levels, change to Pass to A // If going from Pass/Fail to 3 levels, change to Pass to A
if (gradeLength === 1 && this.descendingCutoffs[0]['designation'] === 'Pass') { if (gradeLength === 1 && this.descendingCutoffs[0].designation === 'Pass') {
this.descendingCutoffs[0]['designation'] = this.GRADES[0]; this.descendingCutoffs[0].designation = this.GRADES[0];
this.setTopGradeLabel(); this.setTopGradeLabel();
} }
this.setFailLabel(); this.setFailLabel();
...@@ -349,10 +357,10 @@ var GradingView = ValidatingView.extend({ ...@@ -349,10 +357,10 @@ var GradingView = ValidatingView.extend({
else return 'F'; else return 'F';
}, },
setFailLabel: function() { setFailLabel: function() {
this.$el.find('.grades .letter-grade').last().html(this.failLabel()); this.$el.find('.grades .letter-grade').last().text(this.failLabel());
}, },
setTopGradeLabel: function() { 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() { setupCutoffs: function() {
// Instrument grading scale // Instrument grading scale
......
define(["js/views/validation", "codemirror", "underscore", "jquery", "jquery.ui", "js/utils/date_utils", "js/models/uploads", 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", "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, function(ValidatingView, CodeMirror, _, $, ui, DateUtils, FileUploadModel,
FileUploadDialog, LicenseView, LicenseModel, NotificationView, FileUploadDialog, LicenseView, LicenseModel, NotificationView,
timepicker, date, gettext) { timepicker, date, gettext, StringUtils) {
var DetailsView = ValidatingView.extend({ var DetailsView = ValidatingView.extend({
// Model class is CMS.Models.Settings.CourseDetails // Model class is CMS.Models.Settings.CourseDetails
...@@ -25,7 +26,6 @@ var DetailsView = ValidatingView.extend({ ...@@ -25,7 +26,6 @@ var DetailsView = ValidatingView.extend({
initialize : function(options) { initialize : function(options) {
options = options || {}; options = options || {};
this.fileAnchorTemplate = _.template('<a href="<%= fullpath %>"> <i class="icon fa fa-file"></i><%= filename %></a>');
// fill in fields // fill in fields
this.$el.find("#course-language").val(this.model.get('language')); this.$el.find("#course-language").val(this.model.get('language'));
this.$el.find("#course-organization").val(this.model.get('org')); this.$el.find("#course-organization").val(this.model.get('org'));
...@@ -115,7 +115,7 @@ var DetailsView = ValidatingView.extend({ ...@@ -115,7 +115,7 @@ var DetailsView = ValidatingView.extend({
paceToggleTip.text(gettext('Course pacing cannot be changed once a course has started.')); paceToggleTip.text(gettext('Course pacing cannot be changed once a course has started.'));
} }
this.licenseView.render() this.licenseView.render();
return this; return this;
}, },
...@@ -139,14 +139,16 @@ var DetailsView = ValidatingView.extend({ ...@@ -139,14 +139,16 @@ var DetailsView = ValidatingView.extend({
var now = new Date(), var now = new Date(),
hours = now.getUTCHours(), hours = now.getUTCHours(),
minutes = now.getUTCMinutes(), 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, { $(e.currentTarget).attr('title', currentTimeText);
'hours': hours,
'minutes': minutes
}, true));
}, },
updateModel: function(event) { updateModel: function(event) {
switch (event.currentTarget.id) { switch (event.currentTarget.id) {
case 'course-language': case 'course-language':
...@@ -322,8 +324,8 @@ var DetailsView = ValidatingView.extend({ ...@@ -322,8 +324,8 @@ var DetailsView = ValidatingView.extend({
}, },
handleLicenseChange: function() { handleLicenseChange: function() {
this.showNotificationBar() this.showNotificationBar();
this.model.set("license", this.licenseModel.toString()) this.model.set("license", this.licenseModel.toString());
} }
}); });
......
define(["js/views/baseview", "underscore", "jquery", "gettext", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_alert", "js/views/baseview", "jquery.smoothScroll"], define(["edx-ui-toolkit/js/utils/html-utils",
function(BaseView, _, $, gettext, NotificationView, AlertView) { "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({ var ValidatingView = BaseView.extend({
// Intended as an abstract class which catches validation errors on the model and // Intended as an abstract class which catches validation errors on the model and
...@@ -10,7 +18,7 @@ var ValidatingView = BaseView.extend({ ...@@ -10,7 +18,7 @@ var ValidatingView = BaseView.extend({
this.selectorToField = _.invert(this.fieldToSelectorMap); this.selectorToField = _.invert(this.fieldToSelectorMap);
}, },
errorTemplate : _.template('<span class="message-error"><%= message %></span>'), errorTemplate : HtmlUtils.template('<span class="message-error"><%- message %></span>'),
save_title: gettext("You've made some changes"), save_title: gettext("You've made some changes"),
save_message: gettext("Your changes will not take effect until you save your progress."), save_message: gettext("Your changes will not take effect until you save your progress."),
...@@ -34,7 +42,7 @@ var ValidatingView = BaseView.extend({ ...@@ -34,7 +42,7 @@ var ValidatingView = BaseView.extend({
var ele = this.$el.find('#' + this.fieldToSelectorMap[field]); var ele = this.$el.find('#' + this.fieldToSelectorMap[field]);
this._cacheValidationErrors.push(ele); this._cacheValidationErrors.push(ele);
this.getInputElements(ele).addClass('error'); 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'); $('.wrapper-notification-warning').addClass('wrapper-notification-warning-w-errors');
$('.action-save').addClass('is-disabled'); $('.action-save').addClass('is-disabled');
...@@ -60,7 +68,7 @@ var ValidatingView = BaseView.extend({ ...@@ -60,7 +68,7 @@ var ValidatingView = BaseView.extend({
// Set model field and return the new value. // Set model field and return the new value.
this.clearValidationErrors(); this.clearValidationErrors();
var field = this.selectorToField[event.currentTarget.id]; var field = this.selectorToField[event.currentTarget.id];
var newVal = '' var newVal = '';
if(event.currentTarget.type == 'checkbox'){ if(event.currentTarget.type == 'checkbox'){
newVal = $(event.currentTarget).is(":checked").toString(); newVal = $(event.currentTarget).is(":checked").toString();
}else{ }else{
......
<li class="grade-specific-bar" style="width:<%- width %>%">
<span class="letter-grade" contenteditable="<%- contenteditable %>"><%- descriptor %></span>
<span class="range"></span>
<% if (removable) {%><a href="#" class="remove-button">remove</a><% ;} %>
</li>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%> %>
<%block name="header_extras"> <%block name="header_extras">
% for template_name in ["course_grade_policy"]: % for template_name in ["course_grade_policy", "course_grade_cutoff"]:
<script type="text/template" id="${template_name}-tpl"> <script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" /> <%static:include path="js/${template_name}.underscore" />
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment