Merge pull request #11631 from edx/fedx/upgrade-libraries

Upgrade Underscore.js and Underscore.string.js
This commit is contained in:
Andy Armstrong
2016-03-18 16:32:16 -04:00
91 changed files with 229 additions and 488 deletions

View File

@@ -129,9 +129,9 @@ function ($, _, Backbone, gettext,
if (event && event.preventDefault) { event.preventDefault(); }
var model = this.model;
var self = this;
var titleText = gettext('Delete "<%= signatoryName %>" from the list of signatories?');
var titleTextTemplate = _.template(gettext('Delete "<%= signatoryName %>" from the list of signatories?'));
var confirm = new PromptView.Warning({
title: _.template(titleText, {signatoryName: model.get('name')}),
title: titleTextTemplate({signatoryName: model.get('name')}),
message: gettext('This action cannot be undone.'),
actions: {
primary: {

View File

@@ -66,9 +66,10 @@ var CourseGrader = Backbone.Model.extend({
else attrs.drop_count = intDropCount;
}
if (_.has(attrs, 'min_count') && _.has(attrs, 'drop_count') && !_.has(errors, 'min_count') && !_.has(errors, 'drop_count') && attrs.drop_count > attrs.min_count) {
errors.drop_count = _.template(
gettext("Cannot drop more <% attrs.types %> than will assigned."),
attrs, {variable: 'attrs'});
var template = _.template(
gettext("Cannot drop more <%= types %> assignments than are assigned.")
);
errors.drop_count = template({types: attrs.type});
}
if (!_.isEmpty(errors)) return errors;
}

View File

@@ -15,8 +15,7 @@ var FileUpload = Backbone.Model.extend({
validate: function(attrs, options) {
if(attrs.selectedFile && !this.checkTypeValidity(attrs.selectedFile)) {
return {
message: _.template(
gettext("Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload."),
message: _.template(gettext("Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload."))( // jshint ignore:line
this.formatValidTypes()
),
attributes: {selectedFile: true}
@@ -64,7 +63,7 @@ var FileUpload = Backbone.Model.extend({
}
var or = gettext('or');
var formatTypes = function(types) {
return _.template('<%= initial %> <%= or %> <%= last %>', {
return _.template('<%= initial %> <%= or %> <%= last %>')({
initial: _.initial(types).join(', '),
or: or,
last: _.last(types)

View File

@@ -359,12 +359,12 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "draggabilly",
makeDraggable: function (element, options) {
var draggable;
options = _.defaults({
type: null,
handleClass: null,
droppableClass: null,
parentLocationSelector: null,
refresh: null,
ensureChildrenRendered: null
type: undefined,
handleClass: undefined,
droppableClass: undefined,
parentLocationSelector: undefined,
refresh: undefined,
ensureChildrenRendered: undefined
}, options);
if ($(element).data('droppable-class') !== options.droppableClass) {

View File

@@ -67,7 +67,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
ViewUtils.hideLoadingIndicator();
// Create the table
this.$el.html(_.template(asset_library_template, {typeData: this.typeData}));
this.$el.html(_.template(asset_library_template)({typeData: this.typeData}));
tableBody = this.$('#asset-table-body');
this.tableBody = tableBody;
this.pagingHeader = new PagingHeader({view: this, el: $('#asset-paging-header')});

View File

@@ -1,3 +1,5 @@
/*global course */
define(["js/views/baseview", "underscore", "underscore.string", "jquery", "gettext", "js/models/uploads", "js/views/uploads"],
function(BaseView, _, str, $, gettext, FileUploadModel, UploadDialogView) {
_.str = str; // used in template
@@ -52,10 +54,8 @@ define(["js/views/baseview", "underscore", "underscore.string", "jquery", "gette
asset_path: this.$("input.chapter-asset-path").val()
});
var msg = new FileUploadModel({
title: _.template(
gettext("Upload a new PDF to “<%= name %>”"),
{name: window.course.escape('name')}
),
title: _.template(gettext("Upload a new PDF to “<%= name %>”"))(
{name: course.escape('name')}),
message: gettext("Please select a PDF file to upload."),
mimeTypes: ['application/pdf']
});

View File

@@ -54,8 +54,8 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
title: messages.alreadyMember.title,
message: _.template(
messages.alreadyMember.messageTpl,
{email: email, container: containerName},
{interpolate: /\{(.+?)}/g}
{interpolate: /\{(.+?)}/g})(
{email: email, container: containerName}
),
actions: {
primary: {
@@ -140,7 +140,9 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
roles = _.object(_.pluck(this.roles, 'key'), _.pluck(this.roles, "name")),
adminRoleCount = this.getAdminRoleCount(),
viewHelpers = {
format: function (template, data) { return _.template(template, data, {interpolate: /\{(.+?)}/g}); }
format: function (template, data) {
return _.template(template, {interpolate: /\{(.+?)}/g})(data);
}
};
for (var i = 0; i < this.users.length; i++) {
var user = this.users[i],
@@ -284,8 +286,8 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
title: self.messages.deleteUser.title,
message: _.template(
self.messages.deleteUser.messageTpl,
{email: email, container: self.containerName},
{interpolate: /\{(.+?)}/g}
{interpolate: /\{(.+?)}/g})(
{email: email, container: self.containerName}
),
actions: {
primary: {

View File

@@ -1,242 +0,0 @@
define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "common/js/components/views/feedback_notification",
"js/utils/cancel_on_escape", "js/utils/date_utils", "js/utils/module", "common/js/components/utils/view_utils"],
function (domReady, $, ui, _, gettext, NotificationView, CancelOnEscape,
DateUtils, ModuleUtils, ViewUtils) {
var modalSelector = '.edit-section-publish-settings';
var toggleSections = function(e) {
e.preventDefault();
var $section = $('.courseware-section');
var $button = $(this);
var $labelCollapsed = $('<i class="icon fa fa-arrow-up"></i> <span class="label">' +
gettext('Collapse All Sections') + '</span>');
var $labelExpanded = $('<i class="icon fa fa-arrow-down"></i> <span class="label">' +
gettext('Expand All Sections') + '</span>');
var buttonLabel = $button.hasClass('is-activated') ? $labelCollapsed : $labelExpanded;
$button.toggleClass('is-activated').html(buttonLabel);
if ($button.hasClass('is-activated')) {
$section.addClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse').removeClass('collapse').addClass('expand');
} else {
$section.removeClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse').removeClass('expand').addClass('collapse');
}
};
var toggleSubmodules = function(e) {
e.preventDefault();
$(this).toggleClass('expand collapse');
$(this).closest('.is-collapsible, .window').toggleClass('collapsed');
};
var closeModalNew = function (e) {
if (e) {
e.preventDefault();
}
$('body').removeClass('modal-window-is-shown');
$('.edit-section-publish-settings').removeClass('is-shown');
};
var editSectionPublishDate = function (e) {
e.preventDefault();
var $modal = $(modalSelector);
$modal.attr('data-locator', $(this).attr('data-locator'));
$modal.find('.start-date').val($(this).attr('data-date'));
$modal.find('.start-time').val($(this).attr('data-time'));
if ($modal.find('.start-date').val() == '' && $modal.find('.start-time').val() == '') {
$modal.find('.save-button').hide();
}
$modal.find('.section-name').html('"' + $(this).closest('.courseware-section').find('.section-name-span').text() + '"');
$('body').addClass('modal-window-is-shown');
$('.edit-section-publish-settings').addClass('is-shown');
};
var saveSetSectionScheduleDate = function (e) {
e.preventDefault();
var datetime = DateUtils.getDate(
$('.edit-section-publish-settings .start-date'),
$('.edit-section-publish-settings .start-time')
);
var locator = $(modalSelector).attr('data-locator');
analytics.track('Edited Section Release Date', {
'course': course_location_analytics,
'id': locator,
'start': datetime
});
var saving = new NotificationView.Mini({
title: gettext("Saving")
});
saving.show();
// call into server to commit the new order
$.ajax({
url: ModuleUtils.getUpdateUrl(locator),
type: "PUT",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
'metadata': {
'start': datetime
}
})
}).success(function() {
var pad2 = function(number) {
// pad a number to two places: useful for formatting months, days, hours, etc
// when displaying a date/time
return (number < 10 ? '0' : '') + number;
};
var $thisSection = $('.courseware-section[data-locator="' + locator + '"]');
var html = _.template(
'<span class="published-status">' +
'<strong>' + gettext("Release date:") + '&nbsp;</strong>' +
gettext("{month}/{day}/{year} at {hour}:{minute} UTC") +
'</span>' +
'<a href="#" class="edit-release-date action" data-date="{month}/{day}/{year}" data-time="{hour}:{minute}" data-locator="{locator}"><i class="icon fa fa-time"></i> <span class="sr">' +
gettext("Edit section release date") +
'</span></a>',
{year: datetime.getUTCFullYear(), month: pad2(datetime.getUTCMonth() + 1), day: pad2(datetime.getUTCDate()),
hour: pad2(datetime.getUTCHours()), minute: pad2(datetime.getUTCMinutes()),
locator: locator},
{interpolate: /\{(.+?)\}/g});
$thisSection.find('.section-published-date').html(html);
saving.hide();
closeModalNew();
});
};
var addNewSection = function (e) {
e.preventDefault();
$(e.target).addClass('disabled');
var $newSection = $($('#new-section-template').html());
var $cancelButton = $newSection.find('.new-section-name-cancel');
$('.courseware-overview').prepend($newSection);
$newSection.find('.new-section-name').focus().select();
$newSection.find('.section-name-form').bind('submit', saveNewSection);
$cancelButton.bind('click', cancelNewSection);
CancelOnEscape($cancelButton);
};
var saveNewSection = function (e) {
e.preventDefault();
var $saveButton = $(this).find('.new-section-name-save');
var parent = $saveButton.data('parent');
var category = $saveButton.data('category');
var display_name = $(this).find('.new-section-name').val();
analytics.track('Created a Section', {
'course': course_location_analytics,
'display_name': display_name
});
$.postJSON(ModuleUtils.getUpdateUrl(), {
'parent_locator': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.locator != undefined) location.reload();
});
};
var cancelNewSection = function (e) {
e.preventDefault();
$('.new-courseware-section-button').removeClass('disabled');
$(this).parents('section.new-section').remove();
};
var addNewSubsection = function (e) {
e.preventDefault();
var $section = $(this).closest('.courseware-section');
var $newSubsection = $($('#new-subsection-template').html());
$section.find('.subsection-list > ol').append($newSubsection);
$section.find('.new-subsection-name-input').focus().select();
var $saveButton = $newSubsection.find('.new-subsection-name-save');
var $cancelButton = $newSubsection.find('.new-subsection-name-cancel');
var parent = $(this).parents("section.courseware-section").data("locator");
$saveButton.data('parent', parent);
$saveButton.data('category', $(this).data('category'));
$newSubsection.find('.new-subsection-form').bind('submit', saveNewSubsection);
$cancelButton.bind('click', cancelNewSubsection);
CancelOnEscape($cancelButton);
};
var saveNewSubsection = function (e) {
e.preventDefault();
var parent = $(this).find('.new-subsection-name-save').data('parent');
var category = $(this).find('.new-subsection-name-save').data('category');
var display_name = $(this).find('.new-subsection-name-input').val();
analytics.track('Created a Subsection', {
'course': course_location_analytics,
'display_name': display_name
});
$.postJSON(ModuleUtils.getUpdateUrl(), {
'parent_locator': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.locator != undefined) {
location.reload();
}
});
};
var cancelNewSubsection = function (e) {
e.preventDefault();
$(this).parents('li.courseware-subsection').remove();
};
domReady(function() {
// toggling overview section details
$(function() {
if ($('.courseware-section').length > 0) {
$('.toggle-button-sections').addClass('is-shown');
}
});
$('.toggle-button-sections').bind('click', toggleSections);
$('.expand-collapse').bind('click', toggleSubmodules);
$('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function () {
$('.wrapper-alert-announcement').remove();
}));
var $body = $('body');
$body.on('click', '.section-published-date .edit-release-date', editSectionPublishDate);
$body.on('click', '.edit-section-publish-settings .action-save', saveSetSectionScheduleDate);
$body.on('click', '.edit-section-publish-settings .action-cancel', closeModalNew);
$('.new-courseware-section-button').bind('click', addNewSection);
$('.new-subsection-item').bind('click', addNewSubsection);
});
return {
saveSetSectionScheduleDate: saveSetSectionScheduleDate
};
});

View File

@@ -22,9 +22,7 @@ define(["underscore", "backbone", "gettext", "text!templates/paging-header.under
currentPage = collection.currentPage,
lastPage = collection.totalPages - 1,
messageHtml = this.messageHtml();
this.$el.html(_.template(paging_header_template, {
messageHtml: messageHtml
}));
this.$el.html(_.template(paging_header_template)({ messageHtml: messageHtml}));
this.$(".previous-page-link").toggleClass("is-disabled", currentPage === 0).attr('aria-disabled', currentPage === 0);
this.$(".next-page-link").toggleClass("is-disabled", currentPage === lastPage).attr('aria-disabled', currentPage === lastPage);
return this;

View File

@@ -27,10 +27,9 @@ define(["js/views/baseview", "underscore", "gettext", "common/js/components/view
},
confirmDelete: function(e) {
if(e && e.preventDefault) { e.preventDefault(); }
var textbook = this.model, collection = this.model.collection;
var msg = new PromptView.Warning({
title: _.template(
gettext("Delete “<%= name %>”?"),
var textbook = this.model;
new PromptView.Warning({
title: _.template(gettext("Delete “<%= name %>”?"))(
{name: textbook.get('name')}
),
message: gettext("Deleting a textbook cannot be undone and once deleted any reference to it in your courseware's navigation will also be removed."),

View File

@@ -18,7 +18,9 @@ function($, Backbone, _, Utils) {
uploadTpl: '#file-upload',
initialize: function () {
_.bindAll(this);
_.bindAll(this,
'changeHandler', 'clickHandler', 'xhrResetProgressBar', 'xhrProgressHandler', 'xhrCompleteHandler'
);
this.file = false;
this.render();

View File

@@ -29,7 +29,9 @@ function($, Backbone, _, Utils, FileUploader, gettext) {
},
initialize: function () {
_.bindAll(this);
_.bindAll(this,
'importHandler', 'replaceHandler', 'chooseHandler', 'useExistingHandler', 'showError', 'hideError'
);
this.component_locator = this.$el.closest('[data-locator]').data('locator');

View File

@@ -2,17 +2,17 @@
<div class "error-header">
<p>
<%= _.template(
ngettext(
"There was {strong_start}{num_errors} validation error{strong_end} while trying to save the course settings in the database.",
"There were {strong_start}{num_errors} validation errors{strong_end} while trying to save the course settings in the database.",
num_errors
),
{
strong_start:'<strong>',
num_errors: num_errors,
strong_end: '</strong>'
},
{interpolate: /\{(.+?)\}/g})%>
ngettext(
"There was {strong_start}{num_errors} validation error{strong_end} while trying to save the course settings in the database.",
"There were {strong_start}{num_errors} validation errors{strong_end} while trying to save the course settings in the database.",
num_errors
),
{interpolate: /\{(.+?)\}/g})(
{
strong_start:'<strong>',
num_errors: num_errors,
strong_end: '</strong>'
})%>
<%= gettext("Please check the following validation feedbacks and reflect them in your course settings:")%></p>
</div>

View File

@@ -361,9 +361,14 @@ function (VideoPlayer) {
describe('onSeek', function () {
beforeEach(function () {
// jasmine.Clock can't be used to fake out debounce with newer versions of underscore
spyOn(_, 'debounce').andCallFake(function (func) {
return function () {
func.apply(this, arguments);
};
});
state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
jasmine.Clock.useMock();
spyOn(state.videoPlayer, 'duration').andReturn(120);
});
@@ -384,9 +389,6 @@ function (VideoPlayer) {
spyOn(state.videoPlayer, 'stopTimer');
spyOn(state.videoPlayer, 'runTimer');
state.videoPlayer.seekTo(10);
// Video player uses _.debounce (with a wait time in 300 ms) for seeking.
// That's why we have to do this tick(300).
jasmine.Clock.tick(300);
expect(state.videoPlayer.currentTime).toBe(10);
expect(state.videoPlayer.stopTimer).toHaveBeenCalled();
expect(state.videoPlayer.runTimer).toHaveBeenCalled();
@@ -399,9 +401,6 @@ function (VideoPlayer) {
state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 30 }
);
// Video player uses _.debounce (with a wait time in 300 ms) for seeking.
// That's why we have to do this tick(300).
jasmine.Clock.tick(300);
expect(state.videoPlayer.currentTime).toBe(30);
expect(state.videoPlayer.player.seekTo).toHaveBeenCalledWith(30, true);
});
@@ -413,9 +412,6 @@ function (VideoPlayer) {
state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 30 }
);
// Video player uses _.debounce (with a wait time in 300 ms) for seeking.
// That's why we have to do this tick(300).
jasmine.Clock.tick(300);
expect(state.videoPlayer.currentTime).toBe(30);
expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(30, true);
});
@@ -426,17 +422,11 @@ function (VideoPlayer) {
state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 20 }
);
// Video player uses _.debounce (with a wait time in 300 ms) for seeking.
// That's why we have to do this tick(300).
jasmine.Clock.tick(300);
state.videoPlayer.pause();
expect(state.videoPlayer.currentTime).toBe(20);
state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 10 }
);
// Video player uses _.debounce (with a wait time in 300 ms) for seeking.
// That's why we have to do this tick(300).
jasmine.Clock.tick(300);
expect(state.videoPlayer.currentTime).toBe(10);
});

View File

@@ -13,7 +13,7 @@ var setupFullScreenModal = function() {
"largeALT": smallImageObject.attr('alt'),
"largeSRC": largeImageSRC
};
var html = _.template($("#image-modal-tpl").text(), data);
var html = _.template($("#image-modal-tpl").text())(data);
$(this).replaceWith(html);
}
});

View File

@@ -115,7 +115,7 @@ describe "ThreadResponseShowView", ->
expect(@view.$(".posted-details").text()).not.toMatch("marked as answer")
it "allows a moderator to mark an answer in a question thread", ->
DiscussionUtil.loadRoles({"Moderator": parseInt(window.user.id)})
DiscussionUtil.loadRoles({"Moderator": [parseInt(window.user.id)]})
@thread.set({
"thread_type": "question",
"user_id": (parseInt(window.user.id) + 1).toString()

View File

@@ -1,28 +0,0 @@
class @DiscussionFilter
# TODO: this helper class duplicates functionality in DiscussionThreadListView.filterTopics
# for use with a very similar category dropdown in the New Post form. The two menus' implementations
# should be merged into a single reusable view.
@filterDrop: (e) ->
$drop = $(e.target).parents('.topic-menu-wrapper')
query = $(e.target).val()
$items = $drop.find('.topic-menu-item')
if(query.length == 0)
$items.removeClass('hidden')
return;
$items.addClass('hidden')
$items.each (i) ->
path = $(this).parents(".topic-menu-item").andSelf()
pathTitles = path.children(".topic-title").map((i, elem) -> $(elem).text()).get()
pathText = pathTitles.join(" / ").toLowerCase()
if query.split(" ").every((term) -> pathText.search(term.toLowerCase()) != -1)
$(this).removeClass('hidden')
# show children
$(this).find('.topic-menu-item').removeClass('hidden');
# show parents
$(this).parents('.topic-menu-item').removeClass('hidden');

View File

@@ -19,7 +19,7 @@
this.threadType = this.model.get('thread_type');
this.topicId = this.model.get('commentable_id');
this.context = options.context || 'course';
_.bindAll(this);
_.bindAll(this, 'updateHandler', 'cancelHandler');
return this;
},

View File

@@ -39,9 +39,9 @@ if Backbone?
@searchAlertCollection.on "add", (searchAlert) =>
content = _.template(
$("#search-alert-template").html(),
$("#search-alert-template").html())(
{'message': searchAlert.attributes.message, 'cid': searchAlert.cid}
)
)
@$(".search-alerts").append(content)
@$("#search-alert-" + searchAlert.cid + " a.dismiss").bind "click", searchAlert, (event) =>
@removeSearchAlert(event.data.cid)
@@ -491,7 +491,7 @@ if Backbone?
message = interpolate(
_.escape(gettext('Show posts by %(username)s.')),
{"username":
_.template('<a class="link-jump" href="<%= url %>"><%- username %></a>', {
_.template('<a class="link-jump" href="<%= url %>"><%- username %></a>')({
url: DiscussionUtil.urlFor("user_profile", response.users[0].id),
username: response.users[0].username
})

View File

@@ -6,7 +6,7 @@
'click .post-topic-button': 'toggleTopicDropdown',
'click .topic-menu-wrapper': 'handleTopicEvent',
'click .topic-filter-label': 'ignoreClick',
'keyup .topic-filter-input': this.DiscussionFilter.filterDrop
'keyup .topic-filter-input': 'filterDrop'
},
attributes: {
@@ -17,7 +17,9 @@
this.course_settings = options.course_settings;
this.currentTopicId = options.topicId;
this.maxNameWidth = 100;
_.bindAll(this);
_.bindAll(this,
'toggleTopicDropdown', 'handleTopicEvent', 'hideTopicDropdown', 'ignoreClick'
);
return this;
},
@@ -34,7 +36,7 @@
render: function() {
var context = _.clone(this.course_settings.attributes);
context.topics_html = this.renderCategoryMap(this.course_settings.get('category_map'));
this.$el.html(_.template($('#topic-template').html(), context));
this.$el.html(_.template($('#topic-template').html())(context));
this.dropdownButton = this.$('.post-topic-button');
this.topicMenu = this.$('.topic-menu-wrapper');
this.selectedTopic = this.$('.js-selected-topic');
@@ -187,6 +189,38 @@
}
}
return name;
},
// TODO: this helper class duplicates functionality in DiscussionThreadListView.filterTopics
// for use with a very similar category dropdown in the New Post form. The two menus' implementations
// should be merged into a single reusable view.
filterDrop: function (e) {
var $drop, $items, query;
$drop = $(e.target).parents('.topic-menu-wrapper');
query = $(e.target).val();
$items = $drop.find('.topic-menu-item');
if (query.length === 0) {
$items.removeClass('hidden');
return;
}
$items.addClass('hidden');
$items.each(function (_index, item) {
var path, pathText, pathTitles;
path = $(item).parents(".topic-menu-item").andSelf();
pathTitles = path.children(".topic-title").map(function (_, elem) {
return $(elem).text();
}).get();
pathText = pathTitles.join(" / ").toLowerCase();
if (query.split(" ").every(function (term) {
return pathText.search(term.toLowerCase()) !== -1;
})) {
$(item).removeClass('hidden');
$(item).find('.topic-menu-item').removeClass('hidden');
$(item).parents('.topic-menu-item').removeClass('hidden');
}
});
}
});
}

View File

@@ -17,7 +17,7 @@ if Backbone?
mode: @mode,
form_id: @mode + (if @topicId then "-" + @topicId else "")
})
@$el.html(_.template($("#new-post-template").html(), context))
@$el.html(_.template($("#new-post-template").html())(context))
threadTypeTemplate = _.template($("#thread-type-template").html());
if $('.js-group-select').is(':disabled')
$('.group-selector-wrapper').addClass('disabled')

View File

@@ -79,6 +79,9 @@
* underlying server API.
*/
getPage: function () {
// TODO: this.currentPage is currently returning a function sometimes when it is called.
// It is possible it always did this, but we either need to investigate more, or just wait until
// we replace this code with the pattern library.
return this.currentPage + (this.isZeroIndexed ? 1 : 0);
},

View File

@@ -244,7 +244,7 @@
if (!validateTotalKeyLength(key_field_selectors)) {
$(selectors.errorWrapper).addClass(classes.shown).removeClass(classes.hiding);
$(selectors.errorMessage).html(
'<p>' + _.template(message_tpl, {limit: MAX_SUM_KEY_LENGTH}) + '</p>'
'<p>' + _.template(message_tpl)({limit: MAX_SUM_KEY_LENGTH}) + '</p>'
);
$(selectors.save).addClass(classes.disabled);
} else {

View File

@@ -2,7 +2,7 @@
'use strict';
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
function($, _, str, SystemFeedbackView) {
str = str || _.str;
var Alert = SystemFeedbackView.extend({
options: $.extend({}, SystemFeedbackView.prototype.options, {
type: "alert"

View File

@@ -2,7 +2,7 @@
'use strict';
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
function($, _, str, SystemFeedbackView) {
str = str || _.str;
var Notification = SystemFeedbackView.extend({
options: $.extend({}, SystemFeedbackView.prototype.options, {
type: "notification",

View File

@@ -2,7 +2,7 @@
'use strict';
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
function($, _, str, SystemFeedbackView) {
str = str || _.str;
var Prompt = SystemFeedbackView.extend({
options: $.extend({}, SystemFeedbackView.prototype.options, {
type: "prompt",

View File

@@ -50,7 +50,7 @@
},
render: function () {
this.$el.html(_.template(paginatedViewTemplate, {type: this.type}));
this.$el.html(_.template(paginatedViewTemplate)({type: this.type}));
this.assign(this.listView, '.' + this.type + '-list');
if (this.headerView) {
this.assign(this.headerView, '.' + this.type + '-paging-header');

View File

@@ -30,7 +30,7 @@
this.$el.removeClass('hidden');
}
}
this.$el.html(_.template(paging_footer_template, {
this.$el.html(_.template(paging_footer_template)({
current_page: this.collection.getPage(),
total_pages: this.collection.totalPages
}));

View File

@@ -33,7 +33,7 @@
context, true
);
}
this.$el.html(_.template(headerTemplate, {
this.$el.html(_.template(headerTemplate)({
message: message,
srInfo: this.srInfo,
sortableFields: this.collection.sortableFields,

View File

@@ -37,7 +37,7 @@
},
render: function() {
this.$el.html(_.template(searchFieldTemplate, {
this.$el.html(_.template(searchFieldTemplate)({
type: this.type,
searchString: this.collection.searchString,
searchLabel: this.label

View File

@@ -15,9 +15,6 @@
* by the access view, but doing it here helps keep the
* utility self-contained.
*/
if (_.isUndefined(_s)) {
_s = _.str;
}
_.mixin( _s.exports() );
utils = (function(){

View File

@@ -1,6 +1,6 @@
<% if (!readOnly) { %>
<ul class="<%= contentType %>-actions-list">
<% _.each(primaryActions, function(action) { print(_.template($('#forum-action-' + action).html(), {})) }) %>
<% _.each(primaryActions, function(action) { print(_.template($('#forum-action-' + action).html())({})) }) %>
<li class="actions-item is-visible">
<div class="more-wrapper">
<a href="javascript:void(0)" class="action-button action-more" role="button" aria-haspopup="true" aria-controls="action-menu-<%= contentId %>">
@@ -9,7 +9,7 @@
</a>
<div class="actions-dropdown" id="action-menu-<%= contentType %>" aria-expanded="false">
<ul class="actions-dropdown-list">
<% _.each(secondaryActions, function(action) { print(_.template($('#forum-action-' + action).html(), {})) }) %>
<% _.each(secondaryActions, function(action) { print(_.template($('#forum-action-' + action).html())({})) }) %>
</ul>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<div class="response-body"><%- body %></div>
<%=
_.template(
$('#forum-actions').html(),
$('#forum-actions').html())(
{
contentId: cid,
contentType: 'comment',

View File

@@ -44,7 +44,7 @@
<div class="response-header-actions">
<%=
_.template(
$('#forum-actions').html(),
$('#forum-actions').html())(
{
contentId: cid,
contentType: 'response',

View File

@@ -30,7 +30,7 @@
<div class="post-header-actions post-extended-content">
<%=
_.template(
$('#forum-actions').html(),
$('#forum-actions').html())(
{
contentId: cid,
contentType: 'post',

View File

@@ -21,7 +21,7 @@
*/
var interpolate_ntext = function (singular, plural, count, values) {
var text = count === 1 ? singular : plural;
return _.template(text, values, {interpolate: /\{(.+?)\}/g});
return _.template(text, {interpolate: /\{(.+?)\}/g})(values);
};
this.interpolate_ntext = interpolate_ntext;
@@ -42,7 +42,7 @@
* @returns the text with placeholder values filled in
*/
var interpolate_text = function (text, values) {
return _.template(text, values, {interpolate: /\{(.+?)\}/g});
return _.template(text, {interpolate: /\{(.+?)\}/g})(values);
};
this.interpolate_text = interpolate_text;
}).call(this, _);

View File

@@ -12,7 +12,7 @@
}
this.hide();
_.bindAll(this);
_.bindAll(this, 'show', 'hide', 'showTooltip', 'moveTooltip', 'hideTooltip', 'click');
this.bindEvents();
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
../../../../node_modules/underscore.string/dist/underscore.string.min.js

View File

@@ -508,12 +508,6 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
self.q(css='{} .section-name .save-button'.format(parent_css)).first.click()
self.wait_for_ajax()
def click_release_date(self):
"""
Open release date edit modal of first section in course outline
"""
self.q(css='div.section-published-date a.edit-release-date').first.click()
def sections(self):
"""
Returns the sections of this course outline page.

View File

@@ -44,7 +44,7 @@
certificates: this.certificates
};
this.setResults(_.template(resultsTpl, context));
this.setResults(_.template(resultsTpl)(context));
},
renderError: function(error) {

View File

@@ -35,7 +35,7 @@
render: function () {
var user = this.enrollments.user;
this.$el.html(_.template(enrollmentTemplate, {
this.$el.html(_.template(enrollmentTemplate)({
user: user,
enrollments: this.enrollments,
formatDate: function (date) {

View File

@@ -21,7 +21,7 @@
},
render: function () {
this.$el.html(_.template(this.template, {
this.$el.html(_.template(this.template)({
enrollment: this.enrollment,
modes: this.modes,
reasons: this.reasons,

View File

@@ -31,7 +31,7 @@
var memberships = this.model.get('membership'),
discussionTopicID = this.model.get('discussion_topic_id'),
isMember = TeamUtils.isUserMemberOfTeam(memberships, this.context.userInfo.username);
this.$el.html(_.template(teamTemplate, {
this.$el.html(_.template(teamTemplate)({
courseID: this.context.courseID,
discussionTopicID: discussionTopicID,
readOnly: !(this.context.userInfo.privileged || isMember),
@@ -56,7 +56,7 @@
renderTeamMembers: function() {
var view = this;
_.each(this.model.get('membership'), function(membership) {
view.$('.members-info').append(_.template(teamMemberTemplate, {
view.$('.members-info').append(_.template(teamMemberTemplate)({
imageUrl: membership.user.profile_image.image_url_medium,
username: membership.user.username,
memberProfileUrl: '/u/' + membership.user.username

View File

@@ -51,7 +51,7 @@
'span_end': '</a>'
}
);
self.$el.append(_.template(teamActionsTemplate, {message: message}));
self.$el.append(_.template(teamActionsTemplate)({message: message}));
}
});
return this;

View File

@@ -1237,6 +1237,7 @@ base_vendor_js = [
'js/vendor/jquery.cookie.js',
'js/vendor/url.min.js',
'js/vendor/underscore-min.js',
'js/vendor/underscore.string.min.js',
'js/vendor/requirejs/require.js',
'js/RequireJS-namespace-undefine.js',
'js/vendor/URI.min.js',

View File

@@ -117,7 +117,7 @@ class AuthListWidget extends MemberListWidget
# create revoke button and insert it into the row
label_trans = gettext("Revoke access")
$revoke_btn = $ _.template('<div class="revoke"><i class="icon fa fa-times-circle" aria-hidden="true"></i> <%= label %></div>', {label: label_trans}),
$revoke_btn = $ _.template('<div class="revoke"><i class="icon fa fa-times-circle" aria-hidden="true"></i> <%= label %></div>')({label: label_trans}),
class: 'revoke'
$revoke_btn.click =>
@modify_member_access member.email, 'revoke', (error) =>

View File

@@ -62,7 +62,7 @@ class SendEmail
success_message = gettext("Your email was successfully queued for sending. Please note that for large classes, it may take up to an hour (or more, if other courses are simultaneously sending email) to send all emails.")
subject = @$subject.val()
full_confirm_message = _.template(confirm_message, {subject: subject})
full_confirm_message = _.template(confirm_message)({subject: subject})
if confirm full_confirm_message

View File

@@ -73,7 +73,7 @@ class @StudentAdmin
if not unique_student_identifier
return @$request_response_error_progress.text gettext("Please enter a student email address or username.")
error_message = gettext("Error getting student progress url for '<%= student_id %>'. Make sure that the student identifier is spelled correctly.")
full_error_message = _.template(error_message, {student_id: unique_student_identifier})
full_error_message = _.template(error_message)({student_id: unique_student_identifier})
$.ajax
dataType: 'json'
@@ -97,8 +97,8 @@ class @StudentAdmin
delete_module: false
success_message = gettext("Success! Problem attempts reset for problem '<%= problem_id %>' and student '<%= student_id %>'.")
error_message = gettext("Error resetting problem attempts for problem '<%= problem_id %>' and student '<%= student_id %>'. Make sure that the problem and student identifiers are complete and correct.")
full_success_message = _.template(success_message, {problem_id: problem_to_reset, student_id: unique_student_identifier})
full_error_message = _.template(error_message, {problem_id: problem_to_reset, student_id: unique_student_identifier})
full_success_message = _.template(success_message)({problem_id: problem_to_reset, student_id: unique_student_identifier})
full_error_message = _.template(error_message)({problem_id: problem_to_reset, student_id: unique_student_identifier})
$.ajax
dataType: 'json'
@@ -116,7 +116,7 @@ class @StudentAdmin
if not problem_to_reset
return @$request_response_error_grade.text gettext("Please enter a problem location.")
confirm_message = gettext("Delete student '<%= student_id %>'s state on problem '<%= problem_id %>'?")
full_confirm_message = _.template(confirm_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
full_confirm_message = _.template(confirm_message)({student_id: unique_student_identifier, problem_id: problem_to_reset})
if window.confirm full_confirm_message
send_data =
@@ -124,7 +124,7 @@ class @StudentAdmin
problem_to_reset: problem_to_reset
delete_module: true
error_message = gettext("Error deleting student '<%= student_id %>'s state on problem '<%= problem_id %>'. Make sure that the problem and student identifiers are complete and correct.")
full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
full_error_message = _.template(error_message)({student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
@@ -148,9 +148,9 @@ class @StudentAdmin
unique_student_identifier: unique_student_identifier
problem_to_reset: problem_to_reset
success_message = gettext("Started rescore problem task for problem '<%= problem_id %>' and student '<%= student_id %>'. Click the 'Show Background Task History for Student' button to see the status of the task.")
full_success_message = _.template(success_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
full_success_message = _.template(success_message)({student_id: unique_student_identifier, problem_id: problem_to_reset})
error_message = gettext("Error starting a task to rescore problem '<%= problem_id %>' for student '<%= student_id %>'. Make sure that the the problem and student identifiers are complete and correct.")
full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
full_error_message = _.template(error_message)({student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
@@ -171,7 +171,7 @@ class @StudentAdmin
unique_student_identifier: unique_student_identifier
problem_location_str: problem_to_reset
error_message = gettext("Error getting task history for problem '<%= problem_id %>' and student '<%= student_id %>'. Make sure that the problem and student identifiers are complete and correct.")
full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
full_error_message = _.template(error_message)({student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
@@ -293,15 +293,15 @@ class @StudentAdmin
if not problem_to_reset
return @$request_response_error_all.text gettext("Please enter a problem location.")
confirm_message = gettext("Reset attempts for all students on problem '<%= problem_id %>'?")
full_confirm_message = _.template(confirm_message, {problem_id: problem_to_reset})
full_confirm_message = _.template(confirm_message)({problem_id: problem_to_reset})
if window.confirm full_confirm_message
send_data =
all_students: true
problem_to_reset: problem_to_reset
success_message = gettext("Successfully started task to reset attempts for problem '<%= problem_id %>'. Click the 'Show Background Task History for Problem' button to see the status of the task.")
full_success_message = _.template(success_message, {problem_id: problem_to_reset})
full_success_message = _.template(success_message)({problem_id: problem_to_reset})
error_message = gettext("Error starting a task to reset attempts for all students on problem '<%= problem_id %>'. Make sure that the problem identifier is complete and correct.")
full_error_message = _.template(error_message, {problem_id: problem_to_reset})
full_error_message = _.template(error_message)({problem_id: problem_to_reset})
$.ajax
dataType: 'json'
@@ -319,15 +319,15 @@ class @StudentAdmin
if not problem_to_reset
return @$request_response_error_all.text gettext("Please enter a problem location.")
confirm_message = gettext("Rescore problem '<%= problem_id %>' for all students?")
full_confirm_message = _.template(confirm_message, {problem_id: problem_to_reset})
full_confirm_message = _.template(confirm_message)({problem_id: problem_to_reset})
if window.confirm full_confirm_message
send_data =
all_students: true
problem_to_reset: problem_to_reset
success_message = gettext("Successfully started task to rescore problem '<%= problem_id %>' for all students. Click the 'Show Background Task History for Problem' button to see the status of the task.")
full_success_message = _.template(success_message, {problem_id: problem_to_reset})
full_success_message = _.template(success_message)({problem_id: problem_to_reset})
error_message = gettext("Error starting a task to rescore problem '<%= problem_id %>'. Make sure that the problem identifier is complete and correct.")
full_error_message = _.template(error_message, {problem_id: problem_to_reset})
full_error_message = _.template(error_message)({problem_id: problem_to_reset})
$.ajax
dataType: 'json'

View File

@@ -1134,7 +1134,7 @@
// The main dialog box.
dialog = doc.createElement("div");
dialog.innerHTML = _.template(
document.getElementById("customwmd-prompt-template").innerHTML, {
document.getElementById("customwmd-prompt-template").innerHTML)({
title: title,
uploadFieldClass: (imageUploadHandler ? 'file-upload' : ''),
urlLabel: urlLabel,

View File

@@ -30,7 +30,7 @@
},
validate: function(attrs){
if (!_.str.trim(attrs.user_name) && !_.str.trim(attrs.user_email)) {
if (!str.trim(attrs.user_name) && !str.trim(attrs.user_email)) {
return gettext('Student username/email field is required and can not be empty. ' +
'Kindly fill in username/email and then press "Add to Exception List" button.');
}

View File

@@ -8,6 +8,7 @@
['underscore', 'underscore.string', 'gettext', 'backbone'],
function(_, str, gettext, Backbone) {
return Backbone.Model.extend({
idAttribute: 'id',
@@ -23,7 +24,7 @@
},
validate: function(attrs) {
if (!_.str.trim(attrs.user)) {
if (!str.trim(attrs.user)) {
// A username or email must be provided for certificate invalidation
return gettext('Student username/email field is required and can not be empty. ' +
'Kindly fill in username/email and then press "Invalidate Certificate" button.');

View File

@@ -43,7 +43,7 @@
if (this.collection.findWhere({user: user})) {
message = gettext("Certificate of <%= user %> has already been invalidated. Please check your spelling and retry."); // jshint ignore:line
this.escapeAndShowMessage(_.template(message, {user: user}));
this.escapeAndShowMessage(_.template(message)({user: user}));
}
else if (certificate_invalidation.isValid()) {
var self = this;
@@ -53,7 +53,7 @@
success: function(model) {
self.collection.add(model);
message = gettext('Certificate has been successfully invalidated for <%= user %>.');
self.escapeAndShowMessage(_.template(message, {user: user}));
self.escapeAndShowMessage(_.template(message)({user: user}));
},
error: function(model, response) {

View File

@@ -56,7 +56,7 @@
if(this.collection.findWhere(model)){
message = gettext("<%= user %> already in exception list.");
this.escapeAndShowMessage(
_.template(message, {user: (user_name || user_email)})
_.template(message)({user: (user_name || user_email)})
);
}
else if(certificate_exception.isValid()){
@@ -67,7 +67,7 @@
success: this.showSuccess(
this,
true,
_.template(message, {user: (user_name || user_email)})
_.template(message)({user: (user_name || user_email)})
),
error: this.showError(this)
}

View File

@@ -43,7 +43,7 @@ var edx = edx || {};
courseKey: this.courseKey
});
this.$el.html(_.template(templateHtml, context));
this.$el.html(_.template(templateHtml)(context));
this.trackLinks();
@@ -69,7 +69,7 @@ var edx = edx || {};
context.course_key = this.courseKey;
context.username = this.username;
context.platformName = this.$el.data('platform-name');
providerDiv.html(_.template(templateHtml, context)).removeClass('hidden');
providerDiv.html(_.template(templateHtml)(context)).removeClass('hidden');
},
renderError: function () {

View File

@@ -71,7 +71,7 @@
var self = this;
this.$el.html(this.template({}));
_.each(this.tabs, function(tabInfo, index) {
var tabEl = $(_.template(tabTemplate, {
var tabEl = $(_.template(tabTemplate)({
index: index,
title: tabInfo.title,
url: tabInfo.url,

View File

@@ -97,7 +97,7 @@ var edx = edx || {};
* @returns {DonationView}
*/
render: function() {
var html = _.template($("#donation-tpl").html(), {});
var html = _.template($("#donation-tpl").html())({});
this.$el.html(html);
this.$amount = $("input[name=\"amount\"]", this.$el);
this.$submit = $(".action-donate", this.$el);

View File

@@ -76,7 +76,7 @@
fields: html || '',
});
this.$el.html(_.template(this.tpl, data));
this.$el.html(_.template(this.tpl)(data));
this.postRender();
this.validateCountry();
@@ -85,7 +85,7 @@
},
renderSuccess: function() {
this.$el.html(_.template(successTpl, {
this.$el.html(_.template(successTpl)({
course: this.model.get('course'),
dashboard_url: this.context.dashboard_url
}));

View File

@@ -37,7 +37,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
describe('destroy', function () {

View File

@@ -16,7 +16,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
describe('destroy', function () {

View File

@@ -31,7 +31,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
it('should log edx.course.student_notes.viewed event properly', function() {

View File

@@ -46,7 +46,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
it('should scroll to a note, open it and freeze the annotator if its id is part of the url hash', function() {

View File

@@ -11,7 +11,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
it('can initialize annotator correctly', function() {

View File

@@ -37,7 +37,9 @@ define([
afterEach(function () {
NotesVisibilityFactory.VisibilityDecorator._setVisibility(null);
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
$('.annotator-notice').remove();
});

View File

@@ -46,7 +46,9 @@ define([
});
afterEach(function () {
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
it('does not show the viewer if the editor is opened', function() {

View File

@@ -21,7 +21,9 @@ define([
afterEach(function () {
VisibilityDecorator._setVisibility(null);
_.invoke(Annotator._instances, 'destroy');
while (Annotator._instances.length > 0) {
Annotator._instances[0].destroy();
}
});
it('can initialize Notes if it visibility equals True', function() {

View File

@@ -181,22 +181,7 @@
},
'underscore': {
deps: ['underscore.string'],
exports: '_',
init: function(UnderscoreString) {
/* Mix non-conflicting functions from underscore.string
* (all but include, contains, and reverse) into the
* Underscore namespace. This allows the login, register,
* and password reset templates to render independent of the
* access view.
*/
_.mixin(UnderscoreString.exports());
/* Since the access view is not using RequireJS, we also
* expose underscore.string at _.str, so that the access
* view can perform the mixin on its own.
*/
_.str = UnderscoreString;
}
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
@@ -374,7 +359,12 @@
},
'js/verify_student/views/step_view': {
exports: 'edx.verify_student.StepView',
deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ]
deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ],
init: function() {
// Set global variables that the payment code is expecting to be defined
window._ = require('underscore');
window._.str = require('underscore.string');
}
},
'js/verify_student/views/intro_step_view': {
exports: 'edx.verify_student.IntroStepView',
@@ -515,12 +505,6 @@
],
exports: 'Discussion'
},
'xmodule_js/common_static/coffee/src/discussion/discussion_filter': {
deps: [
'xmodule_js/common_static/coffee/src/discussion/utils'
],
exports: 'DiscussionFilter'
},
'xmodule_js/common_static/coffee/src/discussion/models/discussion_course_settings': {
deps: [
'xmodule_js/common_static/coffee/src/discussion/utils'
@@ -614,7 +598,6 @@
'URI',
'xmodule_js/common_static/coffee/src/discussion/content',
'xmodule_js/common_static/coffee/src/discussion/discussion',
'xmodule_js/common_static/coffee/src/discussion/discussion_filter',
'xmodule_js/common_static/coffee/src/discussion/utils',
'xmodule_js/common_static/coffee/src/discussion/models/discussion_course_settings',
'xmodule_js/common_static/coffee/src/discussion/models/discussion_user',

View File

@@ -8,7 +8,6 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/
describe( 'edx.verify_student.ReverifyView', function() {
var TEMPLATES = [
"reverify",
"webcam_photo",
"image_input",
"error",

View File

@@ -35,15 +35,11 @@ var StaffDebug = (function (){
url: get_url(action.method),
data: pdata,
success: function(data){
var text = _.template(
action.success_msg,
{user: data.student},
{interpolate: /\{(.+?)\}/g}
var text = _.template(action.success_msg, {interpolate: /\{(.+?)\}/g})(
{user: data.student}
);
var html = _.template(
'<p id="idash_msg" class="success">{text}</p>',
{text: text},
{interpolate: /\{(.+?)\}/g}
var html = _.template('<p id="idash_msg" class="success">{text}</p>', {interpolate: /\{(.+?)\}/g})(
{text: text}
);
$("#result_"+sanitized_string(action.locationName)).html(html);
},
@@ -54,18 +50,14 @@ var StaffDebug = (function (){
} catch(e) {
response_json = { error: gettext('Unknown Error Occurred.') };
}
var text = _.template(
'{error_msg} {error}',
var text = _.template('{error_msg} {error}', {interpolate: /\{(.+?)\}/g})(
{
error_msg: action.error_msg,
error: response_json.error
},
{interpolate: /\{(.+?)\}/g}
}
);
var html = _.template(
'<p id="idash_msg" class="error">{text}</p>',
{text: text},
{interpolate: /\{(.+?)\}/g}
var html = _.template('<p id="idash_msg" class="error">{text}</p>', {interpolate: /\{(.+?)\}/g})(
{text: text}
);
$("#result_"+sanitized_string(action.locationName)).html(html);

View File

@@ -84,7 +84,7 @@ var edx = edx || {};
},
render: function() {
this.$el.html(_.template($('#account-tpl').html(), {}));
this.$el.html(_.template($('#account-tpl').html())({}));
this.$email = $('#new-email', this.$el);
this.$password = $('#password', this.$el);
this.$emailStatus = $('#new-email-status', this.$el);
@@ -113,7 +113,7 @@ var edx = edx || {};
event.preventDefault();
this.clearStatus();
self = this;
var self = this;
$.ajax({
url: 'password',
type: 'POST',

View File

@@ -19,10 +19,6 @@
function($, utility, _, _s, Backbone, LoginModel, PasswordResetModel, RegisterModel, LoginView,
PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView) {
if (_.isUndefined(_s)) {
_s = _.str;
}
return Backbone.View.extend({
tpl: '#access-tpl',
events: {
@@ -89,7 +85,7 @@
},
render: function() {
$(this.el).html( _.template( this.tpl, {
$(this.el).html( _.template(this.tpl)({
mode: this.activeForm
}));

View File

@@ -55,7 +55,7 @@
render: function( html ) {
var fields = html || '';
$(this.el).html( _.template( this.tpl, {
$(this.el).html( _.template(this.tpl)({
fields: fields
}));
@@ -84,7 +84,7 @@
data[i].errorMessages = this.escapeStrings( data[i].errorMessages );
}
html.push( _.template( fieldTpl, $.extend( data[i], {
html.push( _.template(fieldTpl)($.extend( data[i], {
form: this.formType,
requiredStr: this.requiredStr
}) ) );

View File

@@ -23,7 +23,7 @@
},
render: function() {
$(this.el).html( _.template( this.tpl, {
$(this.el).html(_.template(this.tpl)({
hintedProvider: this.hintedProvider
}));

View File

@@ -14,7 +14,7 @@
},
render: function() {
$(this.el).html( _.template( this.tpl, {
$(this.el).html(_.template(this.tpl)({
// We pass the context object to the template so that
// we can perform variable interpolation using sprintf
providers: this.providers,

View File

@@ -37,7 +37,7 @@
render: function( html ) {
var fields = html || '';
$(this.el).html( _.template( this.tpl, {
$(this.el).html(_.template(this.tpl)({
// We pass the context object to the template so that
// we can perform variable interpolation using sprintf
context: {

View File

@@ -37,7 +37,7 @@
render: function( html ) {
var fields = html || '';
$(this.el).html( _.template( this.tpl, {
$(this.el).html(_.template(this.tpl)({
/* We pass the context object to the template so that
* we can perform variable interpolation using sprintf
*/

View File

@@ -11,7 +11,7 @@
},
render: function () {
this.$el.html(_.template(accountSettingsTemplate, {
this.$el.html(_.template(accountSettingsTemplate)({
sections: this.options.sectionsData
}));
return this;

View File

@@ -21,7 +21,7 @@
},
render: function () {
this.$el.html(_.template(learnerProfileTemplate, {
this.$el.html(_.template(learnerProfileTemplate)({
username: this.options.accountSettingsModel.get('username'),
ownProfile: this.options.ownProfile,
showFullProfile: this.showFullProfile()

View File

@@ -21,8 +21,7 @@
},
render: function() {
var renderedHtml = _.template(
$( '#error-tpl' ).html(),
var renderedHtml = _.template($( '#error-tpl' ).html())(
{
errorTitle: this.model.get( 'errorTitle' ),
errorMsg: this.model.get( 'errorMsg' )

View File

@@ -24,7 +24,7 @@
},
render: function() {
var renderedHtml = _.template( $( this.template ).html(), {} );
var renderedHtml = _.template( $( this.template ).html())({});
$( this.el ).html( renderedHtml );
// Set the submit button to disabled by default

View File

@@ -40,8 +40,7 @@
},
render: function() {
var renderedTemplate = _.template(
$( this.templateId ).html(),
var renderedTemplate = _.template($( this.templateId ).html())(
{
courseKey: this.courseKey,
platformName: this.platformName

View File

@@ -1,3 +1,5 @@
/*global jQuery, _, Backbone, gettext */
/**
* Base view for defining steps in the payment/verification flow.
*
@@ -8,7 +10,7 @@
*/
var edx = edx || {};
(function( $, _, _s, Backbone, gettext ) {
(function( $, _, Backbone, gettext ) {
'use strict';
edx.verify_student = edx.verify_student || {};
@@ -20,9 +22,9 @@
/* Mix non-conflicting functions from underscore.string
* (all but include, contains, and reverse) into the
* Underscore namespace
* Underscore namespace.
*/
_.mixin( _s.exports() );
_.mixin(_.str.exports());
},
render: function() {
@@ -33,7 +35,7 @@
this.updateContext( this.templateContext() ).done(
function( templateContext ) {
// Render the template into the DOM
$( this.el ).html( _.template( templateHtml, templateContext ) );
$( this.el ).html( _.template( templateHtml)( templateContext ) );
// Allow subclasses to install custom event handlers
this.postRender();
@@ -101,4 +103,4 @@
});
})( jQuery, _, _.str, Backbone, gettext );
})( jQuery, _, Backbone, gettext );

View File

@@ -242,8 +242,7 @@
this.setSubmitButtonEnabled( false );
// Load the template for the webcam into the DOM
renderedHtml = _.template(
$( this.template ).html(),
renderedHtml = _.template($( this.template ).html())(
{ backendName: this.backend.name }
);
$( this.el ).html( renderedHtml );

View File

@@ -17,7 +17,7 @@
if (_.isUndefined(this.message) || _.isNull(this.message)) {
this.$el.html('');
} else {
this.$el.html(_.template(messageBannerTemplate, _.extend(this.options, {
this.$el.html(_.template(messageBannerTemplate)(_.extend(this.options, {
message: this.message
})));
}

View File

@@ -66,6 +66,7 @@
'jquery.url': 'empty:',
'backbone': 'empty:',
'underscore': 'empty:',
'underscore.string': 'empty:',
'logger': 'empty:',
'utility': 'empty:',
'URI': 'empty:',

View File

@@ -18,7 +18,12 @@
}
};
defineDependency("jQuery", "jquery");
defineDependency("_", "underscore");
defineDependency("s", "underscore.string");
// Underscore.string no longer installs itself directly on "_". For compatibility with existing
// code, add it to "_" with its previous name.
if (window._ && window.s) {
window._.str = window.s;
}
defineDependency("gettext", "gettext");
defineDependency("Logger", "logger");
defineDependency("URI", "URI");

View File

@@ -19,7 +19,6 @@ from django.utils.translation import ugettext as _
</%block>
<%block name="js_extra">
<script src="${static.url('js/vendor/jquery.ajax-retry.js')}"></script>
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/src/tooltip_manager.js')}"></script>
<script src="${static.url('js/commerce/credit.js')}"></script>
<script src="${static.url('js/commerce/views/receipt_view.js')}"></script>

View File

@@ -254,13 +254,13 @@ from xmodule.tabs import CourseTabList
htmlStr = "${_('An error has occurred.')}";
% if settings.FEEDBACK_SUBMISSION_EMAIL:
htmlStr += " " + _.template(
"${_('Please {link_start}send us e-mail{link_end}.')}",
{link_start: '<a href="#" id="feedback_email">', link_end: '</a>'},
{interpolate: /\{(.+?)\}/g})
"${_('Please {link_start}send us e-mail{link_end}.')}", {interpolate: /\{(.+?)\}/g})(
{link_start: '<a href="#" id="feedback_email">', link_end: '</a>'}
);
% else:
// If no email is configured, we can't do much other than
// ask the user to try again later
htmlStr += "${_('Please try again later.')}";
htmlStr += " " + "${_('Please try again later.')}";
% endif
$("#feedback_error").html(htmlStr).stop().css("display", "block");
% if settings.FEEDBACK_SUBMISSION_EMAIL:

View File

@@ -18,7 +18,6 @@ from django.utils.translation import ugettext as _
% endfor
</%block>
<%block name="js_extra">
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/src/tooltip_manager.js')}"></script>
<%static:js group='incourse_reverify'/>
</%block>

View File

@@ -41,7 +41,6 @@ from lms.djangoapps.verify_student.views import PayAndVerifyView
% endfor
</%block>
<%block name="js_extra">
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/src/tooltip_manager.js')}"></script>
<%static:js group='verify_student'/>
</%block>

View File

@@ -16,7 +16,6 @@ from django.utils.translation import ugettext as _
% endfor
</%block>
<%block name="js_extra">
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/src/tooltip_manager.js')}"></script>
<%static:js group='reverify'/>
</%block>

View File

@@ -6,7 +6,8 @@
"edx-pattern-library": "0.10.4",
"requirejs": "~2.1.22",
"uglify-js": "2.4.24",
"underscore": "1.4.4"
"underscore": "~1.8.3",
"underscore.string": "~3.3.4"
},
"devDependencies": {
"jshint": "^2.7.0",