diff --git a/cms/static/js/certificates/views/signatory_editor.js b/cms/static/js/certificates/views/signatory_editor.js index 2bd6e2f890ab..d446ea630f26 100644 --- a/cms/static/js/certificates/views/signatory_editor.js +++ b/cms/static/js/certificates/views/signatory_editor.js @@ -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: { diff --git a/cms/static/js/models/settings/course_grader.js b/cms/static/js/models/settings/course_grader.js index 7f7716eb8b22..f31e832bacca 100644 --- a/cms/static/js/models/settings/course_grader.js +++ b/cms/static/js/models/settings/course_grader.js @@ -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; } diff --git a/cms/static/js/models/uploads.js b/cms/static/js/models/uploads.js index 7a19b3c4bdde..6eaf020f6079 100644 --- a/cms/static/js/models/uploads.js +++ b/cms/static/js/models/uploads.js @@ -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) diff --git a/cms/static/js/utils/drag_and_drop.js b/cms/static/js/utils/drag_and_drop.js index 6228a3201974..1393c870a3ea 100644 --- a/cms/static/js/utils/drag_and_drop.js +++ b/cms/static/js/utils/drag_and_drop.js @@ -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) { diff --git a/cms/static/js/views/assets.js b/cms/static/js/views/assets.js index 0a1c4967eb39..f9694096d3ca 100644 --- a/cms/static/js/views/assets.js +++ b/cms/static/js/views/assets.js @@ -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')}); diff --git a/cms/static/js/views/edit_chapter.js b/cms/static/js/views/edit_chapter.js index f70839c2d4b2..895e932f3494 100644 --- a/cms/static/js/views/edit_chapter.js +++ b/cms/static/js/views/edit_chapter.js @@ -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'] }); diff --git a/cms/static/js/views/manage_users_and_roles.js b/cms/static/js/views/manage_users_and_roles.js index dc2202315859..f9d154696ef5 100644 --- a/cms/static/js/views/manage_users_and_roles.js +++ b/cms/static/js/views/manage_users_and_roles.js @@ -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: { diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js deleted file mode 100644 index 12e67280631b..000000000000 --- a/cms/static/js/views/overview.js +++ /dev/null @@ -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 = $(' ' + - gettext('Collapse All Sections') + ''); - var $labelExpanded = $(' ' + - gettext('Expand All Sections') + ''); - - 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( - '' + - '' + gettext("Release date:") + ' ' + - gettext("{month}/{day}/{year} at {hour}:{minute} UTC") + - '' + - ' ' + - gettext("Edit section release date") + - '', - {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 - }; - }); diff --git a/cms/static/js/views/paging_header.js b/cms/static/js/views/paging_header.js index 25c23acf4854..662faf2139c2 100644 --- a/cms/static/js/views/paging_header.js +++ b/cms/static/js/views/paging_header.js @@ -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; diff --git a/cms/static/js/views/show_textbook.js b/cms/static/js/views/show_textbook.js index 2dcc47015469..9f0ecd316a8c 100644 --- a/cms/static/js/views/show_textbook.js +++ b/cms/static/js/views/show_textbook.js @@ -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."), diff --git a/cms/static/js/views/video/transcripts/file_uploader.js b/cms/static/js/views/video/transcripts/file_uploader.js index 77e967ce926a..41f69dd3b75e 100644 --- a/cms/static/js/views/video/transcripts/file_uploader.js +++ b/cms/static/js/views/video/transcripts/file_uploader.js @@ -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(); diff --git a/cms/static/js/views/video/transcripts/message_manager.js b/cms/static/js/views/video/transcripts/message_manager.js index ef15c9d3048d..d405b713e223 100644 --- a/cms/static/js/views/video/transcripts/message_manager.js +++ b/cms/static/js/views/video/transcripts/message_manager.js @@ -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'); diff --git a/cms/templates/js/validation-error-modal.underscore b/cms/templates/js/validation-error-modal.underscore index 5d82d7cd0616..0347b8a06f1c 100644 --- a/cms/templates/js/validation-error-modal.underscore +++ b/cms/templates/js/validation-error-modal.underscore @@ -2,17 +2,17 @@

<%= _.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:'', - num_errors: num_errors, - strong_end: '' - }, - {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:'', + num_errors: num_errors, + strong_end: '' + })%> <%= gettext("Please check the following validation feedbacks and reflect them in your course settings:")%>

diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js index 922908b74354..a8f8fd789b06 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js @@ -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); }); diff --git a/common/lib/xmodule/xmodule/js/src/html/imageModal.js b/common/lib/xmodule/xmodule/js/src/html/imageModal.js index d357ee5763fb..5577c57410dc 100644 --- a/common/lib/xmodule/xmodule/js/src/html/imageModal.js +++ b/common/lib/xmodule/xmodule/js/src/html/imageModal.js @@ -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); } }); diff --git a/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee index 41f9511e7ec4..b68c9538da92 100644 --- a/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee @@ -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() diff --git a/common/static/coffee/src/discussion/discussion_filter.coffee b/common/static/coffee/src/discussion/discussion_filter.coffee deleted file mode 100644 index f9cc710e0ddb..000000000000 --- a/common/static/coffee/src/discussion/discussion_filter.coffee +++ /dev/null @@ -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'); diff --git a/common/static/coffee/src/discussion/views/discussion_thread_edit_view.js b/common/static/coffee/src/discussion/views/discussion_thread_edit_view.js index 21e71e79f674..8f954c5668a2 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_edit_view.js +++ b/common/static/coffee/src/discussion/views/discussion_thread_edit_view.js @@ -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; }, diff --git a/common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee b/common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee index a01ef013d2e7..512df6340501 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee @@ -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('<%- username %>', { + _.template('<%- username %>')({ url: DiscussionUtil.urlFor("user_profile", response.users[0].id), username: response.users[0].username }) diff --git a/common/static/coffee/src/discussion/views/discussion_topic_menu_view.js b/common/static/coffee/src/discussion/views/discussion_topic_menu_view.js index c205a7535ed9..b7350fb0f766 100644 --- a/common/static/coffee/src/discussion/views/discussion_topic_menu_view.js +++ b/common/static/coffee/src/discussion/views/discussion_topic_menu_view.js @@ -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'); + } + }); } }); } diff --git a/common/static/coffee/src/discussion/views/new_post_view.coffee b/common/static/coffee/src/discussion/views/new_post_view.coffee index 75ad7a91bc8c..375ec2761823 100644 --- a/common/static/coffee/src/discussion/views/new_post_view.coffee +++ b/common/static/coffee/src/discussion/views/new_post_view.coffee @@ -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') diff --git a/common/static/common/js/components/collections/paging_collection.js b/common/static/common/js/components/collections/paging_collection.js index a8af9098977c..0259b56c2c34 100644 --- a/common/static/common/js/components/collections/paging_collection.js +++ b/common/static/common/js/components/collections/paging_collection.js @@ -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); }, diff --git a/common/static/common/js/components/utils/view_utils.js b/common/static/common/js/components/utils/view_utils.js index 60226adaae9e..22f072f99e4a 100644 --- a/common/static/common/js/components/utils/view_utils.js +++ b/common/static/common/js/components/utils/view_utils.js @@ -244,7 +244,7 @@ if (!validateTotalKeyLength(key_field_selectors)) { $(selectors.errorWrapper).addClass(classes.shown).removeClass(classes.hiding); $(selectors.errorMessage).html( - '

' + _.template(message_tpl, {limit: MAX_SUM_KEY_LENGTH}) + '

' + '

' + _.template(message_tpl)({limit: MAX_SUM_KEY_LENGTH}) + '

' ); $(selectors.save).addClass(classes.disabled); } else { diff --git a/common/static/common/js/components/views/feedback_alert.js b/common/static/common/js/components/views/feedback_alert.js index 8f3f716a58cc..1b21974ce11f 100644 --- a/common/static/common/js/components/views/feedback_alert.js +++ b/common/static/common/js/components/views/feedback_alert.js @@ -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" diff --git a/common/static/common/js/components/views/feedback_notification.js b/common/static/common/js/components/views/feedback_notification.js index 2fb74f691d14..34910cb59efc 100644 --- a/common/static/common/js/components/views/feedback_notification.js +++ b/common/static/common/js/components/views/feedback_notification.js @@ -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", diff --git a/common/static/common/js/components/views/feedback_prompt.js b/common/static/common/js/components/views/feedback_prompt.js index 31c1e9b4ad97..be69d3001e84 100644 --- a/common/static/common/js/components/views/feedback_prompt.js +++ b/common/static/common/js/components/views/feedback_prompt.js @@ -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", diff --git a/common/static/common/js/components/views/paginated_view.js b/common/static/common/js/components/views/paginated_view.js index 0507d52cbdce..7755a93f1d31 100644 --- a/common/static/common/js/components/views/paginated_view.js +++ b/common/static/common/js/components/views/paginated_view.js @@ -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'); diff --git a/common/static/common/js/components/views/paging_footer.js b/common/static/common/js/components/views/paging_footer.js index 36d2c74f2a52..8b796b52b9ec 100644 --- a/common/static/common/js/components/views/paging_footer.js +++ b/common/static/common/js/components/views/paging_footer.js @@ -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 })); diff --git a/common/static/common/js/components/views/paging_header.js b/common/static/common/js/components/views/paging_header.js index c49af8bc4bc7..b7e8abe531ea 100644 --- a/common/static/common/js/components/views/paging_header.js +++ b/common/static/common/js/components/views/paging_header.js @@ -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, diff --git a/common/static/common/js/components/views/search_field.js b/common/static/common/js/components/views/search_field.js index 955133fe1c54..9cd1a7ca9067 100644 --- a/common/static/common/js/components/views/search_field.js +++ b/common/static/common/js/components/views/search_field.js @@ -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 diff --git a/common/static/common/js/utils/edx.utils.validate.js b/common/static/common/js/utils/edx.utils.validate.js index 4d82f9ff7a3d..4afb247ba1b9 100644 --- a/common/static/common/js/utils/edx.utils.validate.js +++ b/common/static/common/js/utils/edx.utils.validate.js @@ -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(){ diff --git a/common/static/common/templates/discussion/forum-actions.underscore b/common/static/common/templates/discussion/forum-actions.underscore index 5401e4118099..ac637a0bca93 100644 --- a/common/static/common/templates/discussion/forum-actions.underscore +++ b/common/static/common/templates/discussion/forum-actions.underscore @@ -1,6 +1,6 @@ <% if (!readOnly) { %>