Cohort discussion topics via UI in instructor dashboard.
TNL-1256
This commit is contained in:
committed by
Usman Khalid
parent
e07f45b5dd
commit
e6c75529c0
14
lms/static/js/groups/models/cohort_discussions.js
Normal file
14
lms/static/js/groups/models/cohort_discussions.js
Normal file
@@ -0,0 +1,14 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function(Backbone) {
|
||||
'use strict';
|
||||
|
||||
edx.groups = edx.groups || {};
|
||||
|
||||
edx.groups.DiscussionTopicsSettingsModel = Backbone.Model.extend({
|
||||
defaults: {
|
||||
course_wide_discussions: {},
|
||||
inline_discussions: {}
|
||||
}
|
||||
});
|
||||
}).call(this, Backbone);
|
||||
@@ -9,7 +9,8 @@ var edx = edx || {};
|
||||
idAttribute: 'id',
|
||||
defaults: {
|
||||
is_cohorted: false,
|
||||
cohorted_discussions: [],
|
||||
cohorted_inline_discussions: [],
|
||||
cohorted_course_wide_discussions:[],
|
||||
always_cohort_inline_discussions: true
|
||||
}
|
||||
});
|
||||
|
||||
99
lms/static/js/groups/views/cohort_discussions.js
Normal file
99
lms/static/js/groups/views/cohort_discussions.js
Normal file
@@ -0,0 +1,99 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function ($, _, Backbone, gettext, interpolate_text, NotificationModel, NotificationView) {
|
||||
'use strict';
|
||||
|
||||
edx.groups = edx.groups || {};
|
||||
|
||||
edx.groups.CohortDiscussionConfigurationView = Backbone.View.extend({
|
||||
|
||||
/**
|
||||
* Add/Remove the disabled attribute on given element.
|
||||
* @param {object} $element - The element to disable/enable.
|
||||
* @param {bool} disable - The flag to add/remove 'disabled' attribute.
|
||||
*/
|
||||
setDisabled: function($element, disable) {
|
||||
$element.prop('disabled', disable ? 'disabled' : false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the cohorted discussions list.
|
||||
* @param {string} selector - To select the discussion elements whose ids to return.
|
||||
* @returns {Array} - Cohorted discussions.
|
||||
*/
|
||||
getCohortedDiscussions: function(selector) {
|
||||
var self=this,
|
||||
cohortedDiscussions = [];
|
||||
|
||||
_.each(self.$(selector), function (topic) {
|
||||
cohortedDiscussions.push($(topic).data('id'))
|
||||
});
|
||||
return cohortedDiscussions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the cohortSettings' changed attributes to the server via PATCH method.
|
||||
* It shows the error message(s) if any.
|
||||
* @param {object} $element - Messages would be shown before this element.
|
||||
* @param {object} fieldData - Data to update on the server.
|
||||
*/
|
||||
saveForm: function ($element, fieldData) {
|
||||
var self = this,
|
||||
cohortSettingsModel = this.cohortSettings,
|
||||
saveOperation = $.Deferred(),
|
||||
showErrorMessage;
|
||||
|
||||
showErrorMessage = function (message, $element) {
|
||||
self.showMessage(message, $element, 'error');
|
||||
};
|
||||
this.removeNotification();
|
||||
|
||||
cohortSettingsModel.save(
|
||||
fieldData, {patch: true, wait: true}
|
||||
).done(function () {
|
||||
saveOperation.resolve();
|
||||
}).fail(function (result) {
|
||||
var errorMessage = null;
|
||||
try {
|
||||
var jsonResponse = JSON.parse(result.responseText);
|
||||
errorMessage = jsonResponse.error;
|
||||
} catch (e) {
|
||||
// Ignore the exception and show the default error message instead.
|
||||
}
|
||||
if (!errorMessage) {
|
||||
errorMessage = gettext("We've encountered an error. Refresh your browser and then try again.");
|
||||
}
|
||||
showErrorMessage(errorMessage, $element);
|
||||
saveOperation.reject();
|
||||
});
|
||||
return saveOperation.promise();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the notification messages before given element using the NotificationModel.
|
||||
* @param {string} message - Text message to show.
|
||||
* @param {object} $element - Message would be shown before this element.
|
||||
* @param {string} type - Type of message to show e.g. confirmation or error.
|
||||
*/
|
||||
showMessage: function (message, $element, type) {
|
||||
var model = new NotificationModel({type: type || 'confirmation', title: message});
|
||||
this.removeNotification();
|
||||
this.notification = new NotificationView({
|
||||
model: model
|
||||
});
|
||||
$element.before(this.notification.$el);
|
||||
this.notification.render();
|
||||
},
|
||||
|
||||
/**
|
||||
*Removes the notification messages.
|
||||
*/
|
||||
removeNotification: function () {
|
||||
if (this.notification) {
|
||||
this.notification.remove();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}).call(this, $, _, Backbone, gettext, interpolate_text, NotificationModel, NotificationView
|
||||
);
|
||||
83
lms/static/js/groups/views/cohort_discussions_course_wide.js
Normal file
83
lms/static/js/groups/views/cohort_discussions_course_wide.js
Normal file
@@ -0,0 +1,83 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function ($, _, Backbone, gettext, interpolate_text, CohortDiscussionConfigurationView) {
|
||||
'use strict';
|
||||
|
||||
edx.groups = edx.groups || {};
|
||||
|
||||
edx.groups.CourseWideDiscussionsView = CohortDiscussionConfigurationView.extend({
|
||||
events: {
|
||||
'change .check-discussion-subcategory-course-wide': 'discussionCategoryStateChanged',
|
||||
'click .cohort-course-wide-discussions-form .action-save': 'saveCourseWideDiscussionsForm'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.template = _.template($('#cohort-discussions-course-wide-tpl').text());
|
||||
this.cohortSettings = options.cohortSettings;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$('.cohort-course-wide-discussions-nav').html(this.template({
|
||||
courseWideTopics: this.getCourseWideDiscussionsHtml(
|
||||
this.model.get('course_wide_discussions')
|
||||
)
|
||||
}));
|
||||
this.setDisabled(this.$('.cohort-course-wide-discussions-form .action-save'), true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the html list for course-wide discussion topics.
|
||||
* @param {object} courseWideDiscussions - course-wide discussions object from server.
|
||||
* @returns {Array} - HTML list for course-wide discussion topics.
|
||||
*/
|
||||
getCourseWideDiscussionsHtml: function (courseWideDiscussions) {
|
||||
var subCategoryTemplate = _.template($('#cohort-discussions-subcategory-tpl').html()),
|
||||
entries = courseWideDiscussions.entries,
|
||||
children = courseWideDiscussions.children;
|
||||
|
||||
return _.map(children, function (name) {
|
||||
var entry = entries[name];
|
||||
return subCategoryTemplate({
|
||||
name: name,
|
||||
id: entry.id,
|
||||
is_cohorted: entry.is_cohorted,
|
||||
type: 'course-wide'
|
||||
});
|
||||
}).join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the save button for course-wide discussions.
|
||||
*/
|
||||
discussionCategoryStateChanged: function(event) {
|
||||
event.preventDefault();
|
||||
this.setDisabled(this.$('.cohort-course-wide-discussions-form .action-save'), false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends the cohorted_course_wide_discussions to the server and renders the view.
|
||||
*/
|
||||
saveCourseWideDiscussionsForm: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var self = this,
|
||||
courseWideCohortedDiscussions = self.getCohortedDiscussions(
|
||||
'.check-discussion-subcategory-course-wide:checked'
|
||||
),
|
||||
fieldData = { cohorted_course_wide_discussions: courseWideCohortedDiscussions };
|
||||
|
||||
self.saveForm(self.$('.course-wide-discussion-topics'),fieldData)
|
||||
.done(function () {
|
||||
self.model.fetch()
|
||||
.done(function () {
|
||||
self.render();
|
||||
self.showMessage(gettext('Your changes have been saved.'), self.$('.course-wide-discussion-topics'));
|
||||
}).fail(function() {
|
||||
var errorMessage = gettext("We've encountered an error. Refresh your browser and then try again.");
|
||||
self.showMessage(errorMessage, self.$('.course-wide-discussion-topics'), 'error')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortDiscussionConfigurationView);
|
||||
145
lms/static/js/groups/views/cohort_discussions_inline.js
Normal file
145
lms/static/js/groups/views/cohort_discussions_inline.js
Normal file
@@ -0,0 +1,145 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function ($, _, Backbone, gettext, interpolate_text, CohortDiscussionConfigurationView) {
|
||||
'use strict';
|
||||
|
||||
edx.groups = edx.groups || {};
|
||||
|
||||
edx.groups.InlineDiscussionsView = CohortDiscussionConfigurationView.extend({
|
||||
events: {
|
||||
'change .check-discussion-category': 'setSaveButton',
|
||||
'change .check-discussion-subcategory-inline': 'setSaveButton',
|
||||
'click .cohort-inline-discussions-form .action-save': 'saveInlineDiscussionsForm',
|
||||
'change .check-all-inline-discussions': 'setAllInlineDiscussions',
|
||||
'change .check-cohort-inline-discussions': 'setSomeInlineDiscussions'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.template = _.template($('#cohort-discussions-inline-tpl').text());
|
||||
this.cohortSettings = options.cohortSettings;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var alwaysCohortInlineDiscussions = this.cohortSettings.get('always_cohort_inline_discussions');
|
||||
|
||||
this.$('.cohort-inline-discussions-nav').html(this.template({
|
||||
inlineDiscussionTopics: this.getInlineDiscussionsHtml(this.model.get('inline_discussions')),
|
||||
alwaysCohortInlineDiscussions:alwaysCohortInlineDiscussions
|
||||
}));
|
||||
|
||||
// Provides the semantics for a nested list of tri-state checkboxes.
|
||||
// When attached to a jQuery element it listens for change events to
|
||||
// input[type=checkbox] elements, and updates the checked and indeterminate
|
||||
// based on the checked values of any checkboxes in child elements of the DOM.
|
||||
this.$('ul.inline-topics').qubit();
|
||||
|
||||
this.setElementsEnabled(alwaysCohortInlineDiscussions, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate html list for inline discussion topics.
|
||||
* @params {object} inlineDiscussions - inline discussions object from server.
|
||||
* @returns {Array} - HTML for inline discussion topics.
|
||||
*/
|
||||
getInlineDiscussionsHtml: function (inlineDiscussions) {
|
||||
var categoryTemplate = _.template($('#cohort-discussions-category-tpl').html()),
|
||||
entryTemplate = _.template($('#cohort-discussions-subcategory-tpl').html()),
|
||||
isCategoryCohorted = false,
|
||||
children = inlineDiscussions.children,
|
||||
entries = inlineDiscussions.entries,
|
||||
subcategories = inlineDiscussions.subcategories;
|
||||
|
||||
return _.map(children, function (name) {
|
||||
var html = '', entry;
|
||||
if (entries && _.has(entries, name)) {
|
||||
entry = entries[name];
|
||||
html = entryTemplate({
|
||||
name: name,
|
||||
id: entry.id,
|
||||
is_cohorted: entry.is_cohorted,
|
||||
type: 'inline'
|
||||
});
|
||||
} else { // subcategory
|
||||
html = categoryTemplate({
|
||||
name: name,
|
||||
entries: this.getInlineDiscussionsHtml(subcategories[name]),
|
||||
isCategoryCohorted: isCategoryCohorted
|
||||
});
|
||||
}
|
||||
return html;
|
||||
}, this).join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable/Disable the inline discussion elements.
|
||||
*
|
||||
* Disables the category and sub-category checkboxes.
|
||||
* Enables the save button.
|
||||
*/
|
||||
setAllInlineDiscussions: function(event) {
|
||||
event.preventDefault();
|
||||
this.setElementsEnabled(($(event.currentTarget).prop('checked')), false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the inline discussion elements.
|
||||
*
|
||||
* Enables the category and sub-category checkboxes.
|
||||
* Enables the save button.
|
||||
*/
|
||||
setSomeInlineDiscussions: function(event) {
|
||||
event.preventDefault();
|
||||
this.setElementsEnabled(!($(event.currentTarget).prop('checked')), false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable/Disable the inline discussion elements.
|
||||
*
|
||||
* Enable/Disable the category and sub-category checkboxes.
|
||||
* Enable/Disable the save button.
|
||||
* @param {bool} enable_checkboxes - The flag to enable/disable the checkboxes.
|
||||
* @param {bool} enable_save_button - The flag to enable/disable the save button.
|
||||
*/
|
||||
setElementsEnabled: function(enable_checkboxes, enable_save_button) {
|
||||
this.setDisabled(this.$('.check-discussion-category'), enable_checkboxes);
|
||||
this.setDisabled(this.$('.check-discussion-subcategory-inline'), enable_checkboxes);
|
||||
this.setDisabled(this.$('.cohort-inline-discussions-form .action-save'), enable_save_button);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the save button for inline discussions.
|
||||
*/
|
||||
setSaveButton: function(event) {
|
||||
this.setDisabled(this.$('.cohort-inline-discussions-form .action-save'), false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends the cohorted_inline_discussions to the server and renders the view.
|
||||
*/
|
||||
saveInlineDiscussionsForm: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var self = this,
|
||||
cohortedInlineDiscussions = self.getCohortedDiscussions(
|
||||
'.check-discussion-subcategory-inline:checked'
|
||||
),
|
||||
fieldData= {
|
||||
cohorted_inline_discussions: cohortedInlineDiscussions,
|
||||
always_cohort_inline_discussions: self.$('.check-all-inline-discussions').prop('checked')
|
||||
};
|
||||
|
||||
self.saveForm(self.$('.inline-discussion-topics'), fieldData)
|
||||
.done(function () {
|
||||
self.model.fetch()
|
||||
.done(function () {
|
||||
self.render();
|
||||
self.showMessage(gettext('Your changes have been saved.'), self.$('.inline-discussion-topics'));
|
||||
}).fail(function() {
|
||||
var errorMessage = gettext("We've encountered an error. Refresh your browser and then try again.");
|
||||
self.showMessage(errorMessage, self.$('.inline-discussion-topics'), 'error')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortDiscussionConfigurationView);
|
||||
@@ -44,8 +44,7 @@ var edx = edx || {};
|
||||
|
||||
renderGroupHeader: function() {
|
||||
this.$('.cohort-management-group-header').html(this.groupHeaderTemplate({
|
||||
cohort: this.model,
|
||||
studioAdvancedSettingsUrl: this.context.studioAdvancedSettingsUrl
|
||||
cohort: this.model
|
||||
}));
|
||||
},
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function($, _, Backbone, gettext, interpolate_text, CohortModel, CohortEditorView, CohortFormView,
|
||||
CourseCohortSettingsNotificationView, NotificationModel, NotificationView, FileUploaderView) {
|
||||
CourseCohortSettingsNotificationView, NotificationModel, NotificationView, FileUploaderView,
|
||||
InlineDiscussionsView, CourseWideDiscussionsView) {
|
||||
'use strict';
|
||||
|
||||
var hiddenClass = 'is-hidden',
|
||||
@@ -17,7 +18,8 @@ var edx = edx || {};
|
||||
'click .cohort-management-add-form .action-save': 'saveAddCohortForm',
|
||||
'click .cohort-management-add-form .action-cancel': 'cancelAddCohortForm',
|
||||
'click .link-cross-reference': 'showSection',
|
||||
'click .toggle-cohort-management-secondary': 'showCsvUpload'
|
||||
'click .toggle-cohort-management-secondary': 'showCsvUpload',
|
||||
'click .toggle-cohort-management-discussions': 'showDiscussionTopics'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
@@ -120,7 +122,7 @@ var edx = edx || {};
|
||||
fieldData = {is_cohorted: this.getCohortsEnabled()};
|
||||
cohortSettings = this.cohortSettings;
|
||||
cohortSettings.save(
|
||||
fieldData, {wait: true}
|
||||
fieldData, {patch: true, wait: true}
|
||||
).done(function() {
|
||||
self.render();
|
||||
self.renderCourseCohortSettingsNotificationView();
|
||||
@@ -277,6 +279,27 @@ var edx = edx || {};
|
||||
this.$('#file-upload-form-file').focus();
|
||||
}
|
||||
},
|
||||
showDiscussionTopics: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
$(event.currentTarget).addClass(hiddenClass);
|
||||
var cohortDiscussionsElement = this.$('.cohort-discussions-nav').removeClass(hiddenClass);
|
||||
|
||||
if (!this.CourseWideDiscussionsView) {
|
||||
this.CourseWideDiscussionsView = new CourseWideDiscussionsView({
|
||||
el: cohortDiscussionsElement,
|
||||
model: this.context.discussionTopicsSettingsModel,
|
||||
cohortSettings: this.cohortSettings
|
||||
}).render();
|
||||
}
|
||||
if(!this.InlineDiscussionsView) {
|
||||
this.InlineDiscussionsView = new InlineDiscussionsView({
|
||||
el: cohortDiscussionsElement,
|
||||
model: this.context.discussionTopicsSettingsModel,
|
||||
cohortSettings: this.cohortSettings
|
||||
}).render();
|
||||
}
|
||||
},
|
||||
|
||||
getSectionCss: function (section) {
|
||||
return ".instructor-nav .nav-item a[data-section='" + section + "']";
|
||||
@@ -284,4 +307,4 @@ var edx = edx || {};
|
||||
});
|
||||
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortModel, edx.groups.CohortEditorView,
|
||||
edx.groups.CohortFormView, edx.groups.CourseCohortSettingsNotificationView, NotificationModel, NotificationView,
|
||||
FileUploaderView);
|
||||
FileUploaderView, edx.groups.InlineDiscussionsView, edx.groups.CourseWideDiscussionsView);
|
||||
|
||||
41
lms/static/js/groups/views/cohorts_dashboard_factory.js
Normal file
41
lms/static/js/groups/views/cohorts_dashboard_factory.js
Normal file
@@ -0,0 +1,41 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define(['jquery', 'js/groups/views/cohorts', 'js/groups/collections/cohort', 'js/groups/models/course_cohort_settings',
|
||||
'js/groups/models/cohort_discussions'],
|
||||
function($) {
|
||||
|
||||
return function(contentGroups, studioGroupConfigurationsUrl) {
|
||||
|
||||
var cohorts = new edx.groups.CohortCollection(),
|
||||
courseCohortSettings = new edx.groups.CourseCohortSettingsModel(),
|
||||
discussionTopicsSettings = new edx.groups.DiscussionTopicsSettingsModel();
|
||||
|
||||
var cohortManagementElement = $('.cohort-management');
|
||||
|
||||
cohorts.url = cohortManagementElement.data('cohorts_url');
|
||||
courseCohortSettings.url = cohortManagementElement.data('course_cohort_settings_url');
|
||||
discussionTopicsSettings.url = cohortManagementElement.data('discussion-topics-url');
|
||||
|
||||
var cohortsView = new edx.groups.CohortsView({
|
||||
el: cohortManagementElement,
|
||||
model: cohorts,
|
||||
contentGroups: contentGroups,
|
||||
cohortSettings: courseCohortSettings,
|
||||
context: {
|
||||
discussionTopicsSettingsModel: discussionTopicsSettings,
|
||||
uploadCohortsCsvUrl: cohortManagementElement.data('upload_cohorts_csv_url'),
|
||||
studioGroupConfigurationsUrl: studioGroupConfigurationsUrl
|
||||
}
|
||||
});
|
||||
|
||||
cohorts.fetch().done(function() {
|
||||
courseCohortSettings.fetch().done(function() {
|
||||
discussionTopicsSettings.fetch().done(function() {
|
||||
cohortsView.render();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
Reference in New Issue
Block a user